diff --git a/.clang-format b/.clang-format index 24bfb9984..29688b683 100644 --- a/.clang-format +++ b/.clang-format @@ -8,18 +8,18 @@ AlignEscapedNewlines: Left AlignOperands: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true -AllowShortBlocksOnASingleLine: true +AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: Inline -AllowShortIfStatementsOnASingleLine: true +AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: true -AlwaysBreakTemplateDeclarations: true +AlwaysBreakTemplateDeclarations: Yes BinPackArguments: true BinPackParameters: true -BraceWrapping: +BraceWrapping: AfterClass: false AfterControlStatement: false AfterEnum: true @@ -28,6 +28,7 @@ BraceWrapping: AfterObjCDeclaration: false AfterStruct: false AfterUnion: false + AfterExternBlock: false BeforeCatch: true BeforeElse: true IndentBraces: false @@ -37,6 +38,7 @@ BraceWrapping: BreakBeforeBinaryOperators: None BreakBeforeBraces: Custom BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: AfterColon @@ -53,11 +55,12 @@ DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false FixNamespaceComments: true -ForEachMacros: +ForEachMacros: - foreach - Q_FOREACH - BOOST_FOREACH -IncludeCategories: +IncludeBlocks: Preserve +IncludeCategories: - Regex: '^<.*\.h>' Priority: 1 - Regex: '^<.*' @@ -66,7 +69,8 @@ IncludeCategories: Priority: 3 IncludeIsMainRegex: '([-_](test|unittest))?$' IndentCaseLabels: true -IndentWidth: 4 +IndentPPDirectives: None +IndentWidth: 4 IndentWrappedFunctionNames: false JavaScriptQuotes: Leave JavaScriptWrapImports: true @@ -75,6 +79,7 @@ MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 2 NamespaceIndentation: None +ObjCBinPackProtocolList: Auto ObjCBlockIndentWidth: 2 ObjCSpaceAfterProperty: false ObjCSpaceBeforeProtocolList: false @@ -83,6 +88,7 @@ PenaltyBreakBeforeFirstCallParameter: 1 PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Left @@ -92,7 +98,11 @@ SortUsingDeclarations: true SpaceAfterCStyleCast: false SpaceAfterTemplateKeyword: true SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 2 SpacesInAngles: false @@ -104,3 +114,4 @@ Standard: Auto TabWidth: 4 UseTab: Never ... + diff --git a/.travis.yml b/.travis.yml index 4adb31759..48007cd9c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -75,26 +75,22 @@ matrix: - cgal - fftw - ################################## - # KNOWN TO FAIL, so comment - ################################## - - # - os: osx - # env: - # - CACHE_NAME=osx-clang-mpich - # - CXX_COMPILER='clang++' C_COMPILER='clang' Fortran_COMPILER='gfortran' - # - MPI=mpich - # osx_image: xcode9 - - # - os: linux - # compiler: gcc - # env: - # - CACHE_NAME=linux-pgi-openmpi - # - CXX_COMPILER='pgc++' C_COMPILER='pgcc' Fortran_COMPILER='pgfortran' - # - MPI='openmpi' - # - PGI_VERSION="CommunityEdition" - # - ECKIT_CMAKE_OPTIONS="-DRT_LIB=/usr/lib/x86_64-linux-gnu/librt.so -DCURSES_LIBRARY=/usr/lib/x86_64-linux-gnu/libcurses.so" - # - ATLAS_CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=DEBUG -DENABLE_FORTRAN=OFF" # Fortran tests known to be broken with pgi/17.10 + - os: osx + env: + - CACHE_NAME=osx-clang-mpich + - CXX_COMPILER='clang++' C_COMPILER='clang' Fortran_COMPILER='gfortran' + - MPI=mpich + osx_image: xcode9 + + - os: linux + compiler: gcc + env: + - CACHE_NAME=linux-pgi-openmpi + - CXX_COMPILER='pgc++' C_COMPILER='pgcc' Fortran_COMPILER='pgfortran' + - MPI='openmpi' + - PGI_VERSION="CommunityEdition" + - ECKIT_CMAKE_OPTIONS="-DENABLE_ECKIT-395=OFF -DRT_LIB=/usr/lib/x86_64-linux-gnu/librt.so -DCURSES_LIBRARY=/usr/lib/x86_64-linux-gnu/libcurses.so" + - ATLAS_CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=DEBUG" before_install: diff --git a/CHANGELOG.md b/CHANGELOG.md index 994fad0a9..4751d64f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,21 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ## [Unreleased] +## [0.18.0] - 2019-07-15 +### Changed +- Make grid hashes crossplatform + +### Added +- Fortran: Can now use TransLocal +- Fortran: Can now create unstructured grids +- LonLat Bounding box computations for grids using its projection +- Serialisation of Mesh Connectivity tables to/from eckit::Stream + +### Fixed +- Structured interpolation bugs +- StructuredColumns bug with iSend +- Memory corruption in Spectral functionspace with GT CUDA backend + ## [0.17.2] - 2019-06-04 ### Fixed - Compilation with PGI 19.4 @@ -113,6 +128,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.18.0]: https://github.com/ecmwf/atlas/compare/0.17.2...0.18.0 [0.17.2]: https://github.com/ecmwf/atlas/compare/0.17.1...0.17.2 [0.17.1]: https://github.com/ecmwf/atlas/compare/0.17.0...0.17.1 [0.17.0]: https://github.com/ecmwf/atlas/compare/0.16.0...0.17.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index a5350bbf0..12e00d637 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,8 @@ ecbuild_debug( " ECKIT_FEATURES : [${ECKIT_FEATURES}]" ) # options & dependencies -ecbuild_add_cxx11_flags() +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) ecbuild_find_python() @@ -239,12 +240,48 @@ ecbuild_add_option( FEATURE SANDBOX DESCRIPTION "Build the sandbox stuff" ) +### use of atlas-run for tests +ecbuild_add_option( FEATURE ATLAS_RUN + DEFAULT ON + DESCRIPTION "Use atlas/tools/atlas-run to run atlas tests" ) + +if( HAVE_ATLAS_RUN ) + set( MPIEXEC_EXECUTABLE ${CMAKE_CURRENT_SOURCE_DIR}/tools/atlas-run ) + set( MPIEXEC_NUMPROC_FLAG='-n' ) + set( CMAKE_CROSSCOMPILING_EMULATOR ${CMAKE_CURRENT_SOURCE_DIR}/tools/atlas-run ) +endif() + ################################################################################ # sources set( MIR_NEEDS_TRANSI TRUE CACHE BOOL "Deprecated" INTERNAL ) include(CompileFlags) + +find_program (CLANG_TIDY_EXE NAMES "clang-tidy" ) +if( CLANG_TIDY_EXE ) + message(STATUS "Found clang-tidy: ${CLANG_TIDY_EXE}") +endif() +ecbuild_add_option( FEATURE CLANG_TIDY + DESCRIPTION "Use clang-tidy" + CONDITION CLANG_TIDY_EXE ) +if (HAVE_CLANG_TIDY) + set(CLANG_TIDY_CHECKS "-*,readability-braces-around-statements,redundant-string-init") + set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_EXE};-checks=${CLANG_TIDY_CHECKS};-header-filter='${CMAKE_SOURCE_DIR}/*'") +endif() + +find_program (INCLUDE_WHAT_YOU_USE_EXE NAMES "include-what-you-use" ) +if( INCLUDE_WHAT_YOU_USE_EXE ) + message(STATUS "Found include-what-you-use: ${INCLUDE_WHAT_YOU_USE_EXE}" ) +endif() +ecbuild_add_option( FEATURE INCLUDE_WHAT_YOU_USE + DEFAULT OFF # Need clang compiler? + DESCRIPTION "Use include-what-you-use clang-tool" + CONDITION INCLUDE_WHAT_YOU_USE_EXE ) +if( HAVE_INCLUDE_WHAT_YOU_USE ) + set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${INCLUDE_WHAT_YOU_USE_EXE}) +endif() + add_subdirectory( src ) ################################################################################ diff --git a/VERSION.cmake b/VERSION.cmake index f146c319a..fca3a7539 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.17.2" ) +set ( ${PROJECT_NAME}_VERSION_STR "0.18.0" ) diff --git a/doc/example-grids/classic_gaussian_1.json b/doc/example-grids/classic_gaussian_1.json deleted file mode 100644 index c8283931a..000000000 --- a/doc/example-grids/classic_gaussian_1.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "//" : "Classic Gaussian grid 'N16'", - - "type" : "classic_gaussian", - "N" : 16 -} diff --git a/doc/example-grids/classic_gaussian_1.yml b/doc/example-grids/classic_gaussian_1.yml new file mode 100644 index 000000000..93399501a --- /dev/null +++ b/doc/example-grids/classic_gaussian_1.yml @@ -0,0 +1,10 @@ +type : "classic_gaussian" +N : 16 + + +check : + size : 1688 + lonlat(first) : [0,85.7606] + lonlat(last) : [342,-85.7606] + uid : 49cbbc2cde26050896e000d1e0f5fb7b + bounding_box(n,w,s,e) : [90,0,-90,360] diff --git a/doc/example-grids/classic_gaussian_2.json b/doc/example-grids/classic_gaussian_2.json deleted file mode 100644 index 04cb54ede..000000000 --- a/doc/example-grids/classic_gaussian_2.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "//" : "Classic Gaussian grid 'N16'", - - "type" : "classic_gaussian", - "N" : 16, - "projection" : { "type": "rotated_schmidt", "stretching_factor": 2.0, "north_pole": [3.0,47.0] } -} diff --git a/doc/example-grids/classic_gaussian_2.yml b/doc/example-grids/classic_gaussian_2.yml new file mode 100644 index 000000000..a9c6b4165 --- /dev/null +++ b/doc/example-grids/classic_gaussian_2.yml @@ -0,0 +1,16 @@ +# Classic Gaussian grid 'N16' + +type : "classic_gaussian" +N : 16 +projection : + type : "rotated_schmidt" + stretching_factor : 2.0 + north_pole : [3.0,47.0] + + +check : + size : 1688 + lonlat(first) : [3,44.8796] + lonlat(last) : [-172.453,-54.9736] + uid : 64d609c6ee4b036b209047aef97a10eb + bounding_box(n,w,s,e) : [90,0,-90,360] diff --git a/doc/example-grids/classic_gaussian_3.json b/doc/example-grids/classic_gaussian_3.json deleted file mode 100644 index 9569d47ed..000000000 --- a/doc/example-grids/classic_gaussian_3.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "//" : "Classic Gaussian grid 'O16'", - - "name" : "N16" -} diff --git a/doc/example-grids/classic_gaussian_3.yml b/doc/example-grids/classic_gaussian_3.yml new file mode 100644 index 000000000..7199ff429 --- /dev/null +++ b/doc/example-grids/classic_gaussian_3.yml @@ -0,0 +1,11 @@ +# Classic Gaussian grid 'O16' + +name : "N16" + + +check : + size : 1688 + lonlat(first) : [0,85.7606] + lonlat(last) : [342,-85.7606] + uid : 49cbbc2cde26050896e000d1e0f5fb7b + bounding_box(n,w,s,e) : [90,0,-90,360] diff --git a/doc/example-grids/cropped_classic_gaussian_1.json b/doc/example-grids/cropped_classic_gaussian_1.json deleted file mode 100644 index 7879c5ec9..000000000 --- a/doc/example-grids/cropped_classic_gaussian_1.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "//" : "Classic Gaussian grid 'N16'", - - "type" : "classic_gaussian", - "N" : 16, - - "domain" : { "type": "zonal_band", "ymax": 90, "ymin": 45 } -} diff --git a/doc/example-grids/cropped_classic_gaussian_1.yml b/doc/example-grids/cropped_classic_gaussian_1.yml new file mode 100644 index 000000000..1e6c2983c --- /dev/null +++ b/doc/example-grids/cropped_classic_gaussian_1.yml @@ -0,0 +1,17 @@ +# Classic Gaussian grid 'N16' + +type : "classic_gaussian" +N : 16 + +domain : + type : "zonal_band" + ymax : 90 + ymin : 45 + + +check : + size : 332 + lonlat(first) : [0,85.7606] + lonlat(last) : [354,47.0696] + uid : 7f87a4865eb08403c179c6488c2eeeca + bounding_box(n,w,s,e) : [90,0,45,360] diff --git a/doc/example-grids/cropped_classic_gaussian_2.json b/doc/example-grids/cropped_classic_gaussian_2.json deleted file mode 100644 index 434011a81..000000000 --- a/doc/example-grids/cropped_classic_gaussian_2.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "//" : "Classic Gaussian grid 'N16'", - - "type" : "octahedral_gaussian", - "N" : 16, - - "domain" : { "type": "rectangular", "ymax": 45, "ymin": -45, "xmin": 45, "xmax": 90, "units":"degrees" } -} diff --git a/doc/example-grids/cropped_classic_gaussian_2.yml b/doc/example-grids/cropped_classic_gaussian_2.yml new file mode 100644 index 000000000..1b119119f --- /dev/null +++ b/doc/example-grids/cropped_classic_gaussian_2.yml @@ -0,0 +1,20 @@ +# Classic Gaussian grid 'N16' + +type : "octahedral_gaussian" +N : 16 + +domain: + type : "rectangular" + ymax : 45 + ymin : -45 + xmin : 45 + xmax : 90 + units : "degrees" + + +check : + size : 144 + lonlat(first) : [48.4615,41.5325] + lonlat(last) : [90,-41.5325] + uid : e55a302d0bb56f50523e6bc2d28c4234 + bounding_box(n,w,s,e) : [45,45,-45,90] diff --git a/doc/example-grids/cropped_shifted_lonlat_1.json b/doc/example-grids/cropped_shifted_lonlat_1.json deleted file mode 100644 index 1204299dd..000000000 --- a/doc/example-grids/cropped_shifted_lonlat_1.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "//" : "Shifted lonlat grid 'S45'", - - "name" : "S45", - "domain" : { "type": "zonal_band", "ymax": 90, "ymin": 45 } -} diff --git a/doc/example-grids/cropped_shifted_lonlat_1.yml b/doc/example-grids/cropped_shifted_lonlat_1.yml new file mode 100644 index 000000000..6d8f5ecdc --- /dev/null +++ b/doc/example-grids/cropped_shifted_lonlat_1.yml @@ -0,0 +1,15 @@ +# Shifted lonlat grid 'S45' + +name : "S45" +domain : + type : "zonal_band" + ymax : 90 + ymin : 45 + + +check : + size : 4140 + lonlat(first) : [1,89] + lonlat(last) : [359,45] + uid : a1426cb32c8694d07d997cd224805947 + bounding_box(n,w,s,e) : [90,0,45,360] diff --git a/doc/example-grids/custom_structured_1.json b/doc/example-grids/custom_structured_1.json deleted file mode 100644 index 47cce301a..000000000 --- a/doc/example-grids/custom_structured_1.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "//" : "Regular lonlat grid 'L4'", - - "type" : "structured", - "yspace" : { "type":"linear", "N":9, "start":90, "end":-90 }, - "xspace" : { "type":"linear", "N":16, "start":0, "end":360, "endpoint":false } -} diff --git a/doc/example-grids/custom_structured_1.yml b/doc/example-grids/custom_structured_1.yml new file mode 100644 index 000000000..a68752b84 --- /dev/null +++ b/doc/example-grids/custom_structured_1.yml @@ -0,0 +1,13 @@ +# Regular lonlat grid 'L4' but given in custom manner + +type : "structured" +yspace : { type : "linear", N : 9, start : 90, end : -90 } +xspace : { type : "linear", N : 16, start : 0, end : 360, endpoint : false } + + +check : + size : 144 + lonlat(first) : [0,90] + lonlat(last) : [337.5,-90] + uid : 714c5d2db88b5eefdf8f789e8012f0aa + bounding_box(n,w,s,e) : [90,0,-90,360] diff --git a/doc/example-grids/custom_structured_2.json b/doc/example-grids/custom_structured_2.json deleted file mode 100644 index 22e3fbcd4..000000000 --- a/doc/example-grids/custom_structured_2.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "//" : "Regular Gaussian grid 'F4'", - - "type" : "structured", - "yspace" : { "type":"gaussian", "N":8, "start":90, "end":-90 }, - "xspace" : { "type":"linear", "N":16, "start":0, "end":360, "endpoint":false } -} diff --git a/doc/example-grids/custom_structured_2.yml b/doc/example-grids/custom_structured_2.yml new file mode 100644 index 000000000..8f4f92404 --- /dev/null +++ b/doc/example-grids/custom_structured_2.yml @@ -0,0 +1,13 @@ +# Regular Gaussian grid 'F4' coded in custom way + +type : "structured" +yspace : { type :"gaussian", N : 8, start : 90, end : -90 } +xspace : { type :"linear", N : 16, start : 0, end : 360, endpoint:false } + + +check : + size : 128 + lonlat(first) : [0,73.7992] + lonlat(last) : [337.5,-73.7992] + uid : 4db8793a3e589a0f497cbe84ff34e5b8 + bounding_box(n,w,s,e) : [90,0,-90,360] diff --git a/doc/example-grids/custom_structured_3.json b/doc/example-grids/custom_structured_3.json deleted file mode 100644 index 2c1a3eb08..000000000 --- a/doc/example-grids/custom_structured_3.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "//" : "Octahedral Gaussian grid 'O4'", - - "type" : "structured", - "yspace" : { "type":"gaussian", "N":8, "start":90, "end":-90 }, - "xspace[]" : [ - { "type":"linear", "N":16, "start":0, "end":360, "endpoint":false }, - { "type":"linear", "N":20, "start":0, "end":360, "endpoint":false }, - { "type":"linear", "N":24, "start":0, "end":360, "endpoint":false }, - { "type":"linear", "N":28, "start":0, "end":360, "endpoint":false }, - { "type":"linear", "N":28, "start":0, "end":360, "endpoint":false }, - { "type":"linear", "N":24, "start":0, "end":360, "endpoint":false }, - { "type":"linear", "N":20, "start":0, "end":360, "endpoint":false }, - { "type":"linear", "N":16, "start":0, "end":360, "endpoint":false } - ] -} diff --git a/doc/example-grids/custom_structured_3.yml b/doc/example-grids/custom_structured_3.yml new file mode 100644 index 000000000..34479f64d --- /dev/null +++ b/doc/example-grids/custom_structured_3.yml @@ -0,0 +1,21 @@ +# Octahedral Gaussian grid 'O4' + +type : "structured" +yspace : { type : "gaussian", N :8, start : 90, end : -90 } +xspace[] : + - { type : "linear", N : 20, start : 0, end : 360, endpoint : false } + - { type : "linear", N : 24, start : 0, end : 360, endpoint : false } + - { type : "linear", N : 28, start : 0, end : 360, endpoint : false } + - { type : "linear", N : 32, start : 0, end : 360, endpoint : false } + - { type : "linear", N : 32, start : 0, end : 360, endpoint : false } + - { type : "linear", N : 28, start : 0, end : 360, endpoint : false } + - { type : "linear", N : 24, start : 0, end : 360, endpoint : false } + - { type : "linear", N : 20, start : 0, end : 360, endpoint : false } + + +check : + size : 208 + lonlat(first) : [0,73.7992] + lonlat(last) : [342,-73.7992] + uid : 238a876f8ddaf43100fe643f1283f78a + bounding_box(n,w,s,e) : [90,0,-90,360] diff --git a/doc/example-grids/custom_structured_4.json b/doc/example-grids/custom_structured_4.json deleted file mode 100644 index 0646a164a..000000000 --- a/doc/example-grids/custom_structured_4.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "//" : "Octahedral Gaussian grid 'O4'", - - "type" : "structured", - "yspace" : { "type":"gaussian", "start":90, "end":-90, "N":8 }, - "xspace" : { "type":"linear", "start":0, "end":360, "endpoint":false, - "N[]": [ - 16, - 20, - 24, - 28, - 28, - 24, - 20, - 16 - ] - } -} diff --git a/doc/example-grids/custom_structured_4.yml b/doc/example-grids/custom_structured_4.yml new file mode 100644 index 000000000..1e6bcb917 --- /dev/null +++ b/doc/example-grids/custom_structured_4.yml @@ -0,0 +1,23 @@ +# Octahedral Gaussian grid 'O4' + +type : "structured" +yspace : { type : "gaussian", N : 8 } +xspace : { type : "linear", start : 0, length : 360, endpoint : false, + N[]: [ + 20, + 24, + 28, + 32, + 32, + 28, + 24, + 20 + ] } + + +check : + size : 208 + lonlat(first) : [0,73.7992] + lonlat(last) : [342,-73.7992] + uid : 238a876f8ddaf43100fe643f1283f78a + bounding_box(n,w,s,e) : [90,0,-90,360] diff --git a/doc/example-grids/custom_structured_5.json b/doc/example-grids/custom_structured_5.json deleted file mode 100644 index 984e6402a..000000000 --- a/doc/example-grids/custom_structured_5.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "//": "Rotated lonlat grid 'L4'", - - "type" : "structured", - "yspace" : { "type":"linear", "N":9, "start":90, "end":-90 }, - "xspace" : { "type":"linear", "N":16, "start":0, "end":360, "endpoint":false }, - "projection" : { "type":"rotated_lonlat", "north_pole":[3,40] } -} diff --git a/doc/example-grids/custom_structured_5.yml b/doc/example-grids/custom_structured_5.yml new file mode 100644 index 000000000..6dc221daa --- /dev/null +++ b/doc/example-grids/custom_structured_5.yml @@ -0,0 +1,14 @@ +# Rotated lonlat grid 'L4' + +type : "structured" +yspace : { type : "linear", N : 9, start : 90, end : -90 } +xspace : { type : "linear", N : 16, start : 0 , end : 360 , endpoint : false } +projection : { type : "rotated_lonlat", north_pole :[3,40] } + + +check : + size : 144 + lonlat(first) : [3,40] + lonlat(last) : [-177,-40] + uid : d55211f27c4a8c6ce94ea67f0c706e22 + bounding_box(n,w,s,e) : [90,0,-90,360] diff --git a/doc/example-grids/custom_structured_6.json b/doc/example-grids/custom_structured_6.json deleted file mode 100644 index 539782404..000000000 --- a/doc/example-grids/custom_structured_6.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "//" : "Octahedral Gaussian grid 'O4'", - - "type" : "structured", - "yspace" : { "type":"gaussian", "start":90, "end":-90, "N":8 }, - "xspace" : { "type":"linear", "N":16, "length":360, "endpoint":false, - "start[]": [ - 0, - -11.25, - 0, - -11.25, - 0, - -11.25, - 0, - -11.25 - ] - } -} diff --git a/doc/example-grids/custom_structured_6.yml b/doc/example-grids/custom_structured_6.yml new file mode 100644 index 000000000..c517612a1 --- /dev/null +++ b/doc/example-grids/custom_structured_6.yml @@ -0,0 +1,24 @@ +# Zigzag Gaussian grid (N=8) + +type : "structured" +yspace : { type : "gaussian", start : 90, end : -90, N : 8 } +xspace : { type : "linear", N : 16, length : 360, endpoint : false, + start[]: [ + 0, + -11.25, + 0, + -11.25, + 0, + -11.25, + 0, + -11.25 + ] } + + +# Expected +check: + size : 128 + lonlat(first) : [0,73.7992] + lonlat(last) : [326.25,-73.7992] + uid : d5944053929a124fd786c2121ba3d064 + bounding_box(n,w,s,e) : [90,-11.25,-90,360] diff --git a/doc/example-grids/custom_structured_7.json b/doc/example-grids/custom_structured_7.json deleted file mode 100644 index 9155a4d93..000000000 --- a/doc/example-grids/custom_structured_7.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "//" : "Shifted lat grid 'Slat3'", - - "type" : "structured", - "yspace" : { "type":"custom", "N":6, "values":[75,45,15,-15,-45,-75], "interval":[-90,90] }, - "xspace" : { "type":"linear", "N":12, "start":0, "end":360, "endpoint":false } -} diff --git a/doc/example-grids/custom_structured_7.yml b/doc/example-grids/custom_structured_7.yml new file mode 100644 index 000000000..6c7a4c90d --- /dev/null +++ b/doc/example-grids/custom_structured_7.yml @@ -0,0 +1,13 @@ +# Shifted lat grid 'Slat3' + +type : "structured" +yspace : { type: custom, N : 6, values : [75,45,15,-15,-45,-75], interval:[-90,90] } +xspace : { type: linear, N : 12, start:0, end:360, endpoint:false } + + +check : + size : 72 + lonlat(first) : [0,75] + lonlat(last) : [330,-75] + uid : 76839204fa9d69232192dedc19ecef08 + bounding_box(n,w,s,e) : [90,0,-90,360] diff --git a/doc/example-grids/octahedral_gaussian_1.json b/doc/example-grids/octahedral_gaussian_1.json deleted file mode 100644 index 6319f4570..000000000 --- a/doc/example-grids/octahedral_gaussian_1.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "//" : "Octahedral Gaussian grid 'O16'", - - "type" : "octahedral_gaussian", - "N" : 16 -} diff --git a/doc/example-grids/octahedral_gaussian_1.yml b/doc/example-grids/octahedral_gaussian_1.yml new file mode 100644 index 000000000..fdaef07e5 --- /dev/null +++ b/doc/example-grids/octahedral_gaussian_1.yml @@ -0,0 +1,12 @@ +# Octahedral Gaussian grid 'O16' + +type : "octahedral_gaussian" +N : 16 + + +check : + size : 1600 + lonlat(first) : [0,85.7606] + lonlat(last) : [342,-85.7606] + uid : 957667adfecf4f2394e4ec9bb0b25569 + bounding_box(n,w,s,e) : [90,0,-90,360] diff --git a/doc/example-grids/octahedral_gaussian_2.json b/doc/example-grids/octahedral_gaussian_2.json deleted file mode 100644 index 55588bbd3..000000000 --- a/doc/example-grids/octahedral_gaussian_2.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "//" : "Octahedral Gaussian grid 'N16'", - - "type" : "octahedral_gaussian", - "N" : 16, - "projection" : { "type": "rotated_schmidt", "stretching_factor": 4.0, "north_pole": [3.0,47.0] } -} diff --git a/doc/example-grids/octahedral_gaussian_2.yml b/doc/example-grids/octahedral_gaussian_2.yml new file mode 100644 index 000000000..0b8354d23 --- /dev/null +++ b/doc/example-grids/octahedral_gaussian_2.yml @@ -0,0 +1,13 @@ +# Octahedral Gaussian grid 'N16' + +type : "octahedral_gaussian" +N : 16 +projection : { type: "rotated_schmidt", stretching_factor : 4.0, north_pole : [3.0,47.0] } + + +check : + size : 1600 + lonlat(first) : [3,45.9397] + lonlat(last) : [-165.776,-62.6128] + uid : 20308244515b7c78e22709ebaa842246 + bounding_box(n,w,s,e) : [90,0,-90,360] diff --git a/doc/example-grids/octahedral_gaussian_3.json b/doc/example-grids/octahedral_gaussian_3.json deleted file mode 100644 index 861cac459..000000000 --- a/doc/example-grids/octahedral_gaussian_3.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "//" : "Octahedral Gaussian grid 'O16'", - - "name" : "O16" -} diff --git a/doc/example-grids/octahedral_gaussian_3.yml b/doc/example-grids/octahedral_gaussian_3.yml new file mode 100644 index 000000000..50a06742e --- /dev/null +++ b/doc/example-grids/octahedral_gaussian_3.yml @@ -0,0 +1,11 @@ +# Octahedral Gaussian grid 'O16' + +name : "O16" + + +check : + size : 1600 + lonlat(first) : [0,85.7606] + lonlat(last) : [342,-85.7606] + uid : 957667adfecf4f2394e4ec9bb0b25569 + bounding_box(n,w,s,e) : [90,0,-90,360] diff --git a/doc/example-grids/octahedral_gaussian_4.json b/doc/example-grids/octahedral_gaussian_4.json deleted file mode 100644 index 37a42e402..000000000 --- a/doc/example-grids/octahedral_gaussian_4.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "//" : "Octahedral Gaussian grid 'O16'", - - "name" : "O16", - "projection" : { "type": "rotated_schmidt", "stretching_factor": 4.0, "north_pole": [3.0,47.0] } -} diff --git a/doc/example-grids/octahedral_gaussian_4.yml b/doc/example-grids/octahedral_gaussian_4.yml new file mode 100644 index 000000000..5ea110afe --- /dev/null +++ b/doc/example-grids/octahedral_gaussian_4.yml @@ -0,0 +1,12 @@ +# Octahedral Gaussian grid 'O16' + +name : "O16" +projection : { type: "rotated_schmidt", stretching_factor: 4.0, north_pole: [3.0,47.0] } + + +check : + size : 1600 + lonlat(first) : [3,45.9397] + lonlat(last) : [-165.776,-62.6128] + uid : 20308244515b7c78e22709ebaa842246 + bounding_box(n,w,s,e) : [90,0,-90,360] diff --git a/doc/example-grids/regional_lambert_1.json b/doc/example-grids/regional_lambert_1.json deleted file mode 100644 index c6b64e5e3..000000000 --- a/doc/example-grids/regional_lambert_1.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type" : "regional", - "nx" : 50, - "ny" : 40, - "dx" : 50000, - "dy" : 50000, - "lonlat(centre)" : [4,50], - "projection" : { - "type" : "lambert", - "latitude1" : 50, - "longitude0" : 4 - } -} diff --git a/doc/example-grids/regional_lambert_1.yml b/doc/example-grids/regional_lambert_1.yml new file mode 100644 index 000000000..53a680403 --- /dev/null +++ b/doc/example-grids/regional_lambert_1.yml @@ -0,0 +1,19 @@ +type : "regional" +nx : 50 +ny : 40 +dx : 50000 +dy : 50000 +lonlat(centre) : [4,50] +projection : + type : "lambert" + latitude1 : 50 + longitude0 : 4 +y_numbering : +1 + + +check : + size : 2000 + lonlat(first) : [-10.3173,40.22] + lonlat(last) : [24.4368,57.2335] + uid : 1cb0b7c8f91617c3b6065d72b85c65c4 + bounding_box(n,w,s,e) : [58.7333,-16.4378,40.219,24.4378] diff --git a/doc/example-grids/regional_lambert_2.json b/doc/example-grids/regional_lambert_2.json deleted file mode 100644 index a4502a554..000000000 --- a/doc/example-grids/regional_lambert_2.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type" : "regional", - "nx" : 451, - "ny" : 337, - "dx" : 13545, - "dy" : 13545, - "lonlat(xmin,ymin)": [-126.138,16.281], - "projection" : { "type" : "lambert", - "latitude1" : 25, - "longitude0" : -95 - } -} \ No newline at end of file diff --git a/doc/example-grids/regional_lambert_2.yml b/doc/example-grids/regional_lambert_2.yml new file mode 100644 index 000000000..c82c5fda5 --- /dev/null +++ b/doc/example-grids/regional_lambert_2.yml @@ -0,0 +1,19 @@ +type : "regional" +nx : 451 +ny : 337 +dx : 13545.0 +dy : 13545.0 +lonlat(xmin,ymin): [-126.138,16.281] +projection : + type : "lambert" + latitude1 : 25.0 + longitude0 : -95.0 +y_numbering : +1 + + +check : + size : 151987 + lonlat(first) : [-126.138,16.281] + lonlat(last) : [-57.3811,55.4813] + uid : ec98b263e57286710aeb4131a614b5f9 + bounding_box(n,w,s,e) : [58.3664,-139.857,16.28,-57.3801] diff --git a/doc/example-grids/regional_lambert_azimuthal_equal_area_1.yml b/doc/example-grids/regional_lambert_azimuthal_equal_area_1.yml new file mode 100644 index 000000000..cc2fe5da2 --- /dev/null +++ b/doc/example-grids/regional_lambert_azimuthal_equal_area_1.yml @@ -0,0 +1,19 @@ +type : "regional" +nx : 50 +ny : 40 +dx : 50000 +dy : 50000 +lonlat(centre) : [4,50] +projection : + type : "lambert_azimuthal_equal_area" + standard_parallel : 50 + central_longitude : 4 +y_numbering : +1 + + +check : + size : 2000 + lonlat(first) : [-10.4643,40.1877] + lonlat(last) : [24.6228,57.1968] + uid : 16663e1f4f3deb724712dd2698008915 + bounding_box(n,w,s,e) : [58.7776,-16.6238,40.1867,24.6238] diff --git a/doc/example-grids/regional_lambert_azimuthal_equal_area_2.yml b/doc/example-grids/regional_lambert_azimuthal_equal_area_2.yml new file mode 100644 index 000000000..48a72cb50 --- /dev/null +++ b/doc/example-grids/regional_lambert_azimuthal_equal_area_2.yml @@ -0,0 +1,21 @@ +# EFAS grid + +type : "regional" +nx : 1000 +ny : 950 +dx : 5000 +dy : 5000 +lonlat(xmin,ymax) : [-35.034,66.9821] +projection : + type : "lambert_azimuthal_equal_area" + standard_parallel : 52 + central_longitude : 10 +y_numbering : -1 + + +check : + size : 950000 + lonlat(first) : [-35.034,66.9821] + lonlat(last) : [41.2436,23.8962] + bounding_box(n,w,s,e) : [72.647, -35.035, 23.895, 74.144] + uid : a87b2f233e26156d01c05a9ef2466721 diff --git a/doc/example-grids/regional_lonlat_1.json b/doc/example-grids/regional_lonlat_1.json deleted file mode 100644 index fb11fef00..000000000 --- a/doc/example-grids/regional_lonlat_1.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "type" : "regional", - "nx" : 35, - "ny" : 25, - "north" : -10, - "south" : -50, - "east" : 170, - "west" : 100 -} \ No newline at end of file diff --git a/doc/example-grids/regional_lonlat_1.yml b/doc/example-grids/regional_lonlat_1.yml new file mode 100644 index 000000000..1ac19b896 --- /dev/null +++ b/doc/example-grids/regional_lonlat_1.yml @@ -0,0 +1,16 @@ +type : "regional" +nx : 35 +ny : 25 +north : -10 +south : -50 +east : 170 +west : 100 +y_numbering: +1 + + +check : + size : 875 + lonlat(first) : [100,-50] + lonlat(last) : [170,-10] + uid : 3c64a36ae3357c0d8f1148fc0e983cfb + bounding_box(n,w,s,e) : [-10,100,-50,170] diff --git a/doc/example-grids/regional_rotated_mercator_1.json b/doc/example-grids/regional_rotated_mercator_1.json deleted file mode 100644 index e9df2e872..000000000 --- a/doc/example-grids/regional_rotated_mercator_1.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type" : "regional", - "nx" : 50, - "ny" : 40, - "dx" : 50000, - "dy" : 50000, - "lonlat(centre)" : [4,50], - "projection" : { - "type" : "rotated_mercator", - "north_pole" : [-176,40] - } -} - diff --git a/doc/example-grids/regional_rotated_mercator_1.yml b/doc/example-grids/regional_rotated_mercator_1.yml new file mode 100644 index 000000000..57bb6bc2c --- /dev/null +++ b/doc/example-grids/regional_rotated_mercator_1.yml @@ -0,0 +1,18 @@ +type : "regional" +nx : 50 +ny : 40 +dx : 50000 +dy : 50000 +lonlat(centre) : [4,50] +projection : + type : "rotated_mercator" + north_pole : [-176,40] +y_numbering : +1 + + +check : + size : 2000 + lonlat(first) : [-10.319,40.2109] + lonlat(last) : [24.4206,57.2263] + uid : 340321ee9855b47bbaadb581d2c86238 + bounding_box(n,w,s,e) : [58.735,-16.4216,40.2099,24.4216] diff --git a/doc/example-grids/regular_gaussian_1.json b/doc/example-grids/regular_gaussian_1.json deleted file mode 100644 index 44fd4eee4..000000000 --- a/doc/example-grids/regular_gaussian_1.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "//" : "Regular Gaussian grid 'F4'", - - "type" : "regular_gaussian", - "N" : 4 -} diff --git a/doc/example-grids/regular_gaussian_1.yml b/doc/example-grids/regular_gaussian_1.yml new file mode 100644 index 000000000..722bd9216 --- /dev/null +++ b/doc/example-grids/regular_gaussian_1.yml @@ -0,0 +1,12 @@ +# Regular Gaussian grid 'F4' + +type : "regular_gaussian" +N : 4 + + +check : + size : 128 + lonlat(first) : [0,73.7992] + lonlat(last) : [337.5,-73.7992] + uid : 4db8793a3e589a0f497cbe84ff34e5b8 + bounding_box(n,w,s,e) : [90,0,-90,360] diff --git a/doc/example-grids/regular_gaussian_2.json b/doc/example-grids/regular_gaussian_2.json deleted file mode 100644 index 3c0e643b3..000000000 --- a/doc/example-grids/regular_gaussian_2.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "//" : "Regular Gaussian grid 'F4'", - - "type" : "regular_gaussian", - "N" : 4, - "projection" : { "type": "rotated_schmidt", "stretching_factor": 2.0, "north_pole": [3.0,47.0] } -} diff --git a/doc/example-grids/regular_gaussian_2.yml b/doc/example-grids/regular_gaussian_2.yml new file mode 100644 index 000000000..b7cf9d110 --- /dev/null +++ b/doc/example-grids/regular_gaussian_2.yml @@ -0,0 +1,16 @@ +# Regular Gaussian grid 'F4' + +type : "regular_gaussian" +N : 4 +projection : + type : "rotated_schmidt" + stretching_factor : 2.0 + north_pole : [3.0,47.0] + + +check : + size : 128 + lonlat(first) : [3,38.8589] + lonlat(last) : [-135.011,-72.4668] + uid : d179fd0b56811242a1a0a8e83dade6a1 + bounding_box(n,w,s,e) : [90,0,-90,360] diff --git a/doc/example-grids/regular_gaussian_3.json b/doc/example-grids/regular_gaussian_3.json deleted file mode 100644 index 0b0be4f5d..000000000 --- a/doc/example-grids/regular_gaussian_3.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "//" : "Regular Gaussian grid 'F4'", - - "name" : "F4" -} diff --git a/doc/example-grids/regular_gaussian_3.yml b/doc/example-grids/regular_gaussian_3.yml new file mode 100644 index 000000000..3065d3b5b --- /dev/null +++ b/doc/example-grids/regular_gaussian_3.yml @@ -0,0 +1,10 @@ +# Regular Gaussian grid 'F4' +name : "F4" + + +check: + size : 128 + lonlat(first) : [0,73.7992] + lonlat(last) : [337.5,-73.7992] + uid : 4db8793a3e589a0f497cbe84ff34e5b8 + bounding_box(n,w,s,e) : [90,0,-90,360] diff --git a/doc/example-grids/regular_gaussian_4.yml b/doc/example-grids/regular_gaussian_4.yml new file mode 100644 index 000000000..384dd01be --- /dev/null +++ b/doc/example-grids/regular_gaussian_4.yml @@ -0,0 +1,13 @@ +# Regular Gaussian grid (Ngauss=8) starting at -180 and much denser x-spacing than y-spacing + +type : "structured" +yspace : { type : "gaussian", N : 16 } +xspace : { type : "linear", N : 160, start : -180, length : 360, endpoint : false } + + +check : + size : 2560 + lonlat(first) : [-180,81.6506] + lonlat(last) : [177.75,-81.6506] + uid : 8e729027737aece8db5883e3a475d5cb + bounding_box(n,w,s,e) : [90,-180,-90,180] diff --git a/doc/example-grids/regular_lonlat_1.yml b/doc/example-grids/regular_lonlat_1.yml new file mode 100644 index 000000000..82b0489ac --- /dev/null +++ b/doc/example-grids/regular_lonlat_1.yml @@ -0,0 +1,12 @@ +# Regular lonlat +type : "regular_lonlat" +nx : 128 +ny : 65 + + +check: + size : 8320 + lonlat(first) : [0,90] + lonlat(last) : [357.188,-90] + uid : f109da5924c5998453cdb7d5854ebd1a + bounding_box(n,w,s,e) : [90,0,-90,360] diff --git a/doc/example-grids/regular_lonlat_2.yml b/doc/example-grids/regular_lonlat_2.yml new file mode 100644 index 000000000..17793caf8 --- /dev/null +++ b/doc/example-grids/regular_lonlat_2.yml @@ -0,0 +1,21 @@ +# Regular lonlat, cropped and rotated +type : "regular_lonlat" +nx : 360 +ny : 181 +domain : + type : "rectangular" + units : "degrees" + ymax : 90. + xmin : -10. + ymin : 70. + xmax : 10. +projection : + type : "rotated_lonlat" + south_pole : [22., -40.] + +check: + size : 441 + bounding_box(n,w,s,e) : [60.001, -164.730, 39.999, -151.270] + lonlat(first) : [-158., 40.] + lonlat(last) : [-164.729, 59.547] + diff --git a/doc/example-grids/regular_lonlat_3.yml b/doc/example-grids/regular_lonlat_3.yml new file mode 100644 index 000000000..ca002e2fb --- /dev/null +++ b/doc/example-grids/regular_lonlat_3.yml @@ -0,0 +1,21 @@ +# Regular lonlat, cropped and rotated +type : "regular_lonlat" +nx : 360 +ny : 181 +domain : + type : "rectangular" + units : "degrees" + ymax : -70. + xmin : -10. + ymin : -90. + xmax : 10. +projection : + type : "rotated_lonlat" + south_pole : [22., -40.] + +check: + size : 441 + bounding_box(n,w,s,e) : [-19.999, 18.370, -40.001, 25.630] + lonlat(first) : [18.371, -20.243] + lonlat(last) : [22., -40.] + diff --git a/doc/example-grids/shifted_regular_lonlat_1.json b/doc/example-grids/shifted_regular_lonlat_1.json deleted file mode 100644 index 033bb4bda..000000000 --- a/doc/example-grids/shifted_regular_lonlat_1.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "//" : "Shifted lonlat grid 'S45'", - - "name" : "L4", - "!domain" : { "type": "zonal_band", "ymax": 90, "ymin": 45 }, - "projection" : { - "type" : "shifted_lonlat", - "shift" : [-180,0] - } -} diff --git a/doc/example-grids/unstructured_1.yml b/doc/example-grids/unstructured_1.yml new file mode 100644 index 000000000..cf85e8055 --- /dev/null +++ b/doc/example-grids/unstructured_1.yml @@ -0,0 +1,15 @@ +type : "unstructured" + +xy : [ + 0, 90, + 0, -90, + 180,-90, + 180, 90 +] + +check : + size : 4 + lonlat(first) : [0,90] + lonlat(last) : [180,90] + uid : b704ab522505497c6d622f27c429bffe + bounding_box(n,w,s,e) : [90,0,-90,360] diff --git a/doc/example-grids/update_uid.py b/doc/example-grids/update_uid.py new file mode 100755 index 000000000..53923cb2b --- /dev/null +++ b/doc/example-grids/update_uid.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python + +# +# This script checks all example-grids and updates the uid to a newly calculated uid +# The only argument to this script is the path to the "atlas-grids" executable +# +# !!! WARNING !!! +# Execution overwrites existing ".yml" files in the same directory as this script! +# + +def run_program_get_error(file): + import os + from subprocess import check_output, CalledProcessError + + command = [program, file, '--check' ] + + from subprocess import Popen, PIPE + + p = Popen(command, stdout=PIPE, stderr=PIPE) + output, error = p.communicate() + if p.returncode != 0: + return str(error.strip(),'ascii') + return None + + +def process_file( file, newfile ): + + import string + print( "File: " , file ) + + f = open(file,"r+") + text = f.read() + f.close() + + line = run_program_get_error( file ) + if line: + print( line ) + import re + replace = re.match( r"Check failed: grid uid (.*) expected to be (.*)$", line ).group(1) + uid = re.findall( r"^ uid : (.*)$", text, re.MULTILINE)[0] + print("Search/Replace ",uid, " to ", replace ) + newtext = text.replace( uid, replace ) + else: + print( "Nothing to replace, copy-only" ) + newtext = text + + print( "New file: ", newfile) + f = open(newfile,"w") + f.write(newtext) + f.close() + + +import sys +program = sys.argv[1] + +print( "Updating uids of grids with program [",program,"]") + +import os +directory = os.path.dirname(os.path.realpath(__file__)) + +for root, dirs, files in os.walk(directory): + for file in files: + if file.endswith('.yml'): + file = root+"/"+file + newfile = file + process_file(file,newfile) diff --git a/doc/example-grids/zonal_band_1.json b/doc/example-grids/zonal_band_1.json deleted file mode 100644 index ac63ff91b..000000000 --- a/doc/example-grids/zonal_band_1.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type" : "zonal_band", - "nx" : 5, - "ny" : 3, - "north" : 70, - "south" : 30 -} \ No newline at end of file diff --git a/doc/example-grids/zonal_band_1.yml b/doc/example-grids/zonal_band_1.yml new file mode 100644 index 000000000..322bb4352 --- /dev/null +++ b/doc/example-grids/zonal_band_1.yml @@ -0,0 +1,13 @@ +type : "zonal_band" +nx : 5 +ny : 3 +north : 70 +south : 30 + + +check: + size : 15 + lonlat(first) : [0,70] + lonlat(last) : [288,30] + uid : 7f1b0971ad5d9f581e2d35914d916a67 + bounding_box(n,w,s,e) : [70,0,30,360] diff --git a/doc/example-grids/zonal_band_2.json b/doc/example-grids/zonal_band_2.json deleted file mode 100644 index 62c28cb36..000000000 --- a/doc/example-grids/zonal_band_2.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type" : "zonal_band", - "nx" : 36, - "ny" : 7, - "south" : 30 -} diff --git a/doc/example-grids/zonal_band_2.yml b/doc/example-grids/zonal_band_2.yml new file mode 100644 index 000000000..34340dffb --- /dev/null +++ b/doc/example-grids/zonal_band_2.yml @@ -0,0 +1,13 @@ +type : "zonal_band" +nx : 36 +ny : 7 +south : 30 +y_numbering: +1 + + +check: + size : 252 + lonlat(first) : [0,30] + lonlat(last) : [350,90] + uid : 639a6a6b1d29ba4b6523a044eb9b4677 + bounding_box(n,w,s,e) : [90,0,30,360] diff --git a/doc/example-grids/zonal_band_3.json b/doc/example-grids/zonal_band_3.json deleted file mode 100644 index 6cb30f304..000000000 --- a/doc/example-grids/zonal_band_3.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "type" : "zonal_band", - "nx" : 36, - "ny" : 19 -} diff --git a/doc/example-grids/zonal_band_3.yml b/doc/example-grids/zonal_band_3.yml new file mode 100644 index 000000000..3b9991e57 --- /dev/null +++ b/doc/example-grids/zonal_band_3.yml @@ -0,0 +1,12 @@ +type : "zonal_band" +nx : 36 +ny : 19 +y_numbering: +1 + + +check: + size : 684 + lonlat(first) : [0,-90] + lonlat(last) : [350,90] + uid : f1689a410168f86c048e6fa374bac498 + bounding_box(n,w,s,e) : [90,0,-90,360] diff --git a/src/apps/CMakeLists.txt b/src/apps/CMakeLists.txt index 00ec3ee06..a515999bd 100644 --- a/src/apps/CMakeLists.txt +++ b/src/apps/CMakeLists.txt @@ -10,7 +10,6 @@ if( ECKIT_INCLUDE_DIRS ) # eckit not yet ported to CMake3 include_directories( ${ECKIT_INCLUDE_DIRS} ) endif() - ecbuild_add_executable( TARGET atlas-main OUTPUT_NAME atlas diff --git a/src/apps/atlas-benchmark.cc b/src/apps/atlas-benchmark.cc index 7836a6a13..6a80de61b 100644 --- a/src/apps/atlas-benchmark.cc +++ b/src/apps/atlas-benchmark.cc @@ -99,8 +99,12 @@ struct TimerStats { } void update( Trace& timer ) { double t = timer.elapsed(); - if ( min < 0 ) min = t; - if ( max < 0 ) max = t; + if ( min < 0 ) { + min = t; + } + if ( max < 0 ) { + max = t; + } min = std::min( min, t ); max = std::max( max, t ); avg = ( avg * cnt + t ) / ( cnt + 1 ); @@ -122,7 +126,7 @@ struct TimerStats { //---------------------------------------------------------------------------------------------------------------------- class AtlasBenchmark : public AtlasTool { - virtual void execute( const Args& args ); + virtual int execute( const Args& args ); public: AtlasBenchmark( int argc, char** argv ) : AtlasTool( argc, argv ) { @@ -170,14 +174,11 @@ class AtlasBenchmark : public AtlasTool { TimerStats haloexchange_timer; idx_t iter; bool progress; - -public: - int exit_code; }; //---------------------------------------------------------------------------------------------------------------------- -void AtlasBenchmark::execute( const Args& args ) { +int AtlasBenchmark::execute( const Args& args ) { Trace timer( Here(), "atlas-benchmark" ); // Timer::Logging set_channel( Log::info() ); @@ -201,7 +202,9 @@ void AtlasBenchmark::execute( const Args& args ) { iteration_timer = TimerStats( "iteration" ); haloexchange_timer = TimerStats( "halo-exchange" ); - if ( omp_threads > 0 ) atlas_omp_set_num_threads( omp_threads ); + if ( omp_threads > 0 ) { + atlas_omp_set_num_threads( omp_threads ); + } Log::info() << "atlas-benchmark\n" << endl; Log::info() << Library::instance().information() << endl; @@ -234,7 +237,9 @@ void AtlasBenchmark::execute( const Args& args ) { ++tic; } if ( iter == niter - 1 ) { - if ( tic < 51 ) Log::info() << '*'; + if ( tic < 51 ) { + Log::info() << '*'; + } Log::info() << endl; } } @@ -253,8 +258,9 @@ void AtlasBenchmark::execute( const Args& args ) { util::Config report_config; report_config.set( "indent", 4 ); - if ( not args.getBool( "details", false ) ) + if ( not args.getBool( "details", false ) ) { report_config.set( "exclude", std::vector{"halo-exchange", "atlas-benchmark-setup/*"} ); + } Log::info() << timer.report( report_config ) << std::endl; Log::info() << endl; @@ -265,7 +271,7 @@ void AtlasBenchmark::execute( const Args& args ) { double res = result(); Log::info() << endl; - exit_code = verify( res ); + return verify( res ); } //---------------------------------------------------------------------------------------------------------------------- @@ -286,8 +292,9 @@ void AtlasBenchmark::initial_condition( const Field& field, const double& beta ) 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 ( idx_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 ); + } } } @@ -357,10 +364,12 @@ void AtlasBenchmark::setup() { 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 ) + if ( jnode == ip1 ) { node2edge_sign( jnode, jedge ) = 1.; - else + } + else { node2edge_sign( jnode, jedge ) = -1.; + } } } @@ -370,11 +379,14 @@ void AtlasBenchmark::setup() { vector tmp( nedges ); int c( 0 ); for ( idx_t jedge = 0; jedge < nedges; ++jedge ) { - if ( is_pole_edge( jedge ) ) tmp[c++] = jedge; + if ( is_pole_edge( jedge ) ) { + tmp[c++] = jedge; + } } pole_edges.reserve( c ); - for ( idx_t 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().flags() ); is_ghost.reserve( nnodes ); @@ -434,8 +446,9 @@ void AtlasBenchmark::iteration() { idx_t iedge = pole_edges[jedge]; idx_t ip2 = edge2node( iedge, 1 ); // correct for wrong Y-derivatives in previous loop - for ( idx_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; @@ -451,7 +464,9 @@ void AtlasBenchmark::iteration() { grad( jnode, 0, ZZ ) = ( field( jnode, 1 ) - field( jnode, 0 ) ) * dzi; grad( jnode, nlev - 1, ZZ ) = ( field( jnode, nlev - 2 ) - field( jnode, nlev - 1 ) ) * dzi; } - if ( nlev == 1 ) grad( jnode, 0, ZZ ) = 0.; + if ( nlev == 1 ) { + grad( jnode, 0, ZZ ) = 0.; + } } compute.stop(); @@ -479,8 +494,9 @@ void AtlasBenchmark::iteration() { template DATA_TYPE vecnorm( const DATA_TYPE vec[], size_t size ) { DATA_TYPE norm = 0; - for ( size_t j = 0; j < size; ++j ) + for ( size_t j = 0; j < size; ++j ) { norm += vec[j] * vec[j]; + } return norm; } @@ -551,7 +567,7 @@ double AtlasBenchmark::result() { int AtlasBenchmark::verify( const double& norm ) { Log::warning() << "Verification is not yet implemented" << endl; - return 1; + return failed(); } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/apps/atlas-gaussian-latitudes.cc b/src/apps/atlas-gaussian-latitudes.cc index 6cc899623..6d18d50b3 100644 --- a/src/apps/atlas-gaussian-latitudes.cc +++ b/src/apps/atlas-gaussian-latitudes.cc @@ -80,13 +80,17 @@ class AtlasGaussianLatitudes : public eckit::Tool { format = Resource( "--format", std::string( "table" ) ); - if ( N > 0 ) do_run = true; + if ( N > 0 ) { + do_run = true; + } if ( do_run == false ) { - if ( help ) + if ( help ) { Log::info() << help_str << std::endl; - else + } + else { Log::info() << "usage: atlas-gaussian-latitudes [--help] [-N] [OPTION]..." << std::endl; + } } } @@ -101,23 +105,30 @@ class AtlasGaussianLatitudes : public eckit::Tool { //------------------------------------------------------------------------------ void AtlasGaussianLatitudes::run() { - if ( !do_run ) return; + if ( !do_run ) { + return; + } GaussianSpacing lats( 2 * N ); int end = full ? 2 * N : N; if ( format == "table" ) { - for ( int jlat = 0; jlat < end; ++jlat ) + for ( int jlat = 0; jlat < end; ++jlat ) { std::cout << std::setw( 4 ) << jlat + 1 << std::setw( 17 ) << std::setprecision( 12 ) << std::fixed << lats[jlat] << std::endl; + } } if ( format == "C" ) { std::cout << "double lat[] = {" << std::endl; for ( int jlat = 0; jlat < end; ++jlat ) { std::cout << std::setw( 16 ) << std::setprecision( 12 ) << std::fixed << lats[jlat]; - if ( jlat != end - 1 ) std::cout << ","; - if ( ( compact && ( jlat + 1 ) % 5 == 0 ) || !compact || jlat == end - 1 ) std::cout << std::endl; + if ( jlat != end - 1 ) { + std::cout << ","; + } + if ( ( compact && ( jlat + 1 ) % 5 == 0 ) || !compact || jlat == end - 1 ) { + std::cout << std::endl; + } } std::cout << "};" << std::endl; } diff --git a/src/apps/atlas-gmsh-extract.cc b/src/apps/atlas-gmsh-extract.cc index 6a1c1032c..ed367fca9 100644 --- a/src/apps/atlas-gmsh-extract.cc +++ b/src/apps/atlas-gmsh-extract.cc @@ -101,13 +101,17 @@ class gmsh_extract : public eckit::Tool { if ( std::string( argv[i] ) == "-i" ) { for ( int j = i + 1; j < argc; ++j ) { std::string in_file( argv[j] ); - if ( in_file[0] == '-' ) break; + if ( in_file[0] == '-' ) { + break; + } in_files.push_back( in_file ); } } } - if ( in_files.empty() ) throw_Exception( "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: @@ -121,17 +125,22 @@ class gmsh_extract : public eckit::Tool { //------------------------------------------------------------------------------------------------------ void gmsh_extract::run() { - if ( !do_run ) return; + if ( !do_run ) { + return; + } atlas::Library::instance().initialise( argc(), argv() ); Log::debug() << "Command line:" << std::endl; - for ( int i = 0; i < argc(); ++i ) + for ( int i = 0; i < argc(); ++i ) { Log::debug() << argv( i ) << std::endl; + } Log::debug() << Translator, std::string>()( in_files ) << std::endl; 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_CantOpenFile( out_filename ); + if ( !out_file.is_open() ) { + throw_CantOpenFile( out_filename ); + } } std::ostream& out = out_filename.empty() ? std::cout : out_file; @@ -146,13 +155,17 @@ 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_CantOpenFile( gmsh_file ); + if ( !in_file.is_open() ) { + throw_CantOpenFile( gmsh_file ); + } std::string line; std::string ctxt = ""; while ( true ) { std::getline( in_file, line ); - if ( in_file.eof() ) break; + if ( in_file.eof() ) { + break; + } if ( line == "$MeshFormat" ) { out << line << "\n"; std::getline( in_file, line ); @@ -161,9 +174,15 @@ void gmsh_extract::run() { out << line << "\n"; std::getline( in_file, line ); } - if ( line == "$NodeData" ) ctxt = "NodeData"; - if ( line == "$ElementData" ) ctxt = "ElementData"; - if ( line == "$ElementNodeData" ) ctxt = "ElementNodeData"; + if ( line == "$NodeData" ) { + ctxt = "NodeData"; + } + if ( line == "$ElementData" ) { + ctxt = "ElementData"; + } + if ( line == "$ElementNodeData" ) { + ctxt = "ElementNodeData"; + } if ( !ctxt.empty() ) { std::string end_ctxt = "$End" + ctxt; @@ -209,7 +228,9 @@ void gmsh_extract::run() { } } } - if ( !out_filename.empty() ) out_file.close(); + if ( !out_filename.empty() ) { + out_file.close(); + } atlas::Library::instance().finalise(); } diff --git a/src/apps/atlas-grids.cc b/src/apps/atlas-grids.cc index 4c149cbc6..5a76e2483 100644 --- a/src/apps/atlas-grids.cc +++ b/src/apps/atlas-grids.cc @@ -8,14 +8,11 @@ * nor does it submit to any jurisdiction. */ -#include #include -#include #include #include -#include -#include #include +#include #include #include "eckit/config/Resource.h" @@ -23,24 +20,17 @@ #include "eckit/log/Bytes.h" #include "eckit/log/Log.h" #include "eckit/parser/JSON.h" -#include "eckit/runtime/Main.h" +#include "eckit/types/FloatCompare.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::JSON; //---------------------------------------------------------------------------------------------------------------------- -class AtlasGrids : public AtlasTool { +struct AtlasGrids : public atlas::AtlasTool { virtual bool serial() { return true; } - virtual void execute( const Args& args ); + virtual int execute( const Args& args ); virtual std::string briefDescription() { return "Catalogue of available built-in grids"; } virtual std::string usage() { return name() + " GRID [OPTION]... [--help,-h]"; } virtual std::string longDescription() { @@ -52,73 +42,69 @@ class AtlasGrids : public AtlasTool { " Example values: N80, F40, O24, L32\n"; } -public: AtlasGrids( int argc, char** argv ) : AtlasTool( argc, argv ) { add_option( new SimpleOption( "list", "List all grids. The names are possible values for the GRID argument" ) ); - add_option( new SimpleOption( "info", "List information about GRID" ) ); - add_option( new SimpleOption( "json", "Export json" ) ); - add_option( new SimpleOption( "rtable", "Export IFS rtable" ) ); + 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" ) ); } - -private: - bool list; - std::string key; - bool info; - bool json; - bool rtable; - bool do_run; }; //------------------------------------------------------------------------------------------------------ -void AtlasGrids::execute( const Args& args ) { - key = ""; - if ( args.count() ) key = args( 0 ); +int AtlasGrids::execute( const Args& args ) { + using namespace atlas; - info = false; - args.get( "info", info ); + std::string key = args.count() ? args( 0 ) : ""; - if ( info && !key.empty() ) do_run = true; + bool info = false; + args.get( "info", info ); - json = false; + bool json = false; args.get( "json", json ); - if ( json && !key.empty() ) do_run = true; - rtable = false; + bool rtable = false; args.get( "rtable", rtable ); - if ( rtable && !key.empty() ) do_run = true; - list = false; + bool check = false; + args.get( "check", check ); + + bool check_uid = false; + args.get( "check-uid", check_uid ); + + bool check_bbox = false; + args.get( "check-boundingbox", check_bbox ); + + bool list = false; args.get( "list", list ); - if ( list ) do_run = true; - if ( !key.empty() && do_run == false ) { + bool do_run = list || ( !key.empty() && ( info || json || rtable || check ) ); + + if ( !key.empty() && !do_run ) { Log::error() << "Option wrong or missing after '" << key << "'" << std::endl; } + if ( list ) { Log::info() << "usage: atlas-grids GRID [OPTION]... [--help]\n" << std::endl; Log::info() << "Available grids:" << std::endl; - for ( const auto& key : GridFactory::keys() ) { + for ( const auto& key : grid::GridFactory::keys() ) { Log::info() << " -- " << key << std::endl; } } if ( !key.empty() ) { - StructuredGrid grid; - try { - grid = Grid( key ); - } - catch ( eckit::Exception& ) { - } + eckit::PathName path{key}; + Grid grid = path.exists() ? Grid( Grid::Spec{path} ) : Grid( key ); - if ( !grid ) return; + if ( !grid ) { + return failed(); + } if ( info ) { - double deg, km; Log::info() << "Grid " << key << std::endl; Log::info() << " name: " << grid.name() << std::endl; Log::info() << " uid: " << grid.uid() << std::endl; @@ -126,59 +112,239 @@ void AtlasGrids::execute( const Args& args ) { Log::info() << " Gaussian N number: " << gaussian.N() << std::endl; } Log::info() << " number of points: " << grid.size() << std::endl; - Log::info() << " number of latitudes (N-S): " << grid.ny() << std::endl; - Log::info() << " number of longitudes (max): " << grid.nxmax() << std::endl; - - deg = ( grid.y().front() - grid.y().back() ) / ( grid.ny() - 1 ); - km = deg * 40075. / 360.; - Log::info() << " approximate resolution N-S: " << std::setw( 10 ) << std::fixed << deg - << " deg " << km << " km " << std::endl; - - deg = 360. / static_cast( grid.nx( grid.ny() / 2 ) ); - km = deg * 40075. / 360.; - Log::info() << " approximate resolution E-W equator: " << std::setw( 10 ) << std::fixed << deg - << " deg " << km << " km " << std::endl; - deg = 360. * std::cos( grid.y( grid.ny() / 4 ) * M_PI / 180. ) / - static_cast( grid.nx( grid.ny() / 4 ) ); - km = deg * 40075. / 360.; - Log::info() << " approximate resolution E-W midlat: " << std::setw( 10 ) << std::fixed << deg - << " deg " << km << " km " << std::endl; - - deg = 360. * std::cos( grid.y().front() * M_PI / 180. ) / static_cast( grid.nx().front() ); - km = deg * 40075. / 360.; size_t memsize = grid.size() * sizeof( double ); - Log::info() << " approximate resolution E-W pole: " << std::setw( 10 ) << std::fixed << deg - << " deg " << km << " km " << std::endl; - - Log::info() << " spectral truncation -- linear: " << grid.ny() - 1 << std::endl; - Log::info() << " spectral truncation -- quadratic: " - << static_cast( std::floor( 2. / 3. * grid.ny() + 0.5 ) ) - 1 << std::endl; - Log::info() << " spectral truncation -- cubic: " - << static_cast( std::floor( 0.5 * grid.ny() + 0.5 ) ) - 1 << std::endl; - - Log::info() << " memory footprint per field: " << eckit::Bytes( memsize ) << std::endl; + Log::info() << " memory footprint per field (dp): " << eckit::Bytes( memsize ) << std::endl; + + if ( auto structuredgrid = StructuredGrid( grid ) ) { + if ( not grid.projection() ) { + double deg, km; + + Log::info() << " number of latitudes (N-S): " << structuredgrid.ny() << std::endl; + Log::info() << " number of longitudes (max): " << structuredgrid.nxmax() << std::endl; + + deg = ( structuredgrid.y().front() - structuredgrid.y().back() ) / ( structuredgrid.ny() - 1 ); + km = deg * 40075. / 360.; + Log::info() << " approximate resolution N-S: " << std::setw( 10 ) << std::fixed << deg + << " deg " << km << " km " << std::endl; + + deg = 360. / static_cast( structuredgrid.nx( structuredgrid.ny() / 2 ) ); + km = deg * 40075. / 360.; + Log::info() << " approximate resolution E-W equator: " << std::setw( 10 ) << std::fixed << deg + << " deg " << km << " km " << std::endl; + + deg = 360. * std::cos( structuredgrid.y( structuredgrid.ny() / 4 ) * M_PI / 180. ) / + static_cast( structuredgrid.nx( structuredgrid.ny() / 4 ) ); + km = deg * 40075. / 360.; + Log::info() << " approximate resolution E-W midlat: " << std::setw( 10 ) << std::fixed << deg + << " deg " << km << " km " << std::endl; + + deg = 360. * std::cos( structuredgrid.y().front() * M_PI / 180. ) / + static_cast( structuredgrid.nx().front() ); + km = deg * 40075. / 360.; + + + Log::info() << " approximate resolution E-W pole: " << std::setw( 10 ) << std::fixed << deg + << " deg " << km << " km " << std::endl; + + Log::info() << " spectral truncation -- linear: " << structuredgrid.ny() - 1 << std::endl; + Log::info() << " spectral truncation -- quadratic: " + << static_cast( std::floor( 2. / 3. * structuredgrid.ny() + 0.5 ) ) - 1 + << std::endl; + Log::info() << " spectral truncation -- cubic: " + << static_cast( std::floor( 0.5 * structuredgrid.ny() + 0.5 ) ) - 1 << std::endl; + } + + auto precision = Log::info().precision( 3 ); + if ( grid.projection().units() == "meters" ) { + Log::info() << " x : [ " << std::setw( 10 ) << std::fixed << structuredgrid.xspace().min() / 1000. + << " , " << std::setw( 10 ) << std::fixed << structuredgrid.xspace().max() / 1000. + << " ] km" << std::endl; + Log::info() << " y : [ " << std::setw( 10 ) << std::fixed << structuredgrid.yspace().min() / 1000. + << " , " << std::setw( 10 ) << std::fixed << structuredgrid.yspace().max() / 1000. + << " ] km" << std::endl; + if ( structuredgrid.xspace().nxmax() == structuredgrid.xspace().nxmin() ) { + Log::info() << " dx : " << structuredgrid.xspace().dx()[0] / 1000. << " km" << std::endl; + } + Log::info() << " dy : " + << std::abs( structuredgrid.yspace()[1] - structuredgrid.yspace()[0] ) / 1000. << " km" + << std::endl; + Log::info() << " lonlat(centre) : " + << grid.projection().lonlat( + {0.5 * ( structuredgrid.xspace().max() + structuredgrid.xspace().min() ), + 0.5 * ( structuredgrid.yspace().max() + structuredgrid.yspace().min() )} ) + << std::endl; + Log::info() << " lonlat(xmin,ymax) : " + << grid.projection().lonlat( + {structuredgrid.xspace().min(), structuredgrid.yspace().max()} ) + << std::endl; + Log::info() << " lonlat(xmin,ymin) : " + << grid.projection().lonlat( + {structuredgrid.xspace().min(), structuredgrid.yspace().min()} ) + << std::endl; + Log::info() << " lonlat(xmax,ymin) : " + << grid.projection().lonlat( + {structuredgrid.xspace().max(), structuredgrid.yspace().min()} ) + << std::endl; + Log::info() << " lonlat(xmax,ymax) : " + << grid.projection().lonlat( + {structuredgrid.xspace().max(), structuredgrid.yspace().max()} ) + << std::endl; + } + if ( grid.projection().units() == "degrees" ) { + Log::info() << " x : [ " << std::setw( 10 ) << std::fixed << structuredgrid.xspace().min() + << " , " << std::setw( 10 ) << std::fixed << structuredgrid.xspace().max() << " ] deg" + << std::endl; + Log::info() << " y : [ " << std::setw( 10 ) << std::fixed << structuredgrid.yspace().min() + << " , " << std::setw( 10 ) << std::fixed << structuredgrid.yspace().max() << " ] deg" + << std::endl; + } + PointLonLat first_point = *grid.lonlat().begin(); + PointLonLat last_point; + for ( const auto p : grid.lonlat() ) { + last_point = p; + } + Log::info() << " lonlat(first) : " << first_point << std::endl; + Log::info() << " lonlat(last) : " << last_point << std::endl; + Log::info().precision( precision ); + } } + if ( json ) { std::stringstream stream; - JSON js( stream ); + eckit::JSON js( stream ); js.precision( 16 ); js << grid.spec(); std::cout << stream.str() << std::endl; } if ( rtable ) { - std::stringstream stream; - stream << "&NAMRGRI\n"; - 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; - std::cout << stream.str() << std::endl; + if ( auto structuredgrid = StructuredGrid( grid ) ) { + std::stringstream stream; + stream << "&NAMRGRI\n"; + for ( idx_t j = 0; j < structuredgrid.ny(); ++j ) { + stream << " NRGRI(" << std::setfill( '0' ) << std::setw( 5 ) << 1 + j << ")=" << std::setfill( ' ' ) + << std::setw( 5 ) << structuredgrid.nx( j ) << ",\n"; + } + stream << "/" << std::flush; + std::cout << stream.str() << std::endl; + } + } + + if ( check ) { + bool check_failed = false; + Log::Channel out; + out.setStream( Log::error() ); + + eckit::PathName path{key}; + if ( not path.exists() ) { + out << "Check failed: " << key << " is not a file" << std::endl; + return failed(); + } + + util::Config config_check; + if ( not util::Config{path}.get( "check", config_check ) ) { + out << "Check failed: no \"check\" section in " << key << std::endl; + return failed(); + } + + idx_t size; + if ( config_check.get( "size", size ) ) { + if ( grid.size() != size ) { + out << "Check failed: grid size " << grid.size() << " expected to be " << size << std::endl; + check_failed = true; + } + } + else { + Log::warning() << "Check for size skipped" << std::endl; + } + + std::string uid; + if ( config_check.get( "uid", uid ) ) { + if ( grid.uid() != uid ) { + out << "Check failed: grid uid " << grid.uid() << " expected to be " << uid << std::endl; + check_failed = true; + } + } + else if ( check_uid && uid.empty() ) { + out << "Check failed: grid uid " << grid.uid() << " was not encoded in the check" << std::endl; + check_failed = true; + } + else { + Log::warning() << "Check for uid skipped" << std::endl; + } + + + auto equal = []( double a, double b ) { return eckit::types::is_approximately_equal( a, b, 5.e-4 ); }; + + std::vector first_point_lonlat; + if ( config_check.get( "lonlat(first)", first_point_lonlat ) ) { + PointLonLat first_point = *grid.lonlat().begin(); + if ( not equal( first_point.lon(), first_point_lonlat[0] ) or + not equal( first_point.lat(), first_point_lonlat[1] ) ) { + out << "Check failed: lonlat(first) " << first_point << " expected to be " + << PointLonLat( first_point_lonlat.data() ) << std::endl; + check_failed = true; + } + } + else { + Log::warning() << "Check for lonlat(first) skipped" << std::endl; + } + + std::vector last_point_lonlat; + if ( config_check.get( "lonlat(last)", last_point_lonlat ) ) { + PointLonLat last_point; + for ( const auto p : grid.lonlat() ) { + last_point = p; + } + if ( not equal( last_point.lon(), last_point_lonlat[0] ) or + not equal( last_point.lat(), last_point_lonlat[1] ) ) { + out << "Check failed: lonlat(last) " << last_point << " expected to be " + << PointLonLat( last_point_lonlat.data() ) << std::endl; + check_failed = true; + } + } + else { + Log::warning() << "Check for lonlat(last) skipped" << std::endl; + } + + std::vector bbox; + if ( config_check.get( "bounding_box(n,w,s,e)", bbox ) && bbox.size() == 4 ) { + auto bb = grid.lonlatBoundingBox(); + if ( ( check_failed = !bb ) ) { + out << "Check failed: cannot calculate bounding box for " << grid.spec() << std::endl; + } + else if ( ( check_failed = !equal( bb.north(), bbox[0] ) ) ) { + out << "Check failed: n=" << bb.north() << " expected to be " << bbox[0] << std::endl; + } + else if ( ( check_failed = !equal( bb.west(), bbox[1] ) ) ) { + out << "Check failed: w=" << bb.west() << " expected to be " << bbox[1] << std::endl; + } + else if ( ( check_failed = !equal( bb.south(), bbox[2] ) ) ) { + out << "Check failed: s=" << bb.south() << " expected to be " << bbox[2] << std::endl; + } + else if ( ( check_failed = !equal( bb.east(), bbox[3] ) ) ) { + out << "Check failed: e=" << bb.east() << " expected to be " << bbox[3] << std::endl; + } + } + else if ( check_bbox && bbox.size() != 4 ) { + out << "Check failed: grid bounding_box(n,w,s,e) " << grid.lonlatBoundingBox() + << " was not encoded in the check" << std::endl; + check_failed = true; + } + else { + Log::warning() << "Check for bounding_box(n,w,s,e) skipped" << std::endl; + } + + if ( check_failed ) { + return failed(); + } + Log::info() << "SUCCESS: All checks passed" << std::endl; } } + return success(); } //------------------------------------------------------------------------------------------------------ diff --git a/src/apps/atlas-loadbalance.cc b/src/apps/atlas-loadbalance.cc index d337619a5..8df6a73b6 100644 --- a/src/apps/atlas-loadbalance.cc +++ b/src/apps/atlas-loadbalance.cc @@ -77,7 +77,9 @@ class AtlasLoadbalance : public eckit::Tool { key = ""; for ( int i = 0; i < argc; ++i ) { - if ( i == 1 && argv[i][0] != '-' ) { key = std::string( argv[i] ); } + if ( i == 1 && argv[i][0] != '-' ) { + key = std::string( argv[i] ); + } } halo = Resource( "--halo", 1 ); @@ -95,7 +97,9 @@ class AtlasLoadbalance : public eckit::Tool { //------------------------------------------------------------------------------------------------------ void AtlasLoadbalance::run() { - if ( !do_run ) return; + if ( !do_run ) { + return; + } StructuredGrid grid; try { @@ -104,18 +108,24 @@ void AtlasLoadbalance::run() { catch ( eckit::Exception& err ) { } - if ( !grid ) return; + if ( !grid ) { + return; + } MeshGenerator meshgenerator( "structured" ); Mesh mesh = meshgenerator.generate( grid ); functionspace::NodeColumns nodes( mesh, option::halo( halo ) ); - if ( output.size() ) { write_load_balance_report( mesh, output ); } + if ( output.size() ) { + write_load_balance_report( mesh, output ); + } else { std::stringstream s; write_load_balance_report( mesh, s ); - if ( mpi::comm().rank() == 0 ) { std::cout << s.str() << std::endl; } + if ( mpi::comm().rank() == 0 ) { + std::cout << s.str() << std::endl; + } } atlas::Library::instance().finalise(); } diff --git a/src/apps/atlas-meshgen.cc b/src/apps/atlas-meshgen.cc index 1751e2365..ac4a70403 100644 --- a/src/apps/atlas-meshgen.cc +++ b/src/apps/atlas-meshgen.cc @@ -57,7 +57,7 @@ using eckit::PathName; //------------------------------------------------------------------------------ class Meshgen2Gmsh : public AtlasTool { - virtual void execute( const Args& args ); + virtual int execute( const Args& args ); virtual std::string briefDescription() { return "Mesh generator for Structured compatible meshes"; } virtual std::string usage() { return name() + " (--grid.name=name|--grid.json=path) [OPTION]... OUTPUT [--help]"; } @@ -116,7 +116,7 @@ Meshgen2Gmsh::Meshgen2Gmsh( int argc, char** argv ) : AtlasTool( argc, argv ) { //----------------------------------------------------------------------------- -void Meshgen2Gmsh::execute( const Args& args ) { +int Meshgen2Gmsh::execute( const Args& args ) { key = ""; args.get( "grid.name", key ); @@ -138,20 +138,26 @@ void Meshgen2Gmsh::execute( const Args& args ) { args.get( "binary", binary ); std::string path_in_str = ""; - if ( args.get( "grid.json", path_in_str ) ) path_in = path_in_str; + if ( args.get( "grid.json", path_in_str ) ) { + path_in = path_in_str; + } - if ( args.count() ) + if ( args.count() ) { path_out = args( 0 ); - else + } + else { path_out = "mesh.msh"; + } if ( path_in_str.empty() && key.empty() ) { Log::warning() << "missing argument --grid.name or --grid.json" << std::endl; Log::warning() << "Usage: " << usage() << std::endl; - return; + return failed(); } - if ( edges ) halo = std::max( halo, 1l ); + if ( edges ) { + halo = std::max( halo, 1l ); + } StructuredGrid grid; if ( key.size() ) { @@ -174,7 +180,9 @@ void Meshgen2Gmsh::execute( const Args& args ) { Log::error() << "No grid specified." << std::endl; } - if ( !grid ) return; + if ( !grid ) { + return failed(); + } Log::debug() << "Domain: " << grid.domain() << std::endl; Log::debug() << "Periodic: " << grid.periodic() << std::endl; @@ -183,7 +191,9 @@ void Meshgen2Gmsh::execute( const Args& args ) { std::string Implementationype = ( RegularGrid( grid ) ? "regular" : "structured" ); args.get( "generator", Implementationype ); eckit::LocalConfiguration meshgenerator_config( args ); - if ( mpi::comm().size() > 1 || edges ) meshgenerator_config.set( "3d", false ); + if ( mpi::comm().size() > 1 || edges ) { + meshgenerator_config.set( "3d", false ); + } MeshGenerator meshgenerator( Implementationype, meshgenerator_config ); @@ -197,7 +207,9 @@ void Meshgen2Gmsh::execute( const Args& args ) { throw e; } - if ( grid.projection().units() == "degrees" ) { functionspace::NodeColumns nodes_fs( mesh, option::halo( halo ) ); } + if ( grid.projection().units() == "degrees" ) { + functionspace::NodeColumns nodes_fs( mesh, option::halo( halo ) ); + } else { Log::warning() << "Not yet implemented: building halo's with projections " "not defined in degrees" @@ -206,13 +218,17 @@ void Meshgen2Gmsh::execute( const Args& args ) { } if ( edges && grid.projection().units() == "degrees" ) { functionspace::EdgeColumns edges_fs( mesh, option::halo( halo ) ); - if ( brick ) + if ( brick ) { build_brick_dual_mesh( grid, mesh ); - else + } + else { build_median_dual_mesh( mesh ); + } } - if ( stats ) { build_statistics( mesh ); } + if ( stats ) { + build_statistics( mesh ); + } bool torus = false; args.get( "torus", torus ); @@ -239,6 +255,7 @@ void Meshgen2Gmsh::execute( const Args& args ) { mesh.polygon( jhalo ).outputPythonScript( "polygon_halo" + std::to_string( jhalo ) + ".py" ); } } + return success(); } //------------------------------------------------------------------------------ diff --git a/src/apps/atlas.cc b/src/apps/atlas.cc index 0ca8a3860..319ad38d0 100644 --- a/src/apps/atlas.cc +++ b/src/apps/atlas.cc @@ -69,8 +69,9 @@ void Version::run() { << std::endl; return; } - else + else { Log::info() << "usage: atlas [--help] [--version] [--git] [--info]" << std::endl; + } } } // namespace atlas diff --git a/src/atlas/CMakeLists.txt b/src/atlas/CMakeLists.txt index 6b845578c..21fda484d 100644 --- a/src/atlas/CMakeLists.txt +++ b/src/atlas/CMakeLists.txt @@ -391,6 +391,8 @@ trans/detail/TransFactory.h trans/detail/TransFactory.cc trans/detail/TransImpl.h trans/detail/TransImpl.cc +trans/detail/TransInterface.h +trans/detail/TransInterface.cc ) if( ATLAS_HAVE_TRANS ) list( APPEND atlas_numerics_srcs diff --git a/src/atlas/array/ArraySpec.cc b/src/atlas/array/ArraySpec.cc index b78529ac3..b90708394 100644 --- a/src/atlas/array/ArraySpec.cc +++ b/src/atlas/array/ArraySpec.cc @@ -22,7 +22,9 @@ 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; + if ( mod > 0 ) { + _allocated_size += alignment; + } return _allocated_size; } } // namespace @@ -32,7 +34,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 ) ATLAS_NOTIMPLEMENTED; // innermost dimension needs to be padded + if ( int( alignment ) > 1 ) { + ATLAS_NOTIMPLEMENTED; // innermost dimension needs to be padded + } rank_ = static_cast( shape.size() ); size_ = 1; @@ -98,7 +102,9 @@ ArraySpec::ArraySpec( const ArrayShape& shape, const ArrayStrides& strides, cons strides_[j] = strides[j]; layout_[j] = layout[j]; size_ *= shape_[j]; - if ( layout_[j] != idx_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_ ); diff --git a/src/atlas/array/LocalView.cc b/src/atlas/array/LocalView.cc index 53288daef..855deedef 100644 --- a/src/atlas/array/LocalView.cc +++ b/src/atlas/array/LocalView.cc @@ -35,8 +35,9 @@ void LocalView::dump( std::ostream& os ) const { const value_type* data_ = data(); os << "size: " << size() << " , values: "; os << "[ "; - for ( idx_t j = 0; j < size(); ++j ) + for ( idx_t j = 0; j < size(); ++j ) { os << data_[j] << " "; + } os << "]"; } diff --git a/src/atlas/array/LocalView.h b/src/atlas/array/LocalView.h index 1d8c37cc5..abe29e459 100644 --- a/src/atlas/array/LocalView.h +++ b/src/atlas/array/LocalView.h @@ -209,7 +209,9 @@ class LocalView { template void check_bounds_part( Int idx, Ints... next_idx ) const { - if ( idx_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... ); } diff --git a/src/atlas/array/SVector.h b/src/atlas/array/SVector.h index 89041bf2e..78635def1 100644 --- a/src/atlas/array/SVector.h +++ b/src/atlas/array/SVector.h @@ -59,7 +59,8 @@ class SVector { ATLAS_HOST_DEVICE ~SVector() { #ifndef __CUDA_ARCH__ - if ( !externally_allocated_ ) util::delete_managedmem( data_ ); + if ( !externally_allocated_ ) + util::delete_managedmem( data_ ); #endif } @@ -114,7 +115,8 @@ class SVector { idx_t size() const { return size_; } void resize_impl( idx_t N ) { - if ( N == size_ ) return; + if ( N == size_ ) + return; T* d_ = nullptr; util::allocate_managedmem( d_, N ); diff --git a/src/atlas/array/Table.cc b/src/atlas/array/Table.cc index abf59e35f..9f9f3ac79 100644 --- a/src/atlas/array/Table.cc +++ b/src/atlas/array/Table.cc @@ -172,7 +172,8 @@ void Table::add( size_t rows, size_t cols, const idx_t values[], bool fortran_ar ATLAS_ASSERT( owns_, "HybridConnectivity must be owned to be resized directly" ); size_t old_size = size(); - if ( rows_ == 0 ) old_size = 0; + if ( rows_ == 0 ) + old_size = 0; size_t new_size = old_size + rows * cols; size_t new_rows = rows_ + rows; @@ -217,7 +218,8 @@ void Table::add( size_t rows, size_t cols ) { ATLAS_ASSERT( owns_, "HybridConnectivity must be owned to be resized directly" ); size_t old_size = size(); - if ( rows_ == 0 ) old_size = 0; + if ( rows_ == 0 ) + old_size = 0; size_t new_size = old_size + rows * cols; size_t new_rows = rows_ + rows; @@ -281,7 +283,9 @@ void Table::insert( size_t position, size_t rows, const size_t cols[] ) { size_t position_displs = displs_( position ); if ( rows_ == 0 ) { - if ( position > 1 ) { insert_counts_and_displs( position - 1, rows ); } + if ( position > 1 ) { + insert_counts_and_displs( position - 1, rows ); + } } else { insert_counts_and_displs( position, rows ); diff --git a/src/atlas/array/Vector.h b/src/atlas/array/Vector.h index ceddb2cda..a412a9816 100644 --- a/src/atlas/array/Vector.h +++ b/src/atlas/array/Vector.h @@ -33,13 +33,15 @@ class Vector { 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; + if ( N == size_ ) + return; T* d_ = new T[N]; for ( idx_t c = 0; c < size_; ++c ) { d_[c] = data_[c]; } - if ( data_ ) delete[] data_; + if ( data_ ) + delete[] data_; data_ = d_; } diff --git a/src/atlas/array/gridtools/GridToolsArray.cc b/src/atlas/array/gridtools/GridToolsArray.cc index 6da313159..12884958b 100644 --- a/src/atlas/array/gridtools/GridToolsArray.cc +++ b/src/atlas/array/gridtools/GridToolsArray.cc @@ -46,7 +46,7 @@ template using UintSequence = ::gridtools::make_gt_integer_sequence; template class Storage, typename StorageInfo> -static Array* wrap_array(::gridtools::data_store, StorageInfo>* ds, const ArraySpec& spec ) { +static Array* wrap_array( ::gridtools::data_store, StorageInfo>* ds, const ArraySpec& spec ) { assert( ds ); using data_store_t = typename std::remove_pointer::type; ArrayDataStore* data_store = new GridToolsDataStore( ds ); @@ -167,7 +167,8 @@ class ArrayT_impl { throw_Exception( err.str(), Here() ); } - if ( array_.valid() ) array_.syncHostDevice(); + if ( array_.valid() ) + array_.syncHostDevice(); Array* resized = Array::create( ArrayShape{(idx_t)c...} ); @@ -346,10 +347,13 @@ void ArrayT::insert( idx_t idx1, idx_t size1 ) { // if( hostNeedsUpdate() ) { // cloneFromDevice(); //} - if ( not hasDefaultLayout() ) ATLAS_NOTIMPLEMENTED; + if ( not hasDefaultLayout() ) + ATLAS_NOTIMPLEMENTED; ArrayShape nshape = shape(); - if ( idx1 > nshape[0] ) { throw_Exception( "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 ); @@ -495,7 +499,8 @@ ArrayT::ArrayT( const ArrayShape& shape, const ArrayLayout& layout ) { template ArrayT::ArrayT( const ArraySpec& spec ) { - if ( not spec.contiguous() ) ATLAS_NOTIMPLEMENTED; + if ( not spec.contiguous() ) + ATLAS_NOTIMPLEMENTED; ArrayT_impl( *this ).construct( spec.shape(), spec.layout() ); } diff --git a/src/atlas/array/gridtools/GridToolsArrayHelpers.h b/src/atlas/array/gridtools/GridToolsArrayHelpers.h index c058163cb..2fdf7e90e 100644 --- a/src/atlas/array/gridtools/GridToolsArrayHelpers.h +++ b/src/atlas/array/gridtools/GridToolsArrayHelpers.h @@ -119,7 +119,7 @@ struct get_stride_component { template ATLAS_HOST_DEVICE constexpr static Value apply( StorageInfoPtr a ) { - static_assert( (::gridtools::is_storage_info::type>::value ), + static_assert( ( ::gridtools::is_storage_info::type>::value ), "Error: not a storage_info" ); return a->template stride(); } @@ -135,7 +135,7 @@ struct get_shape_component { template ATLAS_HOST_DEVICE constexpr static Value apply( StorageInfoPtr a ) { - static_assert( (::gridtools::is_storage_info::type>::value ), + static_assert( ( ::gridtools::is_storage_info::type>::value ), "Error: not a storage_info" ); return a->template total_length(); } @@ -165,7 +165,9 @@ typename gt_storage_t::type::value>::t typedef gridtools::storage_traits::data_store_t data_store_t; data_store_t* ds; - if (::gridtools::accumulate(::gridtools::multiplies(), dims... ) == 0 ) { ds = new data_store_t(); } + if ( ::gridtools::accumulate( ::gridtools::multiplies(), dims... ) == 0 ) { + ds = new data_store_t(); + } else { storage_info_ty si( dims... ); ds = new data_store_t( si ); @@ -201,7 +203,7 @@ constexpr idx_t zero( idx_t ) { } template -ArrayStrides make_null_strides(::gridtools::gt_integer_sequence ) { +ArrayStrides make_null_strides( ::gridtools::gt_integer_sequence ) { return make_strides( zero( Is )... ); } @@ -232,7 +234,7 @@ struct my_apply_gt_integer_sequence<::gridtools::gt_integer_sequence ArraySpec ATLAS_HOST make_spec( DataStore* gt_data_store_ptr, Dims... dims ) { - static_assert( (::gridtools::is_data_store::value ), "Internal Error: passing a non GT data store" ); + static_assert( ( ::gridtools::is_data_store::value ), "Internal Error: passing a non GT data store" ); if ( gt_data_store_ptr->valid() ) { auto storage_info_ptr = gt_data_store_ptr->get_storage_info_ptr().get(); @@ -251,7 +253,7 @@ ArraySpec ATLAS_HOST make_spec( DataStore* gt_data_store_ptr, Dims... dims ) { } else { return ArraySpec( make_shape( {dims...} ), - make_null_strides(::gridtools::make_gt_integer_sequence() ) ); + make_null_strides( ::gridtools::make_gt_integer_sequence() ) ); } } #endif diff --git a/src/atlas/array/gridtools/GridToolsMakeView.cc b/src/atlas/array/gridtools/GridToolsMakeView.cc index b6115a5dd..33bcb416a 100644 --- a/src/atlas/array/gridtools/GridToolsMakeView.cc +++ b/src/atlas/array/gridtools/GridToolsMakeView.cc @@ -89,7 +89,7 @@ IndexView make_host_indexview( const Array& array ) { data_store_t* ds = reinterpret_cast( const_cast( array.storage() ) ); - return IndexView(::gridtools::make_host_view<::gridtools::access_mode::ReadWrite>( *ds ) ); + return IndexView( ::gridtools::make_host_view<::gridtools::access_mode::ReadWrite>( *ds ) ); } // -------------------------------------------------------------------------------------------- diff --git a/src/atlas/array/helpers/ArrayInitializer.h b/src/atlas/array/helpers/ArrayInitializer.h index f99596471..150551bcb 100644 --- a/src/atlas/array/helpers/ArrayInitializer.h +++ b/src/atlas/array/helpers/ArrayInitializer.h @@ -101,7 +101,9 @@ struct array_initializer_partitioned_val_impl { DimIndexPair... idxs ) { for ( idx_t i = 0; i < orig.shape( Dim ); ++i ) { idx_t displ = i; - if ( Dim == PartDim && i >= pos ) { displ += offset; } + if ( Dim == PartDim && i >= pos ) { + displ += offset; + } std::pair pair_idx{i, displ}; array_initializer_partitioned_val_impl::apply( std::move( orig ), std::move( dest ), pos, offset, idxs..., pair_idx ); diff --git a/src/atlas/array/helpers/ArrayWriter.h b/src/atlas/array/helpers/ArrayWriter.h index 97d4aa173..6f44745fb 100644 --- a/src/atlas/array/helpers/ArrayWriter.h +++ b/src/atlas/array/helpers/ArrayWriter.h @@ -33,7 +33,8 @@ struct array_writer_impl { static void apply( View& arr, std::ostream& out, DimIndex... idxs ) { 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 << " "; + if ( i < arr.shape( Dim ) - 1 ) + out << " "; } } }; diff --git a/src/atlas/array/native/NativeArray.cc b/src/atlas/array/native/NativeArray.cc index 242f0d67f..8ab381ce5 100644 --- a/src/atlas/array/native/NativeArray.cc +++ b/src/atlas/array/native/NativeArray.cc @@ -118,8 +118,9 @@ template ArrayT::ArrayT( const ArrayShape& shape ) { ATLAS_ASSERT( shape.size() > 0 ); idx_t size = 1; - for ( size_t j = 0; j < shape.size(); ++j ) + for ( size_t j = 0; j < shape.size(); ++j ) { size *= shape[j]; + } data_store_ = std::unique_ptr( new native::DataStore( size ) ); spec_ = ArraySpec( shape ); } @@ -128,13 +129,16 @@ template 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 ) + for ( size_t j = 0; j < layout.size(); ++j ) { ATLAS_ASSERT( spec_.layout()[j] == layout[j] ); + } } template ArrayT::ArrayT( const ArraySpec& spec ) { - if ( not spec.contiguous() ) ATLAS_NOTIMPLEMENTED; + if ( not spec.contiguous() ) { + ATLAS_NOTIMPLEMENTED; + } spec_ = spec; data_store_ = std::unique_ptr( new native::DataStore( spec_.size() ) ); } @@ -188,7 +192,9 @@ void ArrayT::resize( const ArrayShape& _shape ) { template void ArrayT::insert( idx_t idx1, idx_t size1 ) { ArrayShape nshape = shape(); - if ( idx1 > nshape[0] ) { throw_Exception( "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 ); @@ -264,7 +270,9 @@ template size_t ArrayT::footprint() const { size_t size = sizeof( *this ); size += bytes(); - if ( not contiguous() ) ATLAS_NOTIMPLEMENTED; + if ( not contiguous() ) { + ATLAS_NOTIMPLEMENTED; + } return size; } diff --git a/src/atlas/array/native/NativeArrayView.h b/src/atlas/array/native/NativeArrayView.h index 5b0b7acdd..014ad1345 100644 --- a/src/atlas/array/native/NativeArrayView.h +++ b/src/atlas/array/native/NativeArrayView.h @@ -229,7 +229,9 @@ class ArrayView { template void check_bounds_part( Int idx, Ints... next_idx ) const { - if ( idx_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... ); } diff --git a/src/atlas/array/native/NativeIndexView.cc b/src/atlas/array/native/NativeIndexView.cc index 2aac81e51..485901b84 100644 --- a/src/atlas/array/native/NativeIndexView.cc +++ b/src/atlas/array/native/NativeIndexView.cc @@ -29,8 +29,9 @@ template void IndexView::dump( std::ostream& os ) const { os << "size: " << size() << " , values: "; os << "[ "; - for ( idx_t j = 0; j < size(); ++j ) + for ( idx_t j = 0; j < size(); ++j ) { os << ( *this )( j ) << " "; + } os << "]" << std::endl; } diff --git a/src/atlas/array/native/NativeIndexView.h b/src/atlas/array/native/NativeIndexView.h index 7036dbee5..2b1a68110 100644 --- a/src/atlas/array/native/NativeIndexView.h +++ b/src/atlas/array/native/NativeIndexView.h @@ -172,7 +172,9 @@ class IndexView { template void check_bounds_part( Int idx, Ints... next_idx ) const { - if ( idx_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... ); } diff --git a/src/atlas/domain/Domain.cc b/src/atlas/domain/Domain.cc index 9d3475c7f..c3cd1fcc8 100644 --- a/src/atlas/domain/Domain.cc +++ b/src/atlas/domain/Domain.cc @@ -26,7 +26,8 @@ RectangularDomain::RectangularDomain( const Interval& x, const Interval& y, cons Domain( ( RD::is_global( x, y, units ) ) ? new atlas::domain::GlobalDomain( x[0] ) : ( RD::is_zonal_band( x, units ) ? new atlas::domain::ZonalBandDomain( y, x[0] ) - : new atlas::domain::RectangularDomain( x, y, units ) ) ) {} + : new atlas::domain::RectangularDomain( x, y, units ) ) ), + domain_( dynamic_cast( get() ) ) {} RectangularDomain::RectangularDomain( const Domain& domain ) : Domain( domain ), @@ -60,14 +61,33 @@ double RectangularDomain::ymax() const { return domain_->ymax(); } +ZonalBandDomain::ZonalBandDomain( const Interval& y ) : + RectangularLonLatDomain( ( ZD::is_global( y ) ) ? new atlas::domain::GlobalDomain() + : new atlas::domain::ZonalBandDomain( y ) ), + domain_( dynamic_cast( get() ) ) {} + ZonalBandDomain::ZonalBandDomain( const Interval& y, const double& west ) : - RectangularDomain( ( ZD::is_global( y ) ) ? new atlas::domain::GlobalDomain( west ) - : new atlas::domain::ZonalBandDomain( y, west ) ) {} + RectangularLonLatDomain( ( ZD::is_global( y ) ) ? new atlas::domain::GlobalDomain( west ) + : new atlas::domain::ZonalBandDomain( y, west ) ), + domain_( dynamic_cast( get() ) ) {} ZonalBandDomain::ZonalBandDomain( const Domain& domain ) : - RectangularDomain( domain ), + RectangularLonLatDomain( domain ), domain_( dynamic_cast( get() ) ) {} +GlobalDomain::GlobalDomain( const double& west ) : + ZonalBandDomain( new atlas::domain::GlobalDomain( west ) ), + domain_( dynamic_cast( get() ) ) {} + +GlobalDomain::GlobalDomain() : + ZonalBandDomain( new atlas::domain::GlobalDomain() ), + domain_( dynamic_cast( get() ) ) {} + +GlobalDomain::GlobalDomain( const Domain& domain ) : + ZonalBandDomain( domain ), + domain_( dynamic_cast( get() ) ) {} + + std::string atlas::Domain::type() const { return get()->type(); } diff --git a/src/atlas/domain/Domain.h b/src/atlas/domain/Domain.h index 685864ef5..d77f832ff 100644 --- a/src/atlas/domain/Domain.h +++ b/src/atlas/domain/Domain.h @@ -90,7 +90,8 @@ class Domain : public util::ObjectHandle { namespace domain { class RectangularDomain; -} +class RectangularLonLatDomain; +} // namespace domain class RectangularDomain : public Domain { public: @@ -102,7 +103,7 @@ class RectangularDomain : public Domain { RectangularDomain( const Domain& ); - operator bool() { return domain_; } + operator bool() const { return domain_; } /// Checks if the x-value is contained in the domain bool contains_x( double x ) const; @@ -123,25 +124,62 @@ class RectangularDomain : public Domain { //--------------------------------------------------------------------------------------------------------------------- +class RectangularLonLatDomain : public RectangularDomain { +public: + using RectangularDomain::RectangularDomain; + RectangularLonLatDomain( const Interval& x, const Interval& y ) : RectangularDomain( x, y, "degrees" ) {} + RectangularLonLatDomain( const double& north, const double& west, const double& south, const double& east ) : + RectangularLonLatDomain( {west, east}, {south, north} ) {} + + operator bool() const { return RectangularDomain::operator bool() && units() == "degrees"; } + + double west() const { return xmin(); } + double east() const { return xmax(); } + double north() const { return ymax(); } + double south() const { return ymin(); } +}; + +//--------------------------------------------------------------------------------------------------------------------- + namespace domain { class ZonalBandDomain; } -class ZonalBandDomain : public RectangularDomain { +class ZonalBandDomain : public RectangularLonLatDomain { public: using Interval = std::array; public: - using RectangularDomain::RectangularDomain; - ZonalBandDomain( const Interval& y, const double& west = 0. ); + using RectangularLonLatDomain::RectangularLonLatDomain; + ZonalBandDomain( const Interval& y, const double& west ); + ZonalBandDomain( const Interval& y ); ZonalBandDomain( const Domain& ); - operator bool() { return domain_; } + operator bool() const { return domain_; } private: const ::atlas::domain::ZonalBandDomain* domain_; }; + +namespace domain { +class GlobalDomain; +} + +//--------------------------------------------------------------------------------------------------------------------- + +class GlobalDomain : public ZonalBandDomain { +public: + GlobalDomain( const double& west ); + GlobalDomain(); + GlobalDomain( const Domain& ); + + operator bool() const { return domain_; } + +private: + const ::atlas::domain::GlobalDomain* domain_; +}; + //--------------------------------------------------------------------------------------------------------------------- } // namespace atlas diff --git a/src/atlas/domain/detail/Domain.cc b/src/atlas/domain/detail/Domain.cc index 0caa806e4..74f712aae 100644 --- a/src/atlas/domain/detail/Domain.cc +++ b/src/atlas/domain/detail/Domain.cc @@ -25,7 +25,9 @@ const Domain* Domain::create() { const Domain* Domain::create( const eckit::Parametrisation& p ) { std::string domain_type; - if ( p.get( "type", domain_type ) ) { return DomainFactory::build( domain_type, p ); } + if ( p.get( "type", domain_type ) ) { + return DomainFactory::build( domain_type, p ); + } // should return error here throw_Exception( "type missing in Params", Here() ); diff --git a/src/atlas/domain/detail/GlobalDomain.cc b/src/atlas/domain/detail/GlobalDomain.cc index b7eeffc01..e6739bae0 100644 --- a/src/atlas/domain/detail/GlobalDomain.cc +++ b/src/atlas/domain/detail/GlobalDomain.cc @@ -40,7 +40,9 @@ GlobalDomain::GlobalDomain( const eckit::Parametrisation& params ) : GlobalDomai GlobalDomain::Spec GlobalDomain::spec() const { Spec domain_spec; domain_spec.set( "type", type() ); - if ( xmin() != 0. ) { domain_spec.set( "west", xmin() ); } + if ( xmin() != 0. ) { + domain_spec.set( "west", xmin() ); + } return domain_spec; } diff --git a/src/atlas/domain/detail/RectangularDomain.cc b/src/atlas/domain/detail/RectangularDomain.cc index 306d5a546..bb2aeb4a2 100644 --- a/src/atlas/domain/detail/RectangularDomain.cc +++ b/src/atlas/domain/detail/RectangularDomain.cc @@ -11,6 +11,8 @@ #include #include +#include "eckit/utils/Hash.h" + #include "atlas/domain/detail/DomainFactory.h" #include "atlas/domain/detail/RectangularDomain.h" #include "atlas/runtime/Exception.h" @@ -25,9 +27,13 @@ namespace { static std::array get_interval_x( const eckit::Parametrisation& params ) { double xmin, xmax; - if ( !params.get( "xmin", xmin ) ) throw_Exception( "xmin missing in Params", Here() ); + if ( !params.get( "xmin", xmin ) ) { + throw_Exception( "xmin missing in Params", Here() ); + } - if ( !params.get( "xmax", xmax ) ) throw_Exception( "xmax missing in Params", Here() ); + if ( !params.get( "xmax", xmax ) ) { + throw_Exception( "xmax missing in Params", Here() ); + } return {xmin, xmax}; } @@ -35,30 +41,40 @@ 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_Exception( "ymin missing in Params", Here() ); + if ( !params.get( "ymin", ymin ) ) { + throw_Exception( "ymin missing in Params", Here() ); + } - if ( !params.get( "ymax", ymax ) ) throw_Exception( "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_Exception( "units missing in Params", Here() ); + if ( !params.get( "units", units ) ) { + throw_Exception( "units missing in Params", Here() ); + } return units; } } // namespace bool RectangularDomain::is_global( const Interval& x, const Interval& y, const std::string& units ) { - if ( units != "degrees" ) return false; + if ( units != "degrees" ) { + return false; + } const double eps = 1.e-12; return std::abs( ( x[1] - x[0] ) - 360. ) < eps && std::abs( std::abs( y[1] - y[0] ) - 180. ) < eps; } bool RectangularDomain::is_zonal_band( const Interval& x, const std::string& units ) { - if ( units != "degrees" ) return false; + if ( units != "degrees" ) { + return false; + } const double eps = 1.e-12; return std::abs( ( x[1] - x[0] ) - 360. ) < eps; @@ -76,8 +92,12 @@ RectangularDomain::RectangularDomain( const Interval& x, const Interval& y, cons unit_degrees_ = ( units_ == "degrees" ) ? true : false; // Make sure xmax>=xmin and ymax>=ymin - if ( xmin_ > xmax_ ) std::swap( xmin_, xmax_ ); - if ( ymin_ > ymax_ ) std::swap( ymin_, ymax_ ); + if ( xmin_ > xmax_ ) { + std::swap( xmin_, xmax_ ); + } + if ( ymin_ > ymax_ ) { + std::swap( ymin_, ymax_ ); + } global_ = is_global( {xmin_, xmax_}, {ymin_, ymax_}, units_ ); const double tol = 1.e-6; @@ -109,7 +129,13 @@ void RectangularDomain::print( std::ostream& os ) const { } void RectangularDomain::hash( eckit::Hash& h ) const { - spec().hash( h ); + auto add_double = [&]( const double& x ) { h.add( std::round( x * 1.e8 ) ); }; + h.add( type() ); + h.add( units() ); + add_double( xmin() ); + add_double( xmax() ); + add_double( ymin() ); + add_double( ymax() ); } bool RectangularDomain::containsNorthPole() const { diff --git a/src/atlas/domain/detail/RectangularDomain.h b/src/atlas/domain/detail/RectangularDomain.h index cccacfd80..8573fcad5 100644 --- a/src/atlas/domain/detail/RectangularDomain.h +++ b/src/atlas/domain/detail/RectangularDomain.h @@ -75,5 +75,15 @@ class RectangularDomain : public Domain { bool unit_degrees_; }; +class RectangularLonLatDomain : public RectangularDomain { +public: + RectangularLonLatDomain( const eckit::Parametrisation& config ) : RectangularDomain( config ) {} + RectangularLonLatDomain( const Interval& x, const Interval& y ) : RectangularDomain( x, y, "degrees" ) {} + double north() const { return ymax(); } + double south() const { return ymin(); } + double west() const { return xmin(); } + double east() const { return xmax(); } +}; + } // namespace domain } // namespace atlas diff --git a/src/atlas/domain/detail/ZonalBandDomain.cc b/src/atlas/domain/detail/ZonalBandDomain.cc index 902e5c84f..fd38dcbc0 100644 --- a/src/atlas/domain/detail/ZonalBandDomain.cc +++ b/src/atlas/domain/detail/ZonalBandDomain.cc @@ -27,9 +27,13 @@ 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_Exception( "ymin missing in Params", Here() ); + if ( !params.get( "ymin", ymin ) ) { + throw_Exception( "ymin missing in Params", Here() ); + } - if ( !params.get( "ymax", ymax ) ) throw_Exception( "ymax missing in Params", Here() ); + if ( !params.get( "ymax", ymax ) ) { + throw_Exception( "ymax missing in Params", Here() ); + } return {ymin, ymax}; } @@ -60,7 +64,7 @@ ZonalBandDomain::ZonalBandDomain( const eckit::Parametrisation& params ) : ZonalBandDomain::ZonalBandDomain( const Interval& interval_y ) : ZonalBandDomain( interval_y, /*west*/ 0. ) {} ZonalBandDomain::ZonalBandDomain( const Interval& interval_y, const double west ) : - RectangularDomain( {west, west + 360.}, interval_y, units_ ) { + RectangularLonLatDomain( {west, west + 360.}, interval_y ) { global_ = _is_global( ymin(), ymax() ); ymin_tol_ = ymin() - 1.e-6; ymax_tol_ = ymax() + 1.e-6; @@ -75,7 +79,9 @@ ZonalBandDomain::Spec ZonalBandDomain::spec() const { domain_spec.set( "type", type() ); domain_spec.set( "ymin", ymin() ); domain_spec.set( "ymax", ymax() ); - if ( xmin() != 0. ) { domain_spec.set( "west", xmin() ); } + if ( xmin() != 0. ) { + domain_spec.set( "west", xmin() ); + } return domain_spec; } diff --git a/src/atlas/domain/detail/ZonalBandDomain.h b/src/atlas/domain/detail/ZonalBandDomain.h index 4e8494edc..f37aa2ab6 100644 --- a/src/atlas/domain/detail/ZonalBandDomain.h +++ b/src/atlas/domain/detail/ZonalBandDomain.h @@ -23,7 +23,7 @@ class ZonalBandDomain; namespace atlas { namespace domain { -class ZonalBandDomain : public atlas::domain::RectangularDomain { +class ZonalBandDomain : public atlas::domain::RectangularLonLatDomain { protected: static constexpr char units_[] = "degrees"; diff --git a/src/atlas/field/Field.cc b/src/atlas/field/Field.cc index 5b57a50dd..18d8abd71 100644 --- a/src/atlas/field/Field.cc +++ b/src/atlas/field/Field.cc @@ -138,6 +138,10 @@ size_t Field::bytes() const { return get()->bytes(); } +bool Field::contiguous() const { + return array().contiguous(); +} + /// @brief Output information of field plus raw data void Field::dump( std::ostream& os ) const { get()->dump( os ); diff --git a/src/atlas/field/Field.h b/src/atlas/field/Field.h index 0ba7fe451..16a70bee0 100644 --- a/src/atlas/field/Field.h +++ b/src/atlas/field/Field.h @@ -125,6 +125,8 @@ class Field : public util::ObjectHandle { /// @brief Number of bytes occupied by the values of this field size_t bytes() const; + bool contiguous() const; + /// @brief Output information of field friend std::ostream& operator<<( std::ostream& os, const Field& v ); diff --git a/src/atlas/field/FieldCreator.cc b/src/atlas/field/FieldCreator.cc index b9faf4bb5..e5cb95090 100644 --- a/src/atlas/field/FieldCreator.cc +++ b/src/atlas/field/FieldCreator.cc @@ -102,8 +102,9 @@ FieldCreator* FieldCreatorFactory::build( const std::string& name ) { if ( j == m->end() ) { Log::error() << "No FieldCreatorFactory for [" << name << "]" << '\n'; Log::error() << "FieldCreatorFactories are:" << '\n'; - for ( j = m->begin(); j != m->end(); ++j ) + for ( j = m->begin(); j != m->end(); ++j ) { Log::error() << " " << ( *j ).first << '\n'; + } throw_Exception( std::string( "No FieldCreatorFactory called " ) + name ); } @@ -122,8 +123,9 @@ FieldCreator* FieldCreatorFactory::build( const std::string& name, const eckit:: if ( j == m->end() ) { Log::error() << "No FieldCreatorFactory for [" << name << "]" << '\n'; Log::error() << "FieldCreatorFactories are:" << '\n'; - for ( j = m->begin(); j != m->end(); ++j ) + for ( j = m->begin(); j != m->end(); ++j ) { Log::error() << " " << ( *j ).first << '\n'; + } throw_Exception( std::string( "No FieldCreatorFactory called " ) + name ); } diff --git a/src/atlas/field/FieldCreatorArraySpec.cc b/src/atlas/field/FieldCreatorArraySpec.cc index 1c7dca179..83aa66b04 100644 --- a/src/atlas/field/FieldCreatorArraySpec.cc +++ b/src/atlas/field/FieldCreatorArraySpec.cc @@ -24,20 +24,26 @@ namespace field { FieldImpl* FieldCreatorArraySpec::createField( const eckit::Parametrisation& params ) const { std::vector shape; - if ( !params.get( "shape", shape ) ) throw_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() ); bool fortran( false ); params.get( "fortran", fortran ); - if ( fortran ) + if ( fortran ) { std::reverse_copy( shape.begin(), shape.end(), s.begin() ); - else + } + else { s.assign( shape.begin(), shape.end() ); + } array::DataType datatype = array::DataType::create(); std::string datatype_str; - if ( params.get( "datatype", datatype_str ) ) { datatype = array::DataType( datatype_str ); } + if ( params.get( "datatype", datatype_str ) ) { + datatype = array::DataType( datatype_str ); + } else { array::DataType::kind_t kind( array::DataType::kind() ); params.get( "kind", kind ); diff --git a/src/atlas/field/FieldCreatorIFS.cc b/src/atlas/field/FieldCreatorIFS.cc index 652c1a69c..ce7e33a4a 100644 --- a/src/atlas/field/FieldCreatorIFS.cc +++ b/src/atlas/field/FieldCreatorIFS.cc @@ -32,14 +32,18 @@ FieldImpl* FieldCreatorIFS::createField( const eckit::Parametrisation& params ) size_t nproma = 1; size_t nlev = 1; - if ( !params.get( "ngptot", ngptot ) ) throw_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 ); array::DataType datatype = array::DataType::create(); std::string datatype_str; - if ( params.get( "datatype", datatype_str ) ) { datatype = array::DataType( datatype_str ); } + if ( params.get( "datatype", datatype_str ) ) { + datatype = array::DataType( datatype_str ); + } else { array::DataType::kind_t kind( array::DataType::kind() ); params.get( "kind", kind ); @@ -56,10 +60,12 @@ FieldImpl* FieldCreatorIFS::createField( const eckit::Parametrisation& params ) array::ArrayShape s; bool fortran( false ); params.get( "fortran", fortran ); - if ( fortran ) + if ( fortran ) { s = array::make_shape( nproma, nlev, nvar, nblk ); - else + } + else { s = array::make_shape( nblk, nvar, nlev, nproma ); + } std::string name; params.get( "name", name ); diff --git a/src/atlas/field/FieldSet.cc b/src/atlas/field/FieldSet.cc index 83da1add6..6a53950fb 100644 --- a/src/atlas/field/FieldSet.cc +++ b/src/atlas/field/FieldSet.cc @@ -28,7 +28,9 @@ void FieldSetImpl::clear() { } Field FieldSetImpl::add( const Field& field ) { - if ( field.name().size() ) { index_[field.name()] = size(); } + if ( field.name().size() ) { + index_[field.name()] = size(); + } else { std::stringstream name; name << name_ << "[" << size() << "]"; @@ -66,8 +68,9 @@ void FieldSetImpl::set_dirty( bool value ) const { std::vector FieldSetImpl::field_names() const { std::vector ret; - for ( const_iterator field = cbegin(); field != cend(); ++field ) + for ( const_iterator field = cbegin(); field != cend(); ++field ) { ret.push_back( field->name() ); + } return ret; } diff --git a/src/atlas/field/FieldSet.h b/src/atlas/field/FieldSet.h index f73f1686f..f1474e88c 100644 --- a/src/atlas/field/FieldSet.h +++ b/src/atlas/field/FieldSet.h @@ -58,11 +58,13 @@ class FieldSetImpl : public util::Object { Field& operator[]( const std::string& name ) { return field( name ); } const Field& field( const idx_t& i ) const { - if ( i >= size() ) throw_OutOfRange( "fieldset", i, size(), Here() ); + if ( i >= size() ) + throw_OutOfRange( "fieldset", i, size(), Here() ); return fields_[i]; } Field& field( const idx_t& i ) { - if ( i >= size() ) throw_OutOfRange( "fieldset", i, size(), Here() ); + if ( i >= size() ) + throw_OutOfRange( "fieldset", i, size(), Here() ); return fields_[i]; } diff --git a/src/atlas/field/State.cc b/src/atlas/field/State.cc index 80de91240..15257fac6 100644 --- a/src/atlas/field/State.cc +++ b/src/atlas/field/State.cc @@ -112,8 +112,9 @@ const Field& State::field( const idx_t idx ) const { throw_AssertionFailed( msg.str(), Here() ); } FieldMap::const_iterator it = fields_.begin(); - for ( idx_t i = 0; i < idx; ++i ) + for ( idx_t i = 0; i < idx; ++i ) { ++it; + } return it->second; } @@ -123,7 +124,9 @@ Field& State::field( const idx_t idx ) { std::vector State::field_names() const { std::vector ret; - if ( fields_.size() ) ret.reserve( fields_.size() ); + if ( fields_.size() ) { + ret.reserve( fields_.size() ); + } for ( FieldMap::const_iterator it = fields_.begin(); it != fields_.end(); ++it ) { ret.push_back( it->first ); @@ -160,8 +163,9 @@ StateGenerator* StateGeneratorFactory::build( const std::string& name, const eck if ( j == m->end() ) { Log::error() << "No StateGeneratorFactory for [" << name << "]" << std::endl; Log::error() << "StateFactories are:" << std::endl; - for ( j = m->begin(); j != m->end(); ++j ) + for ( j = m->begin(); j != m->end(); ++j ) { Log::error() << " " << ( *j ).first << std::endl; + } throw_Exception( std::string( "No StateGeneratorFactory called " ) + name, Here() ); } diff --git a/src/atlas/field/detail/FieldImpl.cc b/src/atlas/field/detail/FieldImpl.cc index a9e5eb3ba..f0cf99542 100644 --- a/src/atlas/field/detail/FieldImpl.cc +++ b/src/atlas/field/detail/FieldImpl.cc @@ -29,10 +29,11 @@ FieldImpl* FieldImpl::create( const eckit::Parametrisation& params ) { std::unique_ptr creator( field::FieldCreatorFactory::build( creator_factory, params ) ); return creator->createField( params ); } - else + else { throw_Exception( "Could not find parameter 'creator' " "in Parametrisation for call to FieldImpl::create()" ); + } } FieldImpl* FieldImpl::create( const std::string& name, array::DataType datatype, const array::ArrayShape& shape ) { @@ -64,7 +65,9 @@ FieldImpl::FieldImpl( const std::string& name, array::Array* array ) : functions FieldImpl::~FieldImpl() { array_->detach(); - if ( array_->owners() == 0 ) delete array_; + if ( array_->owners() == 0 ) { + delete array_; + } delete functionspace_; } @@ -96,7 +99,9 @@ std::string vector_to_str( const std::vector& t ) { std::stringstream s; s << '['; for ( size_t i = 0; i < t.size(); i++ ) { - if ( i != 0 ) s << ','; + if ( i != 0 ) { + s << ','; + } s << t[i]; } s << ']'; diff --git a/src/atlas/field/detail/FieldInterface.cc b/src/atlas/field/detail/FieldInterface.cc index a03500dee..ed476d3ee 100644 --- a/src/atlas/field/detail/FieldInterface.cc +++ b/src/atlas/field/detail/FieldInterface.cc @@ -221,6 +221,11 @@ int atlas__Field__dirty( FieldImpl* This ) { return This->dirty(); } +int atlas__Field__contiguous( FieldImpl* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Field" ); + return This->array().contiguous(); +} + 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 ); diff --git a/src/atlas/field/detail/FieldInterface.h b/src/atlas/field/detail/FieldInterface.h index 830f654ed..7c0bf190c 100644 --- a/src/atlas/field/detail/FieldInterface.h +++ b/src/atlas/field/detail/FieldInterface.h @@ -63,6 +63,7 @@ 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 ); +int atlas__Field__contiguous( FieldImpl* This ); } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/atlas/functionspace/EdgeColumns.cc b/src/atlas/functionspace/EdgeColumns.cc index 41bc5462c..ff8abcae8 100644 --- a/src/atlas/functionspace/EdgeColumns.cc +++ b/src/atlas/functionspace/EdgeColumns.cc @@ -50,7 +50,9 @@ template array::LocalView make_leveled_view( const Field& field ) { using namespace array; if ( field.levels() ) { - if ( field.variables() ) { return make_view( field ).slice( Range::all(), Range::all(), Range::all() ); } + if ( field.variables() ) { + return make_view( field ).slice( Range::all(), Range::all(), Range::all() ); + } else { return make_view( field ).slice( Range::all(), Range::all(), Range::dummy() ); } @@ -207,7 +209,9 @@ idx_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_Exception( "datatype missing", Here() ); + if ( !config.get( "datatype", kind ) ) { + throw_Exception( "datatype missing", Here() ); + } return array::DataType( kind ); } @@ -230,11 +234,15 @@ array::ArrayShape EdgeColumns::config_shape( const eckit::Configuration& config idx_t levels( nb_levels_ ); config.get( "levels", levels ); - if ( levels > 0 ) shape.push_back( levels ); + if ( levels > 0 ) { + shape.push_back( levels ); + } idx_t variables( 0 ); config.get( "variables", variables ); - if ( variables > 0 ) shape.push_back( variables ); + if ( variables > 0 ) { + shape.push_back( variables ); + } return shape; } @@ -245,7 +253,9 @@ EdgeColumns::EdgeColumns( const Mesh& mesh, const eckit::Configuration& config ) nb_levels_( config.getInt( "levels", 0 ) ), nb_edges_( 0 ) { ATLAS_TRACE(); - if ( config.has( "halo" ) ) { halo_ = mesh::Halo( config.getInt( "halo" ) ); } + if ( config.has( "halo" ) ) { + halo_ = mesh::Halo( config.getInt( "halo" ) ); + } else { halo_ = mesh::Halo( mesh_ ); } @@ -290,7 +300,9 @@ idx_t EdgeColumns::nb_edges() const { } idx_t EdgeColumns::nb_edges_global() const { - if ( nb_edges_global_ >= 0 ) return nb_edges_global_; + if ( nb_edges_global_ >= 0 ) { + return nb_edges_global_; + } nb_edges_global_ = gather().glb_dof(); return nb_edges_global_; } @@ -321,8 +333,9 @@ void EdgeColumns::haloExchange( const FieldSet& fieldset, bool on_device ) const else if ( field.datatype() == array::DataType::kind() ) { halo_exchange().execute( field.array(), on_device ); } - else + else { throw_Exception( "datatype not supported", Here() ); + } field.set_dirty( false ); } } @@ -332,7 +345,9 @@ void EdgeColumns::haloExchange( const Field& field, bool on_device ) const { haloExchange( fieldset, on_device ); } const parallel::HaloExchange& EdgeColumns::halo_exchange() const { - if ( halo_exchange_ ) return *halo_exchange_; + if ( halo_exchange_ ) { + return *halo_exchange_; + } halo_exchange_ = EdgeColumnsHaloExchangeCache::instance().get_or_create( mesh_ ); return *halo_exchange_; } @@ -366,8 +381,9 @@ void EdgeColumns::gather( const FieldSet& local_fieldset, FieldSet& global_field parallel::Field glb_field( make_leveled_view( glb ) ); gather().gather( &loc_field, &glb_field, nb_fields, root ); } - else + else { throw_Exception( "datatype not supported", Here() ); + } } } @@ -379,12 +395,16 @@ void EdgeColumns::gather( const Field& local, Field& global ) const { gather( local_fields, global_fields ); } const parallel::GatherScatter& EdgeColumns::gather() const { - if ( gather_scatter_ ) return *gather_scatter_; + if ( gather_scatter_ ) { + return *gather_scatter_; + } gather_scatter_ = EdgeColumnsGatherScatterCache::instance().get_or_create( mesh_ ); return *gather_scatter_; } const parallel::GatherScatter& EdgeColumns::scatter() const { - if ( gather_scatter_ ) return *gather_scatter_; + if ( gather_scatter_ ) { + return *gather_scatter_; + } gather_scatter_ = EdgeColumnsGatherScatterCache::instance().get_or_create( mesh_ ); return *gather_scatter_; } @@ -419,8 +439,9 @@ void EdgeColumns::scatter( const FieldSet& global_fieldset, FieldSet& local_fiel parallel::Field loc_field( make_leveled_view( loc ) ); scatter().scatter( &glb_field, &loc_field, nb_fields, root ); } - else + else { throw_Exception( "datatype not supported", Here() ); + } glb.metadata().broadcast( loc.metadata(), root ); loc.metadata().set( "global", false ); @@ -443,8 +464,9 @@ std::string checksum_3d_field( const parallel::Checksum& checksum, const Field& 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 ( idx_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 ); + } } } return checksum.execute( surface.data(), surface_field.stride( 0 ) ); @@ -462,31 +484,40 @@ std::string EdgeColumns::checksum( const FieldSet& fieldset ) const { for ( idx_t f = 0; f < fieldset.size(); ++f ) { const Field& field = fieldset[f]; if ( field.datatype() == array::DataType::kind() ) { - if ( field.levels() ) + if ( field.levels() ) { md5 << checksum_3d_field( checksum(), field ); - else + } + else { md5 << checksum_2d_field( checksum(), field ); + } } else if ( field.datatype() == array::DataType::kind() ) { - if ( field.levels() ) + if ( field.levels() ) { md5 << checksum_3d_field( checksum(), field ); - else + } + else { md5 << checksum_2d_field( checksum(), field ); + } } else if ( field.datatype() == array::DataType::kind() ) { - if ( field.levels() ) + if ( field.levels() ) { md5 << checksum_3d_field( checksum(), field ); - else + } + else { md5 << checksum_2d_field( checksum(), field ); + } } else if ( field.datatype() == array::DataType::kind() ) { - if ( field.levels() ) + if ( field.levels() ) { md5 << checksum_3d_field( checksum(), field ); - else + } + else { md5 << checksum_2d_field( checksum(), field ); + } } - else + else { throw_Exception( "datatype not supported", Here() ); + } } return md5; } @@ -497,7 +528,9 @@ std::string EdgeColumns::checksum( const Field& field ) const { } const parallel::Checksum& EdgeColumns::checksum() const { - if ( checksum_ ) return *checksum_; + if ( checksum_ ) { + return *checksum_; + } checksum_ = EdgeColumnsChecksumCache::instance().get_or_create( mesh_ ); return *checksum_; } diff --git a/src/atlas/functionspace/NodeColumns.cc b/src/atlas/functionspace/NodeColumns.cc index 8cec105ae..cdd2e5f2a 100644 --- a/src/atlas/functionspace/NodeColumns.cc +++ b/src/atlas/functionspace/NodeColumns.cc @@ -49,7 +49,9 @@ template array::LocalView make_leveled_view( const Field& field ) { using namespace array; if ( field.levels() ) { - if ( field.variables() ) { return make_view( field ).slice( Range::all(), Range::all(), Range::all() ); } + if ( field.variables() ) { + return make_view( field ).slice( Range::all(), Range::all(), Range::all() ); + } else { return make_view( field ).slice( Range::all(), Range::all(), Range::dummy() ); } @@ -204,7 +206,9 @@ NodeColumns::NodeColumns( Mesh mesh, const eckit::Configuration& config ) : nb_levels_( config.getInt( "levels", 0 ) ), nb_nodes_( 0 ) { ATLAS_TRACE(); - if ( config.has( "halo" ) ) { halo_ = mesh::Halo( config.getInt( "halo" ) ); } + if ( config.has( "halo" ) ) { + halo_ = mesh::Halo( config.getInt( "halo" ) ); + } else { halo_ = mesh::Halo( mesh ); } @@ -221,7 +225,9 @@ NodeColumns::NodeColumns( Mesh mesh, const eckit::Configuration& config ) : if ( !nb_nodes_ ) { std::stringstream ss; ss << "nb_nodes_including_halo[" << halo_.size() << "]"; - if ( !mesh_.metadata().get( ss.str(), nb_nodes_ ) ) { nb_nodes_ = mesh_.nodes().size(); } + if ( !mesh_.metadata().get( ss.str(), nb_nodes_ ) ) { + nb_nodes_ = mesh_.nodes().size(); + } } } @@ -236,8 +242,12 @@ idx_t NodeColumns::nb_nodes() 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(); } + if ( nb_nodes_global_ >= 0 ) { + return nb_nodes_global_; + } + if ( Grid grid = mesh().grid() ) { + nb_nodes_global_ = grid.size(); + } else { nb_nodes_global_ = gather().glb_dof(); } @@ -282,7 +292,9 @@ void NodeColumns::set_field_metadata( const eckit::Configuration& config, Field& array::DataType NodeColumns::config_datatype( const eckit::Configuration& config ) const { array::DataType::kind_t kind; - if ( !config.get( "datatype", kind ) ) throw_Exception( "datatype missing", Here() ); + if ( !config.get( "datatype", kind ) ) { + throw_Exception( "datatype missing", Here() ); + } return array::DataType( kind ); } @@ -305,11 +317,15 @@ array::ArrayShape NodeColumns::config_shape( const eckit::Configuration& config idx_t levels( nb_levels_ ); config.get( "levels", levels ); - if ( levels > 0 ) shape.push_back( levels ); + if ( levels > 0 ) { + shape.push_back( levels ); + } idx_t variables( 0 ); config.get( "variables", variables ); - if ( variables > 0 ) shape.push_back( variables ); + if ( variables > 0 ) { + shape.push_back( variables ); + } return shape; } @@ -348,8 +364,9 @@ void dispatch_haloExchange( Field& field, const parallel::HaloExchange& halo_exc else if ( field.datatype() == array::DataType::kind() ) { halo_exchange.template execute( field.array(), on_device ); } - else + else { throw_Exception( "datatype not supported", Here() ); + } field.set_dirty( false ); } } // namespace @@ -382,7 +399,9 @@ void NodeColumns::haloExchange( const Field& field, bool on_device ) const { haloExchange( fieldset, on_device ); } const parallel::HaloExchange& NodeColumns::halo_exchange() const { - if ( halo_exchange_ ) return *halo_exchange_; + if ( halo_exchange_ ) { + return *halo_exchange_; + } halo_exchange_ = NodeColumnsHaloExchangeCache::instance().get_or_create( mesh_, halo_.size() ); return *halo_exchange_; } @@ -417,8 +436,9 @@ void NodeColumns::gather( const FieldSet& local_fieldset, FieldSet& global_field parallel::Field glb_field( make_leveled_view( glb ) ); gather().gather( &loc_field, &glb_field, nb_fields, root ); } - else + else { throw_Exception( "datatype not supported", Here() ); + } } } @@ -430,12 +450,16 @@ void NodeColumns::gather( const Field& local, Field& global ) const { gather( local_fields, global_fields ); } const parallel::GatherScatter& NodeColumns::gather() const { - if ( gather_scatter_ ) return *gather_scatter_; + if ( gather_scatter_ ) { + return *gather_scatter_; + } gather_scatter_ = NodeColumnsGatherScatterCache::instance().get_or_create( mesh_ ); return *gather_scatter_; } const parallel::GatherScatter& NodeColumns::scatter() const { - if ( gather_scatter_ ) return *gather_scatter_; + if ( gather_scatter_ ) { + return *gather_scatter_; + } gather_scatter_ = NodeColumnsGatherScatterCache::instance().get_or_create( mesh_ ); return *gather_scatter_; } @@ -470,8 +494,9 @@ void NodeColumns::scatter( const FieldSet& global_fieldset, FieldSet& local_fiel parallel::Field loc_field( make_leveled_view( loc ) ); scatter().scatter( &glb_field, &loc_field, nb_fields, root ); } - else + else { throw_Exception( "datatype not supported", Here() ); + } glb.metadata().broadcast( loc.metadata(), root ); loc.metadata().set( "global", false ); @@ -496,8 +521,9 @@ std::string checksum_3d_field( const parallel::Checksum& checksum, const Field& 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 ( idx_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 ); + } } } return checksum.execute( surface.data(), surface_field.stride( 0 ) ); @@ -508,16 +534,21 @@ std::string NodeColumns::checksum( const FieldSet& fieldset ) const { eckit::MD5 md5; for ( idx_t f = 0; f < fieldset.size(); ++f ) { const Field& field = fieldset[f]; - if ( field.datatype() == array::DataType::kind() ) + if ( field.datatype() == array::DataType::kind() ) { md5 << checksum_3d_field( checksum(), field ); - else if ( field.datatype() == array::DataType::kind() ) + } + else if ( field.datatype() == array::DataType::kind() ) { md5 << checksum_3d_field( checksum(), field ); - else if ( field.datatype() == array::DataType::kind() ) + } + else if ( field.datatype() == array::DataType::kind() ) { md5 << checksum_3d_field( checksum(), field ); - else if ( field.datatype() == array::DataType::kind() ) + } + else if ( field.datatype() == array::DataType::kind() ) { md5 << checksum_3d_field( checksum(), field ); - else + } + else { throw_Exception( "datatype not supported", Here() ); + } } return md5; } @@ -528,7 +559,9 @@ std::string NodeColumns::checksum( const Field& field ) const { } const parallel::Checksum& NodeColumns::checksum() const { - if ( checksum_ ) return *checksum_; + if ( checksum_ ) { + return *checksum_; + } checksum_ = NodeColumnsChecksumCache::instance().get_or_create( mesh_ ); return *checksum_; } diff --git a/src/atlas/functionspace/Spectral.cc b/src/atlas/functionspace/Spectral.cc index e25793a04..c176bca21 100644 --- a/src/atlas/functionspace/Spectral.cc +++ b/src/atlas/functionspace/Spectral.cc @@ -42,21 +42,20 @@ namespace atlas { namespace functionspace { namespace detail { - #if ATLAS_HAVE_TRANS class Spectral::Parallelisation { public: Parallelisation( const std::shared_ptr<::Trans_t> other ) : trans_( other ) {} Parallelisation( int truncation ) { - trans_ = std::shared_ptr<::Trans_t>( new ::Trans_t, [](::Trans_t* p ) { - TRANS_CHECK(::trans_delete( p ) ); + trans_ = std::shared_ptr<::Trans_t>( new ::Trans_t, []( ::Trans_t* p ) { + TRANS_CHECK( ::trans_delete( p ) ); delete p; } ); - TRANS_CHECK(::trans_new( trans_.get() ) ); - TRANS_CHECK(::trans_set_trunc( trans_.get(), truncation ) ); - TRANS_CHECK(::trans_use_mpi( mpi::comm().size() > 1 ) ); - TRANS_CHECK(::trans_setup( trans_.get() ) ); + TRANS_CHECK( ::trans_new( trans_.get() ) ); + TRANS_CHECK( ::trans_set_trunc( trans_.get(), truncation ) ); + TRANS_CHECK( ::trans_use_mpi( mpi::comm().size() > 1 ) ); + TRANS_CHECK( ::trans_setup( trans_.get() ) ); } int nb_spectral_coefficients_global() const { return trans_->nspec2g; } @@ -65,17 +64,20 @@ class Spectral::Parallelisation { int nump() const { return trans_->nump; } array::LocalView nvalue() const { - if ( trans_->nvalue == nullptr ) ::trans_inquire( trans_.get(), "nvalue" ); + if ( trans_->nvalue == nullptr ) + ::trans_inquire( trans_.get(), "nvalue" ); return array::LocalView( trans_->nvalue, array::make_shape( trans_->nspec2 ) ); } array::LocalView nmyms() const { - if ( trans_->nmyms == nullptr ) ::trans_inquire( trans_.get(), "nmyms" ); + if ( trans_->nmyms == nullptr ) + ::trans_inquire( trans_.get(), "nmyms" ); return array::LocalView( trans_->nmyms, array::make_shape( nump() ) ); } array::LocalView nasm0() const { - if ( trans_->nasm0 == nullptr ) ::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 ) ); } @@ -175,11 +177,15 @@ Spectral::Spectral( const int truncation, const eckit::Configuration& config ) : Spectral::Spectral( const trans::Trans& trans, const eckit::Configuration& config ) : nb_levels_( 0 ), truncation_( trans.truncation() ), + parallelisation_( [&trans, this]() -> Parallelisation* { #if ATLAS_HAVE_TRANS - parallelisation_( new Parallelisation( dynamic_cast( *trans.get() ).trans_ ) ) { -#else - parallelisation_( new Parallelisation( truncation_ ) ) { + const auto* trans_ifs = dynamic_cast( trans.get() ); + if ( trans_ifs ) { + return new Parallelisation( trans_ifs->trans_ ); + } #endif + return new Parallelisation( truncation_ ); + }() ) { config.get( "levels", nb_levels_ ); } @@ -205,7 +211,9 @@ idx_t Spectral::nb_spectral_coefficients_global() const { array::DataType Spectral::config_datatype( const eckit::Configuration& config ) const { array::DataType::kind_t kind; - if ( !config.get( "datatype", kind ) ) throw_Exception( "datatype missing", Here() ); + if ( !config.get( "datatype", kind ) ) { + throw_Exception( "datatype missing", Here() ); + } return array::DataType( kind ); } @@ -228,7 +236,9 @@ Field Spectral::createField( const eckit::Configuration& options ) const { array_shape.push_back( nb_spec_coeffs ); idx_t levels = config_levels( options ); - if ( levels ) array_shape.push_back( levels ); + if ( levels ) { + array_shape.push_back( levels ); + } Field field = Field( config_name( options ), config_datatype( options ), array_shape ); @@ -258,7 +268,8 @@ void Spectral::gather( const FieldSet& local_fieldset, FieldSet& global_fieldset idx_t rank = static_cast( mpi::comm().rank() ); glb.metadata().get( "owner", root ); ATLAS_ASSERT( loc.shape( 0 ) == nb_spectral_coefficients() ); - if ( rank == root ) ATLAS_ASSERT( glb.shape( 0 ) == nb_spectral_coefficients_global() ); + 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 ) ); @@ -266,12 +277,17 @@ void Spectral::gather( const FieldSet& local_fieldset, FieldSet& global_fieldset nto[i] = root + 1; } + if ( not loc.contiguous() ) { + throw_Exception( "Cannot gather field " + loc.name() + + " using IFS trans library as its data is not contiguous" ); + } + struct ::GathSpec_t args = new_gathspec( *parallelisation_ ); args.nfld = nto.size(); args.rspecg = glb.data(); args.nto = nto.data(); args.rspec = loc.data(); - TRANS_CHECK(::trans_gathspec( &args ) ); + TRANS_CHECK( ::trans_gathspec( &args ) ); #else throw_Exception( @@ -307,7 +323,8 @@ void Spectral::scatter( const FieldSet& global_fieldset, FieldSet& local_fieldse glb.metadata().get( "owner", root ); ATLAS_ASSERT( loc.shape( 0 ) == nb_spectral_coefficients() ); - if ( rank == root ) ATLAS_ASSERT( glb.shape( 0 ) == nb_spectral_coefficients_global() ); + 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 ) ); @@ -315,12 +332,17 @@ void Spectral::scatter( const FieldSet& global_fieldset, FieldSet& local_fieldse nfrom[i] = root + 1; } + if ( not loc.contiguous() ) { + throw_Exception( "Cannot scatter field " + glb.name() + + " using IFS trans library as its data is not contiguous" ); + } + struct ::DistSpec_t args = new_distspec( *parallelisation_ ); args.nfld = int( nfrom.size() ); args.rspecg = glb.data(); args.nfrom = nfrom.data(); args.rspec = loc.data(); - TRANS_CHECK(::trans_distspec( &args ) ); + TRANS_CHECK( ::trans_distspec( &args ) ); glb.metadata().broadcast( loc.metadata(), root ); loc.metadata().set( "global", false ); @@ -358,7 +380,7 @@ void Spectral::norm( const Field& field, double& norm, int rank ) const { args.rspec = field.data(); args.rnorm = &norm; args.nmaster = rank + 1; - TRANS_CHECK(::trans_specnorm( &args ) ); + TRANS_CHECK( ::trans_specnorm( &args ) ); #else throw_Exception( "Cannot compute spectral norms because Atlas has not " @@ -367,12 +389,16 @@ void Spectral::norm( const Field& field, double& norm, int rank ) const { } void Spectral::norm( const Field& field, double norm_per_level[], int rank ) const { #if ATLAS_HAVE_TRANS + if ( not field.contiguous() ) { + throw_Exception( "Cannot compute spectral norm of field " + field.name() + + " using IFS trans library as its data is not contiguous" ); + } struct ::SpecNorm_t args = new_specnorm( *parallelisation_ ); args.nfld = std::max( 1, field.levels() ); args.rspec = field.data(); args.rnorm = norm_per_level; args.nmaster = rank + 1; - TRANS_CHECK(::trans_specnorm( &args ) ); + TRANS_CHECK( ::trans_specnorm( &args ) ); #else throw_Exception( "Cannot compute spectral norms because Atlas has not " @@ -408,6 +434,8 @@ array::LocalView Spectral::nasm0() const { // ---------------------------------------------------------------------- +Spectral::Spectral() : FunctionSpace(), functionspace_{nullptr} {} + Spectral::Spectral( const FunctionSpace& functionspace ) : FunctionSpace( functionspace ), functionspace_( dynamic_cast( get() ) ) {} diff --git a/src/atlas/functionspace/Spectral.h b/src/atlas/functionspace/Spectral.h index cee6e1719..d78a65f63 100644 --- a/src/atlas/functionspace/Spectral.h +++ b/src/atlas/functionspace/Spectral.h @@ -199,7 +199,6 @@ class Spectral : public FunctionSpaceImpl { array::LocalView nmyms() const; // Return list of local zonal wavenumbers "m" array::LocalView nasm0() const; - private: // data idx_t nb_levels_; int truncation_; @@ -214,6 +213,7 @@ class Spectral : public FunctionSpaceImpl { class Spectral : public FunctionSpace { public: + Spectral(); Spectral( const FunctionSpace& ); Spectral( const eckit::Configuration& ); Spectral( const int truncation, const eckit::Configuration& = util::NoConfig() ); diff --git a/src/atlas/functionspace/StructuredColumns.cc b/src/atlas/functionspace/StructuredColumns.cc index 5f05a31c0..94e13637e 100644 --- a/src/atlas/functionspace/StructuredColumns.cc +++ b/src/atlas/functionspace/StructuredColumns.cc @@ -47,7 +47,9 @@ template array::LocalView make_leveled_view( const Field& field ) { using namespace array; if ( field.levels() ) { - if ( field.variables() ) { return make_view( field ).slice( Range::all(), Range::all(), Range::all() ); } + if ( field.variables() ) { + return make_view( field ).slice( Range::all(), Range::all(), Range::all() ); + } else { return make_view( field ).slice( Range::all(), Range::all(), Range::dummy() ); } @@ -71,8 +73,9 @@ std::string checksum_3d_field( const parallel::Checksum& checksum, const Field& 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 ( idx_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 ); + } } } return checksum.execute( surface.data(), surface_field.stride( 0 ) ); @@ -192,25 +195,33 @@ class StructuredColumnsChecksumCache : public util::Cache 0 ) shape.push_back( levels ); + if ( levels > 0 ) { + shape.push_back( levels ); + } idx_t variables( 0 ); config.get( "variables", variables ); - if ( variables > 0 ) shape.push_back( variables ); + if ( variables > 0 ) { + shape.push_back( variables ); + } return shape; } @@ -283,10 +302,12 @@ void StructuredColumns::Map2to1::print( std::ostream& out ) const { out << std::setw( 4 ) << j << " : "; for ( idx_t i = i_min_; i <= i_max_; ++i ) { idx_t v = operator()( i, j ); - if ( v == missing() ) + if ( v == missing() ) { out << std::setw( 6 ) << "X"; - else + } + else { out << std::setw( 6 ) << v; + } } out << '\n'; } @@ -295,10 +316,12 @@ void StructuredColumns::Map2to1::print( std::ostream& out ) const { void StructuredColumns::IndexRange::print( std::ostream& out ) const { for ( idx_t i = min_; i <= max_; ++i ) { idx_t v = operator()( i ); - if ( v == missing() ) + if ( v == missing() ) { out << std::setw( 4 ) << "X"; - else + } + else { out << std::setw( 4 ) << v; + } } out << '\n'; } @@ -365,7 +388,9 @@ StructuredColumns::StructuredColumns( const Grid& grid, const Vertical& vertical grid_( new StructuredGrid( grid ) ) { grid::Partitioner partitioner( p ); if ( not partitioner ) { - if ( grid_->domain().global() ) { partitioner = grid::Partitioner( "equal_regions" ); } + if ( grid_->domain().global() ) { + partitioner = grid::Partitioner( "equal_regions" ); + } else { partitioner = grid::Partitioner( "checkerboard" ); } @@ -453,8 +478,9 @@ void StructuredColumns::gather( const FieldSet& local_fieldset, FieldSet& global parallel::Field glb_field( make_leveled_view( glb ) ); gather().gather( &loc_field, &glb_field, nb_fields, root ); } - else + else { throw_Exception( "datatype not supported", Here() ); + } } } // ---------------------------------------------------------------------------- @@ -504,8 +530,9 @@ void StructuredColumns::scatter( const FieldSet& global_fieldset, FieldSet& loca parallel::Field loc_field( make_leveled_view( loc ) ); scatter().scatter( &glb_field, &loc_field, nb_fields, root ); } - else + else { throw_Exception( "datatype not supported", Here() ); + } glb.metadata().broadcast( loc.metadata(), root ); loc.metadata().set( "global", false ); @@ -529,16 +556,21 @@ std::string StructuredColumns::checksum( const FieldSet& fieldset ) const { eckit::MD5 md5; for ( idx_t f = 0; f < fieldset.size(); ++f ) { const Field& field = fieldset[f]; - if ( field.datatype() == array::DataType::kind() ) + if ( field.datatype() == array::DataType::kind() ) { md5 << checksum_3d_field( checksum(), field ); - else if ( field.datatype() == array::DataType::kind() ) + } + else if ( field.datatype() == array::DataType::kind() ) { md5 << checksum_3d_field( checksum(), field ); - else if ( field.datatype() == array::DataType::kind() ) + } + else if ( field.datatype() == array::DataType::kind() ) { md5 << checksum_3d_field( checksum(), field ); - else if ( field.datatype() == array::DataType::kind() ) + } + else if ( field.datatype() == array::DataType::kind() ) { md5 << checksum_3d_field( checksum(), field ); - else + } + else { throw_Exception( "datatype not supported", Here() ); + } } return md5; } @@ -561,7 +593,9 @@ struct FixupHaloForVectors { template void apply( Field& field ) { std::string type = field.metadata().getString( "type", "scalar" ); - if ( type == "vector " ) { ATLAS_NOTIMPLEMENTED; } + if ( type == "vector " ) { + ATLAS_NOTIMPLEMENTED; + } } }; @@ -647,8 +681,9 @@ void dispatch_haloExchange( Field& field, const parallel::HaloExchange& halo_exc halo_exchange.template execute( field.array(), false ); fixup_halos.template apply( field ); } - else + else { throw_Exception( "datatype not supported", Here() ); + } field.set_dirty( false ); } } // namespace @@ -684,12 +719,24 @@ void StructuredColumns::haloExchange( const Field& field, bool ) const { 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(); + 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; } @@ -712,6 +759,11 @@ 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 grid::Distribution& distribution, + const eckit::Configuration& config ) : + FunctionSpace( new detail::StructuredColumns( grid, distribution, 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() ) ) {} @@ -721,6 +773,11 @@ StructuredColumns::StructuredColumns( const Grid& grid, const Vertical& vertical FunctionSpace( new detail::StructuredColumns( grid, vertical, partitioner, config ) ), functionspace_( dynamic_cast( get() ) ) {} +StructuredColumns::StructuredColumns( const Grid& grid, const grid::Distribution& distribution, + const Vertical& vertical, const eckit::Configuration& config ) : + FunctionSpace( new detail::StructuredColumns( grid, distribution, vertical, config ) ), + functionspace_( dynamic_cast( get() ) ) {} + void StructuredColumns::gather( const FieldSet& local, FieldSet& global ) const { functionspace_->gather( local, global ); } diff --git a/src/atlas/functionspace/StructuredColumns.h b/src/atlas/functionspace/StructuredColumns.h index ba565e818..cd9d1e70d 100644 --- a/src/atlas/functionspace/StructuredColumns.h +++ b/src/atlas/functionspace/StructuredColumns.h @@ -137,7 +137,9 @@ class StructuredColumns : public FunctionSpaceImpl { Field partition() const { return field_partition_; } Field global_index() const { return field_global_index_; } Field remote_index() const { - if ( not field_remote_index_ ) { create_remote_index(); } + if ( not field_remote_index_ ) { + create_remote_index(); + } return field_remote_index_; } Field index_i() const { return field_index_i_; } @@ -164,8 +166,12 @@ class StructuredColumns : public FunctionSpaceImpl { 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 ); } + 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; @@ -307,9 +313,12 @@ 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 grid::Distribution&, 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() ); + StructuredColumns( const Grid&, const grid::Distribution&, const Vertical&, + const eckit::Configuration& = util::NoConfig() ); static std::string type() { return detail::StructuredColumns::static_type(); } diff --git a/src/atlas/functionspace/detail/NodeColumnsInterface.cc b/src/atlas/functionspace/detail/NodeColumnsInterface.cc index 906341fb3..1e0b0b38e 100644 --- a/src/atlas/functionspace/detail/NodeColumnsInterface.cc +++ b/src/atlas/functionspace/detail/NodeColumnsInterface.cc @@ -191,8 +191,9 @@ void atlas__NodesFunctionSpace__sum_arr_double( const NodeColumns* This, const f This->orderIndependentSum( field, sumvec, idx_t_N ); size = sumvec.size(); sum = new double[size]; - for ( idx_t j = 0; j < (idx_t)size; ++j ) + for ( idx_t j = 0; j < (idx_t)size; ++j ) { sum[j] = sumvec[j]; + } N = idx_t_N; } @@ -205,8 +206,9 @@ void atlas__NodesFunctionSpace__sum_arr_float( const NodeColumns* This, const fi This->orderIndependentSum( field, sumvec, idx_t_N ); size = sumvec.size(); sum = new float[size]; - for ( idx_t j = 0; j < (idx_t)size; ++j ) + for ( idx_t j = 0; j < (idx_t)size; ++j ) { sum[j] = sumvec[j]; + } N = idx_t_N; } @@ -219,8 +221,9 @@ void atlas__NodesFunctionSpace__sum_arr_long( const NodeColumns* This, const fie This->orderIndependentSum( field, sumvec, idx_t_N ); size = sumvec.size(); sum = new long[size]; - for ( idx_t j = 0; j < (idx_t)size; ++j ) + for ( idx_t j = 0; j < (idx_t)size; ++j ) { sum[j] = sumvec[j]; + } N = idx_t_N; } @@ -233,8 +236,9 @@ void atlas__NodesFunctionSpace__sum_arr_int( const NodeColumns* This, const fiel This->orderIndependentSum( field, sumvec, idx_t_N ); size = sumvec.size(); sum = new int[size]; - for ( idx_t j = 0; j < (idx_t)size; ++j ) + for ( idx_t j = 0; j < (idx_t)size; ++j ) { sum[j] = sumvec[j]; + } N = idx_t_N; } @@ -274,8 +278,9 @@ void atlas__NodesFunctionSpace__oisum_arr_double( const NodeColumns* This, const This->orderIndependentSum( field, sumvec, idx_t_N ); size = sumvec.size(); sum = new double[size]; - for ( idx_t j = 0; j < (idx_t)size; ++j ) + for ( idx_t j = 0; j < (idx_t)size; ++j ) { sum[j] = sumvec[j]; + } N = idx_t_N; } @@ -288,8 +293,9 @@ void atlas__NodesFunctionSpace__oisum_arr_float( const NodeColumns* This, const This->orderIndependentSum( field, sumvec, idx_t_N ); size = sumvec.size(); sum = new float[size]; - for ( idx_t j = 0; j < (idx_t)size; ++j ) + for ( idx_t j = 0; j < (idx_t)size; ++j ) { sum[j] = sumvec[j]; + } N = idx_t_N; } @@ -360,8 +366,9 @@ void atlas__NodesFunctionSpace__min_arr_double( const NodeColumns* This, const f This->minimum( field, minvec ); size = minvec.size(); minimum = new double[size]; - for ( idx_t j = 0; j < (idx_t)size; ++j ) + 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, @@ -372,8 +379,9 @@ void atlas__NodesFunctionSpace__min_arr_float( const NodeColumns* This, const fi This->minimum( field, minvec ); size = minvec.size(); minimum = new float[size]; - for ( idx_t j = 0; j < (idx_t)size; ++j ) + 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, @@ -384,9 +392,9 @@ void atlas__NodesFunctionSpace__min_arr_long( const NodeColumns* This, const fie This->minimum( field, minvec ); size = minvec.size(); minimum = new long[size]; - for ( idx_t j = 0; j < (idx_t)size; ++j ) + 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, @@ -397,8 +405,9 @@ void atlas__NodesFunctionSpace__min_arr_int( const NodeColumns* This, const fiel This->minimum( field, minvec ); size = minvec.size(); minimum = new int[size]; - for ( idx_t j = 0; j < (idx_t)size; ++j ) + 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, @@ -422,8 +431,9 @@ void atlas__NodesFunctionSpace__max_arr_float( const NodeColumns* This, const fi This->maximum( field, maxvec ); size = maxvec.size(); maximum = new float[size]; - for ( idx_t j = 0; j < (idx_t)size; ++j ) + 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, @@ -434,8 +444,9 @@ void atlas__NodesFunctionSpace__max_arr_long( const NodeColumns* This, const fie This->maximum( field, maxvec ); size = maxvec.size(); maximum = new long[size]; - for ( idx_t j = 0; j < (idx_t)size; ++j ) + 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, @@ -446,8 +457,9 @@ void atlas__NodesFunctionSpace__max_arr_int( const NodeColumns* This, const fiel This->maximum( field, maxvec ); size = maxvec.size(); maximum = new int[size]; - for ( idx_t j = 0; j < (idx_t)size; ++j ) + 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, @@ -686,8 +698,9 @@ void atlas__NodesFunctionSpace__mean_arr_double( const NodeColumns* This, const This->mean( field, meanvec, idx_t_N ); size = meanvec.size(); mean = new double[size]; - for ( idx_t j = 0; j < (idx_t)size; ++j ) + for ( idx_t j = 0; j < (idx_t)size; ++j ) { mean[j] = meanvec[j]; + } N = idx_t_N; } @@ -700,8 +713,9 @@ void atlas__NodesFunctionSpace__mean_arr_float( const NodeColumns* This, const f This->mean( field, meanvec, idx_t_N ); size = meanvec.size(); mean = new float[size]; - for ( idx_t j = 0; j < (idx_t)size; ++j ) + for ( idx_t j = 0; j < (idx_t)size; ++j ) { mean[j] = meanvec[j]; + } N = idx_t_N; } diff --git a/src/atlas/functionspace/detail/NodeColumns_FieldStatistics.cc b/src/atlas/functionspace/detail/NodeColumns_FieldStatistics.cc index c85870788..9c1e604ed 100644 --- a/src/atlas/functionspace/detail/NodeColumns_FieldStatistics.cc +++ b/src/atlas/functionspace/detail/NodeColumns_FieldStatistics.cc @@ -39,7 +39,9 @@ template array::LocalView make_leveled_view( const Field& field ) { using namespace array; if ( field.levels() ) { - if ( field.variables() ) { return make_view( field ).slice( Range::all(), Range::all(), Range::all() ); } + if ( field.variables() ) { + return make_view( field ).slice( Range::all(), Range::all(), Range::all() ); + } else { return make_view( field ).slice( Range::all(), Range::all(), Range::dummy() ); } @@ -57,28 +59,34 @@ array::LocalView make_leveled_view( const Field& field ) { template array::LocalView make_leveled_scalar_view( const Field& field ) { using namespace array; - if ( field.levels() ) + if ( field.levels() ) { return make_view( field ).slice( Range::all(), Range::all() ); - else + } + else { return make_view( field ).slice( Range::all(), Range::dummy() ); + } } template array::LocalView make_surface_view( const Field& field ) { using namespace array; - if ( field.variables() ) + if ( field.variables() ) { return make_view( field ).slice( Range::all(), Range::all() ); - else + } + else { return make_view( field ).slice( Range::all(), Range::dummy() ); + } } template array::LocalView make_per_level_view( const Field& field ) { using namespace array; - if ( field.rank() == 2 ) + if ( field.rank() == 2 ) { return make_view( field ).slice( Range::all(), Range::all() ); - else + } + else { return make_view( field ).slice( Range::all(), Range::dummy() ); + } } } // namespace @@ -97,11 +105,13 @@ void dispatch_sum( const NodeColumns& fs, const Field& field, T& result, idx_t& const array::LocalView arr = make_leveled_scalar_view( field ); T local_sum = 0; const idx_t npts = std::min( arr.shape( 0 ), fs.nb_nodes() ); + const idx_t nlev = arr.shape( 1 ); atlas_omp_pragma( omp parallel for default(shared) reduction(+:local_sum) ) for( idx_t n=0; 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 ); } + if ( field.datatype() == array::DataType::kind() ) { + return dispatch_sum( fs, field, result, N ); + } else { switch ( field.datatype().kind() ) { case array::DataType::KIND_INT32: { @@ -148,17 +160,18 @@ template 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 idx_t npts = std::min( arr.shape( 0 ), fs.nb_nodes() ); + const idx_t nlev = arr.shape( 1 ); 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 idx_t npts = arr.shape( 0 ); atlas_omp_for( idx_t n = 0; n < npts; ++n ) { if ( !is_ghost( n ) ) { - for ( idx_t l = 0; l < arr.shape( 1 ); ++l ) { - for ( idx_t j = 0; j < arr.shape( 2 ); ++j ) { + for ( idx_t l = 0; l < nlev; ++l ) { + for ( idx_t j = 0; j < nvar; ++j ) { local_sum_private[j] += arr( n, l, j ); } } @@ -173,12 +186,14 @@ void dispatch_sum( const NodeColumns& fs, const Field& field, std::vector& re ATLAS_TRACE_MPI( ALLREDUCE ) { mpi::comm().allReduce( local_sum, result, eckit::mpi::sum() ); } - N = fs.nb_nodes_global() * arr.shape( 1 ); + N = fs.nb_nodes_global() * nlev; } template 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 ); } + if ( field.datatype() == array::DataType::kind() ) { + return dispatch_sum( fs, field, result, N ); + } else { switch ( field.datatype().kind() ) { case array::DataType::KIND_INT32: { @@ -217,12 +232,17 @@ void dispatch_sum_per_level( const NodeColumns& fs, const Field& field, Field& s array::ArrayShape shape; shape.reserve( field.rank() - 1 ); - for ( idx_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 ); auto arr = make_leveled_view( field ); + const idx_t npts = std::min( arr.shape( 0 ), fs.nb_nodes() ); + const idx_t nlev = arr.shape( 1 ); + const idx_t nvar = arr.shape( 2 ); + auto sum_per_level = make_per_level_view( sum ); for ( idx_t l = 0; l < sum_per_level.shape( 0 ); ++l ) { @@ -241,11 +261,10 @@ void dispatch_sum_per_level( const NodeColumns& fs, const Field& field, Field& s } } - const idx_t npts = arr.shape( 0 ); atlas_omp_for( idx_t n = 0; n < npts; ++n ) { if ( !is_ghost( n ) ) { - for ( idx_t l = 0; l < arr.shape( 1 ); ++l ) { - for ( idx_t j = 0; j < arr.shape( 2 ); ++j ) { + for ( idx_t l = 0; l < nlev; ++l ) { + for ( idx_t j = 0; j < nvar; ++j ) { sum_per_level_private_view( l, j ) += arr( n, l, j ); } } @@ -266,7 +285,9 @@ void dispatch_sum_per_level( const NodeColumns& fs, const Field& field, Field& s } 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() ); } + 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 ); @@ -361,8 +382,9 @@ void dispatch_order_independent_sum_2d( const NodeColumns& fs, const Field& fiel idx_t& N ) { idx_t nvar = field.variables(); result.resize( nvar ); - for ( idx_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 ) { @@ -381,22 +403,24 @@ void dispatch_order_independent_sum_2d( const NodeColumns& fs, const Field& fiel template void dispatch_order_independent_sum( const NodeColumns& fs, const Field& field, std::vector& result, idx_t& N ) { if ( field.levels() ) { - const idx_t nvar = field.variables(); const auto arr = make_leveled_view( field ); + const idx_t npts = std::min( arr.shape( 0 ), fs.nb_nodes() ); + const idx_t nlev = arr.shape( 1 ); + const idx_t nvar = arr.shape( 2 ); Field surface_field = fs.createField( option::name( "surface" ) | option::variables( nvar ) | option::levels( false ) ); auto surface = make_surface_view( surface_field ); - atlas_omp_for( idx_t n = 0; n < arr.shape( 0 ); ++n ) { - for ( idx_t j = 0; j < arr.shape( 2 ); ++j ) { + atlas_omp_for( idx_t n = 0; n < npts; ++n ) { + for ( idx_t j = 0; j < nvar; ++j ) { surface( n, j ) = 0; } } - 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 ) { + for ( idx_t n = 0; n < npts; ++n ) { + for ( idx_t l = 0; l < nlev; ++l ) { + for ( idx_t j = 0; j < nvar; ++j ) { surface( n, j ) += arr( n, l, j ); } } @@ -451,8 +475,9 @@ template 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 ( idx_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 ); @@ -501,7 +526,9 @@ void dispatch_order_independent_sum_per_level( const NodeColumns& fs, const Fiel } 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() ); } + 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 ); @@ -544,7 +571,9 @@ void dispatch_minimum( const NodeColumns& fs, const Field& field, std::vector template void minimum( const NodeColumns& fs, const Field& field, std::vector& min ) { - if ( field.datatype() == array::DataType::kind() ) { return dispatch_minimum( fs, field, min ); } + if ( field.datatype() == array::DataType::kind() ) { + return dispatch_minimum( fs, field, min ); + } else { switch ( field.datatype().kind() ) { case array::DataType::KIND_INT32: { @@ -604,7 +633,9 @@ void dispatch_maximum( const NodeColumns& fs, const Field& field, std::vector template void maximum( const NodeColumns& fs, const Field& field, std::vector& max ) { - if ( field.datatype() == array::DataType::kind() ) { return dispatch_maximum( fs, field, max ); } + if ( field.datatype() == array::DataType::kind() ) { + return dispatch_maximum( fs, field, max ); + } else { switch ( field.datatype().kind() ) { case array::DataType::KIND_INT32: { @@ -655,8 +686,9 @@ template void dispatch_minimum_per_level( const NodeColumns& fs, const Field& field, Field& min_field ) { array::ArrayShape shape; shape.reserve( field.rank() - 1 ); - for ( idx_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 ); @@ -696,7 +728,9 @@ 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_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 ); @@ -715,8 +749,9 @@ template void dispatch_maximum_per_level( const NodeColumns& fs, const Field& field, Field& max_field ) { array::ArrayShape shape; shape.reserve( field.rank() - 1 ); - for ( idx_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 ); @@ -757,7 +792,9 @@ 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_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 ); @@ -1032,8 +1069,9 @@ 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 ( idx_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 idx_t nvar = arr.shape( 2 ); @@ -1105,7 +1143,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_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_Exception( "glb_idx Field is not of correct datatype", Here() ); } @@ -1129,8 +1169,9 @@ 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 ( idx_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 idx_t nvar = arr.shape( 2 ); @@ -1203,7 +1244,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_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_Exception( "glb_idx Field is not of correct datatype", Here() ); } @@ -1247,7 +1290,9 @@ void dispatch_mean_per_level( const NodeColumns& fs, const Field& field, Field& } 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() ); } + 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 ); diff --git a/src/atlas/functionspace/detail/StructuredColumns_create_remote_index.cc b/src/atlas/functionspace/detail/StructuredColumns_create_remote_index.cc index f07b00f9e..003cf91f0 100644 --- a/src/atlas/functionspace/detail/StructuredColumns_create_remote_index.cc +++ b/src/atlas/functionspace/detail/StructuredColumns_create_remote_index.cc @@ -106,12 +106,14 @@ void StructuredColumns::create_remote_index() const { std::vector recv_requests( neighbours.size() ); std::vector recv_size( neighbours.size() ); + std::vector send_size( neighbours.size() ); + int tag = 0; 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 ); + send_size[j] = static_cast( g_per_neighbour[j].size() ); + send_requests[j] = comm.iSend( send_size[j], neighbours[j], tag ); + recv_requests[j] = comm.iReceive( recv_size[j], neighbours[j], tag ); } ATLAS_TRACE_MPI( WAIT ) { diff --git a/src/atlas/functionspace/detail/StructuredColumns_setup.cc b/src/atlas/functionspace/detail/StructuredColumns_setup.cc index 899dfe0f8..1749d792f 100644 --- a/src/atlas/functionspace/detail/StructuredColumns_setup.cc +++ b/src/atlas/functionspace/detail/StructuredColumns_setup.cc @@ -22,12 +22,9 @@ #include "atlas/grid/StructuredGrid.h" #include "atlas/library/Library.h" #include "atlas/mesh/Mesh.h" -#include "atlas/parallel/Checksum.h" -#include "atlas/parallel/mpi/Statistics.h" #include "atlas/parallel/mpi/mpi.h" #include "atlas/runtime/Exception.h" #include "atlas/runtime/Trace.h" -#include "atlas/util/Checksum.h" #include "atlas/util/CoordinateEnums.h" namespace atlas { @@ -84,7 +81,9 @@ struct GridPointSet { 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() ); } + if ( not( *grid_ ) ) { + throw_Exception( "Grid is not a grid::Structured type", Here() ); + } const eckit::mpi::Comm& comm = mpi::comm(); @@ -137,12 +136,16 @@ void StructuredColumns::setup( const grid::Distribution& distribution, const eck 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; } + 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; }; @@ -222,14 +225,18 @@ void StructuredColumns::setup( const grid::Distribution& distribution, const eck 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; } + 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; } + if ( i == grid_->nx( j ) ) { + ++last; + } jmin = std::min( jmin, jj ); jmax = std::max( jmax, jj ); @@ -353,7 +360,9 @@ void StructuredColumns::setup( const grid::Distribution& distribution, const eck for ( const GridPoint& gp : gridpoints ) { 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 ); } @@ -365,16 +374,34 @@ void StructuredColumns::setup( const grid::Distribution& distribution, const eck gidx_t k = global_offsets[gp.j] + gp.i; part( gp.r ) = distribution.partition( k ); global_idx( gp.r ) = k + 1; - ghost( gp.r ) = 0; } } if ( not in_domain ) { global_idx( gp.r ) = compute_g( gp.i, gp.j ); part( gp.r ) = compute_p( gp.i, gp.j ); - ghost( gp.r ) = 1; } index_i( gp.r ) = gp.i; index_j( gp.r ) = gp.j; + ghost( gp.r ) = 0; + } + + 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 ) { + ghost( index( i, j ) ) = 1; + } + } + for ( idx_t j = j_begin_; j < j_end_; ++j ) { + for ( idx_t i = i_begin_halo_( j ); i < i_begin_[j]; ++i ) { + ghost( index( i, j ) ) = 1; + } + for ( idx_t i = i_end_[j]; i < i_end_halo_( j ); ++i ) { + ghost( index( i, j ) ) = 1; + } + } + 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 ) { + ghost( index( i, j ) ) = 1; + } } } } diff --git a/src/atlas/grid/Grid.cc b/src/atlas/grid/Grid.cc index e564c8898..f6371c0b8 100644 --- a/src/atlas/grid/Grid.cc +++ b/src/atlas/grid/Grid.cc @@ -39,7 +39,9 @@ Grid::IterateLonLat Grid::lonlat() const { Grid::Grid( const std::string& shortname, const Domain& domain ) : Handle( [&] { Config config; - if ( domain ) config.set( "domain", domain.spec() ); + if ( domain ) { + config.set( "domain", domain.spec() ); + } return Grid::Implementation::create( shortname, config ); }() ) {} @@ -63,6 +65,10 @@ const Grid::Domain& Grid::domain() const { return get()->domain(); } +RectangularLonLatDomain Grid::lonlatBoundingBox() const { + return get()->lonlatBoundingBox(); +} + std::string Grid::name() const { return get()->name(); } diff --git a/src/atlas/grid/Grid.h b/src/atlas/grid/Grid.h index f6e9f4ab6..92aec02c3 100644 --- a/src/atlas/grid/Grid.h +++ b/src/atlas/grid/Grid.h @@ -73,6 +73,7 @@ class Grid : public util::ObjectHandle { const Projection& projection() const; const Domain& domain() const; + RectangularLonLatDomain lonlatBoundingBox() const; std::string name() const; std::string uid() const; diff --git a/src/atlas/grid/Partitioner.cc b/src/atlas/grid/Partitioner.cc index f5b67cc6c..8938d67e9 100644 --- a/src/atlas/grid/Partitioner.cc +++ b/src/atlas/grid/Partitioner.cc @@ -38,7 +38,9 @@ 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_Exception( "'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 ); } diff --git a/src/atlas/grid/Spacing.h b/src/atlas/grid/Spacing.h index 94aa6943d..f8d65ef55 100644 --- a/src/atlas/grid/Spacing.h +++ b/src/atlas/grid/Spacing.h @@ -77,6 +77,7 @@ class LinearSpacing : public Spacing { public: using Spacing::Spacing; + LinearSpacing() = default; LinearSpacing( double start, double stop, long N, bool endpoint = true ); LinearSpacing( const Interval&, long N, bool endpoint = true ); }; @@ -86,6 +87,7 @@ class LinearSpacing : public Spacing { class GaussianSpacing : public Spacing { public: using Spacing::Spacing; + GaussianSpacing() = default; GaussianSpacing( long N ); }; diff --git a/src/atlas/grid/StencilComputer.cc b/src/atlas/grid/StencilComputer.cc index c1ac3c90b..c33a66e24 100644 --- a/src/atlas/grid/StencilComputer.cc +++ b/src/atlas/grid/StencilComputer.cc @@ -21,7 +21,9 @@ ComputeLower::ComputeLower( const Vertical& z ) { 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] ); } + if ( jlev + 1 < nlev_ ) { + dz = std::min( dz, z[jlev + 1] - z[jlev] ); + } z_[jlev] = z[jlev] - tol; } @@ -32,14 +34,18 @@ ComputeLower::ComputeLower( const Vertical& z ) { idx_t iref = 0; for ( idx_t jlevaux = 0; jlevaux <= nlevaux_; ++jlevaux ) { - if ( iref + 1 < nlev_ && jlevaux * dzaux >= z[iref + 1] ) { ++iref; } + 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() ); } + if ( not grid.domain().global() ) { + throw_NotImplemented( "Only implemented for global grids", Here() ); + } halo_ = halo; ny_ = grid.ny(); y_.resize( ny_ + 2 * halo_ ); @@ -63,7 +69,9 @@ ComputeNorth::ComputeNorth( const StructuredGrid& grid, idx_t halo ) { ComputeWest::ComputeWest( const StructuredGrid& grid, idx_t halo ) { ATLAS_ASSERT( grid ); - if ( not grid.domain().global() ) { throw_NotImplemented( "Only implemented for global grids", Here() ); } + 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(); diff --git a/src/atlas/grid/StencilComputer.h b/src/atlas/grid/StencilComputer.h index 1fd7c9792..8d3d6168b 100644 --- a/src/atlas/grid/StencilComputer.h +++ b/src/atlas/grid/StencilComputer.h @@ -64,7 +64,9 @@ class ComputeLower { ATLAS_ASSERT( idx < static_cast( nvaux_.size() ) && idx >= 0 ); #endif idx = nvaux_[idx]; - if ( idx < nlev_ - 1 && z > z_[idx + 1] ) { ++idx; } + if ( idx < nlev_ - 1 && z > z_[idx + 1] ) { + ++idx; + } return idx; } }; diff --git a/src/atlas/grid/StructuredGrid.h b/src/atlas/grid/StructuredGrid.h index 38b239643..fcb12d660 100644 --- a/src/atlas/grid/StructuredGrid.h +++ b/src/atlas/grid/StructuredGrid.h @@ -83,6 +83,7 @@ class StructuredGrid : public Grid { using Grid::xy; void xy( idx_t i, idx_t j, double xy[] ) const { grid_->xy( i, j, xy ); } + using Grid::lonlat; 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 ) ); } diff --git a/src/atlas/grid/Vertical.cc b/src/atlas/grid/Vertical.cc index 0f847df05..912033d35 100644 --- a/src/atlas/grid/Vertical.cc +++ b/src/atlas/grid/Vertical.cc @@ -25,12 +25,15 @@ std::vector linspace( double start, double end, idx_t N, bool endpoint ) x_.resize( N ); double step; - if ( endpoint && N > 1 ) + if ( endpoint && N > 1 ) { step = ( end - start ) / double( N - 1 ); - else if ( N > 0 ) + } + else if ( N > 0 ) { step = ( end - start ) / double( N ); - else + } + else { step = 0.; + } for ( idx_t i = 0; i < N; ++i ) { x_[i] = start + i * step; diff --git a/src/atlas/grid/detail/distribution/DistributionImpl.cc b/src/atlas/grid/detail/distribution/DistributionImpl.cc index 60c30f6aa..2e0663586 100644 --- a/src/atlas/grid/detail/distribution/DistributionImpl.cc +++ b/src/atlas/grid/detail/distribution/DistributionImpl.cc @@ -22,8 +22,12 @@ namespace grid { namespace { std::string distribution_type( int N, const Partitioner& p = Partitioner() ) { - if ( N == 1 ) { return "serial"; } - if ( not p ) { return "custom"; } + if ( N == 1 ) { + return "serial"; + } + if ( not p ) { + return "custom"; + } return p.type(); } } // namespace @@ -41,8 +45,9 @@ DistributionImpl::DistributionImpl( const Grid& grid, const Partitioner& partiti 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 ) + 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 ); @@ -68,7 +73,9 @@ 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 << ','; + if ( i != 0 ) { + s << ','; + } s << part_[i]; } s << ']'; diff --git a/src/atlas/grid/detail/grid/Gaussian.cc b/src/atlas/grid/detail/grid/Gaussian.cc index dbaf517d5..96902c577 100644 --- a/src/atlas/grid/detail/grid/Gaussian.cc +++ b/src/atlas/grid/detail/grid/Gaussian.cc @@ -28,13 +28,17 @@ static eckit::Translator to_int; static Projection projection( const Grid::Config& grid ) { Grid::Config config; - if ( grid.get( "projection", config ) ) { return Projection( config ); } + if ( grid.get( "projection", config ) ) { + return Projection( config ); + } return Projection(); } static Domain domain( const Grid::Config& grid ) { Grid::Config config; - if ( grid.get( "domain", config ) ) { return Domain( config ); } + if ( grid.get( "domain", config ) ) { + return Domain( config ); + } return Domain(); } diff --git a/src/atlas/grid/detail/grid/Grid.cc b/src/atlas/grid/detail/grid/Grid.cc index b16c29eaa..a29db3a49 100644 --- a/src/atlas/grid/detail/grid/Grid.cc +++ b/src/atlas/grid/detail/grid/Grid.cc @@ -37,7 +37,9 @@ static void checkSizeOfPoint() { const Grid* Grid::create( const Config& config ) { std::string name; - if ( config.get( "name", name ) ) { return create( name, config ); } + if ( config.get( "name", name ) ) { + return create( name, config ); + } std::string type; if ( config.get( "type", type ) ) { @@ -48,9 +50,15 @@ 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_Exception( "no name or type in configuration", Here() ); } + 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_Exception( "no name or type in configuration", Here() ); + } else { throw_Exception( "name or type in configuration don't exist", Here() ); } @@ -64,7 +72,9 @@ 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 ) { const Grid* grid = it->second->create( name, config ); - if ( grid ) { return grid; } + if ( grid ) { + return grid; + } } // Throw exception @@ -100,7 +110,9 @@ Grid::~Grid() { } Grid::uid_t Grid::uid() const { - if ( uid_.empty() ) { uid_ = hash(); } + if ( uid_.empty() ) { + uid_ = hash(); + } return uid_; } diff --git a/src/atlas/grid/detail/grid/Grid.h b/src/atlas/grid/detail/grid/Grid.h index 7facda769..a6a0def9b 100644 --- a/src/atlas/grid/detail/grid/Grid.h +++ b/src/atlas/grid/detail/grid/Grid.h @@ -99,6 +99,9 @@ class Grid : public util::Object { /// @return area represented by the grid const Domain& domain() const { return domain_; } + /// @return parallel/meridian limits containing the grid + virtual RectangularLonLatDomain lonlatBoundingBox() const = 0; + /// @return projection (mapping between geographic coordinates and grid /// coordinates) const Projection& projection() const { return projection_; } diff --git a/src/atlas/grid/detail/grid/GridBuilder.cc b/src/atlas/grid/detail/grid/GridBuilder.cc index 3cb02aeec..2844e92e8 100644 --- a/src/atlas/grid/detail/grid/GridBuilder.cc +++ b/src/atlas/grid/detail/grid/GridBuilder.cc @@ -35,7 +35,9 @@ size_t regex_count_parens( const std::string& string ) { last_was_backslash = true; continue; } - if ( *step == ')' && !last_was_backslash ) out++; + if ( *step == ')' && !last_was_backslash ) { + out++; + } last_was_backslash = false; } return out; @@ -45,12 +47,16 @@ int regex_match_impl( const std::string& string, const std::string& regex, std:: bool use_substr, bool use_case ) { regex_t re; size_t matchcount = 0; - if ( use_substr ) matchcount = regex_count_parens( regex ); + if ( use_substr ) { + matchcount = regex_count_parens( regex ); + } regmatch_t result[matchcount + 1]; int compiled_ok = !regcomp( &re, regex.c_str(), REG_EXTENDED + ( use_case ? 0 : REG_ICASE ) + ( use_substr ? 0 : REG_NOSUB ) ); - if ( !compiled_ok ) Log::error() << "This regular expression didn't compile: \"" << regex << "\"" << std::endl; + if ( !compiled_ok ) { + Log::error() << "This regular expression didn't compile: \"" << regex << "\"" << std::endl; + } ATLAS_ASSERT( compiled_ok ); @@ -185,11 +191,19 @@ const Grid::Implementation* GridBuilder::create( const Grid::Config& config ) co } std::string type; - if ( config.get( "type", type ) && GridFactory::has( type ) ) { return GridFactory::build( type, 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_Exception( "no name or type in configuration", Here() ); } + 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_Exception( "no name or type in configuration", Here() ); + } else { throw_Exception( "name or type in configuration don't exist", Here() ); } @@ -198,7 +212,9 @@ const Grid::Implementation* GridBuilder::create( const Grid::Config& config ) co bool GridBuilder::match( const std::string& string, std::vector& matches, int& id ) const { id = 0; for ( const std::string& name : names_ ) { - if ( Regex( name ).match( string, matches ) ) return true; + if ( Regex( name ).match( string, matches ) ) { + return true; + } ++id; } return false; diff --git a/src/atlas/grid/detail/grid/LonLat.cc b/src/atlas/grid/detail/grid/LonLat.cc index 5b8faebad..ef1649fb3 100644 --- a/src/atlas/grid/detail/grid/LonLat.cc +++ b/src/atlas/grid/detail/grid/LonLat.cc @@ -27,7 +27,9 @@ static eckit::Translator to_int; static Domain domain( const Grid::Config& grid ) { Grid::Config config; - if ( grid.get( "domain", config ) ) { return Domain( config ); } + if ( grid.get( "domain", config ) ) { + return Domain( config ); + } return Domain(); } @@ -76,18 +78,24 @@ StructuredGrid::grid_t* create_lonlat( long nlon, long nlat, Shift shift, Projection projection; Grid::Config config_projection; - if ( config.get( "projection", config_projection ) ) { projection = Projection( config_projection ); } + if ( config.get( "projection", config_projection ) ) { + projection = Projection( config_projection ); + } std::string name; - if ( shifted_x and shifted_y ) + if ( shifted_x and shifted_y ) { name = "S"; - else if ( shifted_x and not shifted_y ) + } + else if ( shifted_x and not shifted_y ) { name = "Slon"; - else if ( not shifted_x and shifted_y ) + } + else if ( not shifted_x and shifted_y ) { name = "Slat"; - else + } + else { name = "L"; + } name += std::to_string( nlon ) + "x" + std::to_string( nlat ); diff --git a/src/atlas/grid/detail/grid/Regional.cc b/src/atlas/grid/detail/grid/Regional.cc index eb20f1aa0..63e111b13 100644 --- a/src/atlas/grid/detail/grid/Regional.cc +++ b/src/atlas/grid/detail/grid/Regional.cc @@ -25,7 +25,9 @@ namespace { // anonymous static Domain domain( const Grid::Config& grid ) { Grid::Config config; - if ( grid.get( "domain", config ) ) { return Domain( config ); } + if ( grid.get( "domain", config ) ) { + return Domain( config ); + } return Domain(); } @@ -45,10 +47,12 @@ struct ConfigParser { double step( double min, double max, long N, bool endpoint = true ) { double l = max - min; - if ( endpoint && N > 1 ) + if ( endpoint && N > 1 ) { return l / double( N - 1 ); - else + } + else { return l / double( N ); + } } static bool parse( const Projection&, const Grid::Config&, Parsed& x, Parsed& y ); @@ -64,7 +68,9 @@ struct Parse_llc_step : ConfigParser { valid = config.get( "nx", x.N ) && config.get( "ny", y.N ) && config.get( "dx", x.step ) && config.get( "dy", y.step ) && config.get( "lonlat(centre)", centre_lonlat ); - if ( not valid ) return; + if ( not valid ) { + return; + } double centre[] = {centre_lonlat[0], centre_lonlat[1]}; p.lonlat2xy( centre ); @@ -84,7 +90,9 @@ struct Parse_bounds_xy : ConfigParser { valid = config.get( "nx", x.N ) && config.get( "ny", y.N ) && config.get( "xmin", x.min ) && config.get( "xmax", x.max ) && config.get( "ymin", y.min ) && config.get( "ymax", y.max ); - if ( not valid ) return; + if ( not valid ) { + return; + } x.step = step( x.min, x.max, x.N ); y.step = step( y.min, y.max, y.N ); @@ -113,7 +121,9 @@ struct Parse_bounds_lonlat : ConfigParser { } } - if ( not valid ) return; + if ( not valid ) { + return; + } x.step = step( x.min, x.max, x.N ); y.step = step( y.min, y.max, y.N ); @@ -128,7 +138,9 @@ struct Parse_ll00_ll11 : ConfigParser { config.get( "lonlat(xmin,ymin)", sw ) // includes rotation && config.get( "lonlat(xmax,ymax)", ne ); // includes rotation - if ( not valid ) return; + if ( not valid ) { + return; + } p.lonlat2xy( sw.data() ); p.lonlat2xy( ne.data() ); @@ -142,13 +154,30 @@ struct Parse_ll00_ll11 : ConfigParser { } }; +struct Parse_xy01_step : ConfigParser { + Parse_xy01_step( const Projection&, const Grid::Config& config ) { + valid = config.get( "nx", x.N ) && config.get( "ny", y.N ) && config.get( "dx", x.step ) && + config.get( "dy", y.step ) && config.get( "xmin", x.min ) && + config.get( "ymax", y.max ); // includes rotation + + if ( not valid ) { + return; + } + + x.max = x.min + x.step * ( x.N - 1 ); + y.min = y.max - y.step * ( y.N - 1 ); + } +}; + struct Parse_ll00_step : ConfigParser { Parse_ll00_step( const Projection& p, const Grid::Config& config ) { std::vector sw; valid = config.get( "nx", x.N ) && config.get( "ny", y.N ) && config.get( "dx", x.step ) && config.get( "dy", y.step ) && config.get( "lonlat(xmin,ymin)", sw ); // includes rotation - if ( not valid ) return; + if ( not valid ) { + return; + } p.lonlat2xy( sw.data() ); x.min = sw[0]; @@ -159,13 +188,30 @@ struct Parse_ll00_step : ConfigParser { } }; +struct Parse_xy00_step : ConfigParser { + Parse_xy00_step( const Projection&, const Grid::Config& config ) { + valid = config.get( "nx", x.N ) && config.get( "ny", y.N ) && config.get( "dx", x.step ) && + config.get( "dy", y.step ) && config.get( "xmin", x.min ) && config.get( "ymin", y.min ); + + if ( not valid ) { + return; + } + + x.max = x.min + x.step * ( x.N - 1 ); + y.max = y.min + y.step * ( y.N - 1 ); + } +}; + + struct Parse_ll01_step : ConfigParser { // This resembles GRIB input for "lambert_azimutal_equal_area" Parse_ll01_step( const Projection& p, const Grid::Config& config ) { std::vector nw; valid = config.get( "nx", x.N ) && config.get( "ny", y.N ) && config.get( "dx", x.step ) && config.get( "dy", y.step ) && config.get( "lonlat(xmin,ymax)", nw ); // includes rotation - if ( not valid ) return; + if ( not valid ) { + return; + } p.lonlat2xy( nw.data() ); x.min = nw[0]; @@ -190,24 +236,42 @@ bool ConfigParser::parse( const Projection& projection, const Grid::Config& conf bool ConfigParser::parse( const Projection& projection, const Grid::Config& config, Parsed& x, Parsed& y ) { // bounding box using 4 variables (any projection allowed) - if ( ConfigParser::parse( projection, config, x, y ) ) return true; + if ( ConfigParser::parse( projection, config, x, y ) ) { + return true; + } // centre of domain and increments (any projection allowed) - if ( ConfigParser::parse( projection, config, x, y ) ) return true; + if ( ConfigParser::parse( projection, config, x, y ) ) { + return true; + } // top-left of domain and increments (any projection allowed) - if ( ConfigParser::parse( projection, config, x, y ) ) return true; + if ( ConfigParser::parse( projection, config, x, y ) ) { + return true; + } + if ( ConfigParser::parse( projection, config, x, y ) ) { + return true; + } // bottom-left of domain and increments (any projection allowed) - if ( ConfigParser::parse( projection, config, x, y ) ) return true; + if ( ConfigParser::parse( projection, config, x, y ) ) { + return true; + } + if ( ConfigParser::parse( projection, config, x, y ) ) { + return true; + } // bounding box using two points defined in lonlat (any projection allowed) - if ( ConfigParser::parse( projection, config, x, y ) ) return true; + if ( ConfigParser::parse( projection, config, x, y ) ) { + return true; + } //-------- From here on, projection must be (rotated) lonlat --------// // bounding box using 4 variables (south west north east) - if ( ConfigParser::parse( projection, config, x, y ) ) return true; + if ( ConfigParser::parse( projection, config, x, y ) ) { + return true; + } return false; } @@ -231,7 +295,9 @@ static class regional : public GridBuilder { Projection projection; { util::Config config_proj; - if ( config.get( "projection", config_proj ) ) { projection = Projection( config_proj ); } + if ( config.get( "projection", config_proj ) ) { + projection = Projection( config_proj ); + } } // Read grid configuration @@ -240,12 +306,11 @@ static class regional : public GridBuilder { throw_Exception( "Could not parse configuration for RegularRegional grid", Here() ); } - YSpace yspace = config.getBool( "y_increasing", true ) ? LinearSpacing( y.min, y.max, y.N, y.endpoint ) - : LinearSpacing( y.max, y.min, y.N, y.endpoint ); + YSpace yspace = config.getInt( "y_numbering", -1 ) < 0 ? LinearSpacing( y.max, y.min, y.N, y.endpoint ) + : 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 ); - return new StructuredGrid::grid_t( xspace, yspace, projection, domain( config ) ); } @@ -272,7 +337,9 @@ static class zonal_band : public GridBuilder { Projection projection; { util::Config config_proj; - if ( config.get( "projection", config_proj ) ) { projection = Projection( config_proj ); } + if ( config.get( "projection", config_proj ) ) { + projection = Projection( config_proj ); + } } ATLAS_ASSERT( projection.units() == "degrees" ); @@ -280,13 +347,21 @@ static class zonal_band : public GridBuilder { // Read grid configuration ConfigParser::Parsed y; long nx; - 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.; + 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 = config.getBool( "y_increasing", true ) ? LinearSpacing( y.min, y.max, y.N, true ) - : LinearSpacing( y.max, y.min, y.N, true ); + YSpace yspace = config.getInt( "y_numbering", -1 ) < 0 ? LinearSpacing( y.max, y.min, y.N, true ) + : LinearSpacing( y.min, y.max, y.N, true ); XSpace xspace( {0., 360.}, std::vector( y.N, nx ), false ); diff --git a/src/atlas/grid/detail/grid/Structured.cc b/src/atlas/grid/detail/grid/Structured.cc index 2192b75c8..2094cf5ce 100644 --- a/src/atlas/grid/detail/grid/Structured.cc +++ b/src/atlas/grid/detail/grid/Structured.cc @@ -52,10 +52,7 @@ Structured::Structured( const std::string& name, XSpace xspace, YSpace yspace, P xspace_( xspace ), yspace_( yspace ) { // Copy members - if ( projection ) - projection_ = projection; - else - projection_ = Projection(); + projection_ = projection ? projection : Projection(); y_.assign( yspace_.begin(), yspace_.end() ); idx_t ny{static_cast( y_.size() )}; @@ -88,12 +85,11 @@ Structured::Structured( const std::string& name, XSpace xspace, YSpace yspace, P computeTruePeriodicity(); } -void Structured::computeDomain() { - if ( periodic() ) { domain_ = ZonalBandDomain( {yspace().min(), yspace().max()}, xspace().min() ); } - else { - domain_ = RectangularDomain( {xspace().min(), xspace().max()}, {yspace().min(), yspace().max()}, - projection_.units() ); +Domain Structured::computeDomain() const { + if ( periodic() ) { + return ZonalBandDomain( {yspace().min(), yspace().max()}, xspace().min() ); } + return RectangularDomain( {xspace().min(), xspace().max()}, {yspace().min(), yspace().max()}, projection_.units() ); } Structured::~Structured() {} @@ -143,10 +139,18 @@ Structured::XSpace::Implementation::Implementation( const Config& config ) { 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() ) 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 ); + 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(); nxmax_ = 0; @@ -154,10 +158,18 @@ Structured::XSpace::Implementation::Implementation( const Config& config ) { max_ = -std::numeric_limits::max(); 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] ); - if ( not v_length.empty() ) config_xspace.set( "length", v_length[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] ); + } + if ( not v_length.empty() ) { + config_xspace.set( "length", v_length[j] ); + } spacing::LinearSpacing::Params xspace( config_xspace ); xmin_.push_back( xspace.start ); xmax_.push_back( xspace.end ); @@ -301,15 +313,21 @@ Grid::Spec Structured::XSpace::Implementation::spec() const { bool endpoint = std::abs( ( xmax - xmin ) - ( nx - 1 ) * dx ) < 1.e-10; spec.set( "type", "linear" ); - if ( same_xmin ) { spec.set( "start", xmin ); } + if ( same_xmin ) { + spec.set( "start", xmin ); + } else { spec.set( "start[]", xmin_ ); } - if ( same_xmax ) { spec.set( "end", xmax ); } + if ( same_xmax ) { + spec.set( "end", xmax ); + } else { spec.set( "end[]", xmax_ ); } - if ( same_nx ) { spec.set( "N", nx ); } + if ( same_nx ) { + spec.set( "N", nx ); + } else { spec.set( "N[]", nx_ ); } @@ -326,7 +344,9 @@ class Normalise { normalise_( domain.xmin() ) {} double operator()( double x ) const { - if ( degrees_ ) { x = normalise_( x ); } + if ( degrees_ ) { + x = normalise_( x ); + } return x; } @@ -443,7 +463,9 @@ void Structured::crop( const Domain& dom ) { throw_Exception( errmsg.str(), Here() ); } } - domain_ = RectangularDomain( {xspace_.min(), xspace_.max()}, {yspace_.min(), yspace_.max()}, projection_.units() ); + domain_ = + dom ? dom + : RectangularDomain( {xspace_.min(), xspace_.max()}, {yspace_.min(), yspace_.max()}, projection_.units() ); } void Structured::computeTruePeriodicity() { @@ -478,15 +500,24 @@ std::string Structured::type() const { } void Structured::hash( eckit::Hash& h ) const { - h.add( y().data(), sizeof( double ) * y().size() ); + auto add_double = [&]( const double& x ) { h.add( std::round( x * 1.e8 ) ); }; + auto add_double_vector = [&]( const std::vector& xvec ) { + for ( auto& x : xvec ) { + add_double( x ); + } + }; + auto add_long = [&]( const idx_t& x ) { h.add( long( x ) ); }; + auto add_long_vector = [&]( const std::vector& xvec ) { + for ( auto& x : xvec ) { + add_long( x ); + } + }; - // 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() ); + add_double_vector( y() ); + add_long_vector( nx() ); - // also add lonmin and lonmax - h.add( xmin_.data(), sizeof( double ) * xmin_.size() ); - h.add( dx_.data(), sizeof( double ) * dx_.size() ); + add_double_vector( xmin_ ); + add_double_vector( dx_ ); // also add projection information projection().hash( h ); @@ -495,6 +526,10 @@ void Structured::hash( eckit::Hash& h ) const { domain().hash( h ); } +RectangularLonLatDomain Structured::lonlatBoundingBox() const { + return projection_ ? projection_.lonlatBoundingBox( computeDomain() ) : domain(); +} + Grid::Spec Structured::spec() const { Grid::Spec grid_spec; @@ -511,7 +546,7 @@ Grid::Spec Structured::spec() const { return grid_spec; } - // -------------------------------------------------------------------- +// -------------------------------------------------------------------- #if 1 namespace { // anonymous @@ -539,13 +574,19 @@ static class structured : public GridBuilder { Domain domain; Config config_proj; - if ( config.get( "projection", config_proj ) ) projection = Projection( config_proj ); + if ( config.get( "projection", config_proj ) ) { + projection = Projection( config_proj ); + } Config config_domain; - if ( config.get( "domain", config_domain ) ) { domain = Domain( config_domain ); } + if ( config.get( "domain", config_domain ) ) { + domain = Domain( config_domain ); + } Config config_yspace; - if ( not config.get( "yspace", config_yspace ) ) throw_Exception( "yspace missing in configuration", Here() ); + if ( not config.get( "yspace", config_yspace ) ) { + throw_Exception( "yspace missing in configuration", Here() ); + } yspace = Spacing( config_yspace ); XSpace xspace; @@ -553,7 +594,9 @@ static class structured : public GridBuilder { Config config_xspace; std::vector config_xspace_list; - if ( config.get( "xspace[]", config_xspace_list ) ) { xspace = XSpace( config_xspace_list ); } + if ( config.get( "xspace[]", config_xspace_list ) ) { + xspace = XSpace( config_xspace_list ); + } else if ( config.get( "xspace", config_xspace ) ) { xspace = XSpace( config_xspace ); } diff --git a/src/atlas/grid/detail/grid/Structured.h b/src/atlas/grid/detail/grid/Structured.h index 95e126a8a..5fe2f2c10 100644 --- a/src/atlas/grid/detail/grid/Structured.h +++ b/src/atlas/grid/detail/grid/Structured.h @@ -111,7 +111,8 @@ class Structured : public Grid { i_ = 0; } ++n_; - if ( n_ == size_ ) return *this; + if ( n_ == size_ ) + return *this; } while ( not p_( n_ ) ); return *this; } @@ -380,9 +381,11 @@ class Structured : public Grid { virtual void hash( eckit::Hash& ) const override; + virtual RectangularLonLatDomain lonlatBoundingBox() const override; + void computeTruePeriodicity(); - void computeDomain(); + Domain computeDomain() const; void crop( const Domain& ); diff --git a/src/atlas/grid/detail/grid/Unstructured.cc b/src/atlas/grid/detail/grid/Unstructured.cc index 64513e77a..ff33951c2 100644 --- a/src/atlas/grid/detail/grid/Unstructured.cc +++ b/src/atlas/grid/detail/grid/Unstructured.cc @@ -11,6 +11,7 @@ #include "atlas/grid/detail/grid/Unstructured.h" #include +#include #include #include @@ -20,6 +21,7 @@ #include "atlas/array/ArrayView.h" #include "atlas/field/Field.h" #include "atlas/grid/Iterator.h" +#include "atlas/grid/detail/grid/GridBuilder.h" #include "atlas/grid/detail/grid/GridFactory.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" @@ -34,8 +36,6 @@ namespace grid { namespace detail { namespace grid { -//static eckit::ConcreteBuilderT1 builder_Unstructured( Unstructured::static_type() ); - namespace { static GridFactoryBuilder __register_Unstructured( Unstructured::static_type() ); } @@ -64,7 +64,9 @@ class Normalise { normalise_( domain.xmin(), domain.xmax() ) {} double operator()( double x ) const { - if ( degrees_ ) { x = normalise_( x ); } + if ( degrees_ ) { + x = normalise_( x ); + } return x; } @@ -79,19 +81,25 @@ Unstructured::Unstructured( const Grid& grid, Domain domain ) : Grid() { domain_ = domain; points_.reset( new std::vector ); points_->reserve( grid.size() ); - if ( not domain_ ) { domain_ = Domain( option::type( "global" ) ); } + if ( not domain_ ) { + domain_ = GlobalDomain(); + } atlas::grid::IteratorXY it( grid.xy_begin() ); PointXY p; if ( RectangularDomain( domain_ ) ) { auto normalise = Normalise( RectangularDomain( domain_ ) ); while ( it.next( p ) ) { p.x() = normalise( p.x() ); - if ( domain_.contains( p ) ) { points_->emplace_back( p ); } + if ( domain_.contains( p ) ) { + points_->emplace_back( p ); + } } } else if ( ZonalBandDomain( domain_ ) ) { while ( it.next( p ) ) { - if ( domain_.contains( p ) ) { points_->emplace_back( p ); } + if ( domain_.contains( p ) ) { + points_->emplace_back( p ); + } } } else { @@ -102,33 +110,53 @@ Unstructured::Unstructured( const Grid& grid, Domain domain ) : Grid() { points_->shrink_to_fit(); } -Unstructured::Unstructured( const util::Config& ) : Grid() { +Unstructured::Unstructured( const util::Config& config ) : Grid() { util::Config config_domain; - config_domain.set( "type", "global" ); + if ( not config.get( "domain", config_domain ) ) { + config_domain.set( "type", "global" ); + } domain_ = Domain( config_domain ); - ATLAS_NOTIMPLEMENTED; + std::vector xy; + if ( config.get( "xy", xy ) ) { + const size_t N = xy.size() / 2; + points_.reset( new std::vector ); + points_->reserve( N ); + for ( size_t n = 0; n < N; ++n ) { + points_->emplace_back( PointXY{xy[2 * n], xy[2 * n + 1]} ); + } + } + else { + std::vector x; + std::vector y; + if ( not config.get( "x", x ) ) { + throw_Exception( "x missing from configuration" ); + } + if ( not config.get( "y", y ) ) { + throw_Exception( "y missing from configuration" ); + } + ATLAS_ASSERT( x.size() == y.size() ); + points_.reset( new std::vector ); + points_->reserve( x.size() ); + for ( size_t n = 0; n < x.size(); ++n ) { + points_->emplace_back( PointXY{x[n], y[n]} ); + } + } } Unstructured::Unstructured( std::vector* pts ) : Grid(), points_( pts ) { - util::Config config_domain; - config_domain.set( "type", "global" ); - domain_ = Domain( config_domain ); + domain_ = GlobalDomain(); } Unstructured::Unstructured( std::vector&& pts ) : Grid(), points_( new std::vector( std::move( pts ) ) ) { - util::Config config_domain; - config_domain.set( "type", "global" ); - domain_ = Domain( config_domain ); + domain_ = GlobalDomain(); } Unstructured::Unstructured( std::initializer_list initializer_list ) : Grid(), points_( new std::vector( initializer_list ) ) { - util::Config config_domain; - config_domain.set( "type", "global" ); - domain_ = Domain( config_domain ); + domain_ = GlobalDomain(); } Unstructured::~Unstructured() {} @@ -156,13 +184,19 @@ void Unstructured::hash( eckit::Hash& h ) const { projection().hash( h ); } +RectangularLonLatDomain Unstructured::lonlatBoundingBox() const { + return projection_ ? projection_.lonlatBoundingBox( domain_ ) : domain_; +} + idx_t Unstructured::size() const { ATLAS_ASSERT( points_ != nullptr ); return static_cast( points_->size() ); } Grid::Spec Unstructured::spec() const { - if ( cached_spec_ ) return *cached_spec_; + if ( cached_spec_ ) { + return *cached_spec_; + } cached_spec_.reset( new Grid::Spec ); @@ -202,6 +236,53 @@ bool Unstructured::IteratorXYPredicated::next( PointXY& /*xy*/ ) { #endif } +namespace { // anonymous + +static class unstructured : public GridBuilder { + using Implementation = atlas::Grid::Implementation; + using Config = Grid::Config; + +public: + unstructured() : GridBuilder( "unstructured" ) {} + + virtual void print( std::ostream& os ) const { + os << std::left << std::setw( 20 ) << " " + << "Unstructured grid"; + } + + virtual const Implementation* create( const std::string& /* name */, const Config& ) const { + throw_NotImplemented( "Cannot create unstructured grid from name", Here() ); + } + + virtual const Implementation* create( const Config& config ) const { return new Unstructured( config ); } + +} unstructured_; + +} // anonymous namespace + +extern "C" { +const Unstructured* atlas__grid__Unstructured__points( const double xy[], int shapef[], int stridesf[] ) { + size_t nb_points = shapef[1]; + ATLAS_ASSERT( shapef[0] == 2 ); + size_t stride_n = stridesf[1]; + size_t stride_v = stridesf[0]; + std::vector points; + points.reserve( nb_points ); + for ( idx_t n = 0; n < nb_points; ++n ) { + points.emplace_back( PointXY{xy[n * stride_n + 0], xy[n * stride_n + 1 * stride_v]} ); + } + return new Unstructured( std::move( points ) ); +} + +const Unstructured* atlas__grid__Unstructured__config( util::Config* conf ) { + ATLAS_ASSERT( conf != nullptr ); + const Unstructured* grid = dynamic_cast( Grid::create( *conf ) ); + ATLAS_ASSERT( grid != nullptr ); + return grid; +} +} + + } // 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 799f979bf..ad863f76c 100644 --- a/src/atlas/grid/detail/grid/Unstructured.h +++ b/src/atlas/grid/detail/grid/Unstructured.h @@ -79,7 +79,8 @@ class Unstructured : public Grid { p_( p ), size_( static_cast( grid_.points_->size() ) ), n_( begin ? 0 : size_ ) { - if ( begin ) {} + if ( begin ) { + } } virtual bool next( PointXY& xy ); @@ -89,7 +90,8 @@ class Unstructured : public Grid { virtual const Grid::IteratorXY& operator++() { do { ++n_; - if ( n_ == size_ ) return *this; + if ( n_ == size_ ) + return *this; } while ( not p_( n_ ) ); return *this; } @@ -150,8 +152,8 @@ class Unstructured : public Grid { public: // methods static std::string static_type() { return "unstructured"; } - virtual std::string name() const; - virtual std::string type() const { return static_type(); } + virtual std::string name() const override; + virtual std::string type() const override { return static_type(); } /// Constructor converting any Grid with domain to an unstructured grid Unstructured( const Grid&, Domain ); @@ -171,32 +173,35 @@ class Unstructured : public Grid { /// Constructor from initializer list Unstructured( std::initializer_list ); - virtual ~Unstructured(); + virtual ~Unstructured() override; - virtual idx_t size() const; + virtual idx_t size() const override; - virtual Spec spec() const; + virtual Spec spec() const override; PointXY xy( idx_t n ) const { return ( *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 ); } - virtual IteratorLonLat* lonlat_begin() const { return new IteratorLonLat( *this ); } - virtual IteratorLonLat* lonlat_end() const { return new IteratorLonLat( *this, false ); } - virtual IteratorXYPredicated* xy_begin( IteratorXY::Predicate p ) const { + 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 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 ); } private: // methods - virtual void print( std::ostream& ) const; + virtual void print( std::ostream& ) const override; + + /// Hash of the lonlat array + virtual void hash( eckit::Hash& ) const override; - /// Hash of the lonlat array + BoundingBox - virtual void hash( eckit::Hash& ) const; + /// @return parallel/meridian limits containing the grid + virtual RectangularLonLatDomain lonlatBoundingBox() const override; protected: /// Storage of coordinate points @@ -209,6 +214,12 @@ class Unstructured : public Grid { mutable std::unique_ptr cached_spec_; }; +extern "C" { +const Unstructured* atlas__grid__Unstructured__points( const double lonlat[], int shapef[], int stridesf[] ); +const Unstructured* atlas__grid__Unstructured__config( util::Config* conf ); +} + + } // namespace grid } // namespace detail } // namespace grid diff --git a/src/atlas/grid/detail/partitioner/CheckerboardPartitioner.cc b/src/atlas/grid/detail/partitioner/CheckerboardPartitioner.cc index edfef30f7..6e84a15c9 100644 --- a/src/atlas/grid/detail/partitioner/CheckerboardPartitioner.cc +++ b/src/atlas/grid/detail/partitioner/CheckerboardPartitioner.cc @@ -54,7 +54,9 @@ 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_Exception( "Checkerboard Partitioner only works for Regular grids.", Here() ); + if ( !rg ) { + throw_Exception( "Checkerboard Partitioner only works for Regular grids.", Here() ); + } Checkerboard cb; @@ -62,22 +64,30 @@ CheckerboardPartitioner::Checkerboard CheckerboardPartitioner::checkerboard( con cb.ny = rg.ny(); idx_t nparts = nb_partitions(); - if ( nbands_ > 0 ) { cb.nbands = nbands_; } + 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 = (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 + if ( cb.nbands < 1 ) { + cb.nbands = 1; // at least one band + } + if ( cb.nbands > nparts ) { + cb.nbands = nparts; // not more bands than procs + } // true checkerboard means nbands must divide nparts if ( checkerboard_ ) { - while ( nparts % cb.nbands != 0 ) + while ( nparts % cb.nbands != 0 ) { cb.nbands--; + } } } - if ( checkerboard_ && nparts % cb.nbands != 0 ) + if ( checkerboard_ && nparts % cb.nbands != 0 ) { throw_Exception( "number of bands doesn't divide number of partitions", Here() ); + } return cb; } @@ -85,16 +95,24 @@ CheckerboardPartitioner::Checkerboard CheckerboardPartitioner::checkerboard( con bool compare_Y_X( const CheckerboardPartitioner::NodeInt& node1, const CheckerboardPartitioner::NodeInt& node2 ) { // comparison of two locations; X1 < X2 if it's to the south, then to the // east. - if ( node1.y < node2.y ) return true; - if ( node1.y == node2.y ) return ( node1.x < node2.x ); + if ( node1.y < node2.y ) { + return true; + } + if ( node1.y == node2.y ) { + return ( node1.x < node2.x ); + } return false; } bool compare_X_Y( const CheckerboardPartitioner::NodeInt& node1, const CheckerboardPartitioner::NodeInt& node2 ) { // comparison of two locations; X1 < X2 if it's to the east, then to the // south. - if ( node1.x < node2.x ) return true; - if ( node1.x == node2.x ) return ( node1.y < node2.y ); + if ( node1.x < node2.x ) { + return true; + } + if ( node1.x == node2.x ) { + return ( node1.y < node2.y ); + } return false; } @@ -122,8 +140,9 @@ Number of procs per band remainder -= npartsb[iband]; } // distribute remaining procs over first bands - for ( size_t iband = 0; iband < remainder; iband++ ) + for ( size_t iband = 0; iband < remainder; iband++ ) { ++npartsb[iband]; + } /* Number of gridpoints per band @@ -137,8 +156,9 @@ Number of gridpoints per band remainder -= ngpb[iband]; } // distribute remaining gridpoints over first bands - for ( size_t iband = 0; iband < remainder; iband++ ) + for ( size_t iband = 0; iband < remainder; iband++ ) { ++ngpb[iband]; + } } else { remainder = ny; @@ -147,8 +167,9 @@ Number of gridpoints per band remainder -= ngpb[iband] / nx; } // distribute remaining rows over first bands - for ( size_t iband = 0; iband < remainder; iband++ ) + for ( size_t iband = 0; iband < remainder; iband++ ) { ngpb[iband] += nx; + } } // for (int iband=0;iband 0 ) { w = x - 1; - for ( k = 2; k <= n; ++k ) + for ( k = 2; k <= n; ++k ) { w = w * ( x - k ); + } } else { w = 1; - for ( k = 0; k <= -n - 1; ++k ) + for ( k = 0; k <= -n - 1; ++k ) { y = y * ( x + k ); + } } return w / y; } @@ -123,9 +125,15 @@ double polar_colat( int N ) { // Given N, determine the colatitude of the North polar spherical cap. // double polar_c( 0 ); - if ( N == 1 ) polar_c = M_PI; - if ( N == 2 ) polar_c = 0.5 * M_PI; - if ( N > 2 ) polar_c = sradius_of_cap( area_of_ideal_region( N ) ); + if ( N == 1 ) { + polar_c = M_PI; + } + if ( N == 2 ) { + polar_c = 0.5 * M_PI; + } + if ( N > 2 ) { + polar_c = sradius_of_cap( area_of_ideal_region( N ) ); + } return polar_c; } @@ -180,10 +188,12 @@ int num_collars( int N, const double& c_polar, const double& a_ideal ) { // determine n_collars, the number of collars between the polar caps. // bool enough = ( N > 2 ) && ( a_ideal > 0 ); - if ( enough ) + if ( enough ) { return std::max( 1, static_cast( round( ( M_PI - 2. * c_polar ) / a_ideal ) ) ); - else + } + else { return 0; + } } void round_to_naturals( int N, int ncollars, double r_regions[], int n_regions[] ) { @@ -413,8 +423,9 @@ EqualRegionsPartitioner::EqualRegionsPartitioner( int N ) : Partitioner( N ), N_ int EqualRegionsPartitioner::partition( const double& x, const double& y ) const { int b = band( y ); int p = 0; - for ( int n = 0; n < b; ++n ) + for ( int n = 0; n < b; ++n ) { p += sectors_[n]; + } return p + sector( b, x ); } @@ -424,10 +435,12 @@ int EqualRegionsPartitioner::band( const double& y ) const { int EqualRegionsPartitioner::sector( int band, const double& x ) const { double xreg = x; - if ( x < 0. ) + if ( x < 0. ) { xreg += 2. * M_PI; - else if ( x > 2. * M_PI ) + } + else if ( x > 2. * M_PI ) { xreg -= 2. * M_PI; + } return std::floor( xreg * sectors_[band] / ( 2. * M_PI + 1e-8 ) ); } @@ -446,14 +459,22 @@ void EqualRegionsPartitioner::where( int partition, int& band, int& sector ) con } bool compare_NS_WE( const EqualRegionsPartitioner::NodeInt& node1, const EqualRegionsPartitioner::NodeInt& node2 ) { - if ( node1.y > node2.y ) return true; - if ( node1.y == node2.y ) return ( node1.x < node2.x ); + if ( node1.y > node2.y ) { + return true; + } + if ( node1.y == node2.y ) { + return ( node1.x < node2.x ); + } return false; } bool compare_WE_NS( const EqualRegionsPartitioner::NodeInt& node1, const EqualRegionsPartitioner::NodeInt& node2 ) { - if ( node1.x < node2.x ) return true; - if ( node1.x == node2.x ) return ( node1.y > node2.y ); + if ( node1.x < node2.x ) { + return true; + } + if ( node1.x == node2.x ) { + return ( node1.y > node2.y ); + } return false; } @@ -530,8 +551,9 @@ 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 ( idx_t j = 0; j < grid.size(); ++j ) + for ( idx_t j = 0; j < grid.size(); ++j ) { part[j] = 0; + } } else { ATLAS_TRACE( "EqualRegionsPartitioner::partition" ); @@ -579,7 +601,9 @@ void EqualRegionsPartitioner::partition( const Grid& grid, int part[] ) const { for ( int w = 0; w < nb_workers; ++w ) { int w_begin = w * grid.size() / N_; int w_end = ( w + 1 ) * grid.size() / N_; - if ( w == nb_workers - 1 ) w_end = grid.size(); + if ( w == nb_workers - 1 ) { + w_end = grid.size(); + } size_t w_size = w_end - w_begin; int work_rank = std::min( w, mpi_size - 1 ); @@ -636,7 +660,9 @@ void EqualRegionsPartitioner::partition( const Grid& grid, int part[] ) const { for ( int w = 0; w < nb_workers; ++w ) { int w_begin = w * grid.size() / N_; int w_end = ( w + 1 ) * grid.size() / N_; - if ( w == nb_workers - 1 ) w_end = grid.size(); + if ( w == nb_workers - 1 ) { + w_end = grid.size(); + } if ( w != 0 ) { std::inplace_merge( nodes.begin(), nodes.begin() + w_begin, nodes.begin() + w_end, compare_NS_WE ); diff --git a/src/atlas/grid/detail/partitioner/Partitioner.cc b/src/atlas/grid/detail/partitioner/Partitioner.cc index b12ec8297..5c5b1dc19 100644 --- a/src/atlas/grid/detail/partitioner/Partitioner.cc +++ b/src/atlas/grid/detail/partitioner/Partitioner.cc @@ -135,8 +135,9 @@ Partitioner* PartitionerFactory::build( const std::string& name ) { if ( j == m->end() ) { Log::error() << "No PartitionerFactory for [" << name << "]" << '\n'; Log::error() << "PartitionerFactories are:" << '\n'; - for ( j = m->begin(); j != m->end(); ++j ) + for ( j = m->begin(); j != m->end(); ++j ) { Log::error() << " " << ( *j ).first << '\n'; + } throw_Exception( std::string( "No PartitionerFactory called " ) + name ); } @@ -157,8 +158,9 @@ Partitioner* PartitionerFactory::build( const std::string& name, const idx_t nb_ if ( j == m->end() ) { Log::error() << "No PartitionerFactory for [" << name << "]" << '\n'; Log::error() << "PartitionerFactories are:" << '\n'; - for ( j = m->begin(); j != m->end(); ++j ) + for ( j = m->begin(); j != m->end(); ++j ) { Log::error() << " " << ( *j ).first << '\n'; + } throw_Exception( std::string( "No PartitionerFactory called " ) + name ); } diff --git a/src/atlas/grid/detail/partitioner/TransPartitioner.cc b/src/atlas/grid/detail/partitioner/TransPartitioner.cc index 8d1f1c695..40bbc65c4 100644 --- a/src/atlas/grid/detail/partitioner/TransPartitioner.cc +++ b/src/atlas/grid/detail/partitioner/TransPartitioner.cc @@ -48,7 +48,8 @@ void TransPartitioner::partition( const Grid& grid, int part[] ) const { ATLAS_TRACE( "TransPartitioner::partition" ); StructuredGrid g( grid ); - if ( not g ) throw_Exception( "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() != idx_t( t.nproc() ) ) { @@ -90,7 +91,8 @@ void TransPartitioner::partition( const Grid& grid, int part[] ) const { int igl = nptrfrstlat( ja ) + jgl - nfrstlat( ja ); for ( int jl = nsta( jb, igl ) - 1; jl < nsta( jb, igl ) + nonl( jb, igl ) - 1; ++jl ) { idx_t ind = iglobal[jgl * nlonmax + jl] - 1; - if ( ind >= grid.size() ) throw_OutOfRange( "part", ind, grid.size(), Here() ); + if ( ind >= grid.size() ) + throw_OutOfRange( "part", ind, grid.size(), Here() ); part[ind] = iproc; } } diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N.cc b/src/atlas/grid/detail/pl/classic_gaussian/N.cc index 5aaf77b66..3ac081014 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N.cc @@ -23,14 +23,16 @@ namespace classic_gaussian { void PointsPerLatitude::assign( long nlon[], const size_t size ) const { ATLAS_ASSERT( size >= nlon_.size() ); - for ( size_t jlat = 0; jlat < nlon_.size(); ++jlat ) + for ( size_t jlat = 0; jlat < nlon_.size(); ++jlat ) { nlon[jlat] = nlon_[jlat]; + } } void PointsPerLatitude::assign( int nlon[], const size_t size ) const { ATLAS_ASSERT( size >= nlon_.size() ); - for ( size_t jlat = 0; jlat < nlon_.size(); ++jlat ) + for ( size_t jlat = 0; jlat < nlon_.size(); ++jlat ) { nlon[jlat] = nlon_[jlat]; + } } void PointsPerLatitude::assign( std::vector& nlon ) const { diff --git a/src/atlas/grid/detail/spacing/CustomSpacing.cc b/src/atlas/grid/detail/spacing/CustomSpacing.cc index f668a4c80..070fe164b 100644 --- a/src/atlas/grid/detail/spacing/CustomSpacing.cc +++ b/src/atlas/grid/detail/spacing/CustomSpacing.cc @@ -31,7 +31,9 @@ CustomSpacing::CustomSpacing( const eckit::Parametrisation& params ) { params.get( "values", x_ ); size_t N; - if ( params.get( "N", N ) ) { ATLAS_ASSERT( x_.size() == N ); } + if ( params.get( "N", N ) ) { + ATLAS_ASSERT( x_.size() == N ); + } N = x_.size(); std::vector interval; diff --git a/src/atlas/grid/detail/spacing/FocusSpacing.cc b/src/atlas/grid/detail/spacing/FocusSpacing.cc index d2179f477..2b500f44d 100644 --- a/src/atlas/grid/detail/spacing/FocusSpacing.cc +++ b/src/atlas/grid/detail/spacing/FocusSpacing.cc @@ -26,15 +26,25 @@ FocusSpacing::FocusSpacing( const eckit::Parametrisation& params ) { long N; // retrieve xmin, xmax and N from params - 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() ); + 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_Exception( "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 ); } + if ( N == 1 ) { + x_[0] = 0.5 * ( xmin + xmax ); + } else { const double midpoint = 0.5 * ( xmin + xmax ); const double d2 = 2. / double( N - 1 ); diff --git a/src/atlas/grid/detail/spacing/GaussianSpacing.cc b/src/atlas/grid/detail/spacing/GaussianSpacing.cc index a081d845a..35461eb40 100644 --- a/src/atlas/grid/detail/spacing/GaussianSpacing.cc +++ b/src/atlas/grid/detail/spacing/GaussianSpacing.cc @@ -34,7 +34,9 @@ GaussianSpacing::GaussianSpacing( long N ) { GaussianSpacing::GaussianSpacing( const eckit::Parametrisation& params ) { // retrieve N from params long N; - if ( !params.get( "N", N ) ) throw_Exception( "N missing in Params", Here() ); + if ( !params.get( "N", N ) ) { + throw_Exception( "N missing in Params", Here() ); + } // perform checks ATLAS_ASSERT( N % 2 == 0 ); @@ -55,7 +57,9 @@ GaussianSpacing::GaussianSpacing( const eckit::Parametrisation& params ) { start = interval[0]; end = interval[1]; } - if ( start != 90. && end != -90. ) { ATLAS_NOTIMPLEMENTED; } + if ( start != 90. && end != -90. ) { + ATLAS_NOTIMPLEMENTED; + } min_ = std::min( start, end ); max_ = std::max( start, end ); diff --git a/src/atlas/grid/detail/spacing/LinearSpacing.cc b/src/atlas/grid/detail/spacing/LinearSpacing.cc index 54641fb2e..67c33e1c5 100644 --- a/src/atlas/grid/detail/spacing/LinearSpacing.cc +++ b/src/atlas/grid/detail/spacing/LinearSpacing.cc @@ -62,10 +62,12 @@ LinearSpacing::Params::Params( const eckit::Parametrisation& params ) { } length = end - start; - if ( endpoint && N > 1 ) + if ( endpoint && N > 1 ) { step = length / double( N - 1 ); - else + } + else { step = length / double( N ); + } } LinearSpacing::LinearSpacing( const eckit::Parametrisation& params ) { @@ -94,10 +96,12 @@ void LinearSpacing::setup( double start, double end, long N, bool endpoint ) { x_.resize( N ); double step; - if ( endpoint && N > 1 ) + if ( endpoint && N > 1 ) { step = ( end - start ) / double( N - 1 ); - else + } + else { step = ( end - start ) / double( N ); + } for ( long i = 0; i < N; ++i ) { x_[i] = start + i * step; @@ -113,10 +117,12 @@ void LinearSpacing::setup( double start, double end, long N, bool endpoint ) { } double LinearSpacing::step() const { - if ( size() > 1 ) + if ( size() > 1 ) { return x_[1] - x_[0]; - else + } + else { return 0.; + } } bool LinearSpacing::endpoint() const { diff --git a/src/atlas/grid/detail/spacing/Spacing.cc b/src/atlas/grid/detail/spacing/Spacing.cc index 5ae41fc6f..72b1a1ae6 100644 --- a/src/atlas/grid/detail/spacing/Spacing.cc +++ b/src/atlas/grid/detail/spacing/Spacing.cc @@ -20,7 +20,9 @@ namespace spacing { const Spacing* Spacing::create( const eckit::Parametrisation& params ) { std::string spacingType; - if ( not params.get( "type", spacingType ) ) { throw_Exception( "type missing in configuration", Here() ); } + if ( not params.get( "type", spacingType ) ) { + throw_Exception( "type missing in configuration", Here() ); + } return SpacingFactory::build( spacingType, params ); } diff --git a/src/atlas/grid/detail/spacing/gaussian/Latitudes.cc b/src/atlas/grid/detail/spacing/gaussian/Latitudes.cc index 145d60e21..a7d670d18 100644 --- a/src/atlas/grid/detail/spacing/gaussian/Latitudes.cc +++ b/src/atlas/grid/detail/spacing/gaussian/Latitudes.cc @@ -113,7 +113,9 @@ void legpol_newton_iteration( int kn, const double pfn[], double px, double& pxn zdlx = px; zdlk = 0.; - if ( kodd == 0 ) zdlk = 0.5 * pfn[0]; + if ( kodd == 0 ) { + zdlk = 0.5 * pfn[0]; + } zdlxn = 0.; zdlldn = 0.; ik = 1; @@ -214,7 +216,9 @@ void legpol_quadrature( const int kn, const double pfn[], double& pl, double& pw legpol_weight( kn, pfn, zx, zw ); break; } - if ( std::abs( pmod ) <= zeps * 1000. ) iflag = 1; + if ( std::abs( pmod ) <= zeps * 1000. ) { + iflag = 1; + } } if ( iflag != 1 ) { std::stringstream s; diff --git a/src/atlas/grid/detail/spacing/gaussian/N.cc b/src/atlas/grid/detail/spacing/gaussian/N.cc index db147506a..669ebaf9d 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N.cc @@ -28,8 +28,9 @@ return "GaussianLatitudes"; void GaussianLatitudes::assign( double lats[], const size_t size ) const { ATLAS_ASSERT( size >= lats_.size() ); - for ( size_t jlat = 0; jlat < lats_.size(); ++jlat ) + for ( size_t jlat = 0; jlat < lats_.size(); ++jlat ) { lats[jlat] = lats_[jlat]; + } } void GaussianLatitudes::assign( std::vector& lats ) const { diff --git a/src/atlas/interpolation/Interpolation.h b/src/atlas/interpolation/Interpolation.h index a5aae026b..dafa99d4b 100644 --- a/src/atlas/interpolation/Interpolation.h +++ b/src/atlas/interpolation/Interpolation.h @@ -37,16 +37,16 @@ class Interpolation : public util::ObjectHandle { Interpolation() = default; // Setup Interpolation from source to target function space - Interpolation( const Config&, const FunctionSpace& source, const FunctionSpace& target ); + Interpolation( const Config&, const FunctionSpace& source, const FunctionSpace& target ) noexcept( false ); // Setup Interpolation from source to coordinates given in a field with multiple components - Interpolation( const Config&, const FunctionSpace& source, const Field& target ); + Interpolation( const Config&, const FunctionSpace& source, const Field& target ) noexcept( false ); // Setup Interpolation from source to coordinates given by separate fields for each component - Interpolation( const Config&, const FunctionSpace& source, const FieldSet& target ); + Interpolation( const Config&, const FunctionSpace& source, const FieldSet& target ) noexcept( false ); // Setup Interpolation from source grid to target grid - Interpolation( const Config&, const Grid& source, const Grid& target ); + Interpolation( const Config&, const Grid& source, const Grid& target ) noexcept( false ); void execute( const FieldSet& source, FieldSet& target ) const; diff --git a/src/atlas/interpolation/element/Quad3D.cc b/src/atlas/interpolation/element/Quad3D.cc index e946cb41e..1f9140fee 100644 --- a/src/atlas/interpolation/element/Quad3D.cc +++ b/src/atlas/interpolation/element/Quad3D.cc @@ -27,7 +27,9 @@ method::Intersect Quad3D::intersects( const method::Ray& r, double edgeEpsilon, Triag3D T013( v00, v10, v01 ); isect = T013.intersects( r, edgeEpsilon, epsilon ); - if ( isect ) return isect; + if ( isect ) { + return isect; + } Triag3D T231( v11, v01, v10 ); isect = T231.intersects( r, edgeEpsilon, epsilon ); diff --git a/src/atlas/interpolation/element/Quad3D.h b/src/atlas/interpolation/element/Quad3D.h index abd304914..6a5a1cb06 100644 --- a/src/atlas/interpolation/element/Quad3D.h +++ b/src/atlas/interpolation/element/Quad3D.h @@ -53,10 +53,14 @@ class Quad3D { } const Vector3D& p( int i ) { - if ( i == 0 ) return v00; - if ( i == 1 ) return v10; - if ( i == 2 ) return v11; - if ( i == 3 ) return v01; + if ( i == 0 ) + return v00; + if ( i == 1 ) + return v10; + if ( i == 2 ) + return v11; + if ( i == 3 ) + return v01; throw_OutOfRange( "Quad3D::p(i)", i, 4, Here() ); } diff --git a/src/atlas/interpolation/element/Triag3D.cc b/src/atlas/interpolation/element/Triag3D.cc index 2b90b01cf..ba12abaf8 100644 --- a/src/atlas/interpolation/element/Triag3D.cc +++ b/src/atlas/interpolation/element/Triag3D.cc @@ -30,7 +30,9 @@ method::Intersect Triag3D::intersects( const method::Ray& r, double edgeEpsilon, // ray is parallel to triangle (check?) const double det = edge1.dot( pvec ); - if ( fabs( det ) < epsilon ) { return isect.fail(); } + if ( fabs( det ) < epsilon ) { + return isect.fail(); + } const double invDet = 1. / det; @@ -45,7 +47,9 @@ method::Intersect Triag3D::intersects( const method::Ray& r, double edgeEpsilon, if ( w < 0 ) { // check if far outside of triangle, in respect to diagonal edge - if ( w < -edgeEpsilon ) { return isect.fail(); } + if ( w < -edgeEpsilon ) { + return isect.fail(); + } // snap to diagonal edge // Note: we may still be to the left of vertical edge or below the @@ -62,7 +66,9 @@ method::Intersect Triag3D::intersects( const method::Ray& r, double edgeEpsilon, // snap to lower/upper left corners isect.u = 0; - if ( isect.v < 0 ) { isect.v = 0; } + if ( isect.v < 0 ) { + isect.v = 0; + } else if ( isect.v > 1 ) { isect.v = 1; } @@ -76,7 +82,9 @@ method::Intersect Triag3D::intersects( const method::Ray& r, double edgeEpsilon, // snap to lower left/right corners isect.v = 0; - if ( isect.u < 0 ) { isect.u = 0; } + if ( isect.u < 0 ) { + isect.u = 0; + } else if ( isect.u > 1 ) { isect.u = 1; } diff --git a/src/atlas/interpolation/element/Triag3D.h b/src/atlas/interpolation/element/Triag3D.h index fa4c6769c..051a7c837 100644 --- a/src/atlas/interpolation/element/Triag3D.h +++ b/src/atlas/interpolation/element/Triag3D.h @@ -54,9 +54,12 @@ class Triag3D { } const Vector3D& p( int i ) { - if ( i == 0 ) return v0; - if ( i == 1 ) return v1; - if ( i == 2 ) return v2; + if ( i == 0 ) + return v0; + if ( i == 1 ) + return v1; + if ( i == 2 ) + return v2; throw_OutOfRange( "Triag3D::p(i)", i, 3, Here() ); } diff --git a/src/atlas/interpolation/method/Method.cc b/src/atlas/interpolation/method/Method.cc index abccdf9fc..d11709661 100644 --- a/src/atlas/interpolation/method/Method.cc +++ b/src/atlas/interpolation/method/Method.cc @@ -43,9 +43,15 @@ void Method::check_compatibility( const Field& src, const Field& tgt ) const { 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 ); } + 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 ); + } } template @@ -60,8 +66,8 @@ void Method::interpolate_field_rank1( const Field& src, Field& tgt ) const { throw_NotImplemented( "Only double precision interpolation is currently implemented with eckit backend", Here() ); } - ATLAS_ASSERT( src.array().contiguous() ); - ATLAS_ASSERT( tgt.array().contiguous() ); + ATLAS_ASSERT( src.contiguous() ); + ATLAS_ASSERT( tgt.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 ) ); @@ -101,8 +107,9 @@ void Method::interpolate_field_rank2( const Field& src, Field& tgt ) const { 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 k = 0; k < Nk; ++k ) { v_tgt( r, k ) += w * v_src( n, k ); + } } } } @@ -130,9 +137,11 @@ void Method::interpolate_field_rank3( const Field& src, Field& tgt ) const { 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 ) + 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 ); + } + } } } } @@ -169,8 +178,12 @@ void Method::execute( const Field& src, Field& tgt ) const { ATLAS_TRACE( "atlas::interpolation::method::Method::execute()" ); - if ( src.datatype().kind() == array::DataType::KIND_REAL64 ) { interpolate_field( src, tgt ); } - if ( src.datatype().kind() == array::DataType::KIND_REAL32 ) { interpolate_field( src, tgt ); } + if ( src.datatype().kind() == array::DataType::KIND_REAL64 ) { + interpolate_field( src, tgt ); + } + if ( src.datatype().kind() == array::DataType::KIND_REAL32 ) { + interpolate_field( src, tgt ); + } tgt.set_dirty(); } @@ -196,7 +209,9 @@ void Method::haloExchange( const FieldSet& fields ) const { } } void Method::haloExchange( const Field& field ) const { - if ( field.dirty() ) source().haloExchange( field ); + if ( field.dirty() ) { + source().haloExchange( field ); + } } } // namespace interpolation diff --git a/src/atlas/interpolation/method/PointSet.cc b/src/atlas/interpolation/method/PointSet.cc index 22b814719..4076d86b7 100644 --- a/src/atlas/interpolation/method/PointSet.cc +++ b/src/atlas/interpolation/method/PointSet.cc @@ -48,16 +48,18 @@ PointSet::PointSet( Mesh& mesh ) { std::vector pidx; pidx.reserve( npts_ ); - for ( size_t ip = 0; ip < npts_; ++ip ) + for ( size_t ip = 0; ip < npts_; ++ip ) { pidx.push_back( PointIndex3::Value( PointIndex3::Point( coords( ip, 0 ), coords( ip, 1 ), coords( ip, 2 ) ), ip ) ); + } tree_->build( pidx.begin(), pidx.end() ); } else { - for ( size_t ip = 0; ip < npts_; ++ip ) + for ( size_t ip = 0; ip < npts_; ++ip ) { tree_->insert( PointIndex3::Value( PointIndex3::Point( coords( ip, 0 ), coords( ip, 1 ), coords( ip, 2 ) ), ip ) ); + } } } @@ -77,8 +79,9 @@ size_t PointSet::search_unique( const Point& p, size_t idx, uint32_t n ) { // std::cout << " EQUAL !!" << std::endl; equals.push_back( nidx ); } - else + else { break; + } } if ( equals.size() == nearest.size() ) /* need to increase the search to find @@ -90,11 +93,13 @@ size_t PointSet::search_unique( const Point& p, size_t idx, uint32_t n ) { { size_t ret = idx; /* if nothing found return same idx */ - if ( equals.size() >= 1 ) /* if an equal point was found return the first one */ + if ( equals.size() >= 1 ) { /* if an equal point was found return the first one */ ret = equals[0]; + } - for ( size_t n = 1; n < equals.size(); ++n ) + for ( size_t n = 1; n < equals.size(); ++n ) { duplicates_[equals[n]] = ret; + } return ret; } diff --git a/src/atlas/interpolation/method/fe/FiniteElement.cc b/src/atlas/interpolation/method/fe/FiniteElement.cc index 4f83f8176..95867759f 100644 --- a/src/atlas/interpolation/method/fe/FiniteElement.cc +++ b/src/atlas/interpolation/method/fe/FiniteElement.cc @@ -56,7 +56,9 @@ static const double parametricEpsilon = 1e-15; void FiniteElement::setup( const Grid& source, const Grid& target ) { - if ( mpi::comm().size() > 1 ) { ATLAS_NOTIMPLEMENTED; } + if ( mpi::comm().size() > 1 ) { + ATLAS_NOTIMPLEMENTED; + } auto functionspace = []( const Grid& grid ) { Mesh mesh; if ( StructuredGrid{grid} ) { @@ -120,7 +122,9 @@ struct Stencil { void FiniteElement::print( std::ostream& out ) const { functionspace::NodeColumns src( source_ ); functionspace::NodeColumns tgt( target_ ); - if ( not tgt ) ATLAS_NOTIMPLEMENTED; + if ( not tgt ) { + ATLAS_NOTIMPLEMENTED; + } auto gidx_src = array::make_view( src.nodes().global_index() ); ATLAS_ASSERT( tgt.nodes().size() == idx_t( matrix_.rows() ) ); @@ -236,7 +240,9 @@ void FiniteElement::setup( const FunctionSpace& source ) { eckit::ProgressTimer progress( "Computing interpolation weights", out_npts, "point", double( 5 ), Log::debug() ); for ( idx_t ip = 0; ip < out_npts; ++ip, ++progress ) { - if ( out_ghosts( ip ) ) { continue; } + if ( out_ghosts( ip ) ) { + continue; + } PointXYZ p{( *ocoords_ )( ip, 0 ), ( *ocoords_ )( ip, 1 ), ( *ocoords_ )( ip, 2 )}; // lookup point @@ -435,9 +441,13 @@ Method::Triplets FiniteElement::projectPointToElements( size_t ip, const ElemInd w[2] = is.v; if ( on_triag_edge() ) { - if ( on_single_point() ) { triplets.emplace_back( 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(); } + 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.emplace_back( ip, idx[edge.idx[i]], w[edge.idx[i]] ); @@ -476,9 +486,13 @@ 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.emplace_back( 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(); } + 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.emplace_back( ip, idx[edge.idx[i]], w[edge.idx[i]] ); @@ -496,7 +510,9 @@ Method::Triplets FiniteElement::projectPointToElements( size_t ip, const ElemInd } // loop over nearest elements - if ( !triplets.empty() ) { normalise( triplets ); } + if ( !triplets.empty() ) { + normalise( triplets ); + } return triplets; } diff --git a/src/atlas/interpolation/method/knn/KNearestNeighbours.cc b/src/atlas/interpolation/method/knn/KNearestNeighbours.cc index b6d2c3dbb..a2450308c 100644 --- a/src/atlas/interpolation/method/knn/KNearestNeighbours.cc +++ b/src/atlas/interpolation/method/knn/KNearestNeighbours.cc @@ -43,7 +43,9 @@ KNearestNeighbours::KNearestNeighbours( const Method::Config& config ) : KNeares } void KNearestNeighbours::setup( const Grid& source, const Grid& target ) { - if ( mpi::comm().size() > 1 ) { ATLAS_NOTIMPLEMENTED; } + if ( mpi::comm().size() > 1 ) { + ATLAS_NOTIMPLEMENTED; + } auto functionspace = []( const Grid& grid ) -> FunctionSpace { Mesh mesh; if ( StructuredGrid( grid ) ) { diff --git a/src/atlas/interpolation/method/knn/NearestNeighbour.cc b/src/atlas/interpolation/method/knn/NearestNeighbour.cc index 6beae9844..b2dd2d993 100644 --- a/src/atlas/interpolation/method/knn/NearestNeighbour.cc +++ b/src/atlas/interpolation/method/knn/NearestNeighbour.cc @@ -34,7 +34,9 @@ MethodBuilder __builder( "nearest-neighbour" ); } // namespace void NearestNeighbour::setup( const Grid& source, const Grid& target ) { - if ( mpi::comm().size() > 1 ) { ATLAS_NOTIMPLEMENTED; } + if ( mpi::comm().size() > 1 ) { + ATLAS_NOTIMPLEMENTED; + } auto functionspace = []( const Grid& grid ) -> FunctionSpace { Mesh mesh; if ( StructuredGrid( grid ) ) { diff --git a/src/atlas/interpolation/method/structured/StructuredInterpolation2D.tcc b/src/atlas/interpolation/method/structured/StructuredInterpolation2D.tcc index 457f2bd83..b43aeb6b8 100644 --- a/src/atlas/interpolation/method/structured/StructuredInterpolation2D.tcc +++ b/src/atlas/interpolation/method/structured/StructuredInterpolation2D.tcc @@ -86,7 +86,7 @@ void StructuredInterpolation2D::setup( const FunctionSpace& source, cons target_ghost_ = tgt.ghost(); } else { - ATLAS_NOTIMPLEMENTED; + throw_NotImplemented("Only interpolation to functionspaces NodeColumns, PointCloud or StructuredColumns are implemented", Here()); } setup( source ); diff --git a/src/atlas/interpolation/method/structured/kernels/Cubic3DKernel.h b/src/atlas/interpolation/method/structured/kernels/Cubic3DKernel.h index bb60058ad..a00e4d2fe 100644 --- a/src/atlas/interpolation/method/structured/kernels/Cubic3DKernel.h +++ b/src/atlas/interpolation/method/structured/kernels/Cubic3DKernel.h @@ -112,7 +112,9 @@ class Cubic3DKernel { } } - if ( limiter_ ) { limit_scalar( output, index, stencil, input ); } + if ( limiter_ ) { + limit_scalar( output, index, stencil, input ); + } return output; } @@ -129,7 +131,9 @@ class Cubic3DKernel { // x x x x idx_t k = stencil.k_interval(); idx_t k1, k2; - if ( k < 0 ) { k1 = k2 = 0; } + if ( k < 0 ) { + k1 = k2 = 0; + } else if ( k > 2 ) { k1 = k2 = 3; } @@ -153,7 +157,9 @@ class Cubic3DKernel { minval = std::min( minval, f2 ); } } - if ( output < minval ) { output = minval; } + if ( output < minval ) { + output = minval; + } else if ( output > maxval ) { output = maxval; } @@ -216,7 +222,9 @@ class Cubic3DKernel { } } - if ( limiter_ ) { limit_vars( index, stencil, input, output, nvar ); } + if ( limiter_ ) { + limit_vars( index, stencil, input, output, nvar ); + } } template @@ -234,7 +242,9 @@ class Cubic3DKernel { const idx_t k = stencil.k_interval(); idx_t k1, k2; - if ( k < 0 ) { k1 = k2 = stencil.k( 0 ); } + if ( k < 0 ) { + k1 = k2 = stencil.k( 0 ); + } else if ( k > 2 ) { k1 = k2 = stencil.k( 3 ); } @@ -260,7 +270,9 @@ class Cubic3DKernel { minval = std::min( minval, f2 ); } } - if ( limited < minval ) { limited = minval; } + if ( limited < minval ) { + limited = minval; + } else if ( limited > maxval ) { limited = maxval; } diff --git a/src/atlas/interpolation/method/structured/kernels/CubicHorizontalKernel.h b/src/atlas/interpolation/method/structured/kernels/CubicHorizontalKernel.h index 270508517..ff82d1128 100644 --- a/src/atlas/interpolation/method/structured/kernels/CubicHorizontalKernel.h +++ b/src/atlas/interpolation/method/structured/kernels/CubicHorizontalKernel.h @@ -140,7 +140,9 @@ class CubicHorizontalKernel { } } - if ( limiter_ ) { limit( output, index, input ); } + if ( limiter_ ) { + limit( output, index, input ); + } return output; } @@ -164,7 +166,9 @@ class CubicHorizontalKernel { minval = std::min( minval, val ); } } - if ( output < minval ) { output = minval; } + if ( output < minval ) { + output = minval; + } else if ( output > maxval ) { output = maxval; } @@ -189,7 +193,9 @@ class CubicHorizontalKernel { } } - if ( limiter_ ) { limit( index, input, output, r ); } + if ( limiter_ ) { + limit( index, input, output, r ); + } } template @@ -212,7 +218,9 @@ class CubicHorizontalKernel { minval = std::min( minval, val ); } } - if ( output( r ) < minval ) { output( r ) = minval; } + if ( output( r ) < minval ) { + output( r ) = minval; + } else if ( output( r ) > maxval ) { output( r ) = maxval; } @@ -242,7 +250,9 @@ class CubicHorizontalKernel { } } - if ( limiter_ ) { limit( index, input, output, r ); } + if ( limiter_ ) { + limit( index, input, output, r ); + } } template @@ -266,7 +276,9 @@ class CubicHorizontalKernel { minval = std::min( minval, val ); } } - if ( output( r, k ) < minval ) { output( r, k ) = minval; } + if ( output( r, k ) < minval ) { + output( r, k ) = minval; + } else if ( output( r, k ) > maxval ) { output( r, k ) = maxval; } diff --git a/src/atlas/interpolation/method/structured/kernels/CubicVerticalKernel.h b/src/atlas/interpolation/method/structured/kernels/CubicVerticalKernel.h index 291f9d153..081d9d21b 100644 --- a/src/atlas/interpolation/method/structured/kernels/CubicVerticalKernel.h +++ b/src/atlas/interpolation/method/structured/kernels/CubicVerticalKernel.h @@ -149,7 +149,9 @@ class CubicVerticalKernel { if ( limiter_ ) { idx_t k = stencil.k_interval(); idx_t k1, k2; - if ( k < 0 ) { k1 = k2 = 0; } + if ( k < 0 ) { + k1 = k2 = 0; + } else if ( k > 2 ) { k1 = k2 = 3; } diff --git a/src/atlas/interpolation/method/structured/kernels/QuasiCubic3DKernel.h b/src/atlas/interpolation/method/structured/kernels/QuasiCubic3DKernel.h index 140e93a36..ba65f9fd9 100644 --- a/src/atlas/interpolation/method/structured/kernels/QuasiCubic3DKernel.h +++ b/src/atlas/interpolation/method/structured/kernels/QuasiCubic3DKernel.h @@ -198,7 +198,9 @@ class QuasiCubic3DKernel { } - if ( limiter_ ) { limit_scalar( output, index, stencil, input ); } + if ( limiter_ ) { + limit_scalar( output, index, stencil, input ); + } return output; } @@ -215,7 +217,9 @@ class QuasiCubic3DKernel { // x x x x idx_t k = stencil.k_interval(); idx_t k1, k2; - if ( k < 0 ) { k1 = k2 = 0; } + if ( k < 0 ) { + k1 = k2 = 0; + } else if ( k > 2 ) { k1 = k2 = 3; } @@ -239,7 +243,9 @@ class QuasiCubic3DKernel { minval = std::min( minval, f2 ); } } - if ( output < minval ) { output = minval; } + if ( output < minval ) { + output = minval; + } else if ( output > maxval ) { output = maxval; } @@ -350,7 +356,9 @@ class QuasiCubic3DKernel { } - if ( limiter_ ) { limit_vars( index, stencil, input, output, nvar ); } + if ( limiter_ ) { + limit_vars( index, stencil, input, output, nvar ); + } } template @@ -368,7 +376,9 @@ class QuasiCubic3DKernel { const idx_t k = stencil.k_interval(); idx_t k1, k2; - if ( k < 0 ) { k1 = k2 = stencil.k( 0 ); } + if ( k < 0 ) { + k1 = k2 = stencil.k( 0 ); + } else if ( k > 2 ) { k1 = k2 = stencil.k( 3 ); } @@ -394,7 +404,9 @@ class QuasiCubic3DKernel { minval = std::min( minval, f2 ); } } - if ( limited < minval ) { limited = minval; } + if ( limited < minval ) { + limited = minval; + } else if ( limited > maxval ) { limited = maxval; } diff --git a/src/atlas/interpolation/method/structured/kernels/QuasiCubicHorizontalKernel.h b/src/atlas/interpolation/method/structured/kernels/QuasiCubicHorizontalKernel.h index d4b081a16..6ec8644e6 100644 --- a/src/atlas/interpolation/method/structured/kernels/QuasiCubicHorizontalKernel.h +++ b/src/atlas/interpolation/method/structured/kernels/QuasiCubicHorizontalKernel.h @@ -166,7 +166,9 @@ class QuasiCubicHorizontalKernel { } } - if ( limiter_ ) { limit( output, index, input ); } + if ( limiter_ ) { + limit( output, index, input ); + } return output; } @@ -190,7 +192,9 @@ class QuasiCubicHorizontalKernel { minval = std::min( minval, val ); } } - if ( output < minval ) { output = minval; } + if ( output < minval ) { + output = minval; + } else if ( output > maxval ) { output = maxval; } @@ -227,7 +231,9 @@ class QuasiCubicHorizontalKernel { } } - if ( limiter_ ) { limit( index, input, output, r ); } + if ( limiter_ ) { + limit( index, input, output, r ); + } } template @@ -250,7 +256,9 @@ class QuasiCubicHorizontalKernel { minval = std::min( minval, val ); } } - if ( output( r ) < minval ) { output( r ) = minval; } + if ( output( r ) < minval ) { + output( r ) = minval; + } else if ( output( r ) > maxval ) { output( r ) = maxval; } @@ -293,7 +301,9 @@ class QuasiCubicHorizontalKernel { } } - if ( limiter_ ) { limit( index, input, output, r ); } + if ( limiter_ ) { + limit( index, input, output, r ); + } } template @@ -317,7 +327,9 @@ class QuasiCubicHorizontalKernel { minval = std::min( minval, val ); } } - if ( output( r, k ) < minval ) { output( r, k ) = minval; } + if ( output( r, k ) < minval ) { + output( r, k ) = minval; + } else if ( output( r, k ) > maxval ) { output( r, k ) = maxval; } diff --git a/src/atlas/library/Library.cc b/src/atlas/library/Library.cc index 5d705eec9..3fd46f702 100644 --- a/src/atlas/library/Library.cc +++ b/src/atlas/library/Library.cc @@ -50,17 +50,23 @@ std::string str( const eckit::system::Library& lib ) { std::string gitsha1 = lib.gitsha1(); std::stringstream ss; ss << lib.name() << " version (" << lib.version() << "),"; - if ( lib.gitsha1() != "not available" ) { ss << " git-sha1 " << lib.gitsha1( 7 ); } + if ( lib.gitsha1() != "not available" ) { + ss << " git-sha1 " << lib.gitsha1( 7 ); + } return ss.str(); } bool getEnv( const std::string& env, bool default_value ) { - if (::getenv( env.c_str() ) ) { return eckit::Translator()(::getenv( env.c_str() ) ); } + if ( ::getenv( env.c_str() ) ) { + return eckit::Translator()( ::getenv( env.c_str() ) ); + } return default_value; } int getEnv( const std::string& env, int default_value ) { - if (::getenv( env.c_str() ) ) { return eckit::Translator()(::getenv( env.c_str() ) ); } + if ( ::getenv( env.c_str() ) ) { + return eckit::Translator()( ::getenv( env.c_str() ) ); + } return default_value; } @@ -124,9 +130,15 @@ void Library::initialise( const eckit::Parametrisation& config ) { config.get( "trace.report", trace_report_ ); } - if ( not debug_ ) debug_channel_.reset(); - if ( not trace_ ) trace_channel_.reset(); - if ( not info_ ) info_channel_.reset(); + if ( not debug_ ) { + debug_channel_.reset(); + } + if ( not trace_ ) { + trace_channel_.reset(); + } + if ( not info_ ) { + info_channel_.reset(); + } // Summary if ( getEnv( "ATLAS_LOG_RANK", 0 ) == int( mpi::comm().rank() ) ) { @@ -156,7 +168,9 @@ void Library::initialise() { } void Library::finalise() { - if ( ATLAS_HAVE_TRACE && trace_report_ ) { Log::info() << atlas::Trace::report() << std::endl; } + 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; @@ -174,7 +188,9 @@ void Library::finalise() { } eckit::Channel& Library::infoChannel() const { - if ( info_ ) { return eckit::Log::info(); } + if ( info_ ) { + return eckit::Log::info(); + } else if ( !info_channel_ ) { info_channel_.reset( new eckit::Channel() ); } @@ -182,7 +198,9 @@ eckit::Channel& Library::infoChannel() const { } eckit::Channel& Library::traceChannel() const { - if ( trace_channel_ ) return *trace_channel_; + if ( trace_channel_ ) { + return *trace_channel_; + } if ( trace_ ) { trace_channel_.reset( new eckit::Channel( new eckit::PrefixTarget( "ATLAS_TRACE", new eckit::OStreamTarget( eckit::Log::info() ) ) ) ); @@ -194,8 +212,12 @@ eckit::Channel& Library::traceChannel() const { } eckit::Channel& Library::debugChannel() const { - if ( debug_channel_ ) { return *debug_channel_; } - if ( debug_ ) { debug_channel_.reset( new eckit::Channel( new eckit::PrefixTarget( "ATLAS_DEBUG" ) ) ); } + if ( debug_channel_ ) { + return *debug_channel_; + } + if ( debug_ ) { + debug_channel_.reset( new eckit::Channel( new eckit::PrefixTarget( "ATLAS_DEBUG" ) ) ); + } else { debug_channel_.reset( new eckit::Channel() ); } @@ -267,8 +289,12 @@ void Library::Information::print( std::ostream& out ) const { out << " Dependencies: " << "\n"; - if ( Library::exists( "eckit" ) ) { out << " " << str( Library::lookup( "eckit" ) ) << '\n'; } - if ( Library::exists( "fckit" ) ) { out << " " << str( Library::lookup( "fckit" ) ) << '\n'; } + if ( Library::exists( "eckit" ) ) { + out << " " << str( Library::lookup( "eckit" ) ) << '\n'; + } + if ( Library::exists( "fckit" ) ) { + out << " " << str( Library::lookup( "fckit" ) ) << '\n'; + } #if ATLAS_HAVE_TRANS out << " transi version (" << transi_version() << "), " diff --git a/src/atlas/mesh/Connectivity.cc b/src/atlas/mesh/Connectivity.cc index 983527fd6..b342eeda3 100644 --- a/src/atlas/mesh/Connectivity.cc +++ b/src/atlas/mesh/Connectivity.cc @@ -11,6 +11,9 @@ #include #include +#include "eckit/io/Buffer.h" +#include "eckit/serialisation/Stream.h" + #include "atlas/array.h" #include "atlas/array/DataType.h" #include "atlas/array/MakeView.h" @@ -19,6 +22,8 @@ #include "atlas/mesh/Connectivity.h" #include "atlas/runtime/Exception.h" +#include "atlas/runtime/Log.h" + #if ATLAS_HAVE_FORTRAN #define FORTRAN_BASE 1 #define TO_FORTRAN +1 @@ -90,6 +95,10 @@ IrregularConnectivityImpl::IrregularConnectivityImpl( const IrregularConnectivit mincols_( other.mincols_ ), ctxt_( nullptr ) {} +IrregularConnectivityImpl::IrregularConnectivityImpl( eckit::Stream& s ) { + decode_( s ); +} + //------------------------------------------------------------------------------------------------------ IrregularConnectivityImpl::~IrregularConnectivityImpl() { @@ -124,13 +133,17 @@ void IrregularConnectivityImpl::clear() { //------------------------------------------------------------------------------------------------------ void IrregularConnectivityImpl::on_delete() { - if ( ctxt_ && callback_delete_ ) callback_delete_( ctxt_ ); + if ( ctxt_ && callback_delete_ ) { + callback_delete_( ctxt_ ); + } } //------------------------------------------------------------------------------------------------------ void IrregularConnectivityImpl::on_update() { - if ( ctxt_ && callback_update_ ) callback_update_( ctxt_ ); + if ( ctxt_ && callback_update_ ) { + callback_update_( ctxt_ ); + } } void IrregularConnectivityImpl::resize( idx_t old_size, idx_t new_size, bool initialize, const idx_t values[], @@ -155,7 +168,9 @@ void IrregularConnectivityImpl::add( idx_t rows, idx_t cols, const idx_t values[ ATLAS_ASSERT( owns_, "Connectivity must be owned to be resized directly" ); idx_t old_size = values_.size(); - if ( rows_ == 0 ) old_size = 0; + if ( rows_ == 0 ) { + old_size = 0; + } idx_t new_size = old_size + rows * cols; idx_t new_rows = rows_ + rows; @@ -164,7 +179,7 @@ void IrregularConnectivityImpl::add( idx_t rows, idx_t cols, const idx_t values[ // ATLAS_ASSERT( displs_] != nullptr ); // ATLAS_ASSERT( data_[_counts_] != nullptr ); displs_.resize( new_rows + 1 ); - counts_.resize( new_rows + 1 ); + counts_.resize( new_rows ); for ( idx_t j = 0; rows_ < new_rows; ++rows_, ++j ) { displs_[rows_ + 1] = displs_[rows_] + cols; @@ -197,11 +212,12 @@ 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 ) + for ( idx_t j = 0; j < rows; ++j ) { new_size += cols[j]; + } idx_t new_rows = rows_ + rows; displs_.resize( new_rows + 1 ); - counts_.resize( new_rows + 1 ); + counts_.resize( new_rows ); for ( idx_t j = 0; rows_ < new_rows; ++rows_, ++j ) { displs_[rows_ + 1] = displs_[rows_] + cols[j]; @@ -221,7 +237,9 @@ 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; + if ( rows_ == 0 ) { + old_size = 0; + } idx_t new_size = old_size + rows * cols; idx_t new_rows = rows_ + rows; @@ -230,7 +248,7 @@ void IrregularConnectivityImpl::add( idx_t rows, idx_t cols ) { // ATLAS_ASSERT( data_[_displs_] != nullptr ); // ATLAS_ASSERT( data_[_counts_] != nullptr ); displs_.resize( new_rows + 1 ); - counts_.resize( new_rows + 1 ); + counts_.resize( new_rows ); for ( idx_t j = 0; rows_ < new_rows; ++rows_, ++j ) { displs_[rows_ + 1] = displs_[rows_] + cols; @@ -318,8 +336,9 @@ void IrregularConnectivityImpl::insert( idx_t position, idx_t rows, const idx_t } idx_t insert_size( 0 ); - for ( idx_t j = 0; j < rows; ++j ) + for ( idx_t j = 0; j < rows; ++j ) { insert_size += cols[j]; + } values_.insert( position_displs, insert_size ); @@ -343,6 +362,57 @@ void IrregularConnectivityImpl::dump( std::ostream& os ) const { //TODO dump } +eckit::Stream& operator>>( eckit::Stream& s, array::SVector& x ) { + size_t size; + s >> size; + eckit::Buffer buffer( size * sizeof( idx_t ) ); + s >> buffer; + idx_t* data = static_cast( buffer.data() ); + idx_t N = static_cast( size ); + x.resize( N ); + for ( idx_t i = 0; i < N; ++i ) { + x( i ) = data[i]; + } + return s; +} + +eckit::Stream& operator<<( eckit::Stream& s, const array::SVector& x ) { + size_t size = x.size(); + s << size; + eckit::Buffer buffer( reinterpret_cast( x.data() ), size * sizeof( idx_t ) ); + s << buffer; + return s; +} + +void IrregularConnectivityImpl::encode_( eckit::Stream& s ) const { + s << name(); + s << values_; + s << displs_; + s << counts_; + s << missing_value_; + s << rows_; + s << maxcols_; + s << mincols_; +} + + +void IrregularConnectivityImpl::decode_( eckit::Stream& s ) { + std::string name; + s >> name; + s >> values_; + s >> displs_; + s >> counts_; + s >> missing_value_; + s >> rows_; + s >> maxcols_; + s >> mincols_; + if ( not name.empty() ) { + rename( name ); + } + ctxt_ = nullptr; + owns_ = true; +} + //------------------------------------------------------------------------------------------------------ /* } @@ -376,6 +446,10 @@ MultiBlockConnectivityImpl::MultiBlockConnectivityImpl( const std::string& name block_displs_( 0 ) = 0; } +MultiBlockConnectivityImpl::MultiBlockConnectivityImpl( eckit::Stream& s ) : IrregularConnectivityImpl( s ) { + decode_( s ); +} + //------------------------------------------------------------------------------------------------------ MultiBlockConnectivityImpl::~MultiBlockConnectivityImpl() {} @@ -475,8 +549,9 @@ void MultiBlockConnectivityImpl::insert( idx_t position, idx_t rows, idx_t cols, ATLAS_ASSERT( blk_idx >= 0l ); ATLAS_ASSERT( cols == block( blk_idx ).cols() ); - for ( idx_t jblk = blk_idx; jblk < blocks_; ++jblk ) + 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(); @@ -496,8 +571,9 @@ void MultiBlockConnectivityImpl::insert( idx_t position, idx_t rows, idx_t cols IrregularConnectivityImpl::insert( position, rows, cols ); - for ( idx_t jblk = blk_idx; jblk < blocks_; ++jblk ) + for ( idx_t jblk = blk_idx; jblk < blocks_; ++jblk ) { block_displs_[jblk + 1] += rows; + } rebuild_block_connectivity(); } @@ -525,15 +601,16 @@ void MultiBlockConnectivityImpl::insert( idx_t position, idx_t rows, const idx_t IrregularConnectivityImpl::insert( position, rows, cols ); - for ( idx_t jblk = blk_idx; jblk < blocks_; ++jblk ) + 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_, std::move( BlockConnectivityImpl() ) ); + block_.resize( blocks_, BlockConnectivityImpl() ); for ( idx_t b = 0; b < blocks_; ++b ) { block_[b].rebuild( block_displs_[b + 1] - block_displs_[b], // rows @@ -557,6 +634,23 @@ size_t MultiBlockConnectivityImpl::footprint() const { //------------------------------------------------------------------------------------------------------ +void MultiBlockConnectivityImpl::encode_( eckit::Stream& s ) const { + s << blocks_; + s << block_displs_; + s << block_cols_; +} + +//------------------------------------------------------------------------------------------------------ + +void MultiBlockConnectivityImpl::decode_( eckit::Stream& s ) { + s >> blocks_; + s >> block_displs_; + s >> block_cols_; + rebuild_block_connectivity(); +} + +//------------------------------------------------------------------------------------------------------ + BlockConnectivityImpl::BlockConnectivityImpl() : owns_( true ), values_( 0 ), @@ -601,6 +695,10 @@ BlockConnectivityImpl::BlockConnectivityImpl( idx_t rows, idx_t cols, idx_t valu } } +BlockConnectivityImpl::BlockConnectivityImpl( eckit::Stream& s ) { + decode( s ); +} + //------------------------------------------------------------------------------------------------------ BlockConnectivityImpl::BlockConnectivityImpl( idx_t rows, idx_t cols, idx_t values[], bool /*dummy*/ ) : @@ -648,11 +746,28 @@ void BlockConnectivityImpl::add( idx_t rows, idx_t cols, const idx_t values[], b } } +void BlockConnectivityImpl::encode( eckit::Stream& s ) const { + s << values_; + s << rows_; + s << cols_; + s << missing_value_; +} + +void BlockConnectivityImpl::decode( eckit::Stream& s ) { + owns_ = true; + s >> values_; + s >> rows_; + s >> cols_; + s >> missing_value_; +} + //------------------------------------------------------------------------------------------------------ size_t BlockConnectivityImpl::footprint() const { size_t size = sizeof( *this ); - if ( owns() ) size += values_.footprint(); + if ( owns() ) { + size += values_.footprint(); + } return size; } diff --git a/src/atlas/mesh/Connectivity.h b/src/atlas/mesh/Connectivity.h index 5e2be057a..56b3fce97 100644 --- a/src/atlas/mesh/Connectivity.h +++ b/src/atlas/mesh/Connectivity.h @@ -27,8 +27,6 @@ #include #include -#include "atlas/util/Object.h" - #include "atlas/array.h" #include "atlas/array/ArrayView.h" #include "atlas/array/DataType.h" @@ -37,6 +35,11 @@ #include "atlas/array/Vector.h" #include "atlas/array_fwd.h" #include "atlas/library/config.h" +#include "atlas/util/Object.h" + +namespace eckit { +class Stream; +} namespace atlas { namespace mesh { @@ -188,6 +191,9 @@ class IrregularConnectivityImpl { // it is compiled it for a GPU kernel IrregularConnectivityImpl( const IrregularConnectivityImpl& other ); + /// @brief Construct a mesh from a Stream (serialization) + explicit IrregularConnectivityImpl( eckit::Stream& ); + virtual ~IrregularConnectivityImpl(); //-- Accessors @@ -280,11 +286,30 @@ class IrregularConnectivityImpl { return os; } + virtual void encode( eckit::Stream& s ) const { encode_( s ); } + virtual void decode( eckit::Stream& s ) { decode_( s ); } + protected: bool owns() { return owns_; } const idx_t* displs() const { return displs_.data(); } const idx_t* counts() const { return counts_.data(); } + /// @brief Serialization to Stream + void encode_( eckit::Stream& ) const; + + /// @brief Serialization from Stream + void decode_( eckit::Stream& ); + + friend eckit::Stream& operator<<( eckit::Stream& s, const IrregularConnectivityImpl& x ) { + x.encode( s ); + return s; + } + + friend eckit::Stream& operator>>( eckit::Stream& s, IrregularConnectivityImpl& x ) { + x.decode( s ); + return s; + } + private: void on_delete(); void on_update(); @@ -356,6 +381,9 @@ class MultiBlockConnectivityImpl : public IrregularConnectivityImpl { /// Data is owned MultiBlockConnectivityImpl( const std::string& name = "" ); + /// @brief Construct a mesh from a Stream (serialization) + explicit MultiBlockConnectivityImpl( eckit::Stream& ); + virtual ~MultiBlockConnectivityImpl(); //-- Accessors @@ -417,6 +445,32 @@ class MultiBlockConnectivityImpl : public IrregularConnectivityImpl { virtual size_t footprint() const; + virtual void encode( eckit::Stream& s ) const { + IrregularConnectivityImpl::encode_( s ); + encode_( s ); + } + virtual void decode( eckit::Stream& s ) { + IrregularConnectivityImpl::decode_( s ); + decode_( s ); + } + +protected: + /// @brief Serialization to Stream + void encode_( eckit::Stream& ) const; + + /// @brief Serialization from Stream + void decode_( eckit::Stream& ); + + friend eckit::Stream& operator<<( eckit::Stream& s, const MultiBlockConnectivityImpl& x ) { + x.encode( s ); + return s; + } + + friend eckit::Stream& operator>>( eckit::Stream& s, MultiBlockConnectivityImpl& x ) { + x.decode( s ); + return s; + } + private: void rebuild_block_connectivity(); @@ -478,6 +532,9 @@ class BlockConnectivityImpl { BlockConnectivityImpl( BlockConnectivityImpl&& ) = default; BlockConnectivityImpl& operator=( const BlockConnectivityImpl& other ) = default; + /// @brief Construct a mesh from a Stream (serialization) + explicit BlockConnectivityImpl( eckit::Stream& ); + /// @brief Destructor ~BlockConnectivityImpl(); @@ -530,6 +587,23 @@ class BlockConnectivityImpl { bool owns() const { return owns_; } +protected: + /// @brief Serialization to Stream + void encode( eckit::Stream& ) const; + + /// @brief Serialization from Stream + void decode( eckit::Stream& ); + + friend eckit::Stream& operator<<( eckit::Stream& s, const BlockConnectivityImpl& x ) { + x.encode( s ); + return s; + } + + friend eckit::Stream& operator>>( eckit::Stream& s, BlockConnectivityImpl& x ) { + x.decode( s ); + return s; + } + private: bool owns_; array::SVector values_; diff --git a/src/atlas/mesh/Elements.cc b/src/atlas/mesh/Elements.cc index dcd309512..7306f0fd9 100644 --- a/src/atlas/mesh/Elements.cc +++ b/src/atlas/mesh/Elements.cc @@ -51,7 +51,9 @@ Elements::Elements( ElementType* element_type, idx_t nb_elements, const idx_t no } Elements::~Elements() { - if ( owns_ ) delete hybrid_elements_; + if ( owns_ ) { + delete hybrid_elements_; + } } const std::string& Elements::name() const { diff --git a/src/atlas/mesh/HybridElements.cc b/src/atlas/mesh/HybridElements.cc index 32393e029..1da6f5996 100644 --- a/src/atlas/mesh/HybridElements.cc +++ b/src/atlas/mesh/HybridElements.cc @@ -181,10 +181,12 @@ idx_t HybridElements::add( const ElementType* element_type, idx_t nb_elements, c element_types_.push_back( etype ); elements_.resize( element_types_.size() ); for ( idx_t t = 0; t < nb_types(); ++t ) { - if ( elements_[t] ) + if ( elements_[t] ) { elements_[t]->rebuild(); - else + } + else { elements_[t] = util::ObjectHandle( new Elements( *this, t ) ); + } } node_connectivity_->add( nb_elements, nb_nodes, connectivity, fortran_array ); @@ -241,8 +243,9 @@ idx_t HybridElements::elemtype_nb_edges( idx_t elem_idx ) const { 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 ( idx_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 ( idx_t t = 0; t < nb_types(); ++t ) { elements_[t]->rebuild(); } diff --git a/src/atlas/mesh/Nodes.cc b/src/atlas/mesh/Nodes.cc index 76d72f433..dff90b5aa 100644 --- a/src/atlas/mesh/Nodes.cc +++ b/src/atlas/mesh/Nodes.cc @@ -133,7 +133,9 @@ void Nodes::print( std::ostream& os ) const { os << "\t fields=\n"; for ( idx_t i = 0; i < nb_fields(); ++i ) { os << "\t\t" << field( i ); - if ( i != nb_fields() - 1 ) os << ","; + if ( i != nb_fields() - 1 ) { + os << ","; + } os << "\n"; } os << "]"; diff --git a/src/atlas/mesh/PartitionPolygon.cc b/src/atlas/mesh/PartitionPolygon.cc index b42b5447b..6f256383f 100644 --- a/src/atlas/mesh/PartitionPolygon.cc +++ b/src/atlas/mesh/PartitionPolygon.cc @@ -45,7 +45,9 @@ util::Polygon::edge_set_t compute_edges( const detail::MeshImpl& mesh, idx_t hal if ( patch( j ) == 0 && field_halo( j ) <= halo ) { 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 ); } + if ( !edges.erase( edge.reverse() ) ) { + edges.insert( edge ); + } } } } diff --git a/src/atlas/mesh/actions/BuildCellCentres.cc b/src/atlas/mesh/actions/BuildCellCentres.cc index 59bdd99f2..9d26cc5b1 100644 --- a/src/atlas/mesh/actions/BuildCellCentres.cc +++ b/src/atlas/mesh/actions/BuildCellCentres.cc @@ -50,7 +50,9 @@ Field& BuildCellCentres::operator()( Mesh& mesh ) const { array::ArrayView coords = array::make_view( nodes.field( "xyz" ) ); idx_t firstVirtualPoint = std::numeric_limits::max(); - if ( nodes.metadata().has( "NbRealPts" ) ) { firstVirtualPoint = nodes.metadata().get( "NbRealPts" ); } + if ( nodes.metadata().has( "NbRealPts" ) ) { + firstVirtualPoint = nodes.metadata().get( "NbRealPts" ); + } idx_t nb_cells = mesh.cells().size(); auto centroids = array::make_view( mesh.cells().field( field_name_ ) ); @@ -81,7 +83,9 @@ Field& BuildCellCentres::operator()( Mesh& mesh ) const { } idx_t nb_unique_nodes = idx_t( nb_cell_nodes ) - nb_equal_nodes; - if ( nb_unique_nodes < 3 ) { continue; } + if ( nb_unique_nodes < 3 ) { + continue; + } if ( flatten_virtual_elements_ ) { // calculate centroid by averaging coordinates (uses only "real" nodes) diff --git a/src/atlas/mesh/actions/BuildConvexHull3D.cc b/src/atlas/mesh/actions/BuildConvexHull3D.cc index 031e51b1d..67cf37836 100644 --- a/src/atlas/mesh/actions/BuildConvexHull3D.cc +++ b/src/atlas/mesh/actions/BuildConvexHull3D.cc @@ -74,8 +74,9 @@ static Polyhedron_3* create_convex_hull_from_points( const std::vector& // insertion from a vector : std::vector vertices( pts.size() ); - for ( idx_t i = 0, size = vertices.size(); i < 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 @@ -142,8 +143,9 @@ static void cgal_polyhedron_to_atlas_mesh( Mesh& mesh, Polyhedron_3& poly, Point FT innerp = n * p0; - if ( innerp < 0 ) // need to swap an edge of the triag + if ( innerp < 0 ) { // need to swap an edge of the triag std::swap( vts[1], vts[2] ); + } } /* define the triag */ @@ -180,7 +182,9 @@ static void cgal_polyhedron_to_atlas_mesh( Mesh& mesh, Polyhedron_3& poly, Point void BuildConvexHull3D::operator()( Mesh& mesh ) const { // don't tesselate meshes already with triags or quads - if ( mesh.cells().size() ) return; + if ( mesh.cells().size() ) { + return; + } ATLAS_TRACE(); diff --git a/src/atlas/mesh/actions/BuildDualMesh.cc b/src/atlas/mesh/actions/BuildDualMesh.cc index b13f88adb..b1d0900a4 100644 --- a/src/atlas/mesh/actions/BuildDualMesh.cc +++ b/src/atlas/mesh/actions/BuildDualMesh.cc @@ -96,11 +96,13 @@ void build_median_dual_mesh( Mesh& mesh ) { Field dual_volumes = nodes.add( Field( "dual_volumes", array::make_datatype(), array::make_shape( nodes.size() ) ) ); - if ( !mesh.cells().has_field( "centroids_xy" ) ) + if ( !mesh.cells().has_field( "centroids_xy" ) ) { mesh.cells().add( Field( "centroids_xy", build_centroids_xy( mesh.cells(), mesh.nodes().xy() ) ) ); + } - if ( !mesh.edges().has_field( "centroids_xy" ) ) + if ( !mesh.edges().has_field( "centroids_xy" ) ) { mesh.edges().add( Field( "centroids_xy", build_centroids_xy( mesh.edges(), mesh.nodes().xy() ) ) ); + } array::ArrayView v = array::make_view( dual_volumes ); @@ -173,14 +175,17 @@ void add_median_dual_volume_contribution_cells( const mesh::HybridElements& cell // special ordering for bit-identical results idx_t nb_cells = cells.size(); std::vector ordering( nb_cells ); - for ( idx_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 ( idx_t jcell = 0; jcell < nb_cells; ++jcell ) { idx_t icell = ordering[jcell].i; - if ( patch( icell ) ) continue; + if ( patch( icell ) ) { + continue; + } double x0 = cell_centroids( icell, XX ); double y0 = cell_centroids( icell, YY ); @@ -236,10 +241,12 @@ void add_median_dual_volume_contribution_poles( const mesh::HybridElements& edge y1 = edge_centroids( iedge, YY ); y2 = 0.; - if ( std::abs( y1 - max[YY] ) < tol ) + if ( std::abs( y1 - max[YY] ) < tol ) { y2 = 90.; - else if ( std::abs( y1 - min[YY] ) < tol ) + } + else if ( std::abs( y1 - min[YY] ) < tol ) { y2 = -90.; + } if ( y2 != 0 ) { const double quad_area = std::abs( ( x1 - x0 ) * ( y2 - y0 ) ); @@ -305,10 +312,12 @@ void build_dual_normals( Mesh& mesh ) { } if ( cnt == 2 ) { dual_normals( edge, XX ) = 0; - if ( node_xy( node, YY ) < 0. ) + if ( node_xy( node, YY ) < 0. ) { dual_normals( edge, YY ) = -std::abs( x[1] - x[0] ); - else if ( node_xy( node, YY ) > 0. ) + } + else if ( node_xy( node, YY ) > 0. ) { dual_normals( edge, YY ) = std::abs( x[1] - x[0] ); + } // std::cout << "pole dual_normal = " << dual_normals(YY,edge) << // std::endl; @@ -325,10 +334,12 @@ void build_dual_normals( Mesh& mesh ) { xr = edge_centroids( edge, XX ); yr = edge_centroids( edge, YY ); ; - if ( std::abs( yr - max[YY] ) < tol ) + if ( std::abs( yr - max[YY] ) < tol ) { yr = 90.; - else if ( std::abs( yr - min[YY] ) < tol ) + } + else if ( std::abs( yr - min[YY] ) < tol ) { yr = -90.; + } } else { xr = elem_centroids( right_elem, XX ); @@ -370,7 +381,9 @@ void make_dual_normals_outward( Mesh& mesh ) { void build_brick_dual_mesh( const Grid& grid, Mesh& mesh ) { auto g = StructuredGrid( grid ); if ( g ) { - if ( mpi::comm().size() != 1 ) throw_Exception( "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() ); @@ -388,8 +401,9 @@ void build_brick_dual_mesh( const Grid& grid, Mesh& mesh ) { double dlon = 360. / static_cast( g.nx( jlat ) ); for ( idx_t jlon = 0; jlon < g.nx( jlat ); ++jlon ) { - while ( gidx( c ) != n + 1 ) + while ( gidx( c ) != n + 1 ) { c++; + } ATLAS_ASSERT( xy( c, XX ) == g.x( jlon, jlat ) ); ATLAS_ASSERT( xy( c, YY ) == lat ); dual_volumes( c ) = dlon * dlat; diff --git a/src/atlas/mesh/actions/BuildEdges.cc b/src/atlas/mesh/actions/BuildEdges.cc index b114b1f86..a0d93acb5 100644 --- a/src/atlas/mesh/actions/BuildEdges.cc +++ b/src/atlas/mesh/actions/BuildEdges.cc @@ -38,8 +38,8 @@ using atlas::mesh::detail::accumulate_facets_ordered_by_halo; using Topology = atlas::mesh::Nodes::Topology; -using atlas::util::UniqueLonLat; using atlas::util::microdeg; +using atlas::util::UniqueLonLat; namespace atlas { namespace mesh { @@ -87,8 +87,9 @@ void build_element_to_edge_connectivity( Mesh& mesh ) { { UniqueLonLat compute_uid( mesh ); - for ( idx_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 ); } @@ -129,7 +130,9 @@ void build_element_to_edge_connectivity( Mesh& mesh ) { }; for ( idx_t jcell = 0; jcell < mesh.cells().size(); ++jcell ) { - if ( patch( jcell ) ) continue; + if ( patch( jcell ) ) { + continue; + } 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() ); @@ -164,13 +167,15 @@ void build_node_to_edge_connectivity( Mesh& mesh ) { node_to_edge.add( nodes.size(), to_edge_size.data() ); - for ( idx_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 ( idx_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 ( idx_t jedge = 0; jedge < nb_edges; ++jedge ) { @@ -225,7 +230,9 @@ class AccumulatePoleEdges { // 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 ); } + 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 ); } @@ -237,8 +244,9 @@ class AccumulatePoleEdges { int npart = -1; for ( std::set::iterator it = pole_nodes[NS].begin(); it != pole_nodes[NS].end(); ++it ) { int node = *it; - if ( npart == -1 ) + if ( npart == -1 ) { npart = part( node ); + } else if ( part( node ) != npart ) { // Not implemented yet, when pole-lattitude is split. std::stringstream msg; @@ -310,7 +318,9 @@ void accumulate_pole_edges( mesh::Nodes& nodes, std::vector& pole_edge_no // Collect all nodes closest to poles std::vector> pole_nodes( 2 ); for ( idx_t node = 0; node < nb_nodes; ++node ) { - if ( std::abs( xy( node, YY ) - max[YY] ) < tol ) { pole_nodes[NORTH].insert( 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 ); } @@ -322,8 +332,9 @@ void accumulate_pole_edges( mesh::Nodes& nodes, std::vector& pole_edge_no int npart = -1; for ( std::set::iterator it = pole_nodes[NS].begin(); it != pole_nodes[NS].end(); ++it ) { int node = *it; - if ( npart == -1 ) + if ( npart == -1 ) { npart = part( node ); + } else if ( part( node ) != npart ) { // Not implemented yet, when pole-lattitude is split. std::stringstream msg; @@ -372,10 +383,12 @@ struct ComputeUniquePoleEdgeIndex { } centroid[XX] /= 2.; centroid[YY] /= 2.; - if ( centroid[YY] > 0 ) + if ( centroid[YY] > 0 ) { centroid[YY] = 90.; - else + } + else { centroid[YY] = -90.; + } /// FIXME make this into `util::unique_lonlat(centroid)` but this causes /// weird parallel behavior return util::detail::unique32( microdeg( centroid[XX] ), microdeg( centroid[YY] ) ); @@ -404,7 +417,9 @@ void build_edges( Mesh& mesh, const eckit::Configuration& config ) { bool pole_edges{false}; if ( StructuredGrid grid = mesh.grid() ) { - if ( Domain domain = grid.domain() ) { pole_edges = domain.global(); } + if ( Domain domain = grid.domain() ) { + pole_edges = domain.global(); + } } config.get( "pole_edges", pole_edges ); @@ -431,7 +446,9 @@ void build_edges( Mesh& mesh, const eckit::Configuration& config ) { nb_inner_edges, missing_value, edge_halo_offsets ); std::shared_ptr pole_edge_accumulator; - if ( pole_edges ) { pole_edge_accumulator = std::make_shared( nodes ); } + if ( pole_edges ) { + pole_edge_accumulator = std::make_shared( nodes ); + } for ( int halo = 0; halo <= mesh_halo; ++halo ) { edge_start = edge_end; @@ -558,12 +575,16 @@ void build_edges( Mesh& mesh, const eckit::Configuration& config ) { 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 ) ); + 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] ); + 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] ); diff --git a/src/atlas/mesh/actions/BuildHalo.cc b/src/atlas/mesh/actions/BuildHalo.cc index 6c5568d3f..ce58bdcd7 100644 --- a/src/atlas/mesh/actions/BuildHalo.cc +++ b/src/atlas/mesh/actions/BuildHalo.cc @@ -49,9 +49,9 @@ using atlas::mesh::detail::accumulate_facets; using atlas::util::LonLatMicroDeg; +using atlas::util::microdeg; using atlas::util::PeriodicTransform; using atlas::util::UniqueLonLat; -using atlas::util::microdeg; using Topology = atlas::mesh::Nodes::Topology; namespace atlas { @@ -92,20 +92,23 @@ void make_nodes_global_index_human_readable( const mesh::actions::BuildHalo& bui if ( do_all ) { points_to_edit.resize( nodes_glb_idx.size() ); - for ( idx_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 { glb_idx_max = nodes.global_index().metadata().getLong( "max", 0 ); points_to_edit.resize( build_halo.periodic_points_local_index_.size() ); - for ( size_t i = 0; i < points_to_edit.size(); ++i ) + for ( size_t i = 0; i < points_to_edit.size(); ++i ) { points_to_edit[i] = build_halo.periodic_points_local_index_[i]; + } } std::vector glb_idx( points_to_edit.size() ); idx_t nb_nodes = static_cast( glb_idx.size() ); - for ( idx_t i = 0; i < nb_nodes; ++i ) + 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 ); // ATLAS_DEBUG_VAR( points_to_edit.size() ); @@ -158,7 +161,9 @@ void make_nodes_global_index_human_readable( const mesh::actions::BuildHalo& bui 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; } + if ( jnode > 0 && node_sort[jnode].g != node_sort[jnode - 1].g ) { + ++gid; + } int inode = node_sort[jnode].i; glb_idx_gathered[inode] = gid; } @@ -221,8 +226,9 @@ void make_cells_global_index_human_readable( const mesh::actions::BuildHalo& bui std::vector glb_idx( cells_to_edit.size() ); const idx_t nb_cells = static_cast( glb_idx.size() ); - for ( idx_t i = 0; i < nb_cells; ++i ) + 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 @@ -254,7 +260,9 @@ void make_cells_global_index_human_readable( const mesh::actions::BuildHalo& bui gidx_t gid = glb_idx_max + 1; for ( idx_t jcell = 0; jcell < glb_nb_cells; ++jcell ) { - if ( jcell > 0 && cell_sort[jcell].g != cell_sort[jcell - 1].g ) { ++gid; } + if ( jcell > 0 && cell_sort[jcell].g != cell_sort[jcell - 1].g ) { + ++gid; + } idx_t icell = cell_sort[jcell].i; glb_idx_gathered[icell] = gid; } @@ -380,7 +388,9 @@ std::vector filter_nodes( std::vector nodes, const Predicate& predicat std::vector filtered; filtered.reserve( nodes.size() ); for ( int inode : nodes ) { - if ( predicate( inode ) ) filtered.push_back( inode ); + if ( predicate( inode ) ) { + filtered.push_back( inode ); + } } return filtered; } @@ -398,7 +408,9 @@ class Notification { std::string str() const { std::stringstream stream; for ( size_t jnote = 0; jnote < notes.size(); ++jnote ) { - if ( jnote > 0 ) stream << "\n"; + if ( jnote > 0 ) { + stream << "\n"; + } stream << notes[jnote]; } return stream.str(); @@ -440,7 +452,9 @@ void build_lookup_uid2node( Mesh& mesh, Uid2Node& uid2node ) { notes.add_error( msg.str() ); } } - if ( notes.error() ) throw_Exception( 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, @@ -462,10 +476,14 @@ void accumulate_elements( const Mesh& mesh, const mpi::BufferView& reques 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 ( found != uid2node.end() ) { + inode = found->second; + } if ( inode != -1 && inode < nb_nodes ) { for ( const idx_t e : node2elem[inode] ) { - if ( elem_part( e ) == mpi_rank ) { found_elements_set.insert( e ); } + if ( elem_part( e ) == mpi_rank ) { + found_elements_set.insert( e ); + } } } } @@ -703,8 +721,9 @@ class BuildHaloHelper { 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 ( idx_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 ) ); + } } } @@ -821,7 +840,9 @@ class BuildHaloHelper { 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 ); } + if ( not node_already_exists( util::unique_lonlat( crd ) ) ) { + rfn_idx[jpart].push_back( n ); + } } nb_new_nodes += rfn_idx[jpart].size(); } @@ -915,8 +936,9 @@ class BuildHaloHelper { } }; - if ( not status.new_periodic_ghost_cells.size() ) + 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 ( idx_t jpart = 0; jpart < mpi_size; ++jpart ) { @@ -951,7 +973,9 @@ class BuildHaloHelper { // Add new elements BlockConnectivity& node_connectivity = elements.node_connectivity(); - if ( nb_elements_of_type[t] == 0 ) continue; + if ( nb_elements_of_type[t] == 0 ) { + continue; + } idx_t old_size = elements.size(); idx_t new_elems_pos = elements.add( nb_elements_of_type[t] ); @@ -1073,9 +1097,13 @@ void gather_bdry_nodes( const BuildHaloHelper& helper, const std::vector& void increase_halo_interior( BuildHaloHelper& helper ) { helper.update(); - if ( helper.node_to_elem.size() == 0 ) build_lookup_node2elem( helper.mesh, helper.node_to_elem ); + if ( helper.node_to_elem.size() == 0 ) { + build_lookup_node2elem( helper.mesh, helper.node_to_elem ); + } - if ( helper.uid2node.size() == 0 ) build_lookup_uid2node( helper.mesh, helper.uid2node ); + if ( helper.uid2node.size() == 0 ) { + build_lookup_uid2node( helper.mesh, helper.uid2node ); + } // All buffers needed to move elements and nodes BuildHaloHelper::Buffers sendmesh( helper.mesh ); @@ -1090,8 +1118,9 @@ void increase_halo_interior( BuildHaloHelper& helper ) { // 2) Communicate uid of these boundary nodes to other partitions std::vector send_bdry_nodes_uid( bdry_nodes.size() ); - for ( idx_t jnode = 0; jnode < nb_bdry_nodes; ++jnode ) + for ( idx_t jnode = 0; jnode < nb_bdry_nodes; ++jnode ) { send_bdry_nodes_uid[jnode] = helper.compute_uid( bdry_nodes[jnode] ); + } idx_t mpi_size = static_cast( mpi::comm().size() ); atlas::mpi::Buffer recv_bdry_nodes_uid_from_parts( mpi_size ); @@ -1140,8 +1169,12 @@ class PeriodicPoints { } bool operator()( int j ) const { - if ( j >= N_ ) return false; - if ( Topology::check( flags_( j ), flag_ ) ) return true; + if ( j >= N_ ) { + return false; + } + if ( Topology::check( flags_( j ), flag_ ) ) { + return true; + } return false; } @@ -1153,7 +1186,9 @@ class PeriodicPoints { friend std::ostream& operator<<( std::ostream& os, const PeriodicPoints& periodic_points ) { os << "["; for ( idx_t j = 0; j < periodic_points.flags_.shape( 0 ); ++j ) { - if ( periodic_points( j ) ) os << " " << j + 1; + if ( periodic_points( j ) ) { + os << " " << j + 1; + } } os << " ]"; return os; @@ -1177,7 +1212,9 @@ 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.halosize, 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 ); const idx_t nb_bdry_nodes = static_cast( bdry_nodes.size() ); @@ -1244,7 +1281,9 @@ void BuildHalo::operator()( int nb_elems ) { int halo = 0; mesh_.metadata().get( "halo", halo ); - if ( halo == nb_elems ) return; + if ( halo == nb_elems ) { + return; + } ATLAS_TRACE( "Increasing mesh halo" ); diff --git a/src/atlas/mesh/actions/BuildNode2CellConnectivity.cc b/src/atlas/mesh/actions/BuildNode2CellConnectivity.cc index 16dcfd26e..72019c3ec 100644 --- a/src/atlas/mesh/actions/BuildNode2CellConnectivity.cc +++ b/src/atlas/mesh/actions/BuildNode2CellConnectivity.cc @@ -41,8 +41,8 @@ using atlas::mesh::detail::accumulate_facets_ordered_by_halo; using Topology = atlas::mesh::Nodes::Topology; -using atlas::util::UniqueLonLat; using atlas::util::microdeg; +using atlas::util::UniqueLonLat; namespace atlas { namespace mesh { @@ -81,8 +81,9 @@ void BuildNode2CellConnectivity::operator()() { node_to_cell.add( nodes.size(), to_cell_size.data() ); - for ( idx_t jnode = 0; jnode < nodes.size(); ++jnode ) + for ( idx_t jnode = 0; jnode < nodes.size(); ++jnode ) { to_cell_size[jnode] = 0; + } UniqueLonLat compute_uid( mesh_ ); std::vector cell_sort( nb_cells ); diff --git a/src/atlas/mesh/actions/BuildParallelFields.cc b/src/atlas/mesh/actions/BuildParallelFields.cc index c6a80acc2..1f6a814b5 100644 --- a/src/atlas/mesh/actions/BuildParallelFields.cc +++ b/src/atlas/mesh/actions/BuildParallelFields.cc @@ -134,7 +134,9 @@ Field& build_nodes_global_idx( mesh::Nodes& nodes ) { UniqueLonLat compute_uid( nodes ); for ( idx_t jnode = 0; jnode < glb_idx.shape( 0 ); ++jnode ) { - if ( glb_idx( jnode ) <= 0 ) { glb_idx( jnode ) = compute_uid( jnode ); } + if ( glb_idx( jnode ) <= 0 ) { + glb_idx( jnode ) = compute_uid( jnode ); + } } return nodes.global_index(); } @@ -170,7 +172,9 @@ void renumber_nodes_glb_idx( mesh::Nodes& nodes ) { */ int nb_nodes = glb_idx.shape( 0 ); for ( int jnode = 0; jnode < nb_nodes; ++jnode ) { - if ( glb_idx( jnode ) <= 0 ) { glb_idx( jnode ) = compute_uid( jnode ); } + if ( glb_idx( jnode ) <= 0 ) { + glb_idx( jnode ) = compute_uid( jnode ); + } } // 1) Gather all global indices, together with location @@ -213,7 +217,9 @@ void renumber_nodes_glb_idx( mesh::Nodes& nodes ) { 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; } + if ( jnode == 0 ) { + ++gid; + } else if ( node_sort[jnode].g != node_sort[jnode - 1].g ) { ++gid; } @@ -244,8 +250,9 @@ Field& build_nodes_remote_idx( mesh::Nodes& nodes ) { // This piece should be somewhere central ... could be NPROMA ? // ----------> std::vector proc( nparts ); - for ( idx_t jpart = 0; jpart < nparts; ++jpart ) + for ( idx_t jpart = 0; jpart < nparts; ++jpart ) { proc[jpart] = jpart; + } // <--------- auto ridx = array::make_indexview( nodes.remote_index() ); @@ -363,23 +370,37 @@ Field& build_edges_partition( Mesh& mesh ) { return Topology::check( flags( ip1 ), flag ) && Topology::check( flags( ip2 ), flag ); }; 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; } + 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; } + 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; } + if ( check_flags( jedge, Topology::PERIODIC | Topology::WEST ) ) { + return true; + } return false; }; auto periodic_west_bdry = [&]( idx_t jedge ) { - if ( check_flags( jedge, Topology::PERIODIC | Topology::WEST | Topology::BC ) ) { return true; } + if ( check_flags( jedge, Topology::PERIODIC | Topology::WEST | Topology::BC ) ) { + return true; + } return false; }; @@ -395,7 +416,9 @@ Field& build_edges_partition( Mesh& mesh ) { 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 ); } + 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 ) ); } @@ -463,7 +486,9 @@ Field& build_edges_partition( Mesh& mesh ) { ATLAS_NOTIMPLEMENTED; } else if ( elem2 == missing ) { - if ( pn1 == pn2 ) { p = pn1; } + if ( pn1 == pn2 ) { + p = pn1; + } else if ( periodic_east( jedge ) ) { #ifdef DEBUGGING_PARFIELDS if ( FIND_EDGE( jedge ) ) @@ -539,7 +564,8 @@ Field& build_edges_partition( Mesh& mesh ) { 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; + 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 ); @@ -683,7 +709,9 @@ Field& build_edges_partition( Mesh& mesh ) { } } mpi::comm().allReduceInPlace( insane, eckit::mpi::max() ); - if ( insane && eckit::mpi::comm().rank() == 0 ) throw_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) ) @@ -742,7 +770,9 @@ 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 ); @@ -757,10 +787,12 @@ Field& build_edges_remote_idx( Mesh& mesh ) { Topology::check( flags( ip2 ), Topology::PERIODIC ) && !Topology::check( flags( ip2 ), Topology::BC | Topology::WEST ) ) ) { needed = true; - if ( Topology::check( flags( ip1 ), Topology::EAST ) ) + if ( Topology::check( flags( ip1 ), Topology::EAST ) ) { transform( centroid, -1 ); - else + } + else { transform( centroid, +1 ); + } } uid_t uid = util::unique_lonlat( centroid ); @@ -770,7 +802,9 @@ Field& build_edges_remote_idx( Mesh& mesh ) { edge_ridx( jedge ) = jedge; #ifdef DEBUGGING_PARFIELDS - if ( FIND_EDGE( jedge ) ) { ATLAS_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 @@ -876,7 +910,9 @@ 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 ); } } @@ -924,7 +960,9 @@ Field& build_edges_global_idx( Mesh& mesh ) { // Assume edge gid start uid_t gid( 0 ); for ( size_t jedge = 0; jedge < edge_sort.size(); ++jedge ) { - if ( jedge == 0 ) { ++gid; } + if ( jedge == 0 ) { + ++gid; + } else if ( edge_sort[jedge].g != edge_sort[jedge - 1].g ) { ++gid; } diff --git a/src/atlas/mesh/actions/BuildStatistics.cc b/src/atlas/mesh/actions/BuildStatistics.cc index bf3a87955..cdd93d16d 100644 --- a/src/atlas/mesh/actions/BuildStatistics.cc +++ b/src/atlas/mesh/actions/BuildStatistics.cc @@ -117,9 +117,10 @@ void build_statistics( Mesh& mesh ) { array::ArrayView lonlat = array::make_view( nodes.lonlat() ); if ( mesh.edges().size() ) { - if ( !mesh.edges().has_field( "arc_length" ) ) + if ( !mesh.edges().has_field( "arc_length" ) ) { mesh.edges().add( Field( "arc_length", array::make_datatype(), array::make_shape( mesh.edges().size() ) ) ); + } array::ArrayView dist = array::make_view( mesh.edges().field( "arc_length" ) ); const mesh::HybridElements::Connectivity& edge_nodes = mesh.edges().node_connectivity(); @@ -147,7 +148,9 @@ void build_statistics( Mesh& mesh ) { // Cell statistics { - if ( mpi::comm().size() == 1 ) ofs.open( stats_path.localPath(), std::ofstream::app ); + if ( mpi::comm().size() == 1 ) { + ofs.open( stats_path.localPath(), std::ofstream::app ); + } array::ArrayView rho = array::make_view( mesh.cells().add( Field( "stats_rho", array::make_datatype(), array::make_shape( mesh.cells().size() ) ) ) ); @@ -197,7 +200,9 @@ void build_statistics( Mesh& mesh ) { } } } - if ( mpi::comm().size() == 1 ) ofs.close(); + if ( mpi::comm().size() == 1 ) { + ofs.close(); + } } eckit::PathName dual_stats_path( "dual_stats.txt" ); @@ -226,7 +231,9 @@ void build_statistics( Mesh& mesh ) { } } } - if ( mpi::comm().size() == 1 ) ofs.close(); + if ( mpi::comm().size() == 1 ) { + ofs.close(); + } } // ------------------------------------------------------------------ diff --git a/src/atlas/mesh/actions/ExtendNodesGlobal.cc b/src/atlas/mesh/actions/ExtendNodesGlobal.cc index eeb556825..d4cbf2107 100644 --- a/src/atlas/mesh/actions/ExtendNodesGlobal.cc +++ b/src/atlas/mesh/actions/ExtendNodesGlobal.cc @@ -27,7 +27,9 @@ namespace actions { ExtendNodesGlobal::ExtendNodesGlobal( const std::string& gridname ) : gridname_( gridname ) {} void ExtendNodesGlobal::operator()( const Grid& grid, Mesh& mesh ) const { - if ( grid.domain().global() ) return; // don't add virtual points to global domains + if ( grid.domain().global() ) { + return; // don't add virtual points to global domains + } Grid O16( "O16" ); @@ -39,7 +41,9 @@ void ExtendNodesGlobal::operator()( const Grid& grid, Mesh& mesh ) const { for ( const PointLonLat& lonlat : O16.lonlat() ) { PointXY xy = grid.projection().xy( lonlat ); - if ( not grid.domain().contains( xy ) ) { extended_pts.push_back( xy ); } + if ( not grid.domain().contains( xy ) ) { + extended_pts.push_back( xy ); + } } mesh::Nodes& nodes = mesh.nodes(); diff --git a/src/atlas/mesh/actions/WriteLoadBalanceReport.cc b/src/atlas/mesh/actions/WriteLoadBalanceReport.cc index 838d0f7e7..94d0fe5ca 100644 --- a/src/atlas/mesh/actions/WriteLoadBalanceReport.cc +++ b/src/atlas/mesh/actions/WriteLoadBalanceReport.cc @@ -37,7 +37,9 @@ void write_load_balance_report( const Mesh& mesh, const std::string& filename ) write_load_balance_report( mesh, ofs ); - if ( mpi::comm().rank() == 0 ) { ofs.close(); } + if ( mpi::comm().rank() == 0 ) { + ofs.close(); + } } void write_load_balance_report( const Mesh& mesh, std::ostream& ofs ) { @@ -61,10 +63,12 @@ void write_load_balance_report( const Mesh& mesh, std::ostream& ofs ) { idx_t nowned( 0 ); idx_t nghost( 0 ); for ( idx_t n = 0; n < nb_nodes; ++n ) { - if ( is_ghost( n ) ) + if ( is_ghost( n ) ) { ++nghost; - else + } + else { ++nowned; + } } /// @note this could be improved by packing the 3 integers in a vector, and @@ -97,10 +101,12 @@ void write_load_balance_report( const Mesh& mesh, std::ostream& ofs ) { idx_t nowned( 0 ); idx_t nghost( 0 ); for ( idx_t j = 0; j < nb_edges; ++j ) { - if ( is_ghost( edge_nodes( j, 0 ) ) ) + if ( is_ghost( edge_nodes( j, 0 ) ) ) { ++nghost; - else + } + else { ++nowned; + } } /// @note this could be improved by packing the 3 integers in a vector, and diff --git a/src/atlas/mesh/detail/AccumulateFacets.cc b/src/atlas/mesh/detail/AccumulateFacets.cc index 6ad19c8c6..1b5bf9b2c 100644 --- a/src/atlas/mesh/detail/AccumulateFacets.cc +++ b/src/atlas/mesh/detail/AccumulateFacets.cc @@ -31,8 +31,12 @@ void accumulate_facets( const mesh::HybridElements& cells, const mesh::Nodes& no } 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() ); } + 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(); @@ -77,7 +81,9 @@ void accumulate_facets( const mesh::HybridElements& cells, const mesh::Nodes& no std::vector facet_nodes( nb_nodes_in_facet ); for ( idx_t e = 0; e < nb_elems; ++e ) { - if ( patch( e ) ) continue; + if ( patch( e ) ) { + continue; + } for ( idx_t f = 0; f < nb_facets_in_elem; ++f ) { bool found_face = false; @@ -130,8 +136,12 @@ void accumulate_facets_in_range( std::vector& range, const mesh::H 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() ); } + 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(); @@ -178,7 +188,9 @@ void accumulate_facets_in_range( std::vector& range, const mesh::H const idx_t e_end = range[t].end(); for ( idx_t e = e_start; e < e_end; ++e ) { - if ( patch( e ) ) continue; + if ( patch( e ) ) { + continue; + } for ( idx_t f = 0; f < nb_facets_in_elem; ++f ) { bool found_face = false; diff --git a/src/atlas/mesh/detail/MeshImpl.cc b/src/atlas/mesh/detail/MeshImpl.cc index 85813234d..de0ff08db 100644 --- a/src/atlas/mesh/detail/MeshImpl.cc +++ b/src/atlas/mesh/detail/MeshImpl.cc @@ -54,14 +54,28 @@ size_t MeshImpl::footprint() const { size_t size = sizeof( *this ); size += metadata_.footprint(); - if ( nodes_ ) size += nodes_->footprint(); - if ( cells_ ) size += cells_->footprint(); - if ( facets_ ) size += facets_->footprint(); - if ( ridges_ ) size += ridges_->footprint(); - if ( peaks_ ) size += peaks_->footprint(); - if ( partition_graph_ ) size += partition_graph_->footprint(); + if ( nodes_ ) { + size += nodes_->footprint(); + } + if ( cells_ ) { + size += cells_->footprint(); + } + if ( facets_ ) { + size += facets_->footprint(); + } + if ( ridges_ ) { + size += ridges_->footprint(); + } + if ( peaks_ ) { + size += peaks_->footprint(); + } + if ( partition_graph_ ) { + size += partition_graph_->footprint(); + } for ( const auto& polygon : polygons_ ) { - if ( polygon ) size += polygon->footprint(); + if ( polygon ) { + size += polygon->footprint(); + } } return size; @@ -72,12 +86,15 @@ void MeshImpl::createElements() { facets_.reset( new HybridElements() ); ridges_.reset( new HybridElements() ); peaks_.reset( new HybridElements() ); - if ( dimensionality_ == 2 ) + if ( dimensionality_ == 2 ) { edges_ = facets_; - else if ( dimensionality_ == 3 ) + } + else if ( dimensionality_ == 3 ) { edges_ = ridges_; - else + } + else { throw_Exception( "Invalid Mesh dimensionality", Here() ); + } ATLAS_ASSERT( edges_.owners() == 2 ); } @@ -92,7 +109,9 @@ void MeshImpl::setProjection( const Projection& projection ) { void MeshImpl::setGrid( const Grid& grid ) { grid_.reset( new Grid( grid ) ); - if ( not projection_ ) projection_ = grid_->projection(); + if ( not projection_ ) { + projection_ = grid_->projection(); + } } idx_t MeshImpl::nb_partitions() const { @@ -104,31 +123,63 @@ idx_t MeshImpl::partition() const { } void MeshImpl::cloneToDevice() const { - if ( nodes_ ) nodes_->cloneToDevice(); - if ( cells_ ) cells_->cloneToDevice(); - if ( facets_ ) facets_->cloneToDevice(); - if ( ridges_ ) ridges_->cloneToDevice(); - if ( peaks_ ) peaks_->cloneToDevice(); + if ( nodes_ ) { + nodes_->cloneToDevice(); + } + if ( cells_ ) { + cells_->cloneToDevice(); + } + if ( facets_ ) { + facets_->cloneToDevice(); + } + if ( ridges_ ) { + ridges_->cloneToDevice(); + } + if ( peaks_ ) { + peaks_->cloneToDevice(); + } } void MeshImpl::cloneFromDevice() const { - if ( nodes_ ) nodes_->cloneFromDevice(); - if ( cells_ ) cells_->cloneFromDevice(); - if ( facets_ ) facets_->cloneFromDevice(); - if ( ridges_ ) ridges_->cloneFromDevice(); - if ( peaks_ ) peaks_->cloneFromDevice(); + if ( nodes_ ) { + nodes_->cloneFromDevice(); + } + if ( cells_ ) { + cells_->cloneFromDevice(); + } + if ( facets_ ) { + facets_->cloneFromDevice(); + } + if ( ridges_ ) { + ridges_->cloneFromDevice(); + } + if ( peaks_ ) { + peaks_->cloneFromDevice(); + } } void MeshImpl::syncHostDevice() const { - if ( nodes_ ) nodes_->syncHostDevice(); - if ( cells_ ) cells_->syncHostDevice(); - if ( facets_ ) facets_->syncHostDevice(); - if ( ridges_ ) ridges_->syncHostDevice(); - if ( peaks_ ) peaks_->syncHostDevice(); + if ( nodes_ ) { + nodes_->syncHostDevice(); + } + if ( cells_ ) { + cells_->syncHostDevice(); + } + if ( facets_ ) { + facets_->syncHostDevice(); + } + if ( ridges_ ) { + ridges_->syncHostDevice(); + } + if ( peaks_ ) { + peaks_->syncHostDevice(); + } } const PartitionGraph& MeshImpl::partitionGraph() const { - if ( not partition_graph_ ) { partition_graph_.reset( build_partition_graph( *this ) ); } + if ( not partition_graph_ ) { + partition_graph_.reset( build_partition_graph( *this ) ); + } return *partition_graph_; } @@ -137,7 +188,9 @@ PartitionGraph::Neighbours MeshImpl::nearestNeighbourPartitions() const { } const PartitionPolygon& MeshImpl::polygon( idx_t halo ) const { - if ( halo >= static_cast( polygons_.size() ) ) { polygons_.resize( halo + 1 ); } + if ( halo >= static_cast( polygons_.size() ) ) { + polygons_.resize( halo + 1 ); + } if ( not polygons_[halo] ) { int mesh_halo = 0; metadata().get( "halo", mesh_halo ); diff --git a/src/atlas/mesh/detail/PartitionGraph.cc b/src/atlas/mesh/detail/PartitionGraph.cc index 0eb027663..7037a5a8d 100644 --- a/src/atlas/mesh/detail/PartitionGraph.cc +++ b/src/atlas/mesh/detail/PartitionGraph.cc @@ -63,8 +63,12 @@ PartitionGraph* build_partition_graph( const MeshImpl& mesh ) { for ( const PolygonXY& _polygon : polygons ) { for ( const PointXY& pxy : _polygon ) { PointLonLat pll = pxy; - if ( eckit::types::is_strictly_greater( 0., pll.lon() ) ) { pll.lon() += 360.; } - if ( eckit::types::is_approximately_greater_or_equal( pll.lon(), 360. ) ) { pll.lon() -= 360.; } + if ( eckit::types::is_strictly_greater( 0., pll.lon() ) ) { + pll.lon() += 360.; + } + if ( eckit::types::is_approximately_greater_or_equal( pll.lon(), 360. ) ) { + pll.lon() -= 360.; + } uidx_t uid = util::unique_lonlat( pll.data() ); uid_2_parts[uid].insert( jpart ); } @@ -75,7 +79,9 @@ PartitionGraph* build_partition_graph( const MeshImpl& mesh ) { const std::set& parts = u2p.second; for ( idx_t jpart : parts ) { for ( idx_t ipart : parts ) { - if ( jpart != ipart ) { graph[jpart].insert( ipart ); } + if ( jpart != ipart ) { + graph[jpart].insert( ipart ); + } } } } @@ -126,7 +132,9 @@ PartitionGraph::PartitionGraph( idx_t values[], idx_t rows, idx_t displs[], idx_ for ( idx_t neighbour : nearestNeighbours( jpart ) ) { bool found( false ); for ( idx_t nextneighbour : nearestNeighbours( neighbour ) ) { - if ( nextneighbour == jpart ) found = true; + if ( nextneighbour == jpart ) { + found = true; + } } if ( not found ) { values_.insert( values_.begin() + displs_[neighbour] + counts_[neighbour], jpart ); diff --git a/src/atlas/meshgenerator/detail/DelaunayMeshGenerator.cc b/src/atlas/meshgenerator/detail/DelaunayMeshGenerator.cc index 5a591c689..64a96c406 100644 --- a/src/atlas/meshgenerator/detail/DelaunayMeshGenerator.cc +++ b/src/atlas/meshgenerator/detail/DelaunayMeshGenerator.cc @@ -74,6 +74,8 @@ void DelaunayMeshGenerator::generate( const Grid& g, Mesh& mesh ) const { mesh::actions::ExtendNodesGlobal()( g, mesh ); ///< does nothing if global domain mesh::actions::BuildConvexHull3D()( mesh ); + + setGrid( mesh, g, "serial" ); } void DelaunayMeshGenerator::createNodes( const Grid& grid, Mesh& mesh ) const { diff --git a/src/atlas/meshgenerator/detail/MeshGeneratorImpl.cc b/src/atlas/meshgenerator/detail/MeshGeneratorImpl.cc index 8d2a5a4f1..d08b62001 100644 --- a/src/atlas/meshgenerator/detail/MeshGeneratorImpl.cc +++ b/src/atlas/meshgenerator/detail/MeshGeneratorImpl.cc @@ -96,6 +96,10 @@ void MeshGeneratorImpl::setGrid( Mesh& mesh, const Grid& g, const grid::Distribu mesh.setGrid( g ); mesh.metadata().set( "distribution", d.type() ); } +void MeshGeneratorImpl::setGrid( Mesh& mesh, const Grid& g, const std::string& d ) const { + mesh.setGrid( g ); + mesh.metadata().set( "distribution", d ); +} //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/atlas/meshgenerator/detail/MeshGeneratorImpl.h b/src/atlas/meshgenerator/detail/MeshGeneratorImpl.h index 679b61c46..6dd48f27e 100644 --- a/src/atlas/meshgenerator/detail/MeshGeneratorImpl.h +++ b/src/atlas/meshgenerator/detail/MeshGeneratorImpl.h @@ -55,6 +55,7 @@ class MeshGeneratorImpl : public util::Object { void generateGlobalElementNumbering( Mesh& mesh ) const; void setProjection( Mesh&, const Projection& ) const; void setGrid( Mesh&, const Grid&, const grid::Distribution& ) const; + void setGrid( Mesh&, const Grid&, const std::string& distribution ) const; }; //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/atlas/meshgenerator/detail/RegularMeshGenerator.cc b/src/atlas/meshgenerator/detail/RegularMeshGenerator.cc index b47b0c26b..3dc18de62 100644 --- a/src/atlas/meshgenerator/detail/RegularMeshGenerator.cc +++ b/src/atlas/meshgenerator/detail/RegularMeshGenerator.cc @@ -49,10 +49,14 @@ RegularMeshGenerator::RegularMeshGenerator( const eckit::Parametrisation& p ) { // options copied from Structured MeshGenerator size_t nb_parts; - if ( p.get( "nb_parts", nb_parts ) ) options.set( "nb_parts", nb_parts ); + if ( p.get( "nb_parts", nb_parts ) ) { + options.set( "nb_parts", nb_parts ); + } size_t part; - if ( p.get( "part", part ) ) options.set( "part", part ); + if ( p.get( "part", part ) ) { + options.set( "part", part ); + } std::string partitioner; if ( p.get( "partitioner", partitioner ) ) { @@ -66,10 +70,14 @@ RegularMeshGenerator::RegularMeshGenerator( const eckit::Parametrisation& p ) { // options specifically for this MeshGenerator bool periodic_x; - if ( p.get( "periodic_x", periodic_x ) ) options.set( "periodic_x", periodic_x ); + if ( p.get( "periodic_x", periodic_x ) ) { + options.set( "periodic_x", periodic_x ); + } bool periodic_y; - if ( p.get( "periodic_y", periodic_y ) ) options.set( "periodic_y", periodic_y ); + if ( p.get( "periodic_y", periodic_y ) ) { + options.set( "periodic_y", periodic_y ); + } bool biperiodic; if ( p.get( "biperiodic", biperiodic ) ) { @@ -87,10 +95,12 @@ void RegularMeshGenerator::configure_defaults() { // This options sets the default partitioner std::string partitioner; - if ( grid::Partitioner::exists( "trans" ) && mpi::comm().size() > 1 ) + if ( grid::Partitioner::exists( "trans" ) && mpi::comm().size() > 1 ) { partitioner = "trans"; - else + } + else { partitioner = "checkerboard"; + } options.set( "partitioner", partitioner ); // Options for for periodic grids @@ -102,7 +112,9 @@ void RegularMeshGenerator::generate( const Grid& grid, Mesh& mesh ) const { ATLAS_ASSERT( !mesh.generated() ); const RegularGrid rg = RegularGrid( grid ); - if ( !rg ) throw_Exception( "RegularMeshGenerator can only work with a Regular grid", Here() ); + if ( !rg ) { + throw_Exception( "RegularMeshGenerator can only work with a Regular grid", Here() ); + } size_t nb_parts = options.get( "nb_parts" ); @@ -126,7 +138,9 @@ void RegularMeshGenerator::hash( eckit::Hash& h ) const { void RegularMeshGenerator::generate( const Grid& grid, const grid::Distribution& distribution, Mesh& mesh ) const { const auto rg = RegularGrid( grid ); - if ( !rg ) throw_Exception( "Grid could not be cast to a Regular", Here() ); + if ( !rg ) { + throw_Exception( "Grid could not be cast to a Regular", Here() ); + } ATLAS_ASSERT( !mesh.generated() ); @@ -415,7 +429,9 @@ void RegularMeshGenerator::generate_mesh( const RegularGrid& rg, const std::vect // node properties if ( is_node_SR[ii] ) { // set node counter - if ( is_ghost_SR[ii] ) { inode = inode_ghost++; } + if ( is_ghost_SR[ii] ) { + inode = inode_ghost++; + } else { inode = inode_nonghost++; } diff --git a/src/atlas/meshgenerator/detail/StructuredMeshGenerator.cc b/src/atlas/meshgenerator/detail/StructuredMeshGenerator.cc index f9745f6e1..bb859a932 100644 --- a/src/atlas/meshgenerator/detail/StructuredMeshGenerator.cc +++ b/src/atlas/meshgenerator/detail/StructuredMeshGenerator.cc @@ -68,44 +68,65 @@ StructuredMeshGenerator::StructuredMeshGenerator( const eckit::Parametrisation& configure_defaults(); bool include_pole; - if ( p.get( "include_pole", include_pole ) ) options.set( "include_pole", include_pole ); + if ( p.get( "include_pole", include_pole ) ) { + options.set( "include_pole", include_pole ); + } bool patch_pole; - if ( p.get( "patch_pole", patch_pole ) ) options.set( "patch_pole", patch_pole ); + if ( p.get( "patch_pole", patch_pole ) ) { + options.set( "patch_pole", patch_pole ); + } bool unique_pole; - if ( p.get( "unique_pole", unique_pole ) ) options.set( "unique_pole", unique_pole ); + if ( p.get( "unique_pole", unique_pole ) ) { + options.set( "unique_pole", unique_pole ); + } bool force_include_pole; - if ( p.get( "force_include_north_pole", force_include_pole ) ) + if ( p.get( "force_include_north_pole", force_include_pole ) ) { options.set( "force_include_north_pole", force_include_pole ); - if ( p.get( "force_include_south_pole", force_include_pole ) ) + } + if ( p.get( "force_include_south_pole", force_include_pole ) ) { options.set( "force_include_south_pole", force_include_pole ); + } bool three_dimensional; - if ( p.get( "three_dimensional", three_dimensional ) || p.get( "3d", three_dimensional ) ) + if ( p.get( "three_dimensional", three_dimensional ) || p.get( "3d", three_dimensional ) ) { options.set( "3d", three_dimensional ); + } size_t nb_parts; - if ( p.get( "nb_parts", nb_parts ) ) options.set( "nb_parts", nb_parts ); + if ( p.get( "nb_parts", nb_parts ) ) { + options.set( "nb_parts", nb_parts ); + } size_t part; - if ( p.get( "part", part ) ) options.set( "part", part ); + if ( p.get( "part", part ) ) { + options.set( "part", part ); + } double angle; - if ( p.get( "angle", angle ) ) options.set( "angle", angle ); + if ( p.get( "angle", angle ) ) { + options.set( "angle", angle ); + } bool triangulate; - if ( p.get( "triangulate", triangulate ) ) options.set( "triangulate", triangulate ); + if ( p.get( "triangulate", triangulate ) ) { + options.set( "triangulate", triangulate ); + } bool ghost_at_end; - if ( p.get( "ghost_at_end", ghost_at_end ) ) options.set( "ghost_at_end", ghost_at_end ); + if ( p.get( "ghost_at_end", ghost_at_end ) ) { + options.set( "ghost_at_end", ghost_at_end ); + } std::string partitioner; - if ( grid::Partitioner::exists( "trans" ) ) + if ( grid::Partitioner::exists( "trans" ) ) { partitioner = "trans"; - else + } + else { partitioner = "equal_regions"; + } options.set( "partitioner", partitioner ); if ( p.get( "partitioner", partitioner ) ) { @@ -162,17 +183,21 @@ void StructuredMeshGenerator::generate( const Grid& grid, Mesh& mesh ) const { ATLAS_ASSERT( !mesh.generated() ); const StructuredGrid rg = StructuredGrid( grid ); - if ( !rg ) throw_Exception( "Structured can only work with a Structured", Here() ); + if ( !rg ) { + throw_Exception( "Structured can only work with a Structured", Here() ); + } idx_t nb_parts = options.get( "nb_parts" ); std::string partitioner_type = "equal_regions"; options.get( "partitioner", partitioner_type ); - if ( partitioner_type == "trans" && rg.ny() % 2 == 1 ) + if ( partitioner_type == "trans" && rg.ny() % 2 == 1 ) { partitioner_type = "equal_regions"; // Odd number of latitudes - if ( nb_parts == 1 || mpi::comm().size() == 1 ) + } + if ( nb_parts == 1 || mpi::comm().size() == 1 ) { partitioner_type = "equal_regions"; // Only one part --> Trans is slower + } grid::Partitioner partitioner( partitioner_type, nb_parts ); grid::Distribution distribution( partitioner.partition( grid ) ); @@ -188,7 +213,9 @@ void StructuredMeshGenerator::generate( const Grid& grid, const grid::Distributi ATLAS_TRACE(); const StructuredGrid rg = StructuredGrid( grid ); - if ( !rg ) throw_Exception( "Grid could not be cast to a Structured", Here() ); + if ( !rg ) { + throw_Exception( "Grid could not be cast to a Structured", Here() ); + } ATLAS_ASSERT( !mesh.generated() ); @@ -279,8 +306,12 @@ 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 ( idx_t( lat_south + 1 ) <= rg.ny() - 1 && rg.nx( lat_south + 1 ) > 0 ) ++lat_south; + if ( lat_north - 1 >= 0 && rg.nx( lat_north - 1 ) > 0 ) { + --lat_north; + } + 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 ); @@ -322,11 +353,15 @@ We need to connect to next region beginN = 0; endN = rg.nx( latN ) - ( periodic_east_west ? 0 : 1 ); - if ( eckit::types::is_approximately_equal( yN, 90. ) && unique_pole ) endN = beginN; + if ( eckit::types::is_approximately_equal( yN, 90. ) && unique_pole ) { + endN = beginN; + } beginS = 0; endS = rg.nx( latS ) - ( periodic_east_west ? 0 : 1 ); - if ( eckit::types::is_approximately_equal( yS, -90. ) && unique_pole ) endS = beginS; + if ( eckit::types::is_approximately_equal( yS, -90. ) && unique_pole ) { + endS = beginS; + } ipN1 = beginN; ipS1 = beginS; @@ -342,7 +377,9 @@ We need to connect to next region #endif while ( true ) { - if ( ipN1 == endN && ipS1 == endS ) break; + if ( ipN1 == endN && ipS1 == endS ) { + break; + } #if DEBUG_OUTPUT Log::info() << "-------\n"; @@ -352,26 +389,34 @@ We need to connect to next region // ATLAS_ASSERT(offset.at(latS)+ipS1 < parts.size()); int pN1, pS1, pN2, pS2; - if ( ipN1 != rg.nx( latN ) ) + if ( ipN1 != rg.nx( latN ) ) { pN1 = parts.at( offset.at( latN ) + ipN1 ); - else + } + else { pN1 = parts.at( offset.at( latN ) ); - if ( ipS1 != rg.nx( latS ) ) + } + if ( ipS1 != rg.nx( latS ) ) { pS1 = parts.at( offset.at( latS ) + ipS1 ); - else + } + else { pS1 = parts.at( offset.at( latS ) ); + } - if ( ipN2 == rg.nx( latN ) ) + if ( ipN2 == rg.nx( latN ) ) { pN2 = parts.at( offset.at( latN ) ); - else + } + else { pN2 = parts.at( offset.at( latN ) + ipN2 ); - if ( ipS2 == rg.nx( latS ) ) + } + if ( ipS2 == rg.nx( latS ) ) { pS2 = parts.at( offset.at( latS ) ); - else + } + else { pS2 = parts.at( offset.at( latS ) + ipS2 ); + } - // Log::info() << ipN1 << "("<( rg.nx( latN ) ); - if ( stagger && ( latN + 1 ) % 2 == 0 ) xN2 += M_PI / static_cast( rg.nx( latN ) ); - if ( stagger && ( latS + 1 ) % 2 == 0 ) xS1 += M_PI / static_cast( rg.nx( latS ) ); - if ( stagger && ( latS + 1 ) % 2 == 0 ) xS2 += M_PI / static_cast( rg.nx( latS ) ); + if ( stagger && ( latN + 1 ) % 2 == 0 ) { + xN1 += M_PI / static_cast( rg.nx( latN ) ); + } + if ( stagger && ( latN + 1 ) % 2 == 0 ) { + xN2 += M_PI / static_cast( rg.nx( latN ) ); + } + if ( stagger && ( latS + 1 ) % 2 == 0 ) { + xS1 += M_PI / static_cast( rg.nx( latS ) ); + } + if ( stagger && ( latS + 1 ) % 2 == 0 ) { + xS2 += M_PI / static_cast( rg.nx( latS ) ); + } #if DEBUG_OUTPUT Log::info() << "-------\n"; @@ -429,13 +482,17 @@ We need to connect to next region try_make_triangle_down = ( jlat + ipN1 + 1 ) % 2; } else if ( dN1S2 < dS1N2 ) { - if ( ipS1 != ipS2 ) { try_make_triangle_up = true; } + if ( ipS1 != ipS2 ) { + try_make_triangle_up = true; + } else { try_make_triangle_down = true; } } else if ( dN1S2 > dS1N2 ) { - if ( ipN1 != ipN2 ) { try_make_triangle_down = true; } + if ( ipN1 != ipN2 ) { + try_make_triangle_down = true; + } else { try_make_triangle_up = true; } @@ -446,12 +503,15 @@ We need to connect to next region } } else { - if ( ipN1 == ipN2 ) + if ( ipN1 == ipN2 ) { try_make_triangle_up = true; - else if ( ipS1 == ipS2 ) + } + else if ( ipS1 == ipS2 ) { try_make_triangle_down = true; - else + } + else { try_make_quad = true; + } // try_make_quad = true; } @@ -462,16 +522,19 @@ We need to connect to next region // dN2S2 = std::abs(xN2-xS2); // Log::info() << " dN1S2 " << dN1S2 << " dS1N2 " << dS1N2 << " // dN2S2 " << dN2S2 << std::endl; - if ( ( dN1S2 <= dS1N2 ) && ( ipS1 != ipS2 ) ) { try_make_triangle_up = true; } + if ( ( dN1S2 <= dS1N2 ) && ( ipS1 != ipS2 ) ) { + try_make_triangle_up = true; + } else if ( ( dN1S2 >= dS1N2 ) && ( ipN1 != ipN2 ) ) { try_make_triangle_down = true; } - else + else { throw_Exception( "Should not try to make a quadrilateral!", Here() ); + } } - // ------------------------------------------------ - // END RULES - // ------------------------------------------------ + // ------------------------------------------------ + // END RULES + // ------------------------------------------------ #if DEBUG_OUTPUT ATLAS_DEBUG_VAR( jelem ); @@ -492,15 +555,20 @@ We need to connect to next region add_quad = false; std::array np{pN1, pN2, pS1, pS2}; std::array pcnts; - for ( int j = 0; j < 4; ++j ) + for ( int j = 0; j < 4; ++j ) { pcnts[j] = std::count( np.begin(), np.end(), np[j] ); + } if ( pcnts[0] > 2 ) { // 3 or more of pN1 pE = pN1; - if ( latS == rg.ny() - 1 ) pE = pS1; + if ( latS == rg.ny() - 1 ) { + pE = pS1; + } } else if ( pcnts[2] > 2 ) { // 3 or more of pS1 pE = pS1; - if ( latN == 0 ) pE = pN1; + if ( latN == 0 ) { + pE = pN1; + } } else { std::array::iterator p_max = std::max_element( pcnts.begin(), pcnts.end() ); @@ -509,7 +577,9 @@ We need to connect to next region } else { // 3 or 4 points don't belong to mypart pE = pN1; - if ( latS == rg.ny() - 1 ) pE = pS1; + if ( latS == rg.ny() - 1 ) { + pE = pS1; + } } } add_quad = ( pE == mypart ); @@ -518,8 +588,12 @@ We need to connect to next region ++jelem; ++nelems; - if ( region.lat_begin.at( latN ) == -1 ) region.lat_begin.at( latN ) = ipN1; - if ( region.lat_begin.at( latS ) == -1 ) region.lat_begin.at( latS ) = ipS1; + if ( region.lat_begin.at( latN ) == -1 ) { + region.lat_begin.at( latN ) = ipN1; + } + if ( region.lat_begin.at( latS ) == -1 ) { + region.lat_begin.at( latS ) = ipS1; + } 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 ), ipN2 ); @@ -546,7 +620,9 @@ We need to connect to next region elem( 3 ) = ipN2; pE = pN1; - if ( latS == rg.ny() - 1 ) pE = pS1; + if ( latS == rg.ny() - 1 ) { + pE = pS1; + } add_triag = ( mypart == pE ); if ( add_triag ) { @@ -554,8 +630,12 @@ We need to connect to next region ++jelem; ++nelems; - if ( region.lat_begin.at( latN ) == -1 ) region.lat_begin.at( latN ) = ipN1; - if ( region.lat_begin.at( latS ) == -1 ) region.lat_begin.at( latS ) = ipS1; + if ( region.lat_begin.at( latN ) == -1 ) { + region.lat_begin.at( latN ) = ipN1; + } + if ( region.lat_begin.at( latS ) == -1 ) { + region.lat_begin.at( latS ) = ipS1; + } 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 ), ipN2 ); @@ -583,13 +663,19 @@ We need to connect to next region elem( 3 ) = -1; if ( pS1 == pE && pN1 != pE ) { - if ( xN1 < 0.5 * ( xS1 + xS2 ) ) { pE = pN1; } // else pE of previous element + if ( xN1 < 0.5 * ( xS1 + xS2 ) ) { + pE = pN1; + } // else pE of previous element } else { pE = pN1; } - if ( ipN1 == rg.nx( latN ) ) pE = pS1; - if ( latS == rg.ny() - 1 ) pE = pS1; + if ( ipN1 == rg.nx( latN ) ) { + pE = pS1; + } + if ( latS == rg.ny() - 1 ) { + pE = pS1; + } add_triag = ( mypart == pE ); @@ -598,8 +684,12 @@ We need to connect to next region ++jelem; ++nelems; - if ( region.lat_begin.at( latN ) == -1 ) region.lat_begin.at( latN ) = ipN1; - if ( region.lat_begin.at( latS ) == -1 ) region.lat_begin.at( latS ) = ipS1; + if ( region.lat_begin.at( latN ) == -1 ) { + region.lat_begin.at( latN ) = ipN1; + } + if ( region.lat_begin.at( latS ) == -1 ) { + region.lat_begin.at( latS ) = ipS1; + } 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 ); @@ -623,14 +713,22 @@ 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 == region.north ) { ++region.north; } - if ( region.nb_lat_elems.at( jlat ) == 0 && latS == 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), // int(rg.nx(latS)-1)); - if ( yN == 90 && unique_pole ) region.lat_end.at( latN ) = rg.nx( latN ) - 1; - if ( yS == -90 && unique_pole ) region.lat_end.at( latS ) = rg.nx( latS ) - 1; + if ( yN == 90 && unique_pole ) { + region.lat_end.at( latN ) = rg.nx( latN ) - 1; + } + if ( yS == -90 && unique_pole ) { + region.lat_end.at( latS ) = rg.nx( latS ) - 1; + } if ( region.nb_lat_elems.at( jlat ) > 0 ) { region.lat_end.at( latN ) = std::max( region.lat_end.at( latN ), region.lat_begin.at( latN ) ); @@ -720,8 +818,9 @@ void StructuredMeshGenerator::generate_mesh( const StructuredGrid& rg, const std int nnewnodes = ( !has_point_at_north_pole && include_north_pole ? 1 : 0 ) + ( !has_point_at_south_pole && include_south_pole ? 1 : 0 ); - if ( three_dimensional && nparts != 1 ) + if ( three_dimensional && nparts != 1 ) { throw_Exception( "Cannot generate three_dimensional mesh in parallel", Here() ); + } int nnodes = region.nnodes; int ntriags = region.ntriags; int nquads = region.nquads; @@ -744,7 +843,9 @@ void StructuredMeshGenerator::generate_mesh( const StructuredGrid& rg, const std size_t node_numbering_size = nnodes; if ( remove_periodic_ghost_points ) { for ( idx_t jlat = 0; jlat < rg.ny(); ++jlat ) { - if ( region.lat_end[jlat] >= rg.nx( jlat ) ) --nnodes; + if ( region.lat_end[jlat] >= rg.nx( jlat ) ) { + --nnodes; + } } } ATLAS_ASSERT( nnodes >= nnewnodes ); @@ -784,7 +885,9 @@ void StructuredMeshGenerator::generate_mesh( const StructuredGrid& rg, const std } else { 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; } + if ( rg.nx( jlat ) > 0 ) { + periodic_glb.at( jlat ) = offset_glb.at( jlat ) + rg.nx( jlat ) - 1; + } } } int max_glb_idx = n; @@ -863,8 +966,9 @@ void StructuredMeshGenerator::generate_mesh( const StructuredGrid& rg, const std } else // No renumbering { - for ( idx_t jnode = 0; jnode < nnodes; ++jnode ) + for ( idx_t jnode = 0; jnode < nnodes; ++jnode ) { node_numbering.at( jnode ) = jnode; + } } idx_t jnode = 0; @@ -883,7 +987,9 @@ void StructuredMeshGenerator::generate_mesh( const StructuredGrid& rg, const std double x = rg.x( jlon, jlat ); // std::cout << "jlat = " << jlat << "; jlon = " << jlon << "; x = " << // x << std::endl; - if ( stagger && ( jlat + 1 ) % 2 == 0 ) x += 180. / static_cast( rg.nx( jlat ) ); + if ( stagger && ( jlat + 1 ) % 2 == 0 ) { + x += 180. / static_cast( rg.nx( jlat ) ); + } xy( inode, XX ) = x; xy( inode, YY ) = y; @@ -919,7 +1025,9 @@ void StructuredMeshGenerator::generate_mesh( const StructuredGrid& rg, const std 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 ) ); + if ( stagger && ( jlat + 1 ) % 2 == 0 ) { + x += 180. / static_cast( rg.nx( jlat ) ); + } xy( inode, XX ) = x; xy( inode, YY ) = y; @@ -1046,8 +1154,12 @@ void StructuredMeshGenerator::generate_mesh( const StructuredGrid& rg, const std quad_nodes[3] = node_numbering.at( offset_loc.at( ilatN ) + elem( 3 ) - region.lat_begin.at( jlatN ) ); if ( three_dimensional && periodic_east_west ) { - 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 ) ); + 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++; @@ -1066,8 +1178,12 @@ void StructuredMeshGenerator::generate_mesh( const StructuredGrid& rg, const std triag_nodes[2] = node_numbering.at( offset_loc.at( ilatS ) + elem( 2 ) - region.lat_begin.at( jlatS ) ); if ( three_dimensional && periodic_east_west ) { - 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 ) ); + 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 @@ -1079,8 +1195,12 @@ void StructuredMeshGenerator::generate_mesh( const StructuredGrid& rg, const std triag_nodes[2] = node_numbering.at( offset_loc.at( ilatN ) + elem( 3 ) - region.lat_begin.at( jlatN ) ); if ( three_dimensional && periodic_east_west ) { - 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 ) ); + 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++; @@ -1098,7 +1218,9 @@ void StructuredMeshGenerator::generate_mesh( const StructuredGrid& rg, const std 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; + 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 ); triag_nodes[2] = node_numbering.at( offset_loc.at( ilat ) + ip3 ); @@ -1139,7 +1261,9 @@ void StructuredMeshGenerator::generate_mesh( const StructuredGrid& rg, const std cells_part( jcell ) = mypart; Topology::set( cells_flags( jcell ), Topology::PATCH ); - if ( jbackward == jforward + 2 ) break; + if ( jbackward == jforward + 2 ) { + break; + } if ( forward ) { ++jforward; @@ -1163,8 +1287,9 @@ void StructuredMeshGenerator::generate_mesh( const StructuredGrid& rg, const std triag_nodes[0] = node_numbering.at( jsouth + ip1 ); triag_nodes[1] = node_numbering.at( offset_loc.at( ilat ) + ip2 ); triag_nodes[2] = node_numbering.at( offset_loc.at( ilat ) + ip3 ); - if ( three_dimensional && ip2 == rg.nx( jlat ) ) + if ( three_dimensional && ip2 == rg.nx( jlat ) ) { triag_nodes[1] = node_numbering.at( offset_loc.at( ilat ) + 0 ); + } node_connectivity.set( jcell, triag_nodes ); cells_glb_idx( jcell ) = jcell + 1; cells_part( jcell ) = mypart; @@ -1202,7 +1327,9 @@ void StructuredMeshGenerator::generate_mesh( const StructuredGrid& rg, const std cells_part( jcell ) = mypart; Topology::set( cells_flags( jcell ), Topology::PATCH ); - if ( jbackward == jforward + 2 ) break; + if ( jbackward == jforward + 2 ) { + break; + } if ( forward ) { ++jforward; diff --git a/src/atlas/numerics/Nabla.cc b/src/atlas/numerics/Nabla.cc index 9622c2aae..4423d351f 100644 --- a/src/atlas/numerics/Nabla.cc +++ b/src/atlas/numerics/Nabla.cc @@ -127,8 +127,9 @@ const NablaImpl* NablaFactory::build( const Method& method, const eckit::Paramet if ( j == m->end() ) { Log::error() << "No NablaFactory for [" << method.name() << "]" << '\n'; Log::error() << "NablaFactories are:" << '\n'; - for ( j = m->begin(); j != m->end(); ++j ) + for ( j = m->begin(); j != m->end(); ++j ) { Log::error() << " " << ( *j ).first << '\n'; + } throw_Exception( std::string( "No NablaFactory called " ) + method.name() ); } diff --git a/src/atlas/numerics/fvm/Method.cc b/src/atlas/numerics/fvm/Method.cc index 76204a930..91f15dd0e 100644 --- a/src/atlas/numerics/fvm/Method.cc +++ b/src/atlas/numerics/fvm/Method.cc @@ -75,7 +75,9 @@ void Method::setup() { ATLAS_TRACE( "fvm::Method::setup " ); util::Config config; config.set( "halo", halo_.size() ); - if ( levels_ ) config.set( "levels", levels_ ); + if ( levels_ ) { + config.set( "levels", levels_ ); + } node_columns_ = functionspace::NodeColumns( mesh(), config ); edge_columns_ = functionspace::EdgeColumns( mesh(), config ); @@ -104,11 +106,14 @@ void Method::setup() { 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 ) + if ( jnode == ip1 ) { node2edge_sign( jnode, jedge ) = 1.; + } else { node2edge_sign( jnode, jedge ) = -1.; - if ( is_pole_edge( iedge ) ) node2edge_sign( jnode, jedge ) = 1.; + if ( is_pole_edge( iedge ) ) { + node2edge_sign( jnode, jedge ) = 1.; + } } } } diff --git a/src/atlas/numerics/fvm/Nabla.cc b/src/atlas/numerics/fvm/Nabla.cc index 045b5b749..98c883882 100644 --- a/src/atlas/numerics/fvm/Nabla.cc +++ b/src/atlas/numerics/fvm/Nabla.cc @@ -39,7 +39,9 @@ static NablaBuilder __fvm_nabla( "fvm" ); Nabla::Nabla( const numerics::Method& method, const eckit::Parametrisation& p ) : atlas::numerics::NablaImpl( method, p ) { fvm_ = dynamic_cast( &method ); - if ( !fvm_ ) throw_Exception( "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; fvm_->attach(); @@ -60,16 +62,21 @@ void Nabla::setup() { std::vector tmp( nedges ); idx_t c( 0 ); for ( idx_t jedge = 0; jedge < nedges; ++jedge ) { - if ( is_pole_edge( jedge ) ) tmp[c++] = jedge; + if ( is_pole_edge( jedge ) ) { + tmp[c++] = jedge; + } } pole_edges_.clear(); pole_edges_.reserve( c ); - for ( idx_t jedge = 0; jedge < c; ++jedge ) + for ( idx_t jedge = 0; jedge < c; ++jedge ) { pole_edges_.push_back( tmp[jedge] ); + } } void Nabla::gradient( const Field& field, Field& grad_field ) const { - if ( field.variables() > 1 ) { return gradient_of_vector( field, grad_field ); } + if ( field.variables() > 1 ) { + return gradient_of_vector( field, grad_field ); + } else { return gradient_of_scalar( field, grad_field ); } @@ -86,8 +93,9 @@ void Nabla::gradient_of_scalar( const Field& scalar_field, Field& grad_field ) c 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 ) + if ( ( grad_field.levels() ? grad_field.levels() : 1 ) != nlev ) { 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() ) @@ -160,8 +168,9 @@ void Nabla::gradient_of_vector( const Field& vector_field, Field& grad_field ) c 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 ) + if ( vector_field.levels() != nlev ) { throw_AssertionFailed( "gradient field should have same number of levels", Here() ); + } const auto vector = vector_field.levels() @@ -266,8 +275,9 @@ void Nabla::divergence( const Field& vector_field, Field& div_field ) const { 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 ) + if ( div_field.levels() != nlev ) { throw_AssertionFailed( "divergence field should have same number of levels", Here() ); + } const auto vector = vector_field.levels() @@ -350,7 +360,9 @@ void Nabla::curl( const Field& vector_field, Field& curl_field ) const { 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() ); + if ( curl_field.levels() != nlev ) { + throw_AssertionFailed( "curl field should have same number of levels", Here() ); + } const auto vector = vector_field.levels() @@ -425,7 +437,9 @@ void Nabla::laplacian( const Field& scalar, Field& lapl ) const { Field grad( fvm_->node_columns().createField( option::name( "grad" ) | option::levels( scalar.levels() ) | option::variables( 2 ) ) ); gradient( scalar, grad ); - if ( fvm_->node_columns().halo().size() < 2 ) fvm_->node_columns().haloExchange( grad ); + if ( fvm_->node_columns().halo().size() < 2 ) { + fvm_->node_columns().haloExchange( grad ); + } divergence( grad, lapl ); } diff --git a/src/atlas/option/Options.cc b/src/atlas/option/Options.cc index 922f9dd97..d9b2472d3 100644 --- a/src/atlas/option/Options.cc +++ b/src/atlas/option/Options.cc @@ -65,7 +65,9 @@ radius::radius( double _radius ) { } radius::radius( const std::string& key ) { - if ( key == "Earth" ) { set( "radius", util::Earth::radius() ); } + if ( key == "Earth" ) { + set( "radius", util::Earth::radius() ); + } else { ATLAS_NOTIMPLEMENTED; } diff --git a/src/atlas/output/Gmsh.cc b/src/atlas/output/Gmsh.cc index d977ebb7b..f33fe4c4d 100644 --- a/src/atlas/output/Gmsh.cc +++ b/src/atlas/output/Gmsh.cc @@ -46,12 +46,16 @@ std::string GmshFileStream::parallelPathName( const PathName& path, int part ) { GmshFileStream::GmshFileStream( const PathName& file_path, const char* mode, int part ) { PathName par_path( file_path ); std::ios_base::openmode omode = std::ios_base::out; - if ( std::string( mode ) == "w" ) + if ( std::string( mode ) == "w" ) { omode = std::ios_base::out; - else if ( std::string( mode ) == "a" ) + } + else if ( std::string( mode ) == "a" ) { omode = std::ios_base::app; + } - if ( part < 0 || mpi::comm().size() == 1 ) { std::ofstream::open( file_path.localPath(), omode ); } + if ( part < 0 || mpi::comm().size() == 1 ) { + std::ofstream::open( file_path.localPath(), omode ); + } else { if ( mpi::comm().rank() == 0 ) { PathName par_path( file_path ); @@ -118,11 +122,15 @@ detail::GmshIO writer( const Gmsh::Configuration& c ) { std::ios_base::openmode openmode( const Gmsh::Configuration& c ) { std::ios_base::openmode omode( std::ios_base::out ); - if ( std::string( c.openmode ) == "w" ) + if ( std::string( c.openmode ) == "w" ) { omode = std::ios_base::out; - else if ( std::string( c.openmode ) == "a" ) + } + else if ( std::string( c.openmode ) == "a" ) { omode = std::ios_base::app; - if ( c.binary ) omode |= std::ios::binary; + } + if ( c.binary ) { + omode |= std::ios::binary; + } return omode; } diff --git a/src/atlas/output/Output.cc b/src/atlas/output/Output.cc index 8837ad2e6..2b3ee0e27 100644 --- a/src/atlas/output/Output.cc +++ b/src/atlas/output/Output.cc @@ -78,7 +78,9 @@ OutputFactory::OutputFactory( const std::string& name ) : name_( name ) { pthread_once( &once, init ); eckit::AutoLock lock( local_mutex ); - if ( m->find( name ) != m->end() ) { throw_Exception( "Duplicate OutputFactory entry " + name ); } + if ( m->find( name ) != m->end() ) { + throw_Exception( "Duplicate OutputFactory entry " + name ); + } ( *m )[name] = this; } @@ -111,8 +113,9 @@ const OutputImpl* OutputFactory::build( const std::string& name, Stream& stream if ( j == m->end() ) { Log::error() << "No OutputFactory for [" << name << "]" << std::endl; Log::error() << "OutputFactories are:" << std::endl; - for ( j = m->begin(); j != m->end(); ++j ) + for ( j = m->begin(); j != m->end(); ++j ) { Log::error() << " " << ( *j ).first << std::endl; + } throw_Exception( std::string( "No OutputFactory called " ) + name ); } @@ -130,8 +133,9 @@ const OutputImpl* OutputFactory::build( const std::string& name, Stream& stream, if ( j == m->end() ) { Log::error() << "No OutputFactory for [" << name << "]" << std::endl; Log::error() << "OutputFactories are:" << std::endl; - for ( j = m->begin(); j != m->end(); ++j ) + for ( j = m->begin(); j != m->end(); ++j ) { Log::error() << " " << ( *j ).first << std::endl; + } throw_Exception( std::string( "No OutputFactory called " ) + name ); } diff --git a/src/atlas/output/detail/GmshIO.cc b/src/atlas/output/detail/GmshIO.cc index 7c2874301..70dc8ec4b 100644 --- a/src/atlas/output/detail/GmshIO.cc +++ b/src/atlas/output/detail/GmshIO.cc @@ -54,7 +54,9 @@ class GmshFile : public std::ofstream { 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 ); } + 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 ); @@ -108,13 +110,17 @@ template array::LocalView make_level_view( const Field& field, int ndata, int jlev ) { using namespace array; if ( field.levels() ) { - if ( field.variables() ) { return make_view( field ).slice( Range::to( ndata ), jlev, Range::all() ); } + if ( field.variables() ) { + return make_view( field ).slice( Range::to( ndata ), jlev, Range::all() ); + } else { return make_view( field ).slice( Range::to( ndata ), jlev, Range::dummy() ); } } else { - if ( field.variables() ) { return make_view( field ).slice( Range::to( ndata ), Range::all() ); } + if ( field.variables() ) { + return make_view( field ).slice( Range::to( ndata ), Range::all() ); + } else { return make_view( field ).slice( Range::to( ndata ), Range::dummy() ); } @@ -135,10 +141,12 @@ void write_level( std::ostream& out, const array::ArrayView gidx, std::vector data_vec( 3, 0. ); for ( idx_t n = 0; n < ndata; ++n ) { out << gidx( n ); - for ( idx_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 ) + } + for ( int v = 0; v < 3; ++v ) { out << " " << data_vec[v]; + } out << "\n"; } } @@ -152,8 +160,9 @@ void write_level( std::ostream& out, const array::ArrayView gidx, } } out << gidx( n ); - for ( int v = 0; v < 9; ++v ) + for ( int v = 0; v < 9; ++v ) { out << " " << data_vec[v]; + } out << "\n"; } } @@ -165,8 +174,9 @@ void write_level( std::ostream& out, const array::ArrayView gidx, } } out << gidx( n ); - for ( int v = 0; v < 9; ++v ) + for ( int v = 0; v < 9; ++v ) { out << " " << data_vec[v]; + } out << "\n"; } } @@ -185,8 +195,9 @@ std::vector get_levels( int nlev, const Metadata& gmsh_options ) { gmsh_options.get( "levels", gmsh_levels ); if ( gmsh_levels.empty() || nlev == 1 ) { lev.resize( nlev ); - for ( int ilev = 0; ilev < nlev; ++ilev ) + for ( int ilev = 0; ilev < nlev; ++ilev ) { lev[ilev] = ilev; + } } else { lev = gmsh_levels; @@ -214,14 +225,18 @@ int field_step( const Field& field ) { } int field_vars( int nvars ) { - if ( nvars == 1 ) + if ( nvars == 1 ) { return nvars; - else if ( nvars <= 3 ) + } + else if ( nvars <= 3 ) { return 3; - else if ( nvars <= 9 ) + } + else if ( nvars <= 9 ) { return 9; - else + } + else { return nvars; + } } } // namespace @@ -318,7 +333,9 @@ void write_field_nodes( const Metadata& gmsh_options, const functionspace::Struc int jlev = lev[ilev]; char field_lev[6] = {0, 0, 0, 0, 0, 0}; - if ( field.levels() ) { print_field_lev( field_lev, jlev ); } + if ( field.levels() ) { + print_field_lev( field_lev, jlev ); + } out << "$NodeData\n"; out << "1\n"; @@ -510,9 +527,15 @@ Mesh GmshIO::read( const PathName& file_path ) const { namespace { 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(); + 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_Exception( "Element type not supported", Here() ); } } // namespace @@ -520,19 +543,23 @@ mesh::ElementType* make_element_type( int type ) { 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_CantOpenFile( file_path ); + if ( !file.is_open() ) { + throw_CantOpenFile( file_path ); + } std::string line; - while ( line != "$MeshFormat" ) + while ( line != "$MeshFormat" ) { std::getline( file, line ); + } double version; int binary; int size_of_real; file >> version >> binary >> size_of_real; - while ( line != "$Nodes" ) + while ( line != "$Nodes" ) { std::getline( file, line ); + } // Create nodes idx_t nb_nodes; @@ -555,8 +582,9 @@ void GmshIO::read( const PathName& file_path, Mesh& mesh ) const { double xmax = -std::numeric_limits::max(); double zmax = -std::numeric_limits::max(); gidx_t max_glb_idx = 0; - while ( binary && file.peek() == '\n' ) + while ( binary && file.peek() == '\n' ) { file.get(); + } for ( idx_t n = 0; n < nb_nodes; ++n ) { if ( binary ) { file.read( reinterpret_cast( &g ), sizeof( int ) ); @@ -584,19 +612,22 @@ void GmshIO::read( const PathName& file_path, Mesh& mesh ) const { coords( n, YY ) *= rad2deg; } } - for ( int i = 0; i < 3; ++i ) + for ( int i = 0; i < 3; ++i ) { std::getline( file, line ); + } int nb_elements = 0; - while ( line != "$Elements" ) + while ( line != "$Elements" ) { std::getline( file, line ); + } file >> nb_elements; if ( binary ) { - while ( file.peek() == '\n' ) + while ( file.peek() == '\n' ) { file.get(); + } int accounted_elems = 0; while ( accounted_elems < nb_elements ) { int header[3]; @@ -629,8 +660,9 @@ void GmshIO::read( const PathName& file_path, Mesh& mesh ) const { part = 0; egidx( e ) = data[0]; epart( e ) = part; - for ( size_t n = 0; n < nnodes_per_elem; ++n ) + for ( size_t n = 0; n < nnodes_per_elem; ++n ) { conn.set( e, n, glb_to_loc[data[1 + ntags + n]] ); + } } } } @@ -677,12 +709,14 @@ void GmshIO::read( const PathName& file_path, Mesh& mesh ) const { int ntags, tags[100]; for ( int e = 0; e < nb_elements; ++e ) { file >> g >> etype >> ntags; - for ( int t = 0; t < ntags; ++t ) + for ( int t = 0; t < ntags; ++t ) { file >> tags[t]; + } int part = 0; - if ( ntags > 3 ) + if ( ntags > 3 ) { part = std::max( part, *std::max_element( tags + 3, tags + ntags - 1 ) ); // one positive, others negative + } idx_t enodes[4]; @@ -752,14 +786,18 @@ void GmshIO::write( const Mesh& mesh, const PathName& file_path ) const { bool binary = !options.get( "ascii" ); openmode mode = std::ios::out; - if ( binary ) mode = std::ios::out | std::ios::binary; + if ( binary ) { + mode = std::ios::out | std::ios::binary; + } GmshFile file( file_path, mode, part ); // Header - if ( binary ) + if ( binary ) { write_header_binary( file ); - else + } + else { write_header_ascii( file ); + } // Nodes const idx_t nb_nodes = nodes.size(); @@ -769,8 +807,9 @@ void GmshIO::write( const Mesh& mesh, const PathName& file_path ) const { for ( idx_t n = 0; n < nb_nodes; ++n ) { gidx_t g = glb_idx( n ); - for ( idx_t d = 0; d < surfdim; ++d ) + for ( idx_t d = 0; d < surfdim; ++d ) { xyz[d] = coords( n, d ); + } if ( binary ) { file.write( reinterpret_cast( &g ), sizeof( gidx_t ) ); @@ -780,15 +819,21 @@ void GmshIO::write( const Mesh& mesh, const PathName& file_path ) const { file << g << " " << xyz[XX] << " " << xyz[YY] << " " << xyz[ZZ] << "\n"; } } - if ( binary ) file << "\n"; + if ( binary ) { + file << "\n"; + } file << "$EndNodes\n"; // Elements file << "$Elements\n"; { std::vector grouped_elements; - if ( options.get( "elements" ) ) grouped_elements.push_back( &mesh.cells() ); - if ( options.get( "edges" ) ) grouped_elements.push_back( &mesh.edges() ); + if ( options.get( "elements" ) ) { + grouped_elements.push_back( &mesh.cells() ); + } + if ( options.get( "edges" ) ) { + grouped_elements.push_back( &mesh.edges() ); + } idx_t nb_elements( 0 ); for ( const mesh::HybridElements* hybrid : grouped_elements ) { @@ -799,12 +844,18 @@ void GmshIO::write( const Mesh& mesh, const PathName& file_path ) const { 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; + 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; } + if ( exclude( e ) ) { + --nb_elements; + } } } @@ -815,14 +866,18 @@ void GmshIO::write( const Mesh& mesh, const PathName& file_path ) const { const mesh::Elements& elements = hybrid->elements( etype ); const mesh::ElementType& element_type = elements.element_type(); int gmsh_elem_type; - if ( element_type.name() == "Line" ) + if ( element_type.name() == "Line" ) { gmsh_elem_type = 1; - else if ( element_type.name() == "Triangle" ) + } + else if ( element_type.name() == "Triangle" ) { gmsh_elem_type = 2; - else if ( element_type.name() == "Quadrilateral" ) + } + else if ( element_type.name() == "Quadrilateral" ) { gmsh_elem_type = 3; - else + } + else { ATLAS_NOTIMPLEMENTED; + } const mesh::BlockConnectivity& node_connectivity = elements.node_connectivity(); @@ -834,7 +889,9 @@ void GmshIO::write( const Mesh& mesh, const PathName& file_path ) const { idx_t nb_elems = elements.size(); if ( !include_ghost ) { for ( idx_t elem = 0; elem < elements.size(); ++elem ) { - if ( elems_halo( elem ) ) --nb_elems; + if ( elems_halo( elem ) ) { + --nb_elems; + } } } @@ -852,8 +909,9 @@ void GmshIO::write( const Mesh& mesh, const PathName& file_path ) const { if ( include_ghost || !elems_halo( elem ) ) { data[0] = elems_glb_idx( elem ); data[4] = elems_partition( elem ); - for ( idx_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 ); } } @@ -875,7 +933,9 @@ void GmshIO::write( const Mesh& mesh, const PathName& file_path ) const { } } } - if ( binary ) file << "\n"; + if ( binary ) { + file << "\n"; + } file << "$EndElements\n"; file << std::flush; @@ -973,12 +1033,16 @@ void GmshIO::write_delegate( const FieldSet& fieldset, const functionspace::Node const PathName& file_path, openmode mode ) const { bool is_new_file = ( mode != std::ios_base::app || !file_path.exists() ); bool binary( !options.get( "ascii" ) ); - if ( binary ) mode |= std::ios_base::binary; + 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() ) ); // Header - if ( is_new_file ) { write_header_ascii( file ); } + if ( is_new_file ) { + write_header_ascii( file ); + } // field::Fields for ( idx_t field_idx = 0; field_idx < fieldset.size(); ++field_idx ) { @@ -1010,14 +1074,18 @@ void GmshIO::write_delegate( const FieldSet& fieldset, const functionspace::Stru bool is_new_file = ( mode != std::ios_base::app || !file_path.exists() ); bool binary( !options.get( "ascii" ) ); - if ( binary ) mode |= std::ios_base::binary; + 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() ) ); // Header - if ( is_new_file ) write_header_ascii( file ); + if ( is_new_file ) { + write_header_ascii( file ); + } // field::Fields for ( idx_t field_idx = 0; field_idx < fieldset.size(); ++field_idx ) { @@ -1047,24 +1115,30 @@ void GmshIO::write_delegate( const FieldSet& fieldset, const functionspace::Stru // ---------------------------------------------------------------------------- void GmshIO::write( const FieldSet& fieldset, const FunctionSpace& funcspace, const eckit::PathName& file_path, openmode mode ) const { - if ( functionspace::NodeColumns( funcspace ) ) + if ( functionspace::NodeColumns( funcspace ) ) { write_delegate( fieldset, functionspace::NodeColumns( funcspace ), file_path, mode ); - else if ( functionspace::StructuredColumns( funcspace ) ) + } + else if ( functionspace::StructuredColumns( funcspace ) ) { write_delegate( fieldset, functionspace::StructuredColumns( funcspace ), file_path, mode ); - else + } + else { ATLAS_NOTIMPLEMENTED; + } } // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- void GmshIO::write( const Field& field, const FunctionSpace& funcspace, const eckit::PathName& file_path, openmode mode ) const { - if ( functionspace::NodeColumns( funcspace ) ) + if ( functionspace::NodeColumns( funcspace ) ) { write_delegate( field, functionspace::NodeColumns( funcspace ), file_path, mode ); - else if ( functionspace::StructuredColumns( funcspace ) ) + } + else if ( functionspace::StructuredColumns( funcspace ) ) { write_delegate( field, functionspace::StructuredColumns( funcspace ), file_path, mode ); - else + } + else { ATLAS_NOTIMPLEMENTED; + } } // ---------------------------------------------------------------------------- diff --git a/src/atlas/output/detail/PointCloudIO.cc b/src/atlas/output/detail/PointCloudIO.cc index d5b64d2ee..8ae11289c 100644 --- a/src/atlas/output/detail/PointCloudIO.cc +++ b/src/atlas/output/detail/PointCloudIO.cc @@ -43,7 +43,9 @@ std::string sanitize_field_name( const std::string& s ) { std::replace_if( r.begin(), r.end(), ::isspace, '_' ); r.erase( r.find_last_not_of( '_' ) + 1 ); r.erase( 0, r.find_first_not_of( '_' ) ); - if ( !r.length() ) r = "_"; + if ( !r.length() ) { + r = "_"; + } return r; } @@ -70,7 +72,9 @@ 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_CantOpenFile( path.asString() ); + if ( !f.is_open() ) { + throw_CantOpenFile( path.asString() ); + } // header, part 1: // determine number of rows/columns @@ -85,8 +89,12 @@ Mesh PointCloudIO::read( const eckit::PathName& path, std::vector& << ")"; throw_Exception( errmsg.str(), Here() ); } - 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)" ); + 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( static_cast( nb_pts ) ); @@ -137,8 +145,9 @@ Mesh PointCloudIO::read( const eckit::PathName& path, std::vector& lonlat( i, LAT ) = pxy.y(); glb_idx( i ) = i + 1; - for ( j = 0; iss && j < nb_fld; ++j ) + for ( j = 0; iss && j < nb_fld; ++j ) { iss >> fields[j]( i ); + } if ( j < nb_fld ) { oss << " Invalid number of fields in data section, on line " << ( i + 1 ) << ", read " << j << " fields, expected " << nb_fld << "."; @@ -172,7 +181,9 @@ 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_Exception( 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) @@ -190,22 +201,26 @@ void PointCloudIO::write( const eckit::PathName& path, const Mesh& mesh ) { } std::ofstream f( path.asString().c_str() ); - if ( !f.is_open() ) throw_CantOpenFile( path.asString() ); + if ( !f.is_open() ) { + throw_CantOpenFile( path.asString() ); + } const size_t Npts = lonlat.shape( 0 ); const size_t Nfld = vfvalues.size(); // header f << "PointCloudIO\t" << Npts << '\t' << ( 2 + Nfld ) << "\tlon\tlat"; - for ( size_t j = 0; j < Nfld; ++j ) + for ( size_t j = 0; j < Nfld; ++j ) { f << '\t' << vfnames[j]; + } f << '\n'; // data for ( size_t i = 0; i < Npts; ++i ) { f << lonlat( i, 0 ) << '\t' << lonlat( i, 1 ); - for ( size_t j = 0; j < Nfld; ++j ) + for ( size_t j = 0; j < Nfld; ++j ) { f << '\t' << vfvalues[j]( i ); + } f << '\n'; } @@ -225,7 +240,9 @@ void PointCloudIO::write( const eckit::PathName& path, const FieldSet& fieldset, ATLAS_ASSERT( fieldset.size() ); array::ArrayView lonlat = array::make_view( function_space.nodes().xy() ); - if ( !lonlat.size() ) throw_Exception( 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) @@ -242,13 +259,16 @@ void PointCloudIO::write( const eckit::PathName& path, const FieldSet& fieldset, } std::ofstream f( path.asString().c_str() ); - if ( !f.is_open() ) throw_CantOpenFile( path.asString() ); + if ( !f.is_open() ) { + throw_CantOpenFile( path.asString() ); + } const size_t Npts = lonlat.shape( 0 ), Nfld = vfvalues.size(); // header f << "PointCloudIO\t" << Npts << '\t' << ( 2 + Nfld ) << "\tlon\tlat"; - for ( size_t j = 0; j < Nfld; ++j ) + for ( size_t j = 0; j < Nfld; ++j ) { f << '\t' << vfnames[j]; + } f << '\n'; f.precision( std::numeric_limits::digits10 ); @@ -256,8 +276,9 @@ void PointCloudIO::write( const eckit::PathName& path, const FieldSet& fieldset, // data for ( size_t i = 0; i < Npts; ++i ) { f << lonlat( i, 0 ) << '\t' << lonlat( i, 1 ); - for ( size_t j = 0; j < Nfld; ++j ) + for ( size_t j = 0; j < Nfld; ++j ) { f << '\t' << vfvalues[j]( i ); + } f << '\n'; } @@ -268,14 +289,17 @@ 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_Exception( msg + "number of points inconsistent (failed: #lon == #lat)" ); - if ( Nfld != vfnames.size() ) + if ( Npts != lat.size() ) { + throw_Exception( msg + "number of points inconsistent (failed: #lon == #lat)" ); + } + if ( Nfld != vfnames.size() ) { throw_Exception( msg + "number of fields inconsistent (failed: #vfvalues == #vfnames)" ); - for ( size_t j = 0; j < Nfld; ++j ) - if ( Npts != vfvalues[j]->size() ) + } + for ( size_t j = 0; j < Nfld; ++j ) { + if ( Npts != vfvalues[j]->size() ) { throw_Exception( msg + "number of points inconsistent (failed: " "#lon == #lat == #*vfvalues[])" ); + } + } std::ofstream f( path.asString().c_str() ); - if ( !f.is_open() ) throw_CantOpenFile( path.asString() ); + if ( !f.is_open() ) { + throw_CantOpenFile( path.asString() ); + } // header f << "PointCloudIO\t" << Npts << '\t' << ( 2 + Nfld ) << "\tlon\tlat"; - for ( size_t j = 0; j < Nfld; ++j ) + for ( size_t j = 0; j < Nfld; ++j ) { f << '\t' << sanitize_field_name( vfnames[j] ); + } f << '\n'; // data for ( size_t i = 0; i < Npts; ++i ) { f << lon[i] << '\t' << lat[i]; - for ( size_t j = 0; j < Nfld; ++j ) + for ( size_t j = 0; j < Nfld; ++j ) { f << '\t' << vfvalues[j]->operator[]( i ); + } f << '\n'; } @@ -323,24 +356,34 @@ 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_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)" ); + 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_CantOpenFile( path.asString() ); + if ( !f.is_open() ) { + throw_CantOpenFile( path.asString() ); + } // header f << "PointCloudIO\t" << Npts << '\t' << ( 2 + Nfld ) << "\tlon\tlat"; - for ( size_t j = 0; j < Nfld; ++j ) + for ( size_t j = 0; j < Nfld; ++j ) { f << '\t' << sanitize_field_name( afnames[j] ); + } f << '\n'; // data for ( size_t i = 0; i < Npts; ++i ) { f << lon[i] << '\t' << lat[i]; - for ( size_t j = 0; j < Nfld; ++j ) + for ( size_t j = 0; j < Nfld; ++j ) { f << '\t' << afvalues[j][i]; + } f << '\n'; } diff --git a/src/atlas/parallel/Checksum.h b/src/atlas/parallel/Checksum.h index 3fb0c27b8..95b61b657 100644 --- a/src/atlas/parallel/Checksum.h +++ b/src/atlas/parallel/Checksum.h @@ -84,7 +84,9 @@ 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_Exception( "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]; diff --git a/src/atlas/parallel/GatherScatter.cc b/src/atlas/parallel/GatherScatter.cc index 701ea53d0..a3016ac49 100644 --- a/src/atlas/parallel/GatherScatter.cc +++ b/src/atlas/parallel/GatherScatter.cc @@ -34,8 +34,12 @@ struct IsGhostPoint { } bool operator()( idx_t idx ) { - if ( part_[idx] != mypart_ ) return true; - if ( ridx_[idx] != base_ + idx ) return true; + if ( part_[idx] != mypart_ ) { + return true; + } + if ( ridx_[idx] != base_ + idx ) { + return true; + } return false; } int mypart_; @@ -153,7 +157,9 @@ void GatherScatter::setup( const int part[], const idx_t remote_idx[], const int idx_t jproc = node.p; glbmap_[glbdispls_[jproc] + idx[jproc]] = n++; - if ( jproc == myproc ) locmap_[idx[jproc]] = node.i; + if ( jproc == myproc ) { + locmap_[idx[jproc]] = node.i; + } ++idx[jproc]; } diff --git a/src/atlas/parallel/GatherScatter.h b/src/atlas/parallel/GatherScatter.h index 1191a1d76..74731736d 100644 --- a/src/atlas/parallel/GatherScatter.h +++ b/src/atlas/parallel/GatherScatter.h @@ -224,7 +224,9 @@ class GatherScatter : public util::Object { template void GatherScatter::gather( parallel::Field lfields[], parallel::Field gfields[], idx_t nb_fields, const idx_t root ) const { - if ( !is_setup_ ) { throw_Exception( "GatherScatter was not setup", Here() ); } + if ( !is_setup_ ) { + throw_Exception( "GatherScatter was not setup", Here() ); + } for ( idx_t jfield = 0; jfield < nb_fields; ++jfield ) { const idx_t lvar_size = @@ -254,7 +256,8 @@ void GatherScatter::gather( parallel::Field lfields[], parallel ATLAS_TRACE_MPI( GATHER ) { mpi::comm().gatherv( loc_buffer, glb_buffer, glb_counts, glb_displs, root ); } /// Unpack - if ( myproc == root ) unpack_recv_buffer( glbmap_, glb_buffer.data(), gfields[jfield] ); + if ( myproc == root ) + unpack_recv_buffer( glbmap_, glb_buffer.data(), gfields[jfield] ); } } @@ -270,7 +273,9 @@ void GatherScatter::gather( const DATA_TYPE ldata[], const idx_t lvar_strides[], template void GatherScatter::scatter( parallel::Field gfields[], parallel::Field lfields[], const idx_t nb_fields, const idx_t root ) const { - if ( !is_setup_ ) { throw_Exception( "GatherScatter was not setup", Here() ); } + if ( !is_setup_ ) { + throw_Exception( "GatherScatter was not setup", Here() ); + } for ( idx_t jfield = 0; jfield < nb_fields; ++jfield ) { const int lvar_size = @@ -292,7 +297,8 @@ void GatherScatter::scatter( parallel::Field gfields[], paralle } /// Pack - if ( myproc == root ) pack_send_buffer( gfields[jfield], glbmap_, glb_buffer.data() ); + if ( myproc == root ) + pack_send_buffer( gfields[jfield], glbmap_, glb_buffer.data() ); /// Scatter diff --git a/src/atlas/parallel/HaloExchange.cc b/src/atlas/parallel/HaloExchange.cc index 48397f91c..f22f0ea89 100644 --- a/src/atlas/parallel/HaloExchange.cc +++ b/src/atlas/parallel/HaloExchange.cc @@ -33,8 +33,12 @@ struct IsGhostPoint { } bool operator()( idx_t idx ) { - if ( part_[idx] != mypart_ ) return true; - if ( ridx_[idx] != base_ + idx ) return true; + if ( part_[idx] != mypart_ ) { + return true; + } + if ( ridx_[idx] != base_ + idx ) { + return true; + } return false; } int mypart_; @@ -74,7 +78,9 @@ void HaloExchange::setup( const int part[], const idx_t remote_idx[], const int IsGhostPoint is_ghost( part, remote_idx, base, parsize_ ); for ( int jj = 0; jj < parsize_; ++jj ) { - if ( is_ghost( jj ) ) ++recvcounts_[part[jj]]; + if ( is_ghost( jj ) ) { + ++recvcounts_[part[jj]]; + } } recvcnt_ = std::accumulate( recvcounts_.begin(), recvcounts_.end(), 0 ); @@ -127,8 +133,9 @@ void HaloExchange::setup( const int part[], const idx_t remote_idx[], const int here */ sendmap_.resize( sendcnt_ ); - for ( int jj = 0; jj < sendcnt_; ++jj ) + for ( int jj = 0; jj < sendcnt_; ++jj ) { sendmap_[jj] = recv_requests[jj]; + } is_setup_ = true; backdoor.parsize = parsize_; @@ -144,12 +151,14 @@ void execute_halo_exchange( HaloExchange* This, Value field[], int var_strides[] // slowest moving array::ArrayShape shape{This->backdoor.parsize}; - for ( int j = 0; j < var_rank; ++j ) + for ( int j = 0; j < var_rank; ++j ) { shape.push_back( var_extents[j] ); + } array::ArrayStrides strides{var_extents[0] * var_strides[0]}; - for ( int j = 0; j < var_rank; ++j ) + for ( int j = 0; j < var_rank; ++j ) { strides.push_back( var_strides[j] ); + } std::unique_ptr arr( array::Array::wrap( field, array::ArraySpec{shape, strides} ) ); diff --git a/src/atlas/parallel/HaloExchange.h b/src/atlas/parallel/HaloExchange.h index 48a46fd62..5120d7d44 100644 --- a/src/atlas/parallel/HaloExchange.h +++ b/src/atlas/parallel/HaloExchange.h @@ -104,7 +104,9 @@ class HaloExchange : public util::Object { template void HaloExchange::execute( array::Array& field, bool on_device ) const { - if ( !is_setup_ ) { throw_Exception( "HaloExchange was not setup", Here() ); } + if ( !is_setup_ ) { + throw_Exception( "HaloExchange was not setup", Here() ); + } ATLAS_TRACE( "HaloExchange", {"halo-exchange"} ); @@ -161,7 +163,9 @@ void HaloExchange::execute( array::Array& field, bool on_device ) const { /// Wait for receiving to finish ATLAS_TRACE_MPI( WAIT, "mpi-wait receive" ) { for ( int jproc = 0; jproc < nproc; ++jproc ) { - if ( recvcounts_[jproc] > 0 ) { mpi::comm().wait( recv_req[jproc] ); } + if ( recvcounts_[jproc] > 0 ) { + mpi::comm().wait( recv_req[jproc] ); + } } } @@ -171,7 +175,9 @@ void HaloExchange::execute( array::Array& field, bool on_device ) const { /// Wait for sending to finish ATLAS_TRACE_MPI( WAIT, "mpi-wait send" ) { for ( int jproc = 0; jproc < nproc; ++jproc ) { - if ( sendcounts_[jproc] > 0 ) { mpi::comm().wait( send_req[jproc] ); } + if ( sendcounts_[jproc] > 0 ) { + mpi::comm().wait( send_req[jproc] ); + } } } } diff --git a/src/atlas/parallel/mpi/Statistics.h b/src/atlas/parallel/mpi/Statistics.h index 8b8d7a422..4f30f7f16 100644 --- a/src/atlas/parallel/mpi/Statistics.h +++ b/src/atlas/parallel/mpi/Statistics.h @@ -22,7 +22,7 @@ #include "atlas/util/detail/BlackMagic.h" #undef ATLAS_TRACE_MPI -#define ATLAS_TRACE_MPI( ... ) ATLAS_TRACE_MPI_(::atlas::mpi::Trace, Here(), __VA_ARGS__ ) +#define ATLAS_TRACE_MPI( ... ) ATLAS_TRACE_MPI_( ::atlas::mpi::Trace, Here(), __VA_ARGS__ ) #define ATLAS_TRACE_MPI_( Type, location, operation, ... ) \ __ATLAS_TYPE_SCOPE( Type, location, __ATLAS_TRACE_MPI_ENUM( operation ) __ATLAS_COMMA_ARGS( __VA_ARGS__ ) ) diff --git a/src/atlas/parallel/omp/omp.cc b/src/atlas/parallel/omp/omp.cc index fa409d3de..3b3f83368 100644 --- a/src/atlas/parallel/omp/omp.cc +++ b/src/atlas/parallel/omp/omp.cc @@ -42,67 +42,87 @@ extern "C" { void atlas_omp_set_num_threads( int num_threads ) { #if ATLAS_HAVE_OMP - if ( omp_set_num_threads ) omp_set_num_threads( num_threads ); + if ( omp_set_num_threads ) { + omp_set_num_threads( num_threads ); + } #endif } int atlas_omp_get_num_threads( void ) { #if ATLAS_HAVE_OMP - if ( omp_get_num_threads ) return omp_get_num_threads(); + if ( omp_get_num_threads ) { + return omp_get_num_threads(); + } #endif return 1; } int atlas_omp_get_max_threads( void ) { #if ATLAS_HAVE_OMP - if ( omp_get_max_threads ) return omp_get_max_threads(); + if ( omp_get_max_threads ) { + return omp_get_max_threads(); + } #endif return 1; } int atlas_omp_get_thread_num( void ) { #if ATLAS_HAVE_OMP - if ( omp_get_thread_num ) return omp_get_thread_num(); + if ( omp_get_thread_num ) { + return omp_get_thread_num(); + } #endif return 0; } int atlas_omp_get_num_procs( void ) { #if ATLAS_HAVE_OMP - if ( omp_get_num_procs ) return omp_get_num_procs(); + if ( omp_get_num_procs ) { + return omp_get_num_procs(); + } #endif return 1; } int atlas_omp_in_parallel( void ) { #if ATLAS_HAVE_OMP - if ( omp_in_parallel ) return omp_in_parallel(); + if ( omp_in_parallel ) { + return omp_in_parallel(); + } #endif return 0; } void atlas_omp_set_dynamic( int dynamic_threads ) { #if ATLAS_HAVE_OMP - if ( omp_set_dynamic ) omp_set_dynamic( dynamic_threads ); + if ( omp_set_dynamic ) { + omp_set_dynamic( dynamic_threads ); + } #endif } int atlas_omp_get_dynamic( void ) { #if ATLAS_HAVE_OMP - if ( omp_get_dynamic ) return omp_get_dynamic(); + if ( omp_get_dynamic ) { + return omp_get_dynamic(); + } #endif return 0; } void atlas_omp_set_nested( int nested ) { #if ATLAS_HAVE_OMP - if ( omp_set_nested ) omp_set_nested( nested ); + if ( omp_set_nested ) { + omp_set_nested( nested ); + } #endif } int atlas_omp_get_nested( void ) { #if ATLAS_HAVE_OMP - if ( omp_get_nested ) return omp_get_nested(); + if ( omp_get_nested ) { + return omp_get_nested(); + } #endif return 0; } diff --git a/src/atlas/projection/Projection.cc b/src/atlas/projection/Projection.cc index 65acd4199..f01e8b4c9 100644 --- a/src/atlas/projection/Projection.cc +++ b/src/atlas/projection/Projection.cc @@ -50,6 +50,10 @@ bool atlas::Projection::strictlyRegional() const { return get()->strictlyRegional(); } +RectangularLonLatDomain Projection::lonlatBoundingBox( const Domain& domain ) const { + return get()->lonlatBoundingBox( domain ); +} + Projection::Spec atlas::Projection::spec() const { return get()->spec(); } diff --git a/src/atlas/projection/Projection.h b/src/atlas/projection/Projection.h index a7af6650e..8a43a8c4e 100644 --- a/src/atlas/projection/Projection.h +++ b/src/atlas/projection/Projection.h @@ -12,6 +12,7 @@ #include +#include "atlas/domain/Domain.h" #include "atlas/util/ObjectHandle.h" //--------------------------------------------------------------------------------------------------------------------- @@ -57,6 +58,7 @@ class Projection : public util::ObjectHandle PointXY xy( const PointLonLat& ) const; bool strictlyRegional() const; + RectangularLonLatDomain lonlatBoundingBox( const Domain& ) const; Spec spec() const; diff --git a/src/atlas/projection/detail/LambertAzimuthalEqualAreaProjection.cc b/src/atlas/projection/detail/LambertAzimuthalEqualAreaProjection.cc index 3668013c0..7430171c6 100644 --- a/src/atlas/projection/detail/LambertAzimuthalEqualAreaProjection.cc +++ b/src/atlas/projection/detail/LambertAzimuthalEqualAreaProjection.cc @@ -21,9 +21,9 @@ #include "atlas/runtime/Exception.h" #include "atlas/util/Config.h" #include "atlas/util/Constants.h" +#include "atlas/util/CoordinateEnums.h" #include "atlas/util/Earth.h" - namespace atlas { namespace projection { namespace detail { @@ -31,41 +31,41 @@ namespace detail { LambertAzimuthalEqualAreaProjection::LambertAzimuthalEqualAreaProjection( const eckit::Parametrisation& params ) : radius_( util::Earth::radius() ) { - if ( !params.get( "radius", radius_ ) ) radius_ = util::Earth::radius(); - ATLAS_ASSERT( params.get( "central_longitude", reference_[0] ) ); - ATLAS_ASSERT( params.get( "standard_parallel", reference_[1] ) ); + ATLAS_ASSERT( params.get( "central_longitude", reference_[LON] ) ); + ATLAS_ASSERT( params.get( "standard_parallel", reference_[LAT] ) ); + params.get( "radius", radius_ = util::Earth::radius() ); - lambda0_ = util::Constants::degreesToRadians() * reference_[0]; - phi1_ = util::Constants::degreesToRadians() * reference_[1]; + lambda0_ = util::Constants::degreesToRadians() * reference_[LON]; + phi1_ = util::Constants::degreesToRadians() * reference_[LAT]; sin_phi1_ = std::sin( phi1_ ); cos_phi1_ = std::cos( phi1_ ); } void LambertAzimuthalEqualAreaProjection::lonlat2xy( double crd[] ) const { - double dlambda = util::Constants::degreesToRadians() * ( crd[0] - reference_.lon() ); + double dlambda = util::Constants::degreesToRadians() * ( crd[LON] - reference_.lon() ); double cos_dlambda = std::cos( dlambda ); double sin_dlambda = std::sin( dlambda ); - double phi = util::Constants::degreesToRadians() * crd[1]; + double phi = util::Constants::degreesToRadians() * crd[LAT]; double sin_phi = std::sin( phi ); double cos_phi = std::cos( phi ); double kp = radius_ * std::sqrt( 2. / ( 1. + sin_phi1_ * sin_phi + cos_phi1_ * cos_phi * cos_dlambda ) ); - crd[0] = kp * cos_phi * sin_dlambda; - crd[1] = kp * ( cos_phi1_ * sin_phi - sin_phi1_ * cos_phi * cos_dlambda ); + crd[XX] = kp * cos_phi * sin_dlambda; + crd[YY] = kp * ( cos_phi1_ * sin_phi - sin_phi1_ * cos_phi * cos_dlambda ); } void LambertAzimuthalEqualAreaProjection::xy2lonlat( double crd[] ) const { - const double& x = crd[0]; - const double& y = crd[1]; + const double& x = crd[XX]; + const double& y = crd[YY]; const double rho = std::sqrt( x * x + y * y ); - if ( eckit::types::is_approximately_equal( rho, 0. ) ) { - crd[0] = reference_[0]; - crd[1] = reference_[1]; + if ( std::abs( rho ) < 1.e-12 ) { + crd[LON] = reference_[LON]; + crd[LAT] = reference_[LAT]; return; } @@ -73,19 +73,19 @@ void LambertAzimuthalEqualAreaProjection::xy2lonlat( double crd[] ) const { double cos_c = std::cos( c ); double sin_c = std::sin( c ); - double lon_r = lambda0_ + std::atan2( x * sin_c, rho * cos_phi1_ * cos_c - y * sin_phi1_ * sin_c ); - double lat_r = std::asin( cos_c * sin_phi1_ + y * sin_c * cos_phi1_ / rho ); + double lon_r = lambda0_ + std::atan2( x * sin_c, rho * cos_phi1_ * cos_c - y * sin_phi1_ * sin_c ); + double sin_lat_r = cos_c * sin_phi1_ + y * sin_c * cos_phi1_ / rho; - crd[0] = lon_r * util::Constants::radiansToDegrees(); - crd[1] = lat_r * util::Constants::radiansToDegrees(); + crd[LON] = lon_r * util::Constants::radiansToDegrees(); + crd[LAT] = sin_lat_r > 1 ? 90 : sin_lat_r < -1 ? -90 : util::Constants::radiansToDegrees() * std::asin( sin_lat_r ); } LambertAzimuthalEqualAreaProjection::Spec LambertAzimuthalEqualAreaProjection::spec() const { Spec proj; proj.set( "type", static_type() ); - proj.set( "central_longitude", reference_[0] ); - proj.set( "standard_parallel", reference_[1] ); + proj.set( "central_longitude", reference_[LON] ); + proj.set( "standard_parallel", reference_[LAT] ); proj.set( "radius", radius_ ); return proj; @@ -95,8 +95,8 @@ LambertAzimuthalEqualAreaProjection::Spec LambertAzimuthalEqualAreaProjection::s void LambertAzimuthalEqualAreaProjection::hash( eckit::Hash& h ) const { h.add( static_type() ); h.add( radius_ ); - h.add( reference_[0] ); - h.add( reference_[1] ); + h.add( reference_[LON] ); + h.add( reference_[LAT] ); } diff --git a/src/atlas/projection/detail/LambertAzimuthalEqualAreaProjection.h b/src/atlas/projection/detail/LambertAzimuthalEqualAreaProjection.h index 4de3c120d..095ffc7af 100644 --- a/src/atlas/projection/detail/LambertAzimuthalEqualAreaProjection.h +++ b/src/atlas/projection/detail/LambertAzimuthalEqualAreaProjection.h @@ -8,17 +8,15 @@ * nor does it submit to any jurisdiction. */ - #pragma once +#include "atlas/domain.h" #include "atlas/projection/detail/ProjectionImpl.h" - namespace atlas { namespace projection { namespace detail { - class LambertAzimuthalEqualAreaProjection final : public ProjectionImpl { public: // constructor @@ -26,8 +24,6 @@ class LambertAzimuthalEqualAreaProjection final : public ProjectionImpl { // projection name static std::string static_type() { return "lambert_azimuthal_equal_area"; } - - // projection name std::string type() const override { return static_type(); } // projection and inverse projection @@ -35,6 +31,9 @@ class LambertAzimuthalEqualAreaProjection final : public ProjectionImpl { void lonlat2xy( double crd[] ) const override; bool strictlyRegional() const override { return true; } + RectangularLonLatDomain lonlatBoundingBox( const Domain& domain ) const override { + return ProjectionImpl::lonlatBoundingBox( domain ); + } // specification Spec spec() const override; @@ -53,7 +52,6 @@ class LambertAzimuthalEqualAreaProjection final : public ProjectionImpl { double cos_phi1_; }; - } // namespace detail } // namespace projection } // namespace atlas diff --git a/src/atlas/projection/detail/LambertProjection.cc b/src/atlas/projection/detail/LambertProjection.cc index f579e204f..9f892eda5 100644 --- a/src/atlas/projection/detail/LambertProjection.cc +++ b/src/atlas/projection/detail/LambertProjection.cc @@ -44,12 +44,20 @@ namespace detail { // constructors LambertProjection::LambertProjection( const eckit::Parametrisation& params ) { // check presence of radius - if ( !params.get( "radius", radius_ ) ) radius_ = util::Earth::radius(); + if ( !params.get( "radius", radius_ ) ) { + radius_ = util::Earth::radius(); + } // check presence of lat1 and lat2 - if ( !params.get( "latitude1", lat1_ ) ) throw_Exception( "latitude1 missing in Params", Here() ); - if ( !params.get( "latitude2", lat2_ ) ) lat2_ = lat1_; + 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_Exception( "longitude0 missing in Params", Here() ); + if ( !params.get( "longitude0", lon0_ ) ) { + throw_Exception( "longitude0 missing in Params", Here() ); + } setup(); } @@ -57,7 +65,9 @@ LambertProjection::LambertProjection( const eckit::Parametrisation& params ) { void LambertProjection::setup() { // setup (derived) constants is_tangent_ = std::equal_to()( lat1_, lat2_ ); - if ( is_tangent_ ) { n_ = std::sin( D2R( lat1_ ) ); } + if ( is_tangent_ ) { + n_ = std::sin( D2R( lat1_ ) ); + } else { n_ = std::log( std::cos( D2R( lat1_ ) ) / std::cos( D2R( lat2_ ) ) ) / std::log( std::tan( D2R( 45 + lat2_ * 0.5 ) ) / std::tan( D2R( 45. + lat1_ * 0.5 ) ) ); @@ -88,7 +98,9 @@ void LambertProjection::xy2lonlat( double crd[] ) const { crd[0] = theta * inv_n_ + lon0_; // latitude - if ( rho == 0. ) { crd[1] = sign_ * 90.; } + if ( rho == 0. ) { + crd[1] = sign_ * 90.; + } else { crd[1] = 2. * R2D( std::atan( std::pow( radius_ * F_ / rho, inv_n_ ) ) ) - 90.; } @@ -101,7 +113,9 @@ LambertProjection::Spec LambertProjection::spec() const { proj_spec.set( "latitude1", lat1_ ); proj_spec.set( "latitude2", lat2_ ); proj_spec.set( "longitude0", lon0_ ); - if ( std::not_equal_to()( 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; } diff --git a/src/atlas/projection/detail/LambertProjection.h b/src/atlas/projection/detail/LambertProjection.h index 6fb507969..e24b9d7bf 100644 --- a/src/atlas/projection/detail/LambertProjection.h +++ b/src/atlas/projection/detail/LambertProjection.h @@ -10,38 +10,37 @@ #pragma once +#include "atlas/domain.h" #include "atlas/projection/detail/ProjectionImpl.h" namespace atlas { namespace projection { namespace detail { -class LambertProjection : public ProjectionImpl { +class LambertProjection final : public ProjectionImpl { public: // constructor - LambertProjection( const eckit::Parametrisation& p ); + LambertProjection( const eckit::Parametrisation& ); - // destructor - ~LambertProjection() override {} - - // class name + // projection name static std::string static_type() { return "lambert"; } - virtual std::string type() const override { return static_type(); } + std::string type() const override { return static_type(); } // projection and inverse projection - virtual void xy2lonlat( double crd[] ) const override; - virtual void lonlat2xy( double crd[] ) const override; + void xy2lonlat( double crd[] ) const override; + void lonlat2xy( double crd[] ) const override; - virtual bool strictlyRegional() const override { - return true; - } // lambert projection cannot be used for global grids + bool strictlyRegional() const override { return true; } + RectangularLonLatDomain lonlatBoundingBox( const Domain& domain ) const override { + return ProjectionImpl::lonlatBoundingBox( domain ); + } // specification - virtual Spec spec() const override; + Spec spec() const override; - virtual std::string units() const override { return "meters"; } + std::string units() const override { return "meters"; } - virtual void hash( eckit::Hash& ) const override; + void hash( eckit::Hash& ) const override; private: double lat1_, lat2_; // First and second latitude at which the secant cone diff --git a/src/atlas/projection/detail/LonLatProjection.cc b/src/atlas/projection/detail/LonLatProjection.cc index 75a0abb15..09eae7c0f 100644 --- a/src/atlas/projection/detail/LonLatProjection.cc +++ b/src/atlas/projection/detail/LonLatProjection.cc @@ -8,10 +8,17 @@ * nor does it submit to any jurisdiction. */ +#include + +#include "eckit/geometry/GreatCircle.h" +#include "eckit/types/FloatCompare.h" #include "eckit/utils/Hash.h" +#include "atlas/domain.h" #include "atlas/projection/detail/LonLatProjection.h" #include "atlas/projection/detail/ProjectionFactory.h" +#include "atlas/runtime/Exception.h" +#include "atlas/runtime/Log.h" #include "atlas/util/Config.h" namespace atlas { @@ -23,6 +30,153 @@ LonLatProjectionT::LonLatProjectionT( const eckit::Parametrisation& co ProjectionImpl(), rotation_( config ) {} +template <> +void LonLatProjectionT::xy2lonlat( double[] ) const {} + +template <> +void LonLatProjectionT::lonlat2xy( double[] ) const {} + +template <> +RectangularLonLatDomain LonLatProjectionT::lonlatBoundingBox( const Domain& domain ) const { + return domain; +} + +template +RectangularLonLatDomain LonLatProjectionT::lonlatBoundingBox( const Domain& domain ) const { + using eckit::types::is_strictly_greater; + + + // 0. setup + + if ( domain.global() ) { + return domain; + } + RectangularDomain rect( domain ); + ATLAS_ASSERT( rect ); + + constexpr double h = 0.001; + constexpr size_t Niter = 100; + + + // 1. determine box from projected corners + + const std::vector corners{ + {rect.xmin(), rect.ymax()}, {rect.xmax(), rect.ymax()}, {rect.xmax(), rect.ymin()}, {rect.xmin(), rect.ymin()}}; + + BoundLonLat bounds; + for ( auto& p : corners ) { + bounds.extend( lonlat( p ), PointLonLat{h, h} ); + } + + + // 2. locate latitude extrema by checking if poles are included (in the un-projected frame) and if not, find extrema + // not at the corners by refining iteratively + + PointXY NP{xy( {0., 90.} )}; + PointXY SP{xy( {0., -90.} )}; + + bounds.includesNorthPole( rect.contains( NP ) ); + bounds.includesSouthPole( rect.contains( SP ) ); + + for ( size_t i = 0; i < corners.size(); ++i ) { + if ( !bounds.includesNorthPole() || !bounds.includesSouthPole() ) { + PointXY A = corners[i]; + PointXY B = corners[( i + 1 ) % corners.size()]; + + std::unique_ptr derivate( DerivateFactory::build( "central", *this, A, B ) ); + double dAdy = derivate->d( A ).lat(); + double dBdy = derivate->d( B ).lat(); + + if ( !is_strictly_greater( dAdy * dBdy, 0. ) ) { + for ( size_t cnt = 0; cnt < Niter; ++cnt ) { + PointXY M = PointXY::middle( A, B ); + double dMdy = derivate->d( M ).lat(); + if ( is_strictly_greater( dAdy * dMdy, 0. ) ) { + A = M; + dAdy = dMdy; + } + else if ( is_strictly_greater( dBdy * dMdy, 0. ) ) { + B = M; + dBdy = dMdy; + } + else { + break; + } + } + + // update extrema, extended by 'a small amount' (arbitrary) + bounds.extend( lonlat( PointXY::middle( A, B ) ), PointLonLat{0, h} ); + } + } + } + + + // 3. locate latitude extrema by checking if date line is crossed (in the un-projected frame), in which case we + // assume periodicity and if not, find extrema not at the corners by refining iteratively + + if ( !bounds.crossesDateLine() ) { + PointLonLat A{xy( {180., -10.} )}; + PointLonLat B{xy( {180., 10.} )}; + eckit::geometry::GreatCircle DL( A, B ); + + for ( auto lon : {rect.xmin(), rect.xmax()} ) { + if ( !bounds.crossesDateLine() ) { + for ( auto lat : DL.latitude( lon ) ) { + if ( ( bounds.crossesDateLine( domain.contains( lon, lat ) ) ) ) { + break; + } + } + } + } + + for ( auto lat : {rect.ymin(), rect.ymax()} ) { + if ( !bounds.crossesDateLine() ) { + for ( auto lon : DL.longitude( lat ) ) { + if ( ( bounds.crossesDateLine( domain.contains( lon, lat ) ) ) ) { + break; + } + } + } + } + } + + for ( size_t i = 0; i < corners.size(); ++i ) { + if ( !bounds.crossesDateLine() ) { + PointXY A = corners[i]; + PointXY B = corners[( i + 1 ) % corners.size()]; + + std::unique_ptr derivate( DerivateFactory::build( "central", *this, A, B ) ); + double dAdx = derivate->d( A ).lon(); + double dBdx = derivate->d( B ).lon(); + + if ( !is_strictly_greater( dAdx * dBdx, 0. ) ) { + for ( size_t cnt = 0; cnt < Niter; ++cnt ) { + PointXY M = PointXY::middle( A, B ); + double dMdx = derivate->d( M ).lon(); + if ( is_strictly_greater( dAdx * dMdx, 0. ) ) { + A = M; + dAdx = dMdx; + } + else if ( is_strictly_greater( dBdx * dMdx, 0. ) ) { + B = M; + dBdx = dMdx; + } + else { + break; + } + } + + // update extrema, extended by 'a small amount' (arbitrary) + bounds.extend( lonlat( PointXY::middle( A, B ) ), PointLonLat{h, 0} ); + } + } + } + + + // 4. return bounding box + return bounds; +} + template typename LonLatProjectionT::Spec LonLatProjectionT::spec() const { Spec proj_spec; @@ -45,6 +199,8 @@ static ProjectionBuilder register_1( LonLatProjection::static_ static ProjectionBuilder register_2( RotatedLonLatProjection::static_type() ); } // namespace +// namespace + } // namespace detail } // namespace projection } // namespace atlas diff --git a/src/atlas/projection/detail/LonLatProjection.h b/src/atlas/projection/detail/LonLatProjection.h index 9e01459af..204e04165 100644 --- a/src/atlas/projection/detail/LonLatProjection.h +++ b/src/atlas/projection/detail/LonLatProjection.h @@ -21,7 +21,7 @@ namespace projection { namespace detail { template -class LonLatProjectionT : public ProjectionImpl { +class LonLatProjectionT final : public ProjectionImpl { private: friend class atlas::Projection; LonLatProjectionT() = default; @@ -31,26 +31,27 @@ class LonLatProjectionT : public ProjectionImpl { LonLatProjectionT( const eckit::Parametrisation& ); // destructor - ~LonLatProjectionT() {} + ~LonLatProjectionT() = default; - // class name + // projection name static std::string static_type() { return Rotation::typePrefix() + "lonlat"; } - virtual std::string type() const override { return static_type(); } + std::string type() const override { return static_type(); } // projection and inverse projection - virtual void xy2lonlat( double crd[] ) const override { rotation_.rotate( crd ); } - virtual void lonlat2xy( double crd[] ) const override { rotation_.unrotate( crd ); } + void xy2lonlat( double crd[] ) const override { rotation_.rotate( crd ); } + void lonlat2xy( double crd[] ) const override { rotation_.unrotate( crd ); } - virtual bool strictlyRegional() const override { return false; } + bool strictlyRegional() const override { return false; } + RectangularLonLatDomain lonlatBoundingBox( const Domain& ) const override; // specification - virtual Spec spec() const override; + Spec spec() const override; - virtual std::string units() const override { return "degrees"; } + std::string units() const override { return "degrees"; } - virtual operator bool() const override { return rotation_.rotated(); } + operator bool() const override { return rotation_.rotated(); } - virtual void hash( eckit::Hash& ) const override; + void hash( eckit::Hash& ) const override; private: Rotation rotation_; diff --git a/src/atlas/projection/detail/MercatorProjection.cc b/src/atlas/projection/detail/MercatorProjection.cc index 92602299b..ba95815a8 100644 --- a/src/atlas/projection/detail/MercatorProjection.cc +++ b/src/atlas/projection/detail/MercatorProjection.cc @@ -47,9 +47,13 @@ MercatorProjectionT::MercatorProjectionT( const eckit::Parametrisation ProjectionImpl(), rotation_( params ) { // check presence of radius - if ( !params.get( "radius", radius_ ) ) radius_ = util::Earth::radius(); + if ( !params.get( "radius", radius_ ) ) { + radius_ = util::Earth::radius(); + } // check presence of lon0 - if ( !params.get( "longitude0", lon0_ ) ) lon0_ = 0.0; + if ( !params.get( "longitude0", lon0_ ) ) { + lon0_ = 0.0; + } inv_radius_ = 1. / radius_; } @@ -80,7 +84,9 @@ typename MercatorProjectionT::Spec MercatorProjectionT::spec Spec proj_spec; proj_spec.set( "type", static_type() ); proj_spec.set( "longitude0", lon0_ ); - if ( std::not_equal_to()( 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; } diff --git a/src/atlas/projection/detail/MercatorProjection.h b/src/atlas/projection/detail/MercatorProjection.h index cb1f0291a..62ee6082b 100644 --- a/src/atlas/projection/detail/MercatorProjection.h +++ b/src/atlas/projection/detail/MercatorProjection.h @@ -10,6 +10,7 @@ #pragma once +#include "atlas/domain.h" #include "atlas/projection/detail/ProjectionImpl.h" namespace atlas { @@ -17,29 +18,30 @@ namespace projection { namespace detail { template -class MercatorProjectionT : public ProjectionImpl { +class MercatorProjectionT final : public ProjectionImpl { public: // constructor - MercatorProjectionT( const eckit::Parametrisation& p ); + MercatorProjectionT( const eckit::Parametrisation& ); - // class name + // projection name static std::string static_type() { return Rotation::typePrefix() + "mercator"; } - virtual std::string type() const override { return static_type(); } + std::string type() const override { return static_type(); } // projection and inverse projection - virtual void xy2lonlat( double crd[] ) const override; - virtual void lonlat2xy( double crd[] ) const override; + void xy2lonlat( double crd[] ) const override; + void lonlat2xy( double crd[] ) const override; - virtual bool strictlyRegional() const override { - return true; - } // Mercator projection cannot be used for global grids + bool strictlyRegional() const override { return true; } // Mercator projection cannot be used for global grids + RectangularLonLatDomain lonlatBoundingBox( const Domain& domain ) const override { + return ProjectionImpl::lonlatBoundingBox( domain ); + } // specification - virtual Spec spec() const override; + Spec spec() const override; - virtual std::string units() const override { return "meters"; } + std::string units() const override { return "meters"; } - virtual void hash( eckit::Hash& ) const override; + void hash( eckit::Hash& ) const override; protected: double lon0_; // central longitude diff --git a/src/atlas/projection/detail/ProjectionImpl.cc b/src/atlas/projection/detail/ProjectionImpl.cc index a31f0d78f..60b5cb5d5 100644 --- a/src/atlas/projection/detail/ProjectionImpl.cc +++ b/src/atlas/projection/detail/ProjectionImpl.cc @@ -8,27 +8,262 @@ * nor does it submit to any jurisdiction. */ +#include +#include +#include +#include + +#include "eckit/types/FloatCompare.h" #include "eckit/utils/Hash.h" -#include "atlas/projection/detail/LonLatProjection.h" +#include "ProjectionImpl.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 { +// -------------------------------------------------------------------------------------------------------------------- + +namespace { + +template +struct DerivateBuilder : public ProjectionImpl::DerivateFactory { + using DerivateFactory::DerivateFactory; + ProjectionImpl::Derivate* make( const ProjectionImpl& p, PointXY A, PointXY B, double h ) { + return new T( p, A, B, h ); + } +}; + +struct DerivateForwards final : ProjectionImpl::Derivate { + using Derivate::Derivate; + PointLonLat d( PointXY P ) const override { + PointXY A( xy2lonlat( P ) ); + PointXY B( xy2lonlat( PointXY::add( P, H_ ) ) ); + return PointXY::div( PointXY::sub( B, A ), normH_ ); + } +}; + +struct DerivateBackwards final : ProjectionImpl::Derivate { + using Derivate::Derivate; + PointLonLat d( PointXY P ) const override { + PointXY A( xy2lonlat( PointXY::sub( P, H_ ) ) ); + PointXY B( xy2lonlat( P ) ); + return PointXY::div( PointXY::sub( B, A ), normH_ ); + } +}; + +struct DerivateCentral final : ProjectionImpl::Derivate { + DerivateCentral( const ProjectionImpl& p, PointXY A, PointXY B, double h ) : + Derivate( p, A, B, h ), + H2_{PointXY::mul( H_, 0.5 )} {} + const PointXY H2_; + PointLonLat d( PointXY P ) const override { + PointXY A( xy2lonlat( PointXY::sub( P, H2_ ) ) ); + PointXY B( xy2lonlat( PointXY::add( P, H2_ ) ) ); + return PointXY::div( PointXY::sub( B, A ), normH_ ); + } +}; + +} // namespace + +ProjectionImpl::Derivate::Derivate( const ProjectionImpl& p, PointXY A, PointXY B, double h ) : + projection_( p ), + H_{PointXY::mul( PointXY::normalize( PointXY::sub( B, A ) ), h )}, + normH_( PointXY::norm( H_ ) ) {} + +ProjectionImpl::Derivate::~Derivate() = default; + +ProjectionImpl::Derivate* ProjectionImpl::DerivateFactory::build( const std::string& type, const ProjectionImpl& p, + PointXY A, PointXY B, double h ) { + ATLAS_ASSERT( 0. < h ); + + // force_link + static DerivateBuilder __derivate1( "forwards" ); + static DerivateBuilder __derivate2( "backwards" ); + static DerivateBuilder __derivate3( "central" ); + + if ( A.distance2( B ) < h * h ) { + struct DerivateDegenerate final : Derivate { + using Derivate::Derivate; + PointLonLat d( PointXY ) const override { return {}; } + }; + return new DerivateDegenerate( p, A, B, h ); + } + + auto factory = get( type ); + return factory->make( p, A, B, h ); +} + +ProjectionImpl::DerivateFactory::~DerivateFactory() = default; + +// -------------------------------------------------------------------------------------------------------------------- + +ProjectionImpl::BoundLonLat::operator RectangularLonLatDomain() const { + return RectangularLonLatDomain( {min_[0], max_[0]}, {min_[1], max_[1]} ); +} + +bool ProjectionImpl::BoundLonLat::crossesDateLine( bool yes ) { + if ( ( crossesDateLine_ = crossesDateLine_ || yes ) ) { + max_.lon() = min_.lon() + 360.; + } + return crossesDateLine_; +} + +bool ProjectionImpl::BoundLonLat::includesNorthPole( bool yes ) { + if ( ( includesNorthPole_ = includesNorthPole_ || yes ) ) { + max_.lat() = 90.; + } + crossesDateLine( includesNorthPole_ ); + return includesNorthPole_; +} + +bool ProjectionImpl::BoundLonLat::includesSouthPole( bool yes ) { + if ( ( includesSouthPole_ = includesSouthPole_ || yes ) ) { + min_.lat() = -90.; + } + crossesDateLine( includesSouthPole_ ); + return includesSouthPole_; +} + +void ProjectionImpl::BoundLonLat::extend( PointLonLat p, PointLonLat eps ) { + ATLAS_ASSERT( 0. <= eps.lon() && 0. <= eps.lat() ); + + auto sub = PointLonLat::sub( p, eps ); + auto add = PointLonLat::add( p, eps ); + min_ = first_ ? sub : PointLonLat::componentsMin( min_, sub ); + max_ = first_ ? add : PointLonLat::componentsMax( max_, add ); + first_ = false; + + min_.lat() = std::max( min_.lat(), -90. ); + max_.lat() = std::min( max_.lat(), 90. ); + max_.lon() = std::min( max_.lon(), min_.lon() + 360. ); + ATLAS_ASSERT( min_.lon() <= max_.lon() && min_.lat() <= max_.lat() ); + + includesSouthPole( eckit::types::is_approximately_equal( min_.lat(), -90. ) ); + includesNorthPole( eckit::types::is_approximately_equal( max_.lat(), 90. ) ); + crossesDateLine( eckit::types::is_approximately_equal( max_.lon() - min_.lon(), 360. ) ); +} + +// -------------------------------------------------------------------------------------------------------------------- + const ProjectionImpl* ProjectionImpl::create( const eckit::Parametrisation& p ) { std::string projectionType; - if ( p.get( "type", projectionType ) ) { return ProjectionFactory::build( projectionType, p ); } + if ( p.get( "type", projectionType ) ) { + return ProjectionFactory::build( projectionType, p ); + } // should return error here throw_Exception( "type missing in Params", Here() ); } +RectangularLonLatDomain ProjectionImpl::lonlatBoundingBox( const Domain& domain ) const { + using eckit::types::is_strictly_greater; + + + // 0. setup + + if ( domain.global() ) { + return domain; + } + RectangularDomain rect( domain ); + ATLAS_ASSERT( rect ); + + constexpr double h = 0.001; + constexpr size_t Niter = 100; + + + // 1. determine box from projected corners + + const std::vector corners{ + {rect.xmin(), rect.ymax()}, {rect.xmax(), rect.ymax()}, {rect.xmax(), rect.ymin()}, {rect.xmin(), rect.ymin()}}; + + BoundLonLat bounds; + for ( auto& p : corners ) { + bounds.extend( lonlat( p ), PointLonLat{h, h} ); + } + + + // 2. locate latitude extrema by checking if poles are included (in the un-projected frame) and if not, find extrema + // not at the corners by refining iteratively + + for ( size_t i = 0; i < corners.size(); ++i ) { + if ( !bounds.includesNorthPole() || !bounds.includesSouthPole() ) { + PointXY A = corners[i]; + PointXY B = corners[( i + 1 ) % corners.size()]; + + std::unique_ptr derivate( DerivateFactory::build( "central", *this, A, B ) ); + double dAdy = derivate->d( A ).lat(); + double dBdy = derivate->d( B ).lat(); + + if ( !is_strictly_greater( dAdy * dBdy, 0. ) ) { + for ( size_t cnt = 0; cnt < Niter; ++cnt ) { + PointXY M = PointXY::middle( A, B ); + double dMdy = derivate->d( M ).lat(); + if ( is_strictly_greater( dAdy * dMdy, 0. ) ) { + A = M; + dAdy = dMdy; + } + else if ( is_strictly_greater( dBdy * dMdy, 0. ) ) { + B = M; + dBdy = dMdy; + } + else { + break; + } + } + + // update extrema, extended by 'a small amount' (arbitrary) + bounds.extend( lonlat( PointXY::middle( A, B ) ), PointLonLat{0, h} ); + } + } + } + + + // 3. locate latitude extrema not at the corners by refining iteratively + + for ( size_t i = 0; i < corners.size(); ++i ) { + if ( !bounds.crossesDateLine() ) { + PointXY A = corners[i]; + PointXY B = corners[( i + 1 ) % corners.size()]; + + std::unique_ptr derivate( DerivateFactory::build( "central", *this, A, B ) ); + double dAdx = derivate->d( A ).lon(); + double dBdx = derivate->d( B ).lon(); + + if ( !is_strictly_greater( dAdx * dBdx, 0. ) ) { + for ( size_t cnt = 0; cnt < Niter; ++cnt ) { + PointXY M = PointXY::middle( A, B ); + double dMdx = derivate->d( M ).lon(); + if ( is_strictly_greater( dAdx * dMdx, 0. ) ) { + A = M; + dAdx = dMdx; + } + else if ( is_strictly_greater( dBdx * dMdx, 0. ) ) { + B = M; + dBdx = dMdx; + } + else { + break; + } + } + + // update extrema, extended by 'a small amount' (arbitrary) + bounds.extend( lonlat( PointXY::middle( A, B ) ), PointLonLat{h, 0} ); + } + } + } + + + // 4. return bounding box + return bounds; +} + +//--------------------------------------------------------------------------------------------------------------------- + Rotated::Rotated( const PointLonLat& south_pole, double rotation_angle ) : util::Rotation( south_pole, rotation_angle ) {} diff --git a/src/atlas/projection/detail/ProjectionImpl.h b/src/atlas/projection/detail/ProjectionImpl.h index f948ca8c9..d967a0f58 100644 --- a/src/atlas/projection/detail/ProjectionImpl.h +++ b/src/atlas/projection/detail/ProjectionImpl.h @@ -10,9 +10,9 @@ #pragma once -#include #include +#include "atlas/util/Factory.h" #include "atlas/util/Object.h" #include "atlas/util/Point.h" #include "atlas/util/Rotation.h" @@ -23,6 +23,8 @@ class Hash; } // namespace eckit namespace atlas { +class Domain; +class RectangularLonLatDomain; namespace util { class Config; } @@ -39,8 +41,8 @@ class ProjectionImpl : public util::Object { public: static const ProjectionImpl* create( const eckit::Parametrisation& p ); - ProjectionImpl() {} - virtual ~ProjectionImpl() {} // destructor should be virtual + ProjectionImpl() = default; + virtual ~ProjectionImpl() = default; // destructor should be virtual virtual std::string type() const = 0; @@ -50,7 +52,8 @@ class ProjectionImpl : public util::Object { PointLonLat lonlat( const PointXY& ) const; PointXY xy( const PointLonLat& ) const; - virtual bool strictlyRegional() const = 0; + virtual bool strictlyRegional() const = 0; + virtual RectangularLonLatDomain lonlatBoundingBox( const Domain& ) const = 0; virtual Spec spec() const = 0; @@ -59,6 +62,54 @@ class ProjectionImpl : public util::Object { virtual operator bool() const { return true; } virtual void hash( eckit::Hash& ) const = 0; + + struct BoundLonLat { + operator RectangularLonLatDomain() const; + void extend( PointLonLat p, PointLonLat eps ); + + bool crossesDateLine( bool ); + bool includesNorthPole( bool ); + bool includesSouthPole( bool ); + + bool crossesDateLine() const { return crossesDateLine_; } + bool includesNorthPole() const { return includesNorthPole_; } + bool includesSouthPole() const { return includesSouthPole_; } + + private: + PointLonLat min_; + PointLonLat max_; + bool crossesDateLine_ = false; + bool includesNorthPole_ = false; + bool includesSouthPole_ = false; + bool first_ = true; + }; + + struct Derivate { + Derivate( const ProjectionImpl& p, PointXY A, PointXY B, double h ); + virtual ~Derivate(); + virtual PointLonLat d( PointXY ) const = 0; + + protected: + const ProjectionImpl& projection_; + const PointXY H_; + const double normH_; + PointLonLat xy2lonlat( const PointXY& p ) const { + PointLonLat q( p ); + projection_.xy2lonlat( q.data() ); + return q; + } + }; + + struct DerivateFactory : public util::Factory { + static std::string className() { return "DerivateFactory"; } + static ProjectionImpl::Derivate* build( const std::string& type, const ProjectionImpl& p, PointXY A, PointXY B, + double h = 0.001 ); + + protected: + using Factory::Factory; + virtual ~DerivateFactory(); + virtual ProjectionImpl::Derivate* make( const ProjectionImpl& p, PointXY A, PointXY B, double h ) = 0; + }; }; inline PointLonLat ProjectionImpl::lonlat( const PointXY& xy ) const { @@ -73,13 +124,15 @@ inline PointXY ProjectionImpl::xy( const PointLonLat& lonlat ) const { return xy; } +//--------------------------------------------------------------------------------------------------------------------- + class Rotated : public util::Rotation { public: using Spec = ProjectionImpl::Spec; Rotated( const PointLonLat& south_pole, double rotation_angle = 0. ); Rotated( const eckit::Parametrisation& ); - virtual ~Rotated() {} + virtual ~Rotated() = default; static std::string classNamePrefix() { return "Rotated"; } static std::string typePrefix() { return "rotated_"; } @@ -93,9 +146,9 @@ class NotRotated { public: using Spec = ProjectionImpl::Spec; - NotRotated() {} + NotRotated() = default; NotRotated( const eckit::Parametrisation& ) {} - virtual ~NotRotated() {} + virtual ~NotRotated() = default; static std::string classNamePrefix() { return ""; } // deliberately empty static std::string typePrefix() { return ""; } // deliberately empty diff --git a/src/atlas/projection/detail/SchmidtProjection.cc b/src/atlas/projection/detail/SchmidtProjection.cc index 186ce9adc..ed5d782cd 100644 --- a/src/atlas/projection/detail/SchmidtProjection.cc +++ b/src/atlas/projection/detail/SchmidtProjection.cc @@ -37,7 +37,9 @@ template SchmidtProjectionT::SchmidtProjectionT( const eckit::Parametrisation& params ) : ProjectionImpl(), rotation_( params ) { - if ( !params.get( "stretching_factor", c_ ) ) throw_Exception( "stretching_factor missing in Params", Here() ); + if ( !params.get( "stretching_factor", c_ ) ) { + throw_Exception( "stretching_factor missing in Params", Here() ); + } } // constructor diff --git a/src/atlas/projection/detail/SchmidtProjection.h b/src/atlas/projection/detail/SchmidtProjection.h index df61f9da2..3e5e93932 100644 --- a/src/atlas/projection/detail/SchmidtProjection.h +++ b/src/atlas/projection/detail/SchmidtProjection.h @@ -10,6 +10,7 @@ #pragma once +#include "atlas/domain.h" #include "atlas/projection/detail/ProjectionImpl.h" namespace atlas { @@ -17,28 +18,31 @@ namespace projection { namespace detail { template -class SchmidtProjectionT : public ProjectionImpl { +class SchmidtProjectionT final : public ProjectionImpl { public: // constructor SchmidtProjectionT( const eckit::Parametrisation& p ); SchmidtProjectionT(); - // class name + // projection name static std::string static_type() { return Rotation::typePrefix() + "schmidt"; } - virtual std::string type() const override { return static_type(); } + std::string type() const override { return static_type(); } // projection and inverse projection - virtual void xy2lonlat( double crd[] ) const override; - virtual void lonlat2xy( double crd[] ) const override; + void xy2lonlat( double crd[] ) const override; + void lonlat2xy( double crd[] ) const override; - virtual bool strictlyRegional() const override { return false; } // schmidt is global grid + bool strictlyRegional() const override { return false; } // schmidt is global grid + RectangularLonLatDomain lonlatBoundingBox( const Domain& domain ) const override { + return ProjectionImpl::lonlatBoundingBox( domain ); + } // specification - virtual Spec spec() const override; + Spec spec() const override; - virtual std::string units() const override { return "degrees"; } + std::string units() const override { return "degrees"; } - virtual void hash( eckit::Hash& ) const override; + void hash( eckit::Hash& ) const override; private: double c_; // stretching factor diff --git a/src/atlas/runtime/AtlasTool.cc b/src/atlas/runtime/AtlasTool.cc index efd6fc746..6958acc7b 100644 --- a/src/atlas/runtime/AtlasTool.cc +++ b/src/atlas/runtime/AtlasTool.cc @@ -9,8 +9,11 @@ */ #include +#include +#include #include "eckit/config/LibEcKit.h" +#include "eckit/filesystem/LocalPathName.h" #include "eckit/log/FileTarget.h" #include "eckit/log/PrefixTarget.h" @@ -48,7 +51,9 @@ void debug_addTarget( eckit::LogTarget* target ) { lib.debugChannel().addTarget( new eckit::PrefixTarget( debug_prefix( libname ), target ) ); } } - if ( eckit::Log::debug() ) eckit::Log::debug().addTarget( target ); + if ( eckit::Log::debug() ) { + eckit::Log::debug().addTarget( target ); + } } void debug_setTarget( eckit::LogTarget* target ) { @@ -58,29 +63,157 @@ void debug_setTarget( eckit::LogTarget* target ) { lib.debugChannel().setTarget( new eckit::PrefixTarget( debug_prefix( libname ), target ) ); } } - if ( eckit::Log::debug() ) eckit::Log::debug().setTarget( target ); + if ( eckit::Log::debug() ) { + eckit::Log::debug().setTarget( target ); + } } void debug_reset() { for ( std::string libname : eckit::system::Library::list() ) { const eckit::system::Library& lib = eckit::system::Library::lookup( libname ); - if ( lib.debug() ) { lib.debugChannel().reset(); } + if ( lib.debug() ) { + lib.debugChannel().reset(); + } + } + if ( eckit::Log::debug() ) { + eckit::Log::debug().reset(); } - if ( eckit::Log::debug() ) eckit::Log::debug().reset(); } bool getEnv( const std::string& env, bool default_value ) { - if (::getenv( env.c_str() ) ) { return eckit::Translator()(::getenv( env.c_str() ) ); } + if ( ::getenv( env.c_str() ) ) { + return eckit::Translator()( ::getenv( env.c_str() ) ); + } return default_value; } int getEnv( const std::string& env, int default_value ) { - if (::getenv( env.c_str() ) ) { return eckit::Translator()(::getenv( env.c_str() ) ); } + if ( ::getenv( env.c_str() ) ) { + return eckit::Translator()( ::getenv( env.c_str() ) ); + } return default_value; } +std::string getEnv( const std::string& env, const std::string& default_value ) { + if ( ::getenv( env.c_str() ) ) { + return ::getenv( env.c_str() ); + } + return default_value; +} + +void setEnv( const std::string& env, bool value ) { + ::setenv( env.c_str(), eckit::Translator()( value ).c_str(), 0 ); +} + } // namespace +namespace atlas { + +static std::string exception_what; +static eckit::CodeLocation exception_location; +static std::string exception_callstack; +static bool use_logfile; +static std::string logfile_name; +static std::string workdir; + +[[noreturn]] void atlas_terminate() { + // This routine is called for uncaught exceptions. + // It can be set with std::set_terminate( &atlas_terminate ) + + Log::flush(); + + if ( not use_logfile and mpi::comm().size() > 1 ) { + eckit::LogTarget* logfile = new eckit::FileTarget( logfile_name ); + Log::error().addTarget( logfile ); + } + if ( std::exception_ptr eptr = std::current_exception() ) { + std::ostream& out = Log::error(); + try { + std::rethrow_exception( eptr ); // throw to recognise the type + } + catch ( const eckit::Abort& exception ) { + out << "\n" + << "=========================================\n" + << "[" << mpi::comm().rank() << "] Aborting " << eckit::Main::instance().displayName() << "\n" + << "-----------------------------------------\n" + << exception.what() << "\n"; + if ( exception.location() ) { + out << "-----------------------------------------\n" + << "LOCATION: " << exception.location() << "\n"; + } + out << "-----------------------------------------\n" + << "BACKTRACE\n" + << "-----------------------------------------\n" + << exception.callStack() << "\n" + << "=========================================\n" + << std::endl; + exception_what = exception.what(); + exception_location = exception.location(); + exception_callstack = exception.callStack(); + } + catch ( const eckit::Exception& exception ) { + out << "\n" + << "=========================================\n" + << "[" << mpi::comm().rank() << "] TERMINATING " << eckit::Main::instance().displayName() << "\n" + << "-----------------------------------------\n" + << exception.what() << "\n" + << "-----------------------------------------\n"; + + if ( exception.location() ) { + out << "LOCATION: " << exception.location() << "\n" + << "-----------------------------------------\n"; + } + + out << "BACKTRACE\n" + << "-----------------------------------------\n" + << exception.callStack() << "\n" + << "=========================================\n" + << std::endl; + exception_what = exception.what(); + exception_location = exception.location(); + exception_callstack = backtrace(); + } + catch ( const std::exception& exception ) { + out << "\n" + << "=========================================\n" + << "[" << mpi::comm().rank() << "] TERMINATING " << eckit::Main::instance().displayName() << "\n" + << "-----------------------------------------\n" + << exception.what() << "\n" + << "-----------------------------------------\n" + << "BACKTRACE\n" + << "-----------------------------------------\n" + << backtrace() << "\n" + << "=========================================\n" + << std::endl; + exception_what = exception.what(); + exception_location = eckit::CodeLocation(); + exception_callstack = backtrace(); + } + catch ( ... ) { + out << "\n" + << "=========================================\n" + << "[" << mpi::comm().rank() << "] TERMINATING " << eckit::Main::instance().displayName() << "\n" + << "-----------------------------------------\n" + << "BACKTRACE\n" + << "-----------------------------------------\n" + << backtrace() << "\n" + << "=========================================" << std::endl; + exception_what = "Uncaught exception"; + exception_location = eckit::CodeLocation(); + exception_callstack = backtrace(); + } + } + + eckit::LibEcKit::instance().abort(); + + // Just in case we end up here, as last resort, exit immediately without + // cleanup. + std::_Exit( EXIT_FAILURE ); +} + +} // namespace atlas + + void atlas::AtlasTool::add_option( eckit::option::Option* option ) { options_.push_back( option ); } @@ -88,7 +221,9 @@ void atlas::AtlasTool::add_option( eckit::option::Option* option ) { void atlas::AtlasTool::help( std::ostream& out ) { out << "NAME\n" << indent() << name(); std::string brief = briefDescription(); - if ( brief.size() ) out << " - " << brief << '\n'; + if ( brief.size() ) { + out << " - " << brief << '\n'; + } std::string usg = usage(); if ( usg.size() ) { @@ -111,7 +246,9 @@ void atlas::AtlasTool::help( std::ostream& out ) { bool atlas::AtlasTool::handle_help() { for ( int i = 1; i < argc(); ++i ) { if ( argv( i ) == "--help" || argv( i ) == "-h" ) { - if ( taskID() == 0 ) help( std::cout ); + if ( taskID() == 0 ) { + help( std::cout ); + } return true; } } @@ -120,91 +257,125 @@ bool atlas::AtlasTool::handle_help() { atlas::AtlasTool::AtlasTool( int argc, char** argv ) : eckit::Tool( argc, argv ) { eckit::LibEcKit::instance().setAbortHandler( [] { - Log::error() << "[" << atlas::mpi::comm().rank() << "] " - << "calling MPI_Abort" << std::endl; + std::cerr << "[" << atlas::mpi::comm().rank() << "] " + << "calling MPI_Abort"; + if ( not use_logfile and mpi::comm().size() > 1 ) { + std::cerr << ", logfile: " << logfile_name; + } + std::cerr << std::endl; + std::this_thread::sleep_for( std::chrono::milliseconds( 3000 ) ); atlas::mpi::comm().abort( 1 ); } ); - + std::set_terminate( &atlas_terminate ); + setEnv( "ECKIT_EXCEPTION_IS_SILENT", true ); + setEnv( "ECKIT_ASSERT_FAILED_IS_SILENT", true ); add_option( new SimpleOption( "help", "Print this help" ) ); add_option( new SimpleOption( "debug", "Debug level" ) ); taskID( eckit::mpi::comm( "world" ).rank() ); + workdir = getEnv( "ATLAS_WORKDIR", eckit::PathName( eckit::LocalPathName::cwd() ).fullName() ); + + add_option( new SimpleOption( "display-name", "Name to give to program" ) ); } int atlas::AtlasTool::start() { - int status = 0; try { - run(); - } - catch ( eckit::Exception& e ) { - status = 1; - Log::error() << "** " << e.what() << e.location() << std::endl; - Log::error() << "** Backtrace:\n" << e.callStack() << '\n'; - Log::error() << "** Exception caught in " << Here() << " terminates " << name() << std::endl; - } - catch ( std::exception& e ) { - status = 1; - Log::error() << "** " << e.what() << " caught in " << Here() << '\n'; - Log::error() << "** Exception terminates " << name() << std::endl; + if ( handle_help() ) { + return success(); + } + + if ( argc() - 1 < minimumPositionalArguments() ) { + if ( taskID() == 0 ) { + std::cout << "Usage: " << usage() << std::endl; + } + return failed(); + } + Options opts = options_; + Args args( &atlas::usage, opts, numberOfPositionalArguments(), minimumPositionalArguments() ); + + atlas::Library::instance().initialise(); + setupLogging(); + int err_code = execute( args ); + atlas::Library::instance().finalise(); + return err_code; } catch ( ... ) { - status = 1; - Log::error() << "** Exception caught in " << Here() << '\n'; - Log::error() << "** Exception terminates " << name() << std::endl; - } - if ( status ) { - Log::error() << std::flush; - eckit::LibEcKit::instance().abort(); + atlas_terminate(); } - - return status; + // catch ( eckit::Exception& e ) { + // status = 1; + // Log::error() << "** " << e.what() << e.location() << std::endl; + // Log::error() << "** Backtrace:\n" << e.callStack() << '\n'; + // Log::error() << "** Exception caught in " << Here() << " terminates " << name() << std::endl; + // } + // catch ( std::exception& e ) { + // status = 1; + // Log::error() << "** " << e.what() << " caught in " << Here() << '\n'; + // Log::error() << "** Exception terminates " << name() << std::endl; + // } + // catch ( ... ) { + // status = 1; + // Log::error() << "** Exception caught in " << Here() << '\n'; + // Log::error() << "** Exception terminates " << name() << std::endl; + // } + // if ( status ) { + // Log::error() << std::flush; + // eckit::LibEcKit::instance().abort(); + // } } -void atlas::AtlasTool::run() { - if ( handle_help() ) return; +void atlas::AtlasTool::run() {} - if ( argc() - 1 < minimumPositionalArguments() ) { - if ( taskID() == 0 ) std::cout << "Usage: " << usage() << std::endl; - return; - } - Options opts = options_; - Args args( &atlas::usage, opts, numberOfPositionalArguments(), minimumPositionalArguments() ); +void atlas::AtlasTool::setupLogging() { + int log_rank = getEnv( "ATLAS_LOG_RANK", 0 ); + use_logfile = getEnv( "ATLAS_LOG_FILE", false ); - atlas::Library::instance().initialise(); - setupLogging(); - execute( args ); - atlas::Library::instance().finalise(); -} + int d = digits( mpi::comm().size() ); + std::string rankstr = std::to_string( taskID() ); + for ( int i = rankstr.size(); i < d; ++i ) { + rankstr = "0" + rankstr; + } -void atlas::AtlasTool::setupLogging() { - int log_rank = getEnv( "ATLAS_LOG_RANK", 0 ); - bool use_logfile = getEnv( "ATLAS_LOG_FILE", false ); + logfile_name = workdir + "/" + displayName() + ".log.p" + rankstr; if ( use_logfile ) { - int d = digits( mpi::comm().size() ); - std::string rankstr = std::to_string( taskID() ); - for ( int i = rankstr.size(); i < d; ++i ) - rankstr = "0" + rankstr; - - eckit::LogTarget* logfile = new eckit::FileTarget( displayName() + ".log.p" + rankstr ); + eckit::LogTarget* logfile = new eckit::FileTarget( logfile_name ); 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 ); + if ( Log::info() ) { + Log::info().addTarget( logfile ); + } + if ( Log::warning() ) { + Log::warning().addTarget( logfile ); + } + if ( Log::error() ) { + Log::error().addTarget( logfile ); + } debug_addTarget( logfile ); } else { - if ( Log::info() ) Log::info().setTarget( logfile ); - if ( Log::warning() ) Log::warning().setTarget( logfile ); - if ( Log::error() ) Log::error().setTarget( logfile ); + if ( Log::info() ) { + Log::info().setTarget( logfile ); + } + if ( Log::warning() ) { + Log::warning().setTarget( logfile ); + } + if ( Log::error() ) { + Log::error().setTarget( logfile ); + } debug_setTarget( logfile ); } } else { 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(); + if ( Log::info() ) { + Log::info().reset(); + } + if ( Log::warning() ) { + Log::warning().reset(); + } + if ( Log::error() ) { + Log::error().reset(); + } debug_reset(); } } diff --git a/src/atlas/runtime/AtlasTool.h b/src/atlas/runtime/AtlasTool.h index b05b8c568..db0bd44f2 100644 --- a/src/atlas/runtime/AtlasTool.h +++ b/src/atlas/runtime/AtlasTool.h @@ -60,9 +60,12 @@ class AtlasTool : public eckit::Tool { int start(); - virtual void run(); + virtual void run(); // unused - virtual void execute( const Args& ) = 0; + virtual int execute( const Args& ) = 0; + + static constexpr int success() { return 0; } + static constexpr int failed() { return 1; } private: void setupLogging(); diff --git a/src/atlas/runtime/Exception.h b/src/atlas/runtime/Exception.h index 5d477fd2a..163784e96 100644 --- a/src/atlas/runtime/Exception.h +++ b/src/atlas/runtime/Exception.h @@ -35,10 +35,14 @@ namespace atlas { 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 ) ); } + 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 ) ); } + if ( not success ) { + throw_AssertionFailed( code, msg, eckit::CodeLocation( file, line, func ) ); + } } } // namespace detail } // namespace atlas diff --git a/src/atlas/runtime/Trace.h b/src/atlas/runtime/Trace.h index cc86528b0..cef4e8507 100644 --- a/src/atlas/runtime/Trace.h +++ b/src/atlas/runtime/Trace.h @@ -79,8 +79,8 @@ class Trace : public runtime::trace::TraceT { #undef ATLAS_TRACE #undef ATLAS_TRACE_SCOPE -#define ATLAS_TRACE( ... ) __ATLAS_TYPE(::atlas::Trace, Here() __ATLAS_COMMA_ARGS( __VA_ARGS__ ) ) -#define ATLAS_TRACE_SCOPE( ... ) __ATLAS_TYPE_SCOPE(::atlas::Trace, Here() __ATLAS_COMMA_ARGS( __VA_ARGS__ ) ) +#define ATLAS_TRACE( ... ) __ATLAS_TYPE( ::atlas::Trace, Here() __ATLAS_COMMA_ARGS( __VA_ARGS__ ) ) +#define ATLAS_TRACE_SCOPE( ... ) __ATLAS_TYPE_SCOPE( ::atlas::Trace, Here() __ATLAS_COMMA_ARGS( __VA_ARGS__ ) ) #endif diff --git a/src/atlas/runtime/trace/Barriers.cc b/src/atlas/runtime/trace/Barriers.cc index 7df95a173..a7e4b970d 100644 --- a/src/atlas/runtime/trace/Barriers.cc +++ b/src/atlas/runtime/trace/Barriers.cc @@ -42,7 +42,9 @@ class BarriersState { std::string report() const { std::stringstream out; double time = stopwatch_.elapsed(); - if ( time ) { out << "Total time spent in mpi barriers due to load imbalance : " << time << "s" << std::endl; } + if ( time ) { + out << "Total time spent in mpi barriers due to load imbalance : " << time << "s" << std::endl; + } return out.str(); } }; diff --git a/src/atlas/runtime/trace/CallStack.cc b/src/atlas/runtime/trace/CallStack.cc index cc73a7c5d..6341c6dec 100644 --- a/src/atlas/runtime/trace/CallStack.cc +++ b/src/atlas/runtime/trace/CallStack.cc @@ -27,7 +27,9 @@ void CallStack::pop_front() { } size_t CallStack::hash() const { - if ( hash_ ) return hash_; + if ( hash_ ) { + return hash_; + } for ( auto h : stack_ ) { hash_ ^= ( h << 1 ); } diff --git a/src/atlas/runtime/trace/Logging.cc b/src/atlas/runtime/trace/Logging.cc index eec7701c1..bfc9a6109 100644 --- a/src/atlas/runtime/trace/Logging.cc +++ b/src/atlas/runtime/trace/Logging.cc @@ -51,7 +51,9 @@ class LoggingState { void set( std::ostream& channel ) { channel_ = &channel; } void set( bool state ) { - if ( state == false ) channel_ = &empty_channel(); + if ( state == false ) { + channel_ = &empty_channel(); + } } }; @@ -78,11 +80,15 @@ bool Logging::enabled() { } void Logging::start( const std::string& title ) { - if ( enabled() ) channel() << title << " ..." << std::endl; + if ( enabled() ) { + channel() << title << " ..." << std::endl; + } } void Logging::stop( const std::string& title, double seconds ) { - if ( enabled() ) channel() << title << " ... done : " << seconds << "s" << std::endl; + if ( enabled() ) { + channel() << title << " ... done : " << seconds << "s" << std::endl; + } } //----------------------------------------------------------------------------------------------------------- @@ -93,7 +99,9 @@ std::ostream& NoLogging::channel() { //----------------------------------------------------------------------------------------------------------- void LoggingResult::stop( const std::string& title, double seconds ) { - if ( enabled() ) channel() << title << " : " << seconds << "s" << std::endl; + if ( enabled() ) { + channel() << title << " : " << seconds << "s" << std::endl; + } } //----------------------------------------------------------------------------------------------------------- diff --git a/src/atlas/runtime/trace/Nesting.h b/src/atlas/runtime/trace/Nesting.h index c2ec44fa7..14bcd20b2 100644 --- a/src/atlas/runtime/trace/Nesting.h +++ b/src/atlas/runtime/trace/Nesting.h @@ -34,11 +34,13 @@ class CurrentCallStack { } operator CallStack() const { return stack_; } CallStack& push( const CodeLocation& loc, const std::string& id ) { - if ( Control::enabled() ) stack_.push_front( loc, id ); + if ( Control::enabled() ) + stack_.push_front( loc, id ); return stack_; } void pop() { - if ( Control::enabled() ) stack_.pop_front(); + if ( Control::enabled() ) + stack_.pop_front(); } }; diff --git a/src/atlas/runtime/trace/Timings.cc b/src/atlas/runtime/trace/Timings.cc index 58e63f5eb..9d7778a0b 100644 --- a/src/atlas/runtime/trace/Timings.cc +++ b/src/atlas/runtime/trace/Timings.cc @@ -116,8 +116,9 @@ void TimingsRegistry::report( std::ostream& out, const eckit::Configuration& con auto box_horizontal = []( int n ) { std::string s; s.reserve( 2 * n ); - for ( int i = 0; i < n; ++i ) + for ( int i = 0; i < n; ++i ) { s += "\u2500"; + } return s; }; std::string box_corner_tl( "\u250c" ); @@ -166,15 +167,21 @@ void TimingsRegistry::report( std::ostream& out, const eckit::Configuration& con std::set excluded_timers( excluded_timers_vector.begin(), excluded_timers_vector.end() ); auto excluded = [&]( size_t i ) -> bool { - if ( depth and nest_[i] > depth ) return true; + if ( depth and nest_[i] > depth ) { + return true; + } return excluded_timers.count( i ); }; std::vector excluded_nest_stored( size() ); long excluded_nest = size(); for ( size_t j = 0; j < size(); ++j ) { - if ( nest_[j] > excluded_nest ) { excluded_timers.insert( j ); } - if ( not excluded( j ) ) { excluded_nest = nest_[j] + 1; } + if ( nest_[j] > excluded_nest ) { + excluded_timers.insert( j ); + } + if ( not excluded( j ) ) { + excluded_nest = nest_[j] + 1; + } else { excluded_nest = std::min( excluded_nest, nest_[j] ); } @@ -183,7 +190,9 @@ void TimingsRegistry::report( std::ostream& out, const eckit::Configuration& con for ( auto& label : include_back ) { auto timers = labels_[label]; for ( size_t j : timers ) { - if ( nest_[j] == excluded_nest_stored[j] ) excluded_timers.erase( j ); + if ( nest_[j] == excluded_nest_stored[j] ) { + excluded_timers.erase( j ); + } } } @@ -205,7 +214,9 @@ void TimingsRegistry::report( std::ostream& out, const eckit::Configuration& con } } size_t max_count_length = digits( max_count ); - if ( header ) { max_count_length = std::max( std::string( "cnt" ).size(), max_count_length ); } + if ( header ) { + max_count_length = std::max( std::string( "cnt" ).size(), max_count_length ); + } size_t max_digits_before_decimal = digits_before_decimal( max_seconds ); auto print_time = [max_digits_before_decimal, decimals]( double x ) -> std::string { @@ -260,7 +271,9 @@ void TimingsRegistry::report( std::ostream& out, const eckit::Configuration& con auto next_it = next_stack.rbegin(); for ( size_t i = 0; this_it != this_stack.rend() && next_it != next_stack.rend(); ++i, ++this_it, ++next_it ) { - if ( *this_it == *next_it ) { active[i] = active[i] or false; } + if ( *this_it == *next_it ) { + active[i] = active[i] or false; + } else { active[i] = true; } @@ -271,19 +284,25 @@ void TimingsRegistry::report( std::ostream& out, const eckit::Configuration& con std::stringstream out; for ( long i = 0; i < nest - 1; ++i ) { - if ( active[i] ) + if ( active[i] ) { out << box_vertical; - else + } + else { out << " "; - for ( long j = 1; j < indent; ++j ) + } + for ( long j = 1; j < indent; ++j ) { out << " "; + } } - if ( active[nest - 1] ) + if ( active[nest - 1] ) { out << box_T_right; - else + } + else { out << box_corner_bl; - for ( long j = 1; j < indent; ++j ) + } + for ( long j = 1; j < indent; ++j ) { out << box_horizontal( 1 ); + } prefix_[k] = out.str(); } diff --git a/src/atlas/runtime/trace/TraceT.h b/src/atlas/runtime/trace/TraceT.h index cc9d2abed..17c595244 100644 --- a/src/atlas/runtime/trace/TraceT.h +++ b/src/atlas/runtime/trace/TraceT.h @@ -150,7 +150,9 @@ template inline void TraceT::start() { if ( Control::enabled() ) { running_ = true; - if ( not callstack_ ) { callstack_ = CurrentCallStack::instance().push( loc_, title_ ); } + if ( not callstack_ ) { + callstack_ = CurrentCallStack::instance().push( loc_, title_ ); + } registerTimer(); Tracing::start( title_ ); barrier(); diff --git a/src/atlas/trans/Cache.cc b/src/atlas/trans/Cache.cc index 1b18c76ce..5bd96586e 100644 --- a/src/atlas/trans/Cache.cc +++ b/src/atlas/trans/Cache.cc @@ -80,11 +80,15 @@ Cache::~Cache() {} TransCache::TransCache( const Trans& trans ) : Cache( trans.get() ) {} TransCacheOwnedMemoryEntry::TransCacheOwnedMemoryEntry( size_t size ) : size_( size ) { - if ( size_ ) { data_ = std::malloc( size_ ); } + if ( size_ ) { + data_ = std::malloc( size_ ); + } } TransCacheOwnedMemoryEntry::~TransCacheOwnedMemoryEntry() { - if ( size_ ) { std::free( data_ ); } + if ( size_ ) { + std::free( data_ ); + } } } // namespace trans diff --git a/src/atlas/trans/LegendreCacheCreator.cc b/src/atlas/trans/LegendreCacheCreator.cc index 8b5a2cda7..4f13a3b33 100644 --- a/src/atlas/trans/LegendreCacheCreator.cc +++ b/src/atlas/trans/LegendreCacheCreator.cc @@ -58,8 +58,9 @@ LegendreCacheCreatorFactory& factory( const std::string& name ) { if ( j == m->end() ) { Log::error() << "No LegendreCacheCreatorFactory for [" << name << "]" << std::endl; Log::error() << "TransFactories are:" << std::endl; - for ( j = m->begin(); j != m->end(); ++j ) + for ( j = m->begin(); j != m->end(); ++j ) { Log::error() << " " << ( *j ).first << std::endl; + } throw_Exception( std::string( "No LegendreCacheCreatorFactory called " ) + name ); } return *j->second; diff --git a/src/atlas/trans/Trans.cc b/src/atlas/trans/Trans.cc index 9cc8c4376..37f5bb972 100644 --- a/src/atlas/trans/Trans.cc +++ b/src/atlas/trans/Trans.cc @@ -83,6 +83,10 @@ const Grid& Trans::grid() const { return get()->grid(); } +const functionspace::Spectral& Trans::spectral() const { + return get()->spectral(); +} + size_t Trans::spectralCoefficients() const { return get()->spectralCoefficients(); } diff --git a/src/atlas/trans/Trans.h b/src/atlas/trans/Trans.h index 53bc8048f..e1b3da66c 100644 --- a/src/atlas/trans/Trans.h +++ b/src/atlas/trans/Trans.h @@ -25,6 +25,9 @@ class FieldSet; class FunctionSpace; class Grid; class Domain; +namespace functionspace { +class Spectral; +} } // namespace atlas //----------------------------------------------------------------------------- @@ -61,6 +64,7 @@ class Trans : public util::ObjectHandle { int truncation() const; size_t spectralCoefficients() const; const Grid& grid() const; + const functionspace::Spectral& spectral() const; void dirtrans( const Field& gpfield, Field& spfield, const eckit::Configuration& = util::NoConfig() ) const; diff --git a/src/atlas/trans/VorDivToUV.cc b/src/atlas/trans/VorDivToUV.cc index de85938a0..009cd2422 100644 --- a/src/atlas/trans/VorDivToUV.cc +++ b/src/atlas/trans/VorDivToUV.cc @@ -63,8 +63,9 @@ VorDivToUVFactory& factory( const std::string& name ) { if ( j == m->end() ) { Log::error() << "No VorDivToUVFactory for [" << name << "]" << std::endl; Log::error() << "VorDivToUVFactory are:" << std::endl; - for ( j = m->begin(); j != m->end(); ++j ) + for ( j = m->begin(); j != m->end(); ++j ) { Log::error() << " " << ( *j ).first << std::endl; + } throw_Exception( std::string( "No VorDivToUVFactory called " ) + name ); } return *j->second; diff --git a/src/atlas/trans/detail/TransFactory.cc b/src/atlas/trans/detail/TransFactory.cc index dbb480e6d..bcd5c29dc 100644 --- a/src/atlas/trans/detail/TransFactory.cc +++ b/src/atlas/trans/detail/TransFactory.cc @@ -104,7 +104,9 @@ class TransBackend { } void add( const std::string& backend ) { lock_guard lock( mutex_ ); - if ( backends_.find( backend ) == backends_.end() ) { backends_[backend] = 1; } + if ( backends_.find( backend ) == backends_.end() ) { + backends_[backend] = 1; + } else { ++backends_[backend]; } @@ -112,7 +114,9 @@ class TransBackend { void remove( const std::string& backend ) { lock_guard lock( mutex_ ); --backends_[backend]; - if ( backends_[backend] == 0 ) { backends_.erase( backend ); } + if ( backends_[backend] == 0 ) { + backends_.erase( backend ); + } } void backend( const std::string& backend ) { @@ -123,7 +127,9 @@ class TransBackend { 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 ); } + if ( not config.has( "type" ) ) { + default_options_.set( "type", type ); + } } const eckit::Configuration& config() { return default_options_; } diff --git a/src/atlas/trans/detail/TransImpl.cc b/src/atlas/trans/detail/TransImpl.cc index 1d03ee973..33341453b 100644 --- a/src/atlas/trans/detail/TransImpl.cc +++ b/src/atlas/trans/detail/TransImpl.cc @@ -10,11 +10,16 @@ #include "TransImpl.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace trans { TransImpl::~TransImpl() {} +int TransImpl::handle() const { + ATLAS_NOTIMPLEMENTED; +} + } // namespace trans } // namespace atlas diff --git a/src/atlas/trans/detail/TransImpl.h b/src/atlas/trans/detail/TransImpl.h index b75439714..bce310d60 100644 --- a/src/atlas/trans/detail/TransImpl.h +++ b/src/atlas/trans/detail/TransImpl.h @@ -23,6 +23,9 @@ class FieldSet; class FunctionSpace; class Grid; class Domain; +namespace functionspace { +class Spectral; +} } // namespace atlas //----------------------------------------------------------------------------- @@ -34,14 +37,20 @@ namespace trans { class TransImpl : public util::Object { public: + virtual std::string type() const { return "wrong value"; } + virtual ~TransImpl() = 0; virtual int truncation() const = 0; - virtual size_t spectralCoefficients() const = 0; + virtual size_t nb_spectral_coefficients() const = 0; + + virtual size_t nb_spectral_coefficients_global() const = 0; virtual const Grid& grid() const = 0; + virtual const functionspace::Spectral& spectral() const = 0; + virtual void dirtrans( const Field& gpfield, Field& spfield, const eckit::Configuration& = util::NoConfig() ) const = 0; @@ -115,6 +124,15 @@ class TransImpl : public util::Object { */ virtual void dirtrans( const int nb_fields, const double wind_fields[], double vorticity_spectra[], double divergence_spectra[], const eckit::Configuration& = util::NoConfig() ) const = 0; + + + // deprecated + virtual size_t spectralCoefficients() const { return nb_spectral_coefficients(); } + +private: + friend class TransInterface; + // Only for TransIFS backend + virtual int handle() const; }; //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/atlas/trans/detail/TransInterface.cc b/src/atlas/trans/detail/TransInterface.cc new file mode 100644 index 000000000..b1f2a1cb2 --- /dev/null +++ b/src/atlas/trans/detail/TransInterface.cc @@ -0,0 +1,224 @@ +/* + * (C) Copyright 2013 ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not 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 "TransInterface.h" + +#include + +#include "atlas/array.h" +#include "atlas/field/Field.h" +#include "atlas/field/FieldSet.h" +#include "atlas/functionspace/Spectral.h" +#include "atlas/library/config.h" +#include "atlas/mesh/Nodes.h" +#include "atlas/runtime/Exception.h" +#include "atlas/runtime/Log.h" +#include "atlas/trans/Trans.h" +#include "atlas/trans/detail/TransFactory.h" +#include "atlas/trans/detail/TransImpl.h" + +namespace atlas { +namespace trans { + +class TransInterface { +private: + const TransImpl* trans_; + +public: + TransInterface( const TransImpl* trans ) : trans_( trans ) {} + int handle() const { return trans_->handle(); } +}; + +/////////////////////////////////////////////////////////////////////////////// + +extern "C" { + +int atlas__Trans__has_backend( const char* backend ) { + return Trans::hasBackend( std::string( backend ) ); +} +void atlas__Trans__set_backend( const char* backend ) { + Trans::backend( std::string( backend ) ); +} +void atlas__Trans__backend( char*& backend, size_t& size ) { + std::string s = Trans::backend(); + size = s.size() + 1; + backend = new char[size]; + strcpy( backend, s.c_str() ); +} + + +TransImpl* atlas__Trans__new( const Grid::Implementation* grid, int truncation ) { + ATLAS_ASSERT( grid != nullptr, "Grid must not be null" ); + TransImpl* trans; + { + Grid g( grid ); + Trans t( g, truncation ); + trans = t.get(); + trans->attach(); + } + trans->detach(); + return trans; +} + +TransImpl* atlas__Trans__new_config( const Grid::Implementation* grid, int truncation, + const eckit::Configuration* config ) { + ATLAS_ASSERT( grid != nullptr, "Grid must not be null" ); + ATLAS_ASSERT( config != nullptr, "config must not be null" ); + TransImpl* trans; + { + Grid g( grid ); + Trans t( g, truncation, *config ); + trans = t.get(); + trans->attach(); + } + trans->detach(); + return trans; +} + + +void atlas__Trans__delete( TransImpl* This ) { + ATLAS_ASSERT( This != nullptr ); + delete This; +} + +int atlas__Trans__handle( const TransImpl* This ) { + ATLAS_ASSERT( This != nullptr ); + return TransInterface( This ).handle(); +} + + +void atlas__Trans__invtrans_scalar( const TransImpl* t, int nb_fields, double scalar_spectra[], + double scalar_fields[] ) { + ATLAS_ASSERT( t != nullptr ); + return t->invtrans( nb_fields, scalar_spectra, scalar_fields ); +} + +void atlas__Trans__invtrans_vordiv2wind( const TransImpl* t, int nb_fields, double vorticity_spectra[], + double divergence_spectra[], double wind_fields[] ) { + ATLAS_ASSERT( t != nullptr ); + return t->invtrans( nb_fields, vorticity_spectra, divergence_spectra, wind_fields ); +} + +void atlas__Trans__dirtrans_scalar( const TransImpl* t, int nb_fields, double scalar_fields[], + double scalar_spectra[] ) { + ATLAS_ASSERT( t != nullptr ); + return t->dirtrans( nb_fields, scalar_fields, scalar_spectra ); +} + +void atlas__Trans__dirtrans_wind2vordiv( const TransImpl* t, int nb_fields, double wind_fields[], + double vorticity_spectra[], double divergence_spectra[] ) { + ATLAS_ASSERT( t != nullptr ); + return t->dirtrans( nb_fields, wind_fields, vorticity_spectra, divergence_spectra ); +} + +int atlas__Trans__truncation( const TransImpl* This ) { + ATLAS_ASSERT( This != nullptr ); + return This->truncation(); +} + +const Grid::Implementation* atlas__Trans__grid( const TransImpl* This ) { + ATLAS_ASSERT( This != nullptr ); + ATLAS_ASSERT( This->grid() ); + return This->grid().get(); +} + +const functionspace::FunctionSpaceImpl* atlas__Trans__spectral( const TransImpl* This ) { + ATLAS_ASSERT( This != nullptr ); + const auto spectral = This->spectral(); + ATLAS_ASSERT( spectral ); + return spectral.get(); +} + + +void atlas__Trans__dirtrans_fieldset( const TransImpl* This, const field::FieldSetImpl* gpfields, + field::FieldSetImpl* spfields, const eckit::Configuration* 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 TransImpl* This, const field::FieldImpl* gpfield, field::FieldImpl* spfield, + const eckit::Configuration* 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 TransImpl* This, const field::FieldSetImpl* spfields, + field::FieldSetImpl* gpfields, const eckit::Configuration* 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 TransImpl* This, const field::FieldImpl* spfield, field::FieldImpl* gpfield, + const eckit::Configuration* 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 TransImpl* This, const field::FieldImpl* gpwind, + field::FieldImpl* spvor, field::FieldImpl* spdiv, + const eckit::Configuration* 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 TransImpl* This, const field::FieldImpl* spvor, + const field::FieldImpl* spdiv, field::FieldImpl* gpwind, + const eckit::Configuration* 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 TransImpl* 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_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 TransImpl* This, const field::FieldImpl* spfield, + field::FieldImpl* gpfield, const eckit::Configuration* config ) { + ATLAS_ASSERT( This != nullptr ); + ATLAS_ASSERT( spfield ); + ATLAS_ASSERT( gpfield ); + Field fgpfield( gpfield ); + This->invtrans_grad( spfield, fgpfield, *config ); +} +} + +} // namespace trans +} // namespace atlas diff --git a/src/atlas/trans/detail/TransInterface.h b/src/atlas/trans/detail/TransInterface.h new file mode 100644 index 000000000..a29dd60ac --- /dev/null +++ b/src/atlas/trans/detail/TransInterface.h @@ -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. + */ + +#pragma once + +#include "atlas/grid/Grid.h" +#include "atlas/trans/detail/TransImpl.h" + +//----------------------------------------------------------------------------- +// Forward declarations + +namespace eckit { +class Configuration; +} // namespace eckit + +namespace atlas { +class Field; +class FieldSet; +namespace field { +class FieldImpl; +class FieldSetImpl; +} // namespace field +namespace functionspace { +class FunctionSpaceImpl; +} +} // namespace atlas + +//----------------------------------------------------------------------------- + +namespace atlas { +namespace trans { + +//----------------------------------------------------------------------------- + +// C wrapper interfaces to C++ routines + +extern "C" { + +int atlas__Trans__has_backend( const char* backend ); +void atlas__Trans__set_backend( const char* backend ); +void atlas__Trans__backend( char*& backend, size_t& size ); + +TransImpl* atlas__Trans__new( const Grid::Implementation* grid, int truncation ); +TransImpl* atlas__Trans__new_config( const Grid::Implementation* grid, int truncation, + const eckit::Configuration* config ); +void atlas__Trans__delete( TransImpl* trans ); +void atlas__Trans__invtrans( const TransImpl* t, int nb_scalar_fields, double scalar_spectra[], int nb_vordiv_fields, + double vorticity_spectra[], double divergence_spectra[], double gp_fields[], + const eckit::Configuration* parameters ); +void atlas__Trans__invtrans_scalar( const TransImpl* t, int nb_fields, double scalar_spectra[], + double scalar_fields[] ); +void atlas__Trans__invtrans_vordiv2wind( const TransImpl* t, int nb_fields, double vorticity_spectra[], + double divergence_spectra[], double wind_fields[] ); +void atlas__Trans__dirtrans_scalar( const TransImpl* t, int nb_fields, double scalar_fields[], + double scalar_spectra[] ); +void atlas__Trans__dirtrans_wind2vordiv( const TransImpl* t, int nb_fields, double wind_fields[], + double vorticity_spectra[], double divergence_spectra[] ); +void atlas__Trans__dirtrans_wind2vordiv_field( const TransImpl* This, const field::FieldImpl* gpwind, + field::FieldImpl* spvor, field::FieldImpl* spdiv, + const eckit::Configuration* parameters ); +// void atlas__Trans__specnorm( const TransImpl* t, int nb_fields, double spectra[], double norms[], int rank ); +void atlas__Trans__dirtrans_fieldset( const TransImpl* This, const field::FieldSetImpl* gpfields, + field::FieldSetImpl* spfields, const eckit::Configuration* parameters ); +void atlas__Trans__dirtrans_field( const TransImpl* This, const field::FieldImpl* gpfield, field::FieldImpl* spfield, + const eckit::Configuration* parameters ); +void atlas__Trans__invtrans_fieldset( const TransImpl* This, const field::FieldSetImpl* spfields, + field::FieldSetImpl* gpfields, const eckit::Configuration* parameters ); +void atlas__Trans__invtrans_field( const TransImpl* This, const field::FieldImpl* spfield, field::FieldImpl* gpfield, + const eckit::Configuration* parameters ); +void atlas__Trans__invtrans_grad_field( const TransImpl* This, const field::FieldImpl* spfield, + field::FieldImpl* gpfield, const eckit::Configuration* parameters ); +void atlas__Trans__invtrans_vordiv2wind_field( const TransImpl* This, const field::FieldImpl* spvor, + const field::FieldImpl* spdiv, field::FieldImpl* gpwind, + const eckit::Configuration* parameters ); + +int atlas__Trans__handle( const TransImpl* trans ); +int atlas__Trans__truncation( const TransImpl* This ); +// int atlas__Trans__nspec2( const TransImpl* This ); +// int atlas__Trans__nspec2g( const TransImpl* This ); +// int atlas__Trans__ngptot( const TransImpl* This ); +// int atlas__Trans__ngptotg( const TransImpl* This ); +const Grid::Implementation* atlas__Trans__grid( const TransImpl* This ); +const functionspace::FunctionSpaceImpl* atlas__Trans__spectral( const TransImpl* This ); +} + +// ------------------------------------------------------------------ + +} // namespace trans +} // namespace atlas diff --git a/src/atlas/trans/ifs/LegendreCacheCreatorIFS.cc b/src/atlas/trans/ifs/LegendreCacheCreatorIFS.cc index bc42d8da1..db44fde10 100644 --- a/src/atlas/trans/ifs/LegendreCacheCreatorIFS.cc +++ b/src/atlas/trans/ifs/LegendreCacheCreatorIFS.cc @@ -58,7 +58,9 @@ std::string LegendreCacheCreatorIFS::uid() const { std::ostringstream stream; stream << "ifs-T" << truncation_ << "-"; if ( GaussianGrid( grid_ ) ) { - if ( RegularGaussianGrid( grid_ ) ) { stream << "RegularGaussianN" << GaussianGrid( grid_ ).N(); } + if ( RegularGaussianGrid( grid_ ) ) { + stream << "RegularGaussianN" << GaussianGrid( grid_ ).N(); + } else { stream << "ReducedGaussianN" << GaussianGrid( grid_ ).N() << "-PL"; stream << hash( grid_ ); @@ -66,7 +68,9 @@ std::string LegendreCacheCreatorIFS::uid() const { } else if ( RegularLonLatGrid( grid_ ) ) { auto g = RegularLonLatGrid( grid_ ); - if ( g.standard() || g.shifted() ) { stream << ( g.standard() ? "L" : "S" ) << g.nx() << "x" << g.ny(); } + 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 stream << "grid-" << hash( grid_ ); @@ -85,10 +89,14 @@ std::string LegendreCacheCreatorIFS::uid() const { LegendreCacheCreatorIFS::~LegendreCacheCreatorIFS() {} bool LegendreCacheCreatorIFS::supported() const { - if ( GaussianGrid( grid_ ) ) { return true; } + if ( GaussianGrid( grid_ ) ) { + return true; + } else if ( RegularLonLatGrid( grid_ ) ) { auto g = RegularLonLatGrid( grid_ ); - if ( g.standard() || g.shifted() ) { return true; } + 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 114d22369..28b1be16d 100644 --- a/src/atlas/trans/ifs/TransIFS.cc +++ b/src/atlas/trans/ifs/TransIFS.cc @@ -23,6 +23,7 @@ #include "atlas/parallel/mpi/mpi.h" #include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" +#include "atlas/trans/Trans.h" #include "atlas/trans/detail/TransFactory.h" #include "atlas/trans/ifs/TransIFS.h" @@ -89,7 +90,8 @@ namespace { std::string fieldset_functionspace( const FieldSet& fields ) { std::string functionspace( "undefined" ); for ( idx_t jfld = 0; jfld < fields.size(); ++jfld ) { - if ( functionspace == "undefined" ) functionspace = fields[jfld].functionspace().type(); + if ( functionspace == "undefined" ) + functionspace = fields[jfld].functionspace().type(); if ( fields[jfld].functionspace().type() != functionspace ) { throw_Exception( ": fielset has fields with different functionspaces", Here() ); } @@ -256,7 +258,7 @@ void TransIFS::invtrans( const int nb_scalar_fields, const double scalar_spectra args.lvordivgp = params.vorticity_divergence_fields(); args.nproma = params.nproma(); args.ngpblks = params.ngpblks(); - TRANS_CHECK(::trans_invtrans( &args ) ); + TRANS_CHECK( ::trans_invtrans( &args ) ); } /////////////////////////////////////////////////////////////////////////////// @@ -287,7 +289,7 @@ void TransIFS::dirtrans( const int nb_fields, const double scalar_fields[], doub args.lglobal = params.global(); args.nproma = params.nproma(); args.ngpblks = params.ngpblks(); - TRANS_CHECK(::trans_dirtrans( &args ) ); + TRANS_CHECK( ::trans_dirtrans( &args ) ); } /////////////////////////////////////////////////////////////////////////////// @@ -304,7 +306,7 @@ void TransIFS::dirtrans( const int nb_fields, const double wind_fields[], double args.lglobal = params.global(); args.nproma = params.nproma(); args.ngpblks = params.ngpblks(); - TRANS_CHECK(::trans_dirtrans( &args ) ); + TRANS_CHECK( ::trans_dirtrans( &args ) ); } } // namespace trans @@ -367,7 +369,8 @@ struct PackNodeColumns { } void pack_3( const Field& field, idx_t components ) { const ArrayView gpfield = make_view( field ); - if ( not components ) components = gpfield.shape( 2 ); + if ( not components ) + components = gpfield.shape( 2 ); for ( idx_t jcomp = 0; jcomp < components; ++jcomp ) { for ( idx_t jlev = 0; jlev < gpfield.shape( 1 ); ++jlev ) { idx_t n = 0; @@ -524,7 +527,8 @@ struct UnpackNodeColumns { } void unpack_3( Field& field, idx_t components ) { ArrayView gpfield = make_view( field ); - if ( not components ) components = gpfield.shape( 2 ); + if ( not components ) + components = gpfield.shape( 2 ); for ( idx_t jcomp = 0; jcomp < components; ++jcomp ) { for ( idx_t jlev = 0; jlev < gpfield.shape( 1 ); ++jlev ) { idx_t n = 0; @@ -655,10 +659,7 @@ TransIFS::TransIFS( const Cache& cache, const Grid& grid, const long truncation, } TransIFS::TransIFS( const Grid& grid, const long truncation, const eckit::Configuration& config ) : - TransIFS( Cache(), grid, truncation, config ) { - ATLAS_ASSERT( grid.domain().global() ); - ATLAS_ASSERT( not grid.projection() ); -} + TransIFS( Cache(), grid, truncation, config ) {} TransIFS::TransIFS( const Grid& grid, const eckit::Configuration& config ) : TransIFS( grid, /*grid-only*/ -1, config ) {} @@ -737,93 +738,109 @@ const int* atlas::trans::TransIFS::n_regions( int& size ) const { const int* atlas::trans::TransIFS::nfrstlat( int& size ) const { size = trans_->n_regions_NS; - if ( trans_->nfrstlat == nullptr ) ::trans_inquire( trans_.get(), "nfrstlat" ); + if ( trans_->nfrstlat == nullptr ) + ::trans_inquire( trans_.get(), "nfrstlat" ); return trans_->nfrstlat; } const int* atlas::trans::TransIFS::nlstlat( int& size ) const { size = trans_->n_regions_NS; - if ( trans_->nlstlat == nullptr ) ::trans_inquire( trans_.get(), "nlstlat" ); + if ( trans_->nlstlat == nullptr ) + ::trans_inquire( trans_.get(), "nlstlat" ); return trans_->nlstlat; } const int* atlas::trans::TransIFS::nptrfrstlat( int& size ) const { size = trans_->n_regions_NS; - if ( trans_->nptrfrstlat == nullptr ) ::trans_inquire( trans_.get(), "nptrfrstlat" ); + if ( trans_->nptrfrstlat == nullptr ) + ::trans_inquire( trans_.get(), "nptrfrstlat" ); return trans_->nptrfrstlat; } const int* atlas::trans::TransIFS::nsta( int& sizef2, int& sizef1 ) const { sizef1 = trans_->ndgl + trans_->n_regions_NS - 1; sizef2 = trans_->n_regions_EW; - if ( trans_->nsta == nullptr ) ::trans_inquire( trans_.get(), "nsta" ); + if ( trans_->nsta == nullptr ) + ::trans_inquire( trans_.get(), "nsta" ); return trans_->nsta; } const int* atlas::trans::TransIFS::nonl( int& sizef2, int& sizef1 ) const { sizef1 = trans_->ndgl + trans_->n_regions_NS - 1; sizef2 = trans_->n_regions_EW; - if ( trans_->nonl == nullptr ) ::trans_inquire( trans_.get(), "nonl" ); + if ( trans_->nonl == nullptr ) + ::trans_inquire( trans_.get(), "nonl" ); return trans_->nonl; } const int* atlas::trans::TransIFS::nmyms( int& size ) const { size = trans_->nump; - if ( trans_->nmyms == nullptr ) ::trans_inquire( trans_.get(), "nmyms" ); + if ( trans_->nmyms == nullptr ) + ::trans_inquire( trans_.get(), "nmyms" ); return trans_->nmyms; } const int* atlas::trans::TransIFS::nasm0( int& size ) const { size = trans_->nsmax + 1; // +1 because zeroth wave included - if ( trans_->nasm0 == nullptr ) ::trans_inquire( trans_.get(), "nasm0" ); + if ( trans_->nasm0 == nullptr ) + ::trans_inquire( trans_.get(), "nasm0" ); return trans_->nasm0; } const int* atlas::trans::TransIFS::nvalue( int& size ) const { size = trans_->nspec2; - if ( trans_->nvalue == nullptr ) ::trans_inquire( trans_.get(), "nvalue" ); + if ( trans_->nvalue == nullptr ) + ::trans_inquire( trans_.get(), "nvalue" ); return trans_->nvalue; } array::LocalView atlas::trans::TransIFS::nvalue() const { - if ( trans_->nvalue == nullptr ) ::trans_inquire( trans_.get(), "nvalue" ); + if ( trans_->nvalue == nullptr ) + ::trans_inquire( trans_.get(), "nvalue" ); return array::LocalView( trans_->nvalue, array::make_shape( trans_->nspec2 ) ); } array::LocalView atlas::trans::TransIFS::nasm0() const { - if ( trans_->nasm0 == nullptr ) ::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 ) ); } array::LocalView atlas::trans::TransIFS::nmyms() const { - if ( trans_->nmyms == nullptr ) ::trans_inquire( trans_.get(), "nmyms" ); + if ( trans_->nmyms == nullptr ) + ::trans_inquire( trans_.get(), "nmyms" ); return array::LocalView( trans_->nmyms, array::make_shape( trans_->nump ) ); } array::LocalView atlas::trans::TransIFS::nonl() const { - if ( trans_->nonl == nullptr ) ::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 ) ); } array::LocalView atlas::trans::TransIFS::nsta() const { - if ( trans_->nsta == nullptr ) ::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 ) ); } array::LocalView atlas::trans::TransIFS::nptrfrstlat() const { - if ( trans_->nptrfrstlat == nullptr ) ::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 ) ); } array::LocalView atlas::trans::TransIFS::nlstlat() const { - if ( trans_->nlstlat == nullptr ) ::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 ) ); } array::LocalView atlas::trans::TransIFS::nfrstlat() const { - if ( trans_->nfrstlat == nullptr ) ::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 ) ); } @@ -856,12 +873,23 @@ int atlas::trans::TransIFS::truncation() const { return std::max( 0, trans_->nsmax ); } -size_t atlas::trans::TransIFS::spectralCoefficients() const { +size_t TransIFS::nb_spectral_coefficients() const { + return trans_->nspec2; +} + +size_t TransIFS::nb_spectral_coefficients_global() const { return trans_->nspec2g; } +const functionspace::Spectral& TransIFS::spectral() const { + if ( not spectral_ ) { + spectral_ = functionspace::Spectral( Trans( this ) ); + } + return spectral_; +} + void TransIFS::ctor( const Grid& grid, long truncation, const eckit::Configuration& config ) { - trans_ = std::shared_ptr<::Trans_t>( new ::Trans_t, [](::Trans_t* p ) { + trans_ = std::shared_ptr<::Trans_t>( new ::Trans_t, []( ::Trans_t* p ) { ::trans_delete( p ); delete p; } ); @@ -879,28 +907,18 @@ void TransIFS::ctor( const Grid& grid, long truncation, const eckit::Configurati throw_NotImplemented( "Grid type not supported for Spectral Transforms", Here() ); } -void TransIFS::ctor_spectral_only( long truncation, const eckit::Configuration& ) { - trans_ = std::shared_ptr<::Trans_t>( new ::Trans_t, [](::Trans_t* p ) { - ::trans_delete( p ); - delete p; - } ); - TRANS_CHECK(::trans_new( trans_.get() ) ); - TRANS_CHECK(::trans_set_trunc( trans_.get(), truncation ) ); - TRANS_CHECK(::trans_use_mpi( mpi::comm().size() > 1 ) ); - TRANS_CHECK(::trans_setup( trans_.get() ) ); -} - 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 ) nloen[jlat] = pl[jlat]; - TRANS_CHECK(::trans_new( trans_.get() ) ); - TRANS_CHECK(::trans_use_mpi( mpi::comm().size() > 1 ) ); - TRANS_CHECK(::trans_set_resol( trans_.get(), nlat, nloen.data() ) ); - if ( truncation >= 0 ) TRANS_CHECK(::trans_set_trunc( trans_.get(), truncation ) ); + TRANS_CHECK( ::trans_new( trans_.get() ) ); + TRANS_CHECK( ::trans_use_mpi( mpi::comm().size() > 1 ) ); + TRANS_CHECK( ::trans_set_resol( trans_.get(), nlat, nloen.data() ) ); + if ( truncation >= 0 ) + TRANS_CHECK( ::trans_set_trunc( trans_.get(), truncation ) ); - TRANS_CHECK(::trans_set_cache( trans_.get(), cache_, cachesize_ ) ); + TRANS_CHECK( ::trans_set_cache( trans_.get(), cache_, cachesize_ ) ); if ( p.read_legendre().size() && mpi::comm().size() == 1 ) { eckit::PathName file( p.read_legendre() ); @@ -909,26 +927,27 @@ void TransIFS::ctor_rgg( const long nlat, const idx_t pl[], long truncation, con msg << "File " << file << " doesn't exist"; throw_CantOpenFile( msg.str(), Here() ); } - TRANS_CHECK(::trans_set_read( trans_.get(), file.asString().c_str() ) ); + TRANS_CHECK( ::trans_set_read( trans_.get(), file.asString().c_str() ) ); } if ( p.write_legendre().size() && mpi::comm().size() == 1 ) { eckit::PathName file( p.write_legendre() ); - TRANS_CHECK(::trans_set_write( trans_.get(), file.asString().c_str() ) ); + TRANS_CHECK( ::trans_set_write( trans_.get(), file.asString().c_str() ) ); } trans_->fft = p.fft(); trans_->lsplit = p.split_latitudes(); trans_->flt = p.flt(); - ATLAS_TRACE_SCOPE( "trans_setup" ) { TRANS_CHECK(::trans_setup( trans_.get() ) ); } + ATLAS_TRACE_SCOPE( "trans_setup" ) { TRANS_CHECK( ::trans_setup( trans_.get() ) ); } } void TransIFS::ctor_lonlat( const long nlon, const long nlat, long truncation, const eckit::Configuration& config ) { TransParameters p( *this, config ); - TRANS_CHECK(::trans_new( trans_.get() ) ); - TRANS_CHECK(::trans_use_mpi( mpi::comm().size() > 1 ) ); - TRANS_CHECK(::trans_set_resol_lonlat( trans_.get(), nlon, nlat ) ); - if ( truncation >= 0 ) TRANS_CHECK(::trans_set_trunc( trans_.get(), truncation ) ); - TRANS_CHECK(::trans_set_cache( trans_.get(), cache_, cachesize_ ) ); + TRANS_CHECK( ::trans_new( trans_.get() ) ); + TRANS_CHECK( ::trans_use_mpi( mpi::comm().size() > 1 ) ); + TRANS_CHECK( ::trans_set_resol_lonlat( trans_.get(), nlon, nlat ) ); + if ( truncation >= 0 ) + TRANS_CHECK( ::trans_set_trunc( trans_.get(), truncation ) ); + TRANS_CHECK( ::trans_set_cache( trans_.get(), cache_, cachesize_ ) ); if ( p.read_legendre().size() && mpi::comm().size() == 1 ) { eckit::PathName file( p.read_legendre() ); @@ -937,18 +956,18 @@ void TransIFS::ctor_lonlat( const long nlon, const long nlat, long truncation, c msg << "File " << file << " doesn't exist"; throw_CantOpenFile( msg.str(), Here() ); } - TRANS_CHECK(::trans_set_read( trans_.get(), file.asString().c_str() ) ); + TRANS_CHECK( ::trans_set_read( trans_.get(), file.asString().c_str() ) ); } if ( p.write_legendre().size() && mpi::comm().size() == 1 ) { eckit::PathName file( p.write_legendre() ); - TRANS_CHECK(::trans_set_write( trans_.get(), file.asString().c_str() ) ); + TRANS_CHECK( ::trans_set_write( trans_.get(), file.asString().c_str() ) ); } trans_->fft = p.fft(); trans_->lsplit = p.split_latitudes(); trans_->flt = p.flt(); - TRANS_CHECK(::trans_setup( trans_.get() ) ); + TRANS_CHECK( ::trans_setup( trans_.get() ) ); } // -------------------------------------------------------------------------------------------- @@ -995,7 +1014,7 @@ void TransIFS::__dirtrans( const functionspace::NodeColumns& gp, const FieldSet& transform.nscalar = nfld; transform.rgp = rgp.data(); transform.rspscalar = rsp.data(); - TRANS_CHECK(::trans_dirtrans( &transform ) ); + TRANS_CHECK( ::trans_dirtrans( &transform ) ); } // Unpack the spectral fields @@ -1043,7 +1062,7 @@ void TransIFS::__dirtrans( const StructuredColumns& gp, const Field& gpfield, co transform.rspscalar = rsp.data(); transform.ngpblks = ngptot(); transform.nproma = 1; - TRANS_CHECK(::trans_dirtrans( &transform ) ); + TRANS_CHECK( ::trans_dirtrans( &transform ) ); } // Unpack spectral @@ -1089,7 +1108,7 @@ void TransIFS::__dirtrans( const StructuredColumns& gp, const FieldSet& gpfields transform.rgp = rgp.data(); transform.rspscalar = rsp.data(); - TRANS_CHECK(::trans_dirtrans( &transform ) ); + TRANS_CHECK( ::trans_dirtrans( &transform ) ); } // Unpack the spectral fields @@ -1148,7 +1167,7 @@ void TransIFS::__invtrans_grad( const Spectral& sp, const FieldSet& spfields, co transform.rspscalar = rsp.data(); transform.lscalarders = true; - TRANS_CHECK(::trans_invtrans( &transform ) ); + TRANS_CHECK( ::trans_invtrans( &transform ) ); } // Unpack the gridpoint fields @@ -1233,7 +1252,7 @@ void TransIFS::__invtrans( const Spectral& sp, const FieldSet& spfields, const f transform.nscalar = nfld; transform.rgp = rgp.data(); transform.rspscalar = rsp.data(); - TRANS_CHECK(::trans_invtrans( &transform ) ); + TRANS_CHECK( ::trans_invtrans( &transform ) ); } // Unpack the gridpoint fields @@ -1281,7 +1300,7 @@ void TransIFS::__invtrans( const functionspace::Spectral& sp, const Field& spfie transform.rspscalar = rsp.data(); transform.ngpblks = ngptot(); transform.nproma = 1; - TRANS_CHECK(::trans_invtrans( &transform ) ); + TRANS_CHECK( ::trans_invtrans( &transform ) ); } // Unpack gridpoint fields @@ -1334,7 +1353,7 @@ void TransIFS::__invtrans( const functionspace::Spectral& sp, const FieldSet& sp transform.rgp = rgp.data(); transform.rspscalar = rsp.data(); - TRANS_CHECK(::trans_invtrans( &transform ) ); + TRANS_CHECK( ::trans_invtrans( &transform ) ); } // Unpack the gridpoint fields @@ -1369,8 +1388,10 @@ void TransIFS::__dirtrans_wind2vordiv( const functionspace::NodeColumns& gp, con throw_Exception( msg.str(), Here() ); } - if ( spvor.size() == 0 ) throw_Exception( "dirtrans: spectral vorticity field is empty." ); - if ( spdiv.size() == 0 ) throw_Exception( "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() ); @@ -1397,7 +1418,7 @@ void TransIFS::__dirtrans_wind2vordiv( const functionspace::NodeColumns& gp, con ATLAS_ASSERT( transform.rspvor ); ATLAS_ASSERT( transform.rspdiv ); - TRANS_CHECK(::trans_dirtrans( &transform ) ); + TRANS_CHECK( ::trans_dirtrans( &transform ) ); } // Pack spectral fields @@ -1432,8 +1453,10 @@ void TransIFS::__invtrans_vordiv2wind( const Spectral& sp, const Field& spvor, c 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." ); + 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() ); @@ -1459,7 +1482,7 @@ void TransIFS::__invtrans_vordiv2wind( const Spectral& sp, const Field& spvor, c ATLAS_ASSERT( transform.rspvor ); ATLAS_ASSERT( transform.rspdiv ); - TRANS_CHECK(::trans_invtrans( &transform ) ); + TRANS_CHECK( ::trans_invtrans( &transform ) ); } // Unpack the gridpoint fields @@ -1479,7 +1502,7 @@ void TransIFS::distspec( const int nb_fields, const int origin[], const double g args.rspecg = global_spectra; args.nfrom = origin; args.rspec = spectra; - TRANS_CHECK(::trans_distspec( &args ) ); + TRANS_CHECK( ::trans_distspec( &args ) ); } ///////////////////////////////////////////////////////////////////////////// @@ -1491,7 +1514,7 @@ void TransIFS::gathspec( const int nb_fields, const int destination[], const dou args.rspecg = global_spectra; args.nto = destination; args.rspec = spectra; - TRANS_CHECK(::trans_gathspec( &args ) ); + TRANS_CHECK( ::trans_gathspec( &args ) ); } ///////////////////////////////////////////////////////////////////////////// @@ -1503,7 +1526,7 @@ void TransIFS::distgrid( const int nb_fields, const int origin[], const double g args.nfrom = origin; args.rgpg = global_fields; args.rgp = fields; - TRANS_CHECK(::trans_distgrid( &args ) ); + TRANS_CHECK( ::trans_distgrid( &args ) ); } ///////////////////////////////////////////////////////////////////////////// @@ -1515,7 +1538,7 @@ void TransIFS::gathgrid( const int nb_fields, const int destination[], const dou args.nto = destination; args.rgp = fields; args.rgpg = global_fields; - TRANS_CHECK(::trans_gathgrid( &args ) ); + TRANS_CHECK( ::trans_gathgrid( &args ) ); } /////////////////////////////////////////////////////////////////////////////// @@ -1526,214 +1549,10 @@ void TransIFS::specnorm( const int nb_fields, const double spectra[], double nor args.rspec = spectra; args.rnorm = norms; args.nmaster = rank + 1; - TRANS_CHECK(::trans_specnorm( &args ) ); + TRANS_CHECK( ::trans_specnorm( &args ) ); } /////////////////////////////////////////////////////////////////////////////// -extern "C" { - -TransIFS* atlas__Trans__new( const Grid::Implementation* grid, int nsmax ) { - ATLAS_ASSERT( grid != nullptr ); - return new TransIFS( Grid( grid ), nsmax ); -} - -void atlas__Trans__delete( TransIFS* This ) { - ATLAS_ASSERT( This != nullptr ); - delete This; -} - -int atlas__Trans__handle( const TransIFS* This ) { - 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_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_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_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_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_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_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_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_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_ASSERT( t != nullptr ); - return t->specnorm( nb_fields, spectra, norms, rank ); -} - -int atlas__Trans__nspec2( const TransIFS* This ) { - ATLAS_ASSERT( This != nullptr ); - return This->trans()->nspec2; -} - -int atlas__Trans__nspec2g( const TransIFS* This ) { - ATLAS_ASSERT( This != nullptr ); - return This->trans()->nspec2g; -} - -int atlas__Trans__ngptot( const TransIFS* This ) { - ATLAS_ASSERT( This != nullptr ); - return This->trans()->ngptot; -} - -int atlas__Trans__ngptotg( const TransIFS* This ) { - ATLAS_ASSERT( This != nullptr ); - return This->trans()->ngptotg; -} - -int atlas__Trans__truncation( const TransIFS* This ) { - ATLAS_ASSERT( This != nullptr ); - return This->truncation(); -} - -const Grid::Implementation* atlas__Trans__grid( const TransIFS* This ) { - 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_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_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_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_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_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_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_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_ASSERT( This != nullptr ); - ATLAS_ASSERT( spfield ); - ATLAS_ASSERT( gpfield ); - Field fgpfield( gpfield ); - This->invtrans_grad( spfield, fgpfield, *config ); -} -} - } // namespace trans } // namespace atlas diff --git a/src/atlas/trans/ifs/TransIFS.h b/src/atlas/trans/ifs/TransIFS.h index da24c6b49..1bdb50df4 100644 --- a/src/atlas/trans/ifs/TransIFS.h +++ b/src/atlas/trans/ifs/TransIFS.h @@ -13,6 +13,7 @@ #include "eckit/filesystem/PathName.h" #include "atlas/array/LocalView.h" +#include "atlas/functionspace/Spectral.h" #include "atlas/grid/Grid.h" #include "atlas/grid/StructuredGrid.h" #include "atlas/runtime/Exception.h" @@ -89,9 +90,11 @@ class TransIFS : public trans::TransImpl { ::Trans_t* trans() const { return trans_.get(); } virtual int truncation() const override; - virtual size_t spectralCoefficients() const override; + virtual size_t nb_spectral_coefficients() const override; + virtual size_t nb_spectral_coefficients_global() const override; virtual const Grid& grid() const override { return grid_; } + virtual const functionspace::Spectral& spectral() const override; // pure virtual interface @@ -219,8 +222,6 @@ class TransIFS : public trans::TransImpl { void ctor_lonlat( const long nlon, const long nlat, long nsmax, const eckit::Configuration& ); - void ctor_spectral_only( long truncation, const eckit::Configuration& ); - private: friend class grid::detail::partitioner::TransPartitioner; @@ -228,7 +229,7 @@ class TransIFS : public trans::TransImpl { /// partitioning/parallelisation routines) TransIFS( const Grid& g, const eckit::Configuration& = util::NoConfig() ); - int handle() const; + virtual int handle() const override; int ndgl() const; int nsmax() const; int ngptot() const; @@ -328,57 +329,10 @@ class TransIFS : public trans::TransImpl { StructuredGrid grid_; const void* cache_{nullptr}; size_t cachesize_{0}; -}; - -//----------------------------------------------------------------------------- -// C wrapper interfaces to C++ routines - -extern "C" { -TransIFS* atlas__Trans__new( const Grid::Implementation* grid, int nsmax ); -void atlas__Trans__delete( TransIFS* trans ); -void atlas__Trans__distspec( const TransIFS* t, int nb_fields, int origin[], double global_spectra[], - double spectra[] ); -void atlas__Trans__gathspec( const TransIFS* t, int nb_fields, int destination[], double spectra[], - double global_spectra[] ); -void atlas__Trans__distgrid( const TransIFS* t, int nb_fields, int origin[], double global_fields[], double fields[] ); -void atlas__Trans__gathgrid( const TransIFS* t, int nb_fields, int destination[], double fields[], - double global_fields[] ); -void atlas__Trans__invtrans( const TransIFS* t, int nb_scalar_fields, double scalar_spectra[], int nb_vordiv_fields, - double vorticity_spectra[], double divergence_spectra[], double gp_fields[], - const eckit::Configuration* parameters ); -void atlas__Trans__invtrans_scalar( const TransIFS* t, int nb_fields, double scalar_spectra[], double scalar_fields[] ); -void atlas__Trans__invtrans_vordiv2wind( const TransIFS* t, int nb_fields, double vorticity_spectra[], - double divergence_spectra[], double wind_fields[] ); -void atlas__Trans__dirtrans_scalar( const TransIFS* t, int nb_fields, double scalar_fields[], double scalar_spectra[] ); -void atlas__Trans__dirtrans_wind2vordiv( const TransIFS* t, int nb_fields, double wind_fields[], - double vorticity_spectra[], double divergence_spectra[] ); -void atlas__Trans__dirtrans_wind2vordiv_field( const TransIFS* This, const field::FieldImpl* gpwind, - field::FieldImpl* spvor, field::FieldImpl* spdiv, - const eckit::Configuration* parameters ); -void atlas__Trans__specnorm( const TransIFS* t, int nb_fields, double spectra[], double norms[], int rank ); -void atlas__Trans__dirtrans_fieldset( const TransIFS* This, const field::FieldSetImpl* gpfields, - field::FieldSetImpl* spfields, const eckit::Configuration* parameters ); -void atlas__Trans__dirtrans_field( const TransIFS* This, const field::FieldImpl* gpfield, field::FieldImpl* spfield, - const eckit::Configuration* parameters ); -void atlas__Trans__invtrans_fieldset( const TransIFS* This, const field::FieldSetImpl* spfields, - field::FieldSetImpl* gpfields, const eckit::Configuration* parameters ); -void atlas__Trans__invtrans_field( const TransIFS* This, const field::FieldImpl* spfield, field::FieldImpl* gpfield, - const eckit::Configuration* parameters ); -void atlas__Trans__invtrans_grad_field( const TransIFS* This, const field::FieldImpl* spfield, - field::FieldImpl* gpfield, const eckit::Configuration* 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 ); - -int atlas__Trans__handle( const TransIFS* trans ); -int atlas__Trans__truncation( const TransIFS* This ); -int atlas__Trans__nspec2( const TransIFS* This ); -int atlas__Trans__nspec2g( const TransIFS* This ); -int atlas__Trans__ngptot( const TransIFS* This ); -int atlas__Trans__ngptotg( const TransIFS* This ); -const Grid::Implementation* atlas__Trans__grid( const TransIFS* This ); -} +protected: + mutable functionspace::Spectral spectral_; +}; // ------------------------------------------------------------------ diff --git a/src/atlas/trans/ifs/TransIFSNodeColumns.cc b/src/atlas/trans/ifs/TransIFSNodeColumns.cc index 2c8ef92ae..73d75161d 100644 --- a/src/atlas/trans/ifs/TransIFSNodeColumns.cc +++ b/src/atlas/trans/ifs/TransIFSNodeColumns.cc @@ -24,6 +24,7 @@ TransIFSNodeColumns::TransIFSNodeColumns( const Cache& cache, const functionspac const functionspace::Spectral& sp, const eckit::Configuration& config ) : TransIFS( cache, gp.mesh().grid(), sp.truncation(), config ) { assertCompatibleDistributions( gp, sp ); + spectral_ = sp; } TransIFSNodeColumns::~TransIFSNodeColumns() {} diff --git a/src/atlas/trans/ifs/TransIFSStructuredColumns.cc b/src/atlas/trans/ifs/TransIFSStructuredColumns.cc index af999a777..1da27e1ef 100644 --- a/src/atlas/trans/ifs/TransIFSStructuredColumns.cc +++ b/src/atlas/trans/ifs/TransIFSStructuredColumns.cc @@ -26,6 +26,7 @@ TransIFSStructuredColumns::TransIFSStructuredColumns( const Cache& cache, const const eckit::Configuration& config ) : TransIFS( cache, gp.grid(), sp.truncation(), config ) { assertCompatibleDistributions( gp, sp ); + spectral_ = sp; } TransIFSStructuredColumns::~TransIFSStructuredColumns() {} diff --git a/src/atlas/trans/ifs/VorDivToUVIFS.cc b/src/atlas/trans/ifs/VorDivToUVIFS.cc index 374adcce3..7adcaccf7 100644 --- a/src/atlas/trans/ifs/VorDivToUVIFS.cc +++ b/src/atlas/trans/ifs/VorDivToUVIFS.cc @@ -49,7 +49,7 @@ void VorDivToUVIFS::execute( const int nb_coeff, const int nb_fields, const doub vordiv_to_UV.nfld = nb_fields; vordiv_to_UV.ncoeff = nb_coeff; vordiv_to_UV.nsmax = truncation_; - TRANS_CHECK(::trans_vordiv_to_UV( &vordiv_to_UV ) ); + TRANS_CHECK( ::trans_vordiv_to_UV( &vordiv_to_UV ) ); } VorDivToUVIFS::VorDivToUVIFS( const int truncation, const eckit::Configuration& ) : truncation_( truncation ) {} diff --git a/src/atlas/trans/local/LegendreCacheCreatorLocal.cc b/src/atlas/trans/local/LegendreCacheCreatorLocal.cc index 6e7231a83..5cec303e2 100644 --- a/src/atlas/trans/local/LegendreCacheCreatorLocal.cc +++ b/src/atlas/trans/local/LegendreCacheCreatorLocal.cc @@ -120,8 +120,12 @@ LegendreCacheCreatorLocal::LegendreCacheCreatorLocal( const Grid& grid, int trun config_( config ) {} bool LegendreCacheCreatorLocal::supported() const { - if ( not StructuredGrid( grid_ ) ) return false; - if ( grid_.projection() ) return false; + if ( not StructuredGrid( grid_ ) ) { + return false; + } + if ( grid_.projection() ) { + return false; + } return true; } diff --git a/src/atlas/trans/local/LegendrePolynomials.cc b/src/atlas/trans/local/LegendrePolynomials.cc index ac6a523c4..8e2a986c7 100644 --- a/src/atlas/trans/local/LegendrePolynomials.cc +++ b/src/atlas/trans/local/LegendrePolynomials.cc @@ -124,7 +124,9 @@ void compute_legendre_polynomials_lat( const int trc, // truncation (in) double sq = std::sqrt( ( 2. * jn + 1. ) / ( 2. * jn ) ); legpol[idxmn( jn, jn )] = legpol[idxmn( jn - 1, jn - 1 )] * zdlsita * sq; - if ( std::abs( legpol[idxmn( jn, jn )] ) < zdls ) legpol[idxmn( jn, jn )] = 0.0; + if ( std::abs( legpol[idxmn( jn, jn )] ) < zdls ) { + legpol[idxmn( jn, jn )] = 0.0; + } } // --------------------------------------------- diff --git a/src/atlas/trans/local/TransLocal.cc b/src/atlas/trans/local/TransLocal.cc index 2b1ec9707..ddbf815eb 100644 --- a/src/atlas/trans/local/TransLocal.cc +++ b/src/atlas/trans/local/TransLocal.cc @@ -24,12 +24,14 @@ #include "eckit/types/FloatCompare.h" #include "atlas/array.h" +#include "atlas/field.h" #include "atlas/grid/Iterator.h" #include "atlas/grid/StructuredGrid.h" #include "atlas/option.h" #include "atlas/parallel/mpi/mpi.h" #include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" +#include "atlas/trans/Trans.h" #include "atlas/trans/VorDivToUV.h" #include "atlas/trans/detail/TransFactory.h" #include "atlas/trans/local/LegendrePolynomials.h" @@ -186,7 +188,9 @@ 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 ) { @@ -301,6 +305,7 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma nlatsLegReduced_ = 0; bool useGlobalLeg = true; bool no_nest = false; + if ( StructuredGrid( grid_ ) && not grid_.projection() ) { StructuredGrid g( grid_ ); nlats = g.ny(); @@ -317,7 +322,9 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma nlatsNH_++; nlatsSH_++; } - if ( nlatsNH_ >= nlatsSH_ ) { nlatsLegDomain_ = nlatsNH_; } + if ( nlatsNH_ >= nlatsSH_ ) { + nlatsLegDomain_ = nlatsNH_; + } else { nlatsLegDomain_ = nlatsSH_; } @@ -355,11 +362,15 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma jlonMin_[0] = 0; jlatMin_ = 0; nlatsGlobal_ = gs_global.ny(); - if ( grid_.domain().global() ) { Log::debug() << "Global grid with " << nlats << " latitudes." << std::endl; } + if ( grid_.domain().global() ) { + Log::debug() << "Global grid with " << nlats << " latitudes." << std::endl; + } else { Log::debug() << "Grid has " << nlats << " latitudes. Global grid has " << nlatsGlobal_ << std::endl; } - if ( useGlobalLeg ) { nlatsLeg_ = ( nlatsGlobal_ + 1 ) / 2; } + if ( useGlobalLeg ) { + nlatsLeg_ = ( nlatsGlobal_ + 1 ) / 2; + } else { nlatsLeg_ = nlatsLegDomain_; nlatsLegReduced_ = nlatsLeg_; @@ -372,12 +383,18 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma } //Log::info() << std::endl; int jlatMinLeg_ = jlatMin_; - if ( nlatsNH_ < nlatsSH_ ) { jlatMinLeg_ += nlatsNH_ - nlatsSH_; }; + if ( nlatsNH_ < nlatsSH_ ) { + jlatMinLeg_ += nlatsNH_ - nlatsSH_; + }; if ( jlatMin_ >= ( nlatsGlobal_ + 1 ) / 2 ) { jlatMinLeg_ -= 2 * ( jlatMin_ - ( nlatsGlobal_ + 1 ) / 2 ); - if ( nlatsGlobal_ % 2 == 1 ) { jlatMinLeg_--; } + if ( nlatsGlobal_ % 2 == 1 ) { + jlatMinLeg_--; + } }; - if ( useGlobalLeg ) { nlatsLegReduced_ = jlatMinLeg_ + nlatsLegDomain_; } + if ( useGlobalLeg ) { + nlatsLegReduced_ = jlatMinLeg_ + nlatsLegDomain_; + } // reduce truncation towards the pole for reduced meshes: nlat0_.resize( truncation_ + 1 ); @@ -394,7 +411,9 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma RegularGrid( gs_global ) ); nmen = std::max( nmen0, nmen ); int ndgluj = nlatsLeg_ - std::min( nlatsLeg_, nlatsLeg_ + jlatMinLeg_ - jlat ); - if ( useGlobalLeg ) { ndgluj = std::max( jlatMinLeg_, jlat ); } + if ( useGlobalLeg ) { + ndgluj = std::max( jlatMinLeg_, jlat ); + } for ( int j = nmen0 + 1; j <= nmen; j++ ) { nlat0_[j] = ndgluj; } @@ -411,17 +430,23 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma // compute longitudinal location of domain within global grid for using FFT: auto wrapAngle = [&]( double angle ) { double result = std::fmod( angle, 360. ); - if ( result < 0. ) { result += 360.; } + if ( result < 0. ) { + result += 360.; + } return result; }; if ( useFFT_ ) { double lonmin = wrapAngle( g.x( 0, 0 ) ); - if ( nlonsMax < fft_threshold * nlonsMaxGlobal_ ) { useFFT_ = false; } + if ( nlonsMax < fft_threshold * nlonsMaxGlobal_ ) { + useFFT_ = false; + } else { // need to use FFT with cropped grid if ( RegularGrid( gridGlobal_ ) ) { for ( idx_t jlon = 0; jlon < nlonsMaxGlobal_; ++jlon ) { - if ( gs_global.x( jlon, 0 ) < lonmin ) { jlonMin_[0]++; } + if ( gs_global.x( jlon, 0 ) < lonmin ) { + jlonMin_[0]++; + } } } else { @@ -432,7 +457,9 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma nlonsGlobal_[jlat] = gs_global.nx( jlat + jlatMin_ ); jlonMin_[jlat] = 0; for ( idx_t jlon = 0; jlon < nlonsGlobal_[jlat]; ++jlon ) { - if ( gs_global.x( jlon, jlat + jlatMin_ ) < lonmin ) { jlonMin_[jlat]++; } + if ( gs_global.x( jlon, jlat + jlatMin_ ) < lonmin ) { + jlonMin_[jlat]++; + } } } } @@ -444,16 +471,24 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma if ( nlatsNH_ >= nlatsSH_ || useGlobalLeg ) { for ( idx_t j = 0; j < nlatsLeg_; ++j ) { double lat = gsLeg.y( j ); - if ( lat > latPole ) { lat = latPole; } - if ( lat < -latPole ) { lat = -latPole; } + if ( lat > latPole ) { + lat = latPole; + } + if ( lat < -latPole ) { + lat = -latPole; + } lats[j] = lat * util::Constants::degreesToRadians(); } } else { 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; } + if ( lat > latPole ) { + lat = latPole; + } + if ( lat < -latPole ) { + lat = -latPole; + } lats[idx] = -lat * util::Constants::degreesToRadians(); } } @@ -584,7 +619,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(); @@ -608,7 +643,9 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma int idx = 0; for ( int jm = 0; jm < truncation_ + 1; jm++ ) { double factor = 1.; - if ( jm > 0 ) { factor = 2.; } + if ( jm > 0 ) { + factor = 2.; + } for ( int jlon = 0; jlon < nlonsMax; jlon++ ) { fourier_[idx++] = +std::cos( jm * lons[jlon] ) * factor; // real part } @@ -624,7 +661,9 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma for ( int jlon = 0; jlon < nlonsMax; jlon++ ) { double factor = 1.; for ( int jm = 0; jm < truncation_ + 1; jm++ ) { - if ( jm > 0 ) { factor = 2.; } + if ( jm > 0 ) { + factor = 2.; + } fourier_[idx++] = +std::cos( jm * lons[jlon] ) * factor; // real part fourier_[idx++] = -std::sin( jm * lons[jlon] ) * factor; // imaginary part } @@ -663,7 +702,7 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma "Caching for unstructured grids or structured grids with projections not yet implemented", Here() ); } } -} // namespace trans +} // -------------------------------------------------------------------------------------------------------------------- @@ -700,20 +739,47 @@ TransLocal::~TransLocal() { } } else { - if ( unstruct_precomp_ ) { free_aligned( legendre_, "Legendre coeffs." ); } + if ( unstruct_precomp_ ) { + free_aligned( legendre_, "Legendre coeffs." ); + } } } // -------------------------------------------------------------------------------------------------------------------- -void TransLocal::invtrans( const Field& /*spfield*/, Field& /*gpfield*/, const eckit::Configuration& ) const { - ATLAS_NOTIMPLEMENTED; +const functionspace::Spectral& TransLocal::spectral() const { + if ( not spectral_ ) { + spectral_ = functionspace::Spectral( Trans( this ) ); + } + return spectral_; } // -------------------------------------------------------------------------------------------------------------------- -void TransLocal::invtrans( const FieldSet& /*spfields*/, FieldSet& /*gpfields*/, const eckit::Configuration& ) const { - ATLAS_NOTIMPLEMENTED; +void TransLocal::invtrans( const Field& spfield, Field& gpfield, const eckit::Configuration& config ) const { + // VERY PRELIMINARY IMPLEMENTATION WITHOUT ANY GUARANTEES + int nb_scalar_fields = 1; + const auto scalar_spectra = array::make_view( spfield ); + auto gp_fields = array::make_view( gpfield ); + + if ( gp_fields.shape( 0 ) < grid().size() ) { + // Hopefully the halo (if present) is appended + ATLAS_DEBUG_VAR( gp_fields.shape( 0 ) ); + ATLAS_DEBUG_VAR( grid().size() ); + ATLAS_ASSERT( gp_fields.shape( 0 ) < grid().size() ); + } + + invtrans( nb_scalar_fields, scalar_spectra.data(), gp_fields.data(), config ); +} + +// -------------------------------------------------------------------------------------------------------------------- + +void TransLocal::invtrans( const FieldSet& spfields, FieldSet& gpfields, const eckit::Configuration& config ) const { + // VERY PRELIMINARY IMPLEMENTATION WITHOUT ANY GUARANTEES + ATLAS_ASSERT( spfields.size() == gpfields.size() ); + for ( idx_t f = 0; f < spfields.size(); ++f ) { + invtrans( spfields[f], gpfields[f], config ); + } } // -------------------------------------------------------------------------------------------------------------------- @@ -731,28 +797,46 @@ void TransLocal::invtrans_grad( const FieldSet& /*spfields*/, FieldSet& /*gradfi // -------------------------------------------------------------------------------------------------------------------- -void TransLocal::invtrans_vordiv2wind( const Field& /*spvor*/, const Field& /*spdiv*/, Field& /*gpwind*/, - const eckit::Configuration& ) const { - ATLAS_NOTIMPLEMENTED; +void gp_transpose( const int nb_size, const int nb_fields, const double gp_tmp[], double gp_fields[] ) { + for ( int jgp = 0; jgp < nb_size; jgp++ ) { + for ( int jfld = 0; jfld < nb_fields; jfld++ ) { + gp_fields[jfld * nb_size + jgp] = gp_tmp[jgp * nb_fields + jfld]; + } + } } // -------------------------------------------------------------------------------------------------------------------- -void TransLocal::invtrans( const int nb_scalar_fields, const double scalar_spectra[], double gp_fields[], - const eckit::Configuration& config ) const { - invtrans_uv( truncation_, nb_scalar_fields, 0, scalar_spectra, gp_fields, config ); +void TransLocal::invtrans_vordiv2wind( const Field& spvor, const Field& spdiv, Field& gpwind, + const eckit::Configuration& config ) const { + // VERY PRELIMINARY IMPLEMENTATION WITHOUT ANY GUARANTEES + int nb_vordiv_fields = 1; + const auto vorticity_spectra = array::make_view( spvor ); + const auto divergence_spectra = array::make_view( spdiv ); + auto gp_fields = array::make_view( gpwind ); + + if ( gp_fields.shape( 1 ) == grid().size() && gp_fields.shape( 0 ) == 2 ) { + invtrans( nb_vordiv_fields, vorticity_spectra.data(), divergence_spectra.data(), gp_fields.data(), config ); + } + else if ( gp_fields.shape( 0 ) == grid().size() && gp_fields.shape( 1 ) == 2 ) { + array::ArrayT gpwind_t( gp_fields.shape( 1 ), gp_fields.shape( 0 ) ); + auto gp_fields_t = array::make_view( gpwind_t ); + invtrans( nb_vordiv_fields, vorticity_spectra.data(), divergence_spectra.data(), gp_fields_t.data(), config ); + gp_transpose( grid().size(), 2, gp_fields_t.data(), gp_fields.data() ); + } + else { + ATLAS_NOTIMPLEMENTED; + } } // -------------------------------------------------------------------------------------------------------------------- -void gp_transpose( const int nb_size, const int nb_fields, const double gp_tmp[], double gp_fields[] ) { - for ( int jgp = 0; jgp < nb_size; jgp++ ) { - for ( int jfld = 0; jfld < nb_fields; jfld++ ) { - gp_fields[jfld * nb_size + jgp] = gp_tmp[jgp * nb_fields + jfld]; - } - } +void TransLocal::invtrans( const int nb_scalar_fields, const double scalar_spectra[], double gp_fields[], + const eckit::Configuration& config ) const { + invtrans_uv( truncation_, nb_scalar_fields, 0, scalar_spectra, gp_fields, config ); } + // -------------------------------------------------------------------------------------------------------------------- void TransLocal::invtrans_legendre( const int truncation, const int nlats, const int nb_fields, @@ -795,13 +879,17 @@ void TransLocal::invtrans_legendre( const int truncation, const int nlats, const for ( int jfld = 0; jfld < nb_fields; jfld++ ) { idx = jfld + nb_fields * ( imag + 2 * ( jn - jm ) ); if ( jn <= truncation && jm < truncation ) { - if ( ( jn - jm ) % 2 == 0 ) { scalar_sym[is++] = scalar_spectra[idx + ioff]; } + if ( ( jn - jm ) % 2 == 0 ) { + scalar_sym[is++] = scalar_spectra[idx + ioff]; + } else { scalar_asym[ia++] = scalar_spectra[idx + ioff]; } } else { - if ( ( jn - jm ) % 2 == 0 ) { scalar_sym[is++] = 0.; } + if ( ( jn - jm ) % 2 == 0 ) { + scalar_sym[is++] = 0.; + } else { scalar_asym[ia++] = 0.; } @@ -937,7 +1025,9 @@ void TransLocal::invtrans_fourier_regular( const int nlats, const int nlons, con for ( int jlat = 0; jlat < nlats; jlat++ ) { for ( int jlon = 0; jlon < nlons; jlon++ ) { int j = jlon + jlonMin_[0]; - if ( j >= nlonsMaxGlobal_ ) { j -= nlonsMaxGlobal_; } + if ( j >= nlonsMaxGlobal_ ) { + j -= nlonsMaxGlobal_; + } gp_fields[jlon + nlons * ( jlat + nlats * jfld )] = fftw_->out[j + nlonsMaxGlobal_ * jlat]; } } @@ -1024,12 +1114,16 @@ void TransLocal::invtrans_fourier_reduced( const int nlats, const StructuredGrid //Log::info() << std::endl; //Log::info() << jlat << "out:" << std::endl; int jplan = nlatsLegDomain_ - nlatsNH_ + jlat; - if ( jplan >= nlatsLegDomain_ ) { jplan = nlats - 1 + nlatsLegDomain_ - nlatsSH_ - jlat; }; + if ( jplan >= nlatsLegDomain_ ) { + jplan = nlats - 1 + nlatsLegDomain_ - nlatsSH_ - jlat; + }; //ASSERT( jplan < nlatsLeg_ && jplan >= 0 ); fftw_execute_dft_c2r( fftw_->plans[jplan], fftw_->in, fftw_->out ); for ( int jlon = 0; jlon < g.nx( jlat ); jlon++ ) { int j = jlon + jlonMin_[jlat]; - if ( j >= nlonsGlobal_[jlat] ) { j -= nlonsGlobal_[jlat]; } + if ( j >= nlonsGlobal_[jlat] ) { + j -= nlonsGlobal_[jlat]; + } //Log::info() << fftw_->out[j] << " "; ATLAS_ASSERT( j < nlonsMaxGlobal_ ); gp_fields[jgp++] = fftw_->out[j]; @@ -1293,8 +1387,12 @@ void TransLocal::invtrans_uv( const int truncation, const int nb_scalar_fields, std::vector coslatinvs( nlats ); for ( idx_t j = 0; j < nlats; ++j ) { double lat = g.y( j ); - if ( lat > latPole ) { lat = latPole; } - if ( lat < -latPole ) { lat = -latPole; } + if ( lat > latPole ) { + lat = latPole; + } + if ( lat < -latPole ) { + lat = -latPole; + } double coslat = std::cos( lat * util::Constants::degreesToRadians() ); coslatinvs[j] = 1. / coslat; //Log::info() << "lat=" << g.y( j ) << " coslat=" << coslat << std::endl; @@ -1342,7 +1440,9 @@ void extend_truncation( const int old_truncation, const int nb_fields, const dou for ( int n = m; n <= old_truncation + 1; n++ ) { // total wavenumber for ( int imag = 0; imag < 2; imag++ ) { // imaginary/real part for ( int jfld = 0; jfld < nb_fields; jfld++ ) { // field - if ( m == old_truncation + 1 || n == old_truncation + 1 ) { new_spectra[k++] = 0.; } + if ( m == old_truncation + 1 || n == old_truncation + 1 ) { + new_spectra[k++] = 0.; + } else { new_spectra[k++] = old_spectra[k_old++]; } diff --git a/src/atlas/trans/local/TransLocal.h b/src/atlas/trans/local/TransLocal.h index 2d5611cf3..ca1458c9c 100644 --- a/src/atlas/trans/local/TransLocal.h +++ b/src/atlas/trans/local/TransLocal.h @@ -14,6 +14,7 @@ #include #include "atlas/array.h" +#include "atlas/functionspace/Spectral.h" #include "atlas/grid/Grid.h" #include "atlas/trans/detail/TransImpl.h" @@ -76,9 +77,14 @@ class TransLocal : public trans::TransImpl { virtual ~TransLocal() override; virtual int truncation() const override { return truncation_; } - virtual size_t spectralCoefficients() const override { return ( truncation_ + 1 ) * ( truncation_ + 2 ); } + + virtual size_t nb_spectral_coefficients() const override { return ( truncation_ + 1 ) * ( truncation_ + 2 ); } + virtual size_t nb_spectral_coefficients_global() const override { + return ( truncation_ + 1 ) * ( truncation_ + 2 ); + } virtual const Grid& grid() const override { return grid_; } + virtual const functionspace::Spectral& spectral() const override; virtual void invtrans( const Field& spfield, Field& gpfield, const eckit::Configuration& = util::NoConfig() ) const override; @@ -162,6 +168,7 @@ class TransLocal : public trans::TransImpl { friend class LegendreCacheCreatorLocal; private: + mutable functionspace::Spectral spectral_; Grid grid_; Grid gridGlobal_; bool useFFT_; diff --git a/src/atlas/trans/local/VorDivToUVLocal.cc b/src/atlas/trans/local/VorDivToUVLocal.cc index 56bf78c99..8f2bcbe43 100644 --- a/src/atlas/trans/local/VorDivToUVLocal.cc +++ b/src/atlas/trans/local/VorDivToUVLocal.cc @@ -100,7 +100,9 @@ void vd2uv( const int truncation, // truncation int ij = truncation + 3 - jn; if ( jn >= 0 ) { zlapin[ij] = rlapin[jn]; - if ( jn < km ) { zepsnm[ij] = 0.; } + if ( jn < km ) { + zepsnm[ij] = 0.; + } else { zepsnm[ij] = repsnm[jn + ( 2 * truncation - km + 5 ) * km / 2]; } diff --git a/src/atlas/util/Allocate.cc b/src/atlas/util/Allocate.cc index 8d2136381..3d85081fb 100644 --- a/src/atlas/util/Allocate.cc +++ b/src/atlas/util/Allocate.cc @@ -29,7 +29,8 @@ 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() ); + if ( err != cudaSuccess ) + throw_AssertionFailed( "failed to allocate GPU memory", Here() ); #else *ptr = malloc( size ); #endif @@ -38,11 +39,13 @@ void allocate_cudamanaged( void** ptr, size_t size ) { 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() ); + 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() ); + if ( err != cudaSuccess ) + throw_AssertionFailed( "failed to free GPU memory", Here() ); #else free( ptr ); #endif diff --git a/src/atlas/util/Config.cc b/src/atlas/util/Config.cc index 8240b2639..d0d6b74e9 100644 --- a/src/atlas/util/Config.cc +++ b/src/atlas/util/Config.cc @@ -37,9 +37,13 @@ static eckit::Value yaml_from_stream( std::istream& stream ) { } static eckit::Value yaml_from_path( const eckit::PathName& path ) { - if ( !path.exists() ) { throw_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_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; @@ -72,8 +76,9 @@ Config& Config::set( const eckit::LocalConfiguration& other ) { Config& Config::set( const std::string& name, const std::vector& values ) { std::vector metadatavalues( values.size() ); - for ( size_t i = 0; i < metadatavalues.size(); ++i ) + for ( size_t i = 0; i < metadatavalues.size(); ++i ) { metadatavalues[i] = values[i]; + } set( name, metadatavalues ); return *this; } @@ -175,7 +180,9 @@ void atlas__Config__set_array_double( Config* This, const char* name, double val int atlas__Config__get_config( Config* This, const char* name, Config* value ) { ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); - if ( !This->get( std::string( name ), *value ) ) return false; + if ( !This->get( std::string( name ), *value ) ) { + return false; + } return true; } @@ -183,7 +190,9 @@ int atlas__Config__get_config_list( Config* This, const char* name, Config**& va ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); value = nullptr; std::vector vector; - if ( !This->get( std::string( name ), vector ) ) return false; + if ( !This->get( std::string( name ), vector ) ) { + return false; + } size = vector.size(); value = new Config*[size]; allocated = true; @@ -196,26 +205,34 @@ int atlas__Config__get_config_list( Config* This, const char* name, Config**& va 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; - if ( !This->get( std::string( name ), long_value ) ) return false; + 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_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); - if ( !This->get( std::string( name ), value ) ) return false; + 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; - if ( !This->get( std::string( name ), double_value ) ) return false; + 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_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); - if ( !This->get( std::string( name ), value ) ) return false; + 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 ) { @@ -234,7 +251,9 @@ int atlas__Config__get_string( Config* This, const char* name, char*& value, int int atlas__Config__get_array_int( Config* This, const char* name, int*& value, int& size, int& allocated ) { ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); std::vector v; - if ( !This->get( std::string( name ), v ) ) return false; + 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 ) { @@ -247,18 +266,23 @@ int atlas__Config__get_array_int( Config* This, const char* name, int*& value, i int atlas__Config__get_array_long( Config* This, const char* name, long*& value, int& size, int& allocated ) { ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); std::vector v; - if ( !This->get( std::string( name ), v ) ) return false; + 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 ) + 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_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); std::vector v; - if ( !This->get( std::string( name ), v ) ) return false; + 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 ) { @@ -270,11 +294,14 @@ int atlas__Config__get_array_float( Config* This, const char* name, float*& valu int atlas__Config__get_array_double( Config* This, const char* name, double*& value, int& size, int& allocated ) { ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); std::vector v; - if ( !This->get( std::string( name ), v ) ) return false; + 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 ) + for ( size_t j = 0; j < v.size(); ++j ) { value[j] = v[j]; + } allocated = true; return true; } diff --git a/src/atlas/util/Factory.cc b/src/atlas/util/Factory.cc index ef6516644..a9252edff 100644 --- a/src/atlas/util/Factory.cc +++ b/src/atlas/util/Factory.cc @@ -97,11 +97,15 @@ void FactoryRegistry::list( std::ostream& out ) const { FactoryBase::FactoryBase( FactoryRegistry& registry, const std::string& builder ) : registry_( registry ), builder_( builder ) { - if ( not builder_.empty() ) { registry_.add( builder, this ); } + if ( not builder_.empty() ) { + registry_.add( builder, this ); + } } FactoryBase::~FactoryBase() { - if ( not builder_.empty() ) { registry_.remove( builder_ ); } + if ( not builder_.empty() ) { + registry_.remove( builder_ ); + } } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/atlas/util/LonLatMicroDeg.h b/src/atlas/util/LonLatMicroDeg.h index a9d689349..832677af9 100644 --- a/src/atlas/util/LonLatMicroDeg.h +++ b/src/atlas/util/LonLatMicroDeg.h @@ -80,8 +80,10 @@ class LonLatMicroDeg { // ------------------------------------------------------------------------------------ inline bool LonLatMicroDeg::operator<( const LonLatMicroDeg& other ) const { - if ( p_[LAT] > other.p_[LAT] ) return true; - if ( p_[LAT] == other.p_[LAT] ) return ( p_[LON] < other.p_[LON] ); + if ( p_[LAT] > other.p_[LAT] ) + return true; + if ( p_[LAT] == other.p_[LAT] ) + return ( p_[LON] < other.p_[LON] ); return false; } diff --git a/src/atlas/util/LonLatPolygon.cc b/src/atlas/util/LonLatPolygon.cc index 4cca4f1d1..d4c3a02ad 100644 --- a/src/atlas/util/LonLatPolygon.cc +++ b/src/atlas/util/LonLatPolygon.cc @@ -65,7 +65,9 @@ bool LonLatPolygon::contains( const PointLonLat& P ) const { if ( APB != BPA ) { const double side = cross_product_analog( P, A, B ); - if ( APB && side > 0 ) { ++wn; } + if ( APB && side > 0 ) { + ++wn; + } else if ( BPA && side < 0 ) { --wn; } diff --git a/src/atlas/util/Metadata.cc b/src/atlas/util/Metadata.cc index e4c3357db..055935555 100644 --- a/src/atlas/util/Metadata.cc +++ b/src/atlas/util/Metadata.cc @@ -69,7 +69,9 @@ void Metadata::broadcast( Metadata& dest, const size_t root ) { ATLAS_TRACE_MPI( BROADCAST ) { atlas::mpi::comm().broadcast( buffer_size, root ); } - if ( atlas::mpi::comm().rank() != root ) { buffer.resize( buffer_size ); } + if ( atlas::mpi::comm().rank() != root ) { + buffer.resize( buffer_size ); + } ATLAS_TRACE_MPI( BROADCAST ) { atlas::mpi::comm().broadcast( buffer.begin(), buffer.end(), root ); } @@ -101,7 +103,9 @@ void Metadata::broadcast( Metadata& dest, const size_t root ) const { ATLAS_TRACE_MPI( BROADCAST ) { atlas::mpi::comm().broadcast( buffer_size, root ); } - if ( atlas::mpi::comm().rank() != root ) { buffer.resize( buffer_size ); } + if ( atlas::mpi::comm().rank() != root ) { + buffer.resize( buffer_size ); + } ATLAS_TRACE_MPI( BROADCAST ) { atlas::mpi::comm().broadcast( buffer.begin(), buffer.end(), root ); } @@ -206,8 +210,9 @@ void atlas__Metadata__get_array_int( Metadata* This, const char* name, int*& val std::vector v = This->get>( std::string( name ) ); size = v.size(); value = new int[size]; - for ( size_t j = 0; j < v.size(); ++j ) + 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 ) { @@ -215,8 +220,9 @@ void atlas__Metadata__get_array_long( Metadata* This, const char* name, long*& v std::vector v = This->get>( std::string( name ) ); size = v.size(); value = new long[size]; - for ( size_t j = 0; j < v.size(); ++j ) + 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 ) { @@ -224,8 +230,9 @@ void atlas__Metadata__get_array_float( Metadata* This, const char* name, float*& std::vector v = This->get>( std::string( name ) ); size = v.size(); value = new float[size]; - for ( size_t j = 0; j < v.size(); ++j ) + 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 ) { diff --git a/src/atlas/util/Metadata.h b/src/atlas/util/Metadata.h index be62406ea..7fc6c179f 100644 --- a/src/atlas/util/Metadata.h +++ b/src/atlas/util/Metadata.h @@ -38,7 +38,8 @@ class Metadata : public eckit::LocalConfiguration { template ValueT get( const std::string& name ) const { ValueT value; - if ( not eckit::LocalConfiguration::get( name, value ) ) throw_not_found( name ); + if ( not eckit::LocalConfiguration::get( name, value ) ) + throw_not_found( name ); return value; } diff --git a/src/atlas/util/ObjectHandle.cc b/src/atlas/util/ObjectHandle.cc index 15f6d0d53..add7aa9fe 100644 --- a/src/atlas/util/ObjectHandle.cc +++ b/src/atlas/util/ObjectHandle.cc @@ -43,7 +43,9 @@ void ObjectHandleBase::assign( const ObjectHandleBase& other ) { } void ObjectHandleBase::assign( const Object* other ) { - if ( object_ ) { release(); } + if ( object_ ) { + release(); + } object_ = const_cast( other ); @@ -52,7 +54,9 @@ void ObjectHandleBase::assign( const Object* other ) { void ObjectHandleBase::attach() { - if ( !null() ) object_->attach(); + if ( !null() ) { + object_->attach(); + } } // ------------------------------------------------------------------ diff --git a/src/atlas/util/ObjectHandle.h b/src/atlas/util/ObjectHandle.h index 975847314..c6309a268 100644 --- a/src/atlas/util/ObjectHandle.h +++ b/src/atlas/util/ObjectHandle.h @@ -21,18 +21,24 @@ class ObjectHandleBase { ObjectHandleBase( const Object* object ) : object_( const_cast( object ) ) { attach(); } virtual ~ObjectHandleBase() { - if ( object_ ) { release(); } + if ( object_ ) { + release(); + } } const ObjectHandleBase& operator=( const ObjectHandleBase& other ) { - if ( object_ != other.object_ ) { assign( 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 ); } + if ( object_ != other ) { + assign( other ); + } } int owners() const; diff --git a/src/atlas/util/Polygon.cc b/src/atlas/util/Polygon.cc index d578ecd41..9daa14c14 100644 --- a/src/atlas/util/Polygon.cc +++ b/src/atlas/util/Polygon.cc @@ -44,7 +44,9 @@ Polygon::Polygon( const Polygon::edge_set_t& edges ) { // 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 ); } + if ( !extEdges.erase( e.reverse() ) ) { + extEdges.insert( e ); + } } ATLAS_ASSERT( extEdges.size() >= 2 ); @@ -72,7 +74,9 @@ Polygon::operator bool() const { } Polygon& Polygon::operator+=( const Polygon& other ) { - if ( empty() ) { return operator=( other ); } + if ( empty() ) { + return operator=( other ); + } // polygon can have multiple cycles, but must be connected graphs // Note: a 'cycle' is handled by repeating the indices, excluding (repeated) diff --git a/src/atlas/util/Rotation.cc b/src/atlas/util/Rotation.cc index b30ef0972..71ff2a7a5 100644 --- a/src/atlas/util/Rotation.cc +++ b/src/atlas/util/Rotation.cc @@ -13,14 +13,43 @@ #include #include +#include "eckit/config/Parametrisation.h" +#include "eckit/types/FloatCompare.h" + #include "atlas/util/Constants.h" #include "atlas/util/CoordinateEnums.h" #include "atlas/util/UnitSphere.h" -#include "eckit/config/Parametrisation.h" namespace atlas { namespace util { +namespace { + +PointLonLat wrap_latitude( const PointLonLat& p ) { + double lon = p.lon(); + double lat = p.lat(); + + while ( lat > 90. ) { + lon += 180.; + lat = 180. - lat; + } + + while ( lat < -90. ) { + lon -= 180.; + lat = -180. - lat; + } + + return {lon, lat}; +} + +double wrap_angle( double a ) { + PointLonLat angle{a, 0}; + angle.normalise(); + return angle.lon(); +} + +} // namespace + void Rotation::print( std::ostream& out ) const { out << "north_pole:" << npole_ << ", south_pole:" << spole_ << ", rotation_angle:" << angle_; } @@ -42,7 +71,7 @@ PointLonLat Rotation::unrotate( const PointLonLat& p ) const { } void Rotation::precompute() { - const double theta = -( 90.0 + spole_.lat() ) * Constants::degreesToRadians(); + const double theta = -( 90. + spole_.lat() ) * Constants::degreesToRadians(); const double phi = -spole_.lon() * Constants::degreesToRadians(); const double sin_theta = std::sin( theta ); @@ -50,6 +79,16 @@ void Rotation::precompute() { const double sin_phi = std::sin( phi ); const double cos_phi = std::cos( phi ); + auto eq = []( double a, double b ) { return eckit::types::is_approximately_equal( a, b, 1.e-12 ); }; + + rotated_ = !eq( angle_, 0 ) || !eq( sin_theta, 0 ) || !eq( cos_theta, 1 ) || !eq( sin_phi, 0 ) || !eq( cos_phi, 1 ); + rotation_angle_only_ = eq( sin_theta, 0 ) && eq( cos_theta, 1 ) && rotated_; + + if ( !rotated_ ) { + rotate_ = unrotate_ = {1., 0., 0., 0., 1., 0., 0., 0., 1.}; + return; + } + // Pt = Rot(z) * Rot(y) * P, rotate about y axes then z // Since we're undoing the rotation described in the definition // of the coordinate system, @@ -82,20 +121,15 @@ void Rotation::precompute() { unrotate_ = {cos_theta * cos_phi, -cos_theta * sin_phi, -sin_theta, sin_phi, cos_phi, 0., sin_theta * cos_phi, -sin_theta * sin_phi, cos_theta}; - - if ( spole_.lon() == 0. && spole_.lat() == -90. && angle_ == 0. ) rotated_ = false; - rotation_angle_only_ = spole_.lon() == 0. && spole_.lat() == -90. && rotated_; - - double latrp = ( 90.0 - npole_.lat() ) * Constants::degreesToRadians(); - cos_latrp_ = std::cos( latrp ); - sin_latrp_ = std::sin( latrp ); } Rotation::Rotation( const PointLonLat& south_pole, double rotation_angle ) { spole_ = south_pole; npole_ = PointLonLat( spole_.lon() - 180., spole_.lat() + 180. ); - if ( npole_.lat() > 90 ) npole_.lon() += 180.; - angle_ = rotation_angle; + if ( npole_.lat() > 90 ) { + npole_.lon() += 180.; + } + angle_ = wrap_angle( rotation_angle ); precompute(); } @@ -103,86 +137,28 @@ Rotation::Rotation( const PointLonLat& south_pole, double rotation_angle ) { Rotation::Rotation( const eckit::Parametrisation& p ) { // get rotation angle p.get( "rotation_angle", angle_ ); + angle_ = wrap_angle( angle_ ); // get pole std::vector pole( 2 ); if ( p.get( "north_pole", pole ) ) { npole_ = PointLonLat( pole.data() ); spole_ = PointLonLat( npole_.lon() + 180., npole_.lat() - 180. ); - if ( spole_.lat() < -90 ) spole_.lon() -= 180.; + if ( spole_.lat() < -90 ) { + spole_.lon() -= 180.; + } } else if ( p.get( "south_pole", pole ) ) { spole_ = PointLonLat( pole.data() ); npole_ = PointLonLat( spole_.lon() - 180., spole_.lat() + 180. ); - if ( npole_.lat() > 90 ) npole_.lon() += 180.; + if ( npole_.lat() > 90 ) { + npole_.lon() += 180.; + } } precompute(); } -void Rotation::rotate_old( double crd[] ) const { - // coordinates of the point P on a rotated sphere with specified pole - double lon, lat, lont, latt; - double xt, yt, zt, x, y, z; - double cos_lon, sin_lon, cos_lat, sin_lat; - - lon = crd[LON] * Constants::degreesToRadians(); - lat = crd[LAT] * Constants::degreesToRadians(); - cos_lon = std::cos( lon ); - cos_lat = std::cos( lat ); - sin_lon = std::sin( lon ); - sin_lat = std::sin( lat ); - - // cartesian coordinates - x = cos_lon * cos_lat; - y = sin_lon * cos_lat; - z = sin_lat; - - // tilt - xt = cos_latrp_ * x + sin_latrp_ * z; - yt = y; - zt = -sin_latrp_ * x + cos_latrp_ * z; - - // back to spherical coordinates - lont = std::atan2( yt, xt ) * Constants::radiansToDegrees(); - latt = std::asin( zt ) * Constants::radiansToDegrees(); - - // rotate - crd[0] = lont + npole_.lon(); - crd[1] = latt; -} - -void Rotation::unrotate_old( double crd[] ) const { - // inverse operation of Projection::rotate - - double lont, latt; - double xt, yt, zt, x, y, z; - double cos_lont, sin_lont, cos_latt, sin_latt; - - // unrotate - lont = ( crd[LON] - npole_.lon() ) * Constants::degreesToRadians(); - latt = ( crd[LAT] ) * Constants::degreesToRadians(); - - cos_lont = std::cos( lont ); - cos_latt = std::cos( latt ); - sin_lont = std::sin( lont ); - sin_latt = std::sin( latt ); - - // cartesian coordinates - xt = cos_lont * cos_latt; - yt = sin_lont * cos_latt; - zt = sin_latt; - - // untilt - x = cos_latrp_ * xt - sin_latrp_ * zt; - y = yt; - z = sin_latrp_ * xt + cos_latrp_ * zt; - - // back to spherical coordinates - crd[0] = std::atan2( y, x ) * Constants::radiansToDegrees(); - crd[1] = std::asin( z ) * Constants::radiansToDegrees(); -} - using RotationMatrix = std::array, 3>; inline PointXYZ rotate_geocentric( const PointXYZ& p, const RotationMatrix& R ) { @@ -192,45 +168,45 @@ inline PointXYZ rotate_geocentric( const PointXYZ& p, const RotationMatrix& R ) } void Rotation::rotate( double crd[] ) const { - if ( !rotated_ ) { return; } - else if ( rotation_angle_only_ ) { - crd[LON] -= angle_; + if ( !rotated_ ) { return; } - const PointLonLat L( crd ); - PointXYZ P; - UnitSphere::convertSphericalToCartesian( L, P ); + if ( !rotation_angle_only_ ) { + const PointLonLat L( wrap_latitude( {crd[LON], crd[LAT]} ) ); + PointXYZ P; + UnitSphere::convertSphericalToCartesian( L, P ); - const PointXYZ Pt = rotate_geocentric( P, rotate_ ); + const PointXYZ Pt = rotate_geocentric( P, rotate_ ); + PointLonLat Lt; + UnitSphere::convertCartesianToSpherical( Pt, Lt ); - PointLonLat Lt; - UnitSphere::convertCartesianToSpherical( Pt, Lt ); + crd[LON] = Lt.lon(); + crd[LAT] = Lt.lat(); + } - crd[LON] = Lt.lon() - angle_; - crd[LAT] = Lt.lat(); + crd[LON] -= angle_; } void Rotation::unrotate( double crd[] ) const { - if ( !rotated_ ) { return; } - else if ( rotation_angle_only_ ) { - crd[LON] += angle_; + if ( !rotated_ ) { return; } - PointLonLat Lt( crd ); - Lt.lon() += angle_; + crd[LON] += angle_; - PointXYZ Pt; - UnitSphere::convertSphericalToCartesian( Lt, Pt ); + if ( !rotation_angle_only_ ) { + const PointLonLat Lt( crd ); + PointXYZ Pt; + UnitSphere::convertSphericalToCartesian( Lt, Pt ); - const PointXYZ P = rotate_geocentric( Pt, unrotate_ ); + const PointXYZ P = rotate_geocentric( Pt, unrotate_ ); + PointLonLat L; + UnitSphere::convertCartesianToSpherical( P, L ); - PointLonLat L; - UnitSphere::convertCartesianToSpherical( P, L ); - - crd[LON] = L.lon(); - crd[LAT] = L.lat(); + crd[LON] = L.lon(); + crd[LAT] = L.lat(); + } } } // namespace util diff --git a/src/atlas/util/Rotation.h b/src/atlas/util/Rotation.h index 0a797177f..f2295d15c 100644 --- a/src/atlas/util/Rotation.h +++ b/src/atlas/util/Rotation.h @@ -57,14 +57,7 @@ class Rotation { RotationMatrix unrotate_; // unrotate matrix bool rotation_angle_only_; - bool rotated_ = {true}; - - // ---- Older implementation ---- - - void rotate_old( double crd[] ) const; - void unrotate_old( double crd[] ) const; - double cos_latrp_; // cos( 90 - npole_lat ) - double sin_latrp_; // sin( 90 - npole_lat ) + bool rotated_; }; } // namespace util diff --git a/src/atlas/util/SphericalPolygon.cc b/src/atlas/util/SphericalPolygon.cc index 4c8ef3e80..9a9c0d962 100644 --- a/src/atlas/util/SphericalPolygon.cc +++ b/src/atlas/util/SphericalPolygon.cc @@ -35,7 +35,9 @@ bool SphericalPolygon::contains( const PointLonLat& P ) const { ATLAS_ASSERT( coordinates_.size() >= 2 ); // check first bounding box - if ( coordinatesMax_.lon() <= P.lon() || P.lon() < coordinatesMin_.lon() ) { return false; } + if ( coordinatesMax_.lon() <= P.lon() || P.lon() < coordinatesMin_.lon() ) { + return false; + } // winding number int wn = 0; @@ -61,7 +63,9 @@ bool SphericalPolygon::contains( const PointLonLat& P ) const { }(); ATLAS_ASSERT( !std::isnan( lat ) ); - if ( is_approximately_equal( P.lat(), lat ) ) { return true; } + if ( is_approximately_equal( P.lat(), lat ) ) { + return true; + } wn += ( P.lat() > lat ? -1 : 1 ) * ( APB ? -1 : 1 ); } diff --git a/src/atlas/util/detail/Debug.h b/src/atlas/util/detail/Debug.h index a29d85881..23a3112b5 100644 --- a/src/atlas/util/detail/Debug.h +++ b/src/atlas/util/detail/Debug.h @@ -48,7 +48,8 @@ inline bool is_node_global_index( gidx_t x ) { static std::vector v = eckit::Resource>( "$ATLAS_DEBUG_NODE_GLOBAL_INDEX", std::vector() ); for ( gidx_t g : v ) { - if ( x == g ) return true; + if ( x == g ) + return true; } return false; } @@ -57,7 +58,8 @@ inline bool is_edge_global_index( gidx_t x ) { static std::vector v = eckit::Resource>( "$ATLAS_DEBUG_EDGE_GLOBAL_INDEX", std::vector() ); for ( gidx_t g : v ) { - if ( x == g ) return true; + if ( x == g ) + return true; } return false; } @@ -66,7 +68,8 @@ inline bool is_cell_global_index( gidx_t x ) { static std::vector v = eckit::Resource>( "$ATLAS_DEBUG_CELL_GLOBAL_INDEX", std::vector() ); for ( gidx_t g : v ) { - if ( x == g ) return true; + if ( x == g ) + return true; } return false; } @@ -75,7 +78,8 @@ inline bool is_node_uid( gidx_t x ) { static std::vector v = eckit::Resource>( "$ATLAS_DEBUG_NODE_UID", std::vector() ); for ( gidx_t g : v ) { - if ( x == g ) return true; + if ( x == g ) + return true; } return false; } @@ -84,7 +88,8 @@ inline bool is_cell_uid( gidx_t x ) { static std::vector v = eckit::Resource>( "$ATLAS_DEBUG_CELL_UID", std::vector() ); for ( gidx_t g : v ) { - if ( x == g ) return true; + if ( x == g ) + return true; } return false; } @@ -98,7 +103,8 @@ inline int is_mpi_rank() { static std::vector v = eckit::Resource>( "$ATLAS_DEBUG_MPI_RANK", std::vector() ); static int r = mpi::comm().rank(); for ( long g : v ) { - if ( r == g ) return true; + if ( r == g ) + return true; } return false; } @@ -106,7 +112,8 @@ inline int is_mpi_rank() { inline int is_mpi_rank( int x ) { static std::vector v = eckit::Resource>( "$ATLAS_DEBUG_MPI_RANK", std::vector() ); for ( long g : v ) { - if ( x == g ) return true; + if ( x == g ) + return true; } return false; } diff --git a/src/atlas_f/CMakeLists.txt b/src/atlas_f/CMakeLists.txt index 8f50c54b9..8ed090448 100644 --- a/src/atlas_f/CMakeLists.txt +++ b/src/atlas_f/CMakeLists.txt @@ -58,6 +58,9 @@ 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/detail/grid/Unstructured.h + MODULE atlas_grid_Unstructured_c_binding + OUTPUT grid_Unstructured_c_binding.f90 ) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/grid/detail/distribution/DistributionImpl.h MODULE atlas_distribution_c_binding OUTPUT distribution_c_binding.f90 ) @@ -115,7 +118,7 @@ generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/numerics/fvm/Method.h generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/interpolation/Interpolation.h MODULE atlas_interpolation_c_binding OUTPUT interpolation_c_binding.f90 ) -generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/trans/ifs/TransIFS.h +generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/trans/detail/TransInterface.h MODULE atlas_trans_c_binding OUTPUT trans_c_binding.f90 ) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/util/Allocate.h) diff --git a/src/atlas_f/atlas_module.F90 b/src/atlas_f/atlas_module.F90 index 64358778e..0478bd0c4 100644 --- a/src/atlas_f/atlas_module.F90 +++ b/src/atlas_f/atlas_module.F90 @@ -67,7 +67,8 @@ module atlas_module use atlas_GridDistribution_module, only: & & atlas_GridDistribution use atlas_Grid_module, only: & - & atlas_Grid , & + & atlas_Grid, & + & atlas_UnstructuredGrid, & & atlas_StructuredGrid, & & atlas_GaussianGrid, & & atlas_ReducedGaussianGrid, & diff --git a/src/atlas_f/field/atlas_Field_module.fypp b/src/atlas_f/field/atlas_Field_module.fypp index c88073c3d..574c864c0 100644 --- a/src/atlas_f/field/atlas_Field_module.fypp +++ b/src/atlas_f/field/atlas_Field_module.fypp @@ -57,6 +57,7 @@ contains procedure :: levels => Field__levels procedure :: kind => Field__kind generic :: shape => shape_array, shape_idx + procedure :: contiguous procedure :: halo_exchange procedure :: dirty @@ -665,6 +666,19 @@ end function !------------------------------------------------------------------------------- +function contiguous(this) + use atlas_field_c_binding + logical :: contiguous + class(atlas_Field), intent(in) :: this + if( atlas__Field__contiguous(this%CPTR_PGIBUG_A) == 1 ) then + contiguous = .true. + else + contiguous = .false. + 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/grid/atlas_Grid_module.F90 b/src/atlas_f/grid/atlas_Grid_module.F90 index 82ecc9447..77480bccd 100644 --- a/src/atlas_f/grid/atlas_Grid_module.F90 +++ b/src/atlas_f/grid/atlas_Grid_module.F90 @@ -22,6 +22,7 @@ module atlas_Grid_module private :: c_ptr public :: atlas_Grid +public :: atlas_UnstructuredGrid public :: atlas_StructuredGrid public :: atlas_GaussianGrid public :: atlas_ReducedGaussianGrid @@ -62,6 +63,34 @@ module atlas_Grid_module !------------------------------------------------------------------------------ +TYPE, extends(atlas_Grid) :: atlas_UnstructuredGrid + +! Purpose : +! ------- +! *atlas_UnstructuredGrid* : Object Grid specifications for Reduced Grids + +! Methods : +! ------- + +! Author : +! ------ +! 8-Jun-2019 Willem Deconinck *ECMWF* + +!------------------------------------------------------------------------------ +contains +#if FCKIT_FINAL_NOT_INHERITING + final :: atlas_UnstructuredGrid__final_auto +#endif +END TYPE atlas_UnstructuredGrid + +interface atlas_UnstructuredGrid + module procedure atlas_UnstructuredGrid__ctor_points + module procedure atlas_UnstructuredGrid__ctor_config + module procedure atlas_UnstructuredGrid__ctor_cptr +end interface + +!------------------------------------------------------------------------------ + TYPE, extends(atlas_Grid) :: atlas_StructuredGrid ! Purpose : @@ -265,6 +294,14 @@ ATLAS_FINAL subroutine atlas_Grid__final_auto(this) FCKIT_SUPPRESS_UNUSED( this ) end subroutine +ATLAS_FINAL subroutine atlas_UnstructuredGrid__final_auto(this) + type(atlas_UnstructuredGrid), intent(inout) :: this +#if FCKIT_FINAL_NOT_PROPAGATING + call this%final() +#endif + FCKIT_SUPPRESS_UNUSED( this ) +end subroutine + ATLAS_FINAL subroutine atlas_StructuredGrid__final_auto(this) type(atlas_StructuredGrid), intent(inout) :: this #if FCKIT_FINAL_NOT_PROPAGATING @@ -338,6 +375,42 @@ function atlas_Grid__ctor_cptr(cptr) result(this) ! ----------------------------------------------------------------------------- +function atlas_UnstructuredGrid__ctor_config(config) result(this) + use atlas_grid_unstructured_c_binding + type(atlas_UnstructuredGrid) :: this + type(atlas_Config), intent(in) :: config + call this%reset_c_ptr( atlas__grid__Unstructured__config(config%CPTR_PGIBUG_B) ) + call this%return() +end function + +function atlas_UnstructuredGrid__ctor_cptr(cptr) result(this) + use fckit_c_interop_module, only: c_str + use atlas_grid_unstructured_c_binding + type(atlas_UnstructuredGrid) :: this + type(c_ptr), intent(in) :: cptr + call this%reset_c_ptr( cptr ) + call this%return() +end function + +function atlas_UnstructuredGrid__ctor_points( xy ) result(this) + use, intrinsic :: iso_c_binding, only : c_double, c_int + use fckit_c_interop_module, only : c_str + use fckit_array_module, only : array_strides, array_view1d + use atlas_grid_unstructured_c_binding + type(atlas_UnstructuredGrid) :: this + real(c_double), intent(in) :: xy(:,:) + integer(c_int) :: shapef(2) + integer(c_int) :: stridesf(2) + real(c_double), pointer :: xy1d(:) + xy1d => array_view1d(xy) + shapef = shape(xy) + stridesf = array_strides(xy) + call this%reset_c_ptr( atlas__grid__Unstructured__points( xy1d, shapef, stridesf ) ) + call this%return() +end function + +! ----------------------------------------------------------------------------- + function atlas_StructuredGrid__ctor_id(identifier) result(this) use fckit_c_interop_module, only: c_str use atlas_grid_Structured_c_binding diff --git a/src/atlas_f/internals/Library.cc b/src/atlas_f/internals/Library.cc index 5d174f743..6857bc055 100644 --- a/src/atlas_f/internals/Library.cc +++ b/src/atlas_f/internals/Library.cc @@ -34,10 +34,12 @@ const char* atlas__eckit_git_sha1() { const char* atlas__eckit_git_sha1_abbrev( int length ) { static std::string git_sha1( eckit_git_sha1() ); - if ( git_sha1.empty() ) + if ( git_sha1.empty() ) { git_sha1 = "not available"; - else + } + else { git_sha1 = git_sha1.substr( 0, std::min( length, 40 ) ); + } return git_sha1.c_str(); } diff --git a/src/atlas_f/internals/atlas_read_file.cc b/src/atlas_f/internals/atlas_read_file.cc index cd34f2398..c0aeb8e72 100644 --- a/src/atlas_f/internals/atlas_read_file.cc +++ b/src/atlas_f/internals/atlas_read_file.cc @@ -24,7 +24,9 @@ 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_CantOpenFile( p.asString(), Here() ); } + if ( !in ) { + throw_CantOpenFile( p.asString(), Here() ); + } else { out << in.rdbuf(); in.close(); diff --git a/src/atlas_f/mesh/atlas_MeshGenerator_module.F90 b/src/atlas_f/mesh/atlas_MeshGenerator_module.F90 index 0e0c6a4fc..f5db338c3 100644 --- a/src/atlas_f/mesh/atlas_MeshGenerator_module.F90 +++ b/src/atlas_f/mesh/atlas_MeshGenerator_module.F90 @@ -38,6 +38,7 @@ module atlas_MeshGenerator_module interface atlas_MeshGenerator module procedure atlas_MeshGenerator__cptr module procedure atlas_MeshGenerator__config + module procedure atlas_MeshGenerator__type end interface !------------------------------------------------------------------------------ @@ -56,6 +57,14 @@ function atlas_MeshGenerator__cptr(cptr) result(this) call this%return() end function +function atlas_MeshGenerator__type(type) result(this) + use fckit_c_interop_module, only: c_str + use atlas_MeshGenerator_c_binding + type(atlas_MeshGenerator) :: this + character(len=*), intent(in) :: type + call this%reset_c_ptr( atlas__MeshGenerator__create_noconfig(c_str(type)) ) + call this%return() +end function function atlas_MeshGenerator__config(config) result(this) use fckit_c_interop_module, only: c_str diff --git a/src/atlas_f/trans/atlas_Trans_module.F90 b/src/atlas_f/trans/atlas_Trans_module.F90 index fac94f63b..c97335b3f 100644 --- a/src/atlas_f/trans/atlas_Trans_module.F90 +++ b/src/atlas_f/trans/atlas_Trans_module.F90 @@ -17,6 +17,7 @@ module atlas_Trans_module use atlas_field_module, only : atlas_Field use atlas_fieldset_module, only : atlas_FieldSet use atlas_grid_module, only : atlas_Grid +use atlas_functionspace_module, only : atlas_functionspace implicit none @@ -44,13 +45,20 @@ module atlas_Trans_module !------------------------------------------------------------------------------ contains + procedure, nopass :: has_backend + procedure, nopass :: set_backend + procedure, nopass :: backend + procedure :: handle procedure :: grid procedure :: truncation + procedure :: spectral +#if 0 procedure :: nb_spectral_coefficients procedure :: nb_spectral_coefficients_global procedure :: nb_gridpoints procedure :: nb_gridpoints_global +#endif procedure, private :: dirtrans_field procedure, private :: dirtrans_fieldset @@ -70,6 +78,8 @@ module atlas_Trans_module generic, public :: invtrans_grad => & & invtrans_grad_field +! removed +#if 0 procedure, private :: gathspec_r1 procedure, private :: gathspec_r2 generic, public :: gathspec => gathspec_r1, gathspec_r2 @@ -77,6 +87,7 @@ module atlas_Trans_module procedure, private :: specnorm_r1_scalar procedure, private :: specnorm_r2 generic, public :: specnorm => specnorm_r1_scalar, specnorm_r2 +#endif #if FCKIT_FINAL_NOT_INHERITING final :: atlas_Trans__final_auto @@ -102,37 +113,66 @@ module atlas_Trans_module !======================================================== contains !======================================================== + ! ----------------------------------------------------------------------------- ! Trans routines -#define THROW_ERROR call te("atlas_Trans_module.F90",__LINE__) +function backend() + use, intrinsic :: iso_c_binding, only: c_size_t, c_ptr + use atlas_trans_c_binding + use fckit_c_interop_module, only : c_str, c_ptr_to_string, c_ptr_free + character(len=:), allocatable :: backend + type(c_ptr) :: value_cptr + integer(c_size_t) :: value_size + call atlas__Trans__backend(value_cptr,value_size) + allocate( character(len=value_size) :: backend ) + backend = c_ptr_to_string(value_cptr) + call c_ptr_free(value_cptr) +end function + +function has_backend( backend ) + use, intrinsic :: iso_c_binding, only: c_int + use fckit_c_interop_module, only : c_str + use atlas_trans_c_binding + logical :: has_backend + character(len=*) :: backend + integer(c_int) :: has_backend_int + has_backend_int = atlas__Trans__has_backend( c_str(backend) ) + if( has_backend_int == 1 ) then + has_backend = .True. + else + has_backend = .False. + end if +end function -subroutine te(file,line) - use fckit_exception_module, only : fckit_exception - character(len=*), intent(in) :: file - integer, intent(in) :: line - call fckit_exception%throw( "Cannot use atlas_Trans since atlas is compiled without" // & - & "ENABLE_TRANS=ON", file, line ) +subroutine set_backend( backend ) + use atlas_trans_c_binding + use fckit_c_interop_module, only : c_str + character(len=*), intent(in) :: backend + call atlas__Trans__set_backend( c_str(backend) ) end subroutine -function atlas_Trans__ctor( grid, nsmax ) result(this) + +function atlas_Trans__ctor( grid, nsmax, config ) result(this) use, intrinsic :: iso_c_binding, only: c_null_ptr use atlas_trans_c_binding type(atlas_Trans) :: this class(atlas_Grid), intent(in) :: grid integer, intent(in), optional :: nsmax -#if ATLAS_HAVE_TRANS - if( present(nsmax) ) then - call this%reset_c_ptr( atlas__Trans__new( grid%CPTR_PGIBUG_A, nsmax ) ) + type(atlas_Config), intent(in), optional :: config + if( present( config ) ) then + if( present(nsmax) ) then + call this%reset_c_ptr( atlas__Trans__new_config( grid%CPTR_PGIBUG_A, nsmax, config%CPTR_PGIBUG_B ) ) + else + call this%reset_c_ptr( atlas__Trans__new_config( grid%CPTR_PGIBUG_A, 0, config%CPTR_PGIBUG_B ) ) + endif else - call this%reset_c_ptr( atlas__Trans__new( grid%CPTR_PGIBUG_A, 0 ) ) + if( present(nsmax) ) then + call this%reset_c_ptr( atlas__Trans__new( grid%CPTR_PGIBUG_A, nsmax ) ) + else + call this%reset_c_ptr( atlas__Trans__new( grid%CPTR_PGIBUG_A, 0 ) ) + endif endif -#else - ! IGNORE - call this%reset_c_ptr( c_null_ptr ) - FCKIT_SUPPRESS_UNUSED( grid ) - FCKIT_SUPPRESS_UNUSED( nsmax ) -#endif call this%return() end function atlas_Trans__ctor @@ -140,78 +180,22 @@ function handle( this ) use atlas_trans_c_binding integer :: handle class(atlas_Trans) :: this -#if ATLAS_HAVE_TRANS handle = atlas__Trans__handle (this%CPTR_PGIBUG_A) -#else - THROW_ERROR - handle = 0 - FCKIT_SUPPRESS_UNUSED( this ) -#endif end function function truncation( this ) use atlas_trans_c_binding integer :: truncation class(atlas_Trans) :: this -#if ATLAS_HAVE_TRANS truncation = atlas__Trans__truncation (this%CPTR_PGIBUG_A) -#else - THROW_ERROR - truncation = 0 - FCKIT_SUPPRESS_UNUSED( this ) -#endif end function -function nb_spectral_coefficients( this ) +function spectral( this ) use atlas_trans_c_binding - integer :: nb_spectral_coefficients + type(atlas_FunctionSpace) :: spectral class(atlas_Trans) :: this -#if ATLAS_HAVE_TRANS - nb_spectral_coefficients = atlas__Trans__nspec2 (this%CPTR_PGIBUG_A) -#else - THROW_ERROR - nb_spectral_coefficients = 0 - FCKIT_SUPPRESS_UNUSED( this ) -#endif -end function - -function nb_spectral_coefficients_global( this ) - use atlas_trans_c_binding - integer :: nb_spectral_coefficients_global - class(atlas_Trans) :: this -#if ATLAS_HAVE_TRANS - nb_spectral_coefficients_global = atlas__Trans__nspec2g (this%CPTR_PGIBUG_A) -#else - THROW_ERROR - nb_spectral_coefficients_global = 0 - FCKIT_SUPPRESS_UNUSED( this ) -#endif -end function - -function nb_gridpoints( this ) - use atlas_trans_c_binding - integer :: nb_gridpoints - class(atlas_Trans) :: this -#if ATLAS_HAVE_TRANS - nb_gridpoints = atlas__Trans__ngptot (this%CPTR_PGIBUG_A) -#else - THROW_ERROR - nb_gridpoints = 0 - FCKIT_SUPPRESS_UNUSED( this ) -#endif -end function - -function nb_gridpoints_global( this ) - use atlas_trans_c_binding - integer :: nb_gridpoints_global - class(atlas_Trans) :: this -#if ATLAS_HAVE_TRANS - nb_gridpoints_global = atlas__Trans__ngptotg (this%CPTR_PGIBUG_A) -#else - THROW_ERROR - nb_gridpoints_global = 0 - FCKIT_SUPPRESS_UNUSED( this ) -#endif + spectral = atlas_FunctionSpace( atlas__Trans__spectral (this%CPTR_PGIBUG_A) ) + call spectral%return() end function function grid( this ) @@ -219,15 +203,8 @@ function grid( this ) use atlas_trans_c_binding class(atlas_Trans) :: this type(atlas_Grid) :: grid -#if ATLAS_HAVE_TRANS grid = atlas_Grid( atlas__Trans__grid(this%CPTR_PGIBUG_A) ) call grid%return() -#else - THROW_ERROR - FCKIT_SUPPRESS_UNUSED( this ) - grid = atlas_Grid( c_null_ptr ) - FCKIT_SUPPRESS_UNUSED( grid ) -#endif end function @@ -237,7 +214,6 @@ subroutine dirtrans_fieldset(this, gpfields, spfields, config) class(atlas_FieldSet), intent(in) :: gpfields class(atlas_FieldSet), intent(inout) :: spfields class(atlas_Config), intent(in), optional :: config -#if ATLAS_HAVE_TRANS type(atlas_Config) :: p if( present(config) ) then @@ -254,13 +230,6 @@ subroutine dirtrans_fieldset(this, gpfields, spfields, config) if( .not. present(config) ) then call p%final() endif -#else - THROW_ERROR - FCKIT_SUPPRESS_UNUSED( this ) - FCKIT_SUPPRESS_UNUSED( gpfields ) - FCKIT_SUPPRESS_UNUSED( spfields ) - FCKIT_SUPPRESS_UNUSED( config ) -#endif end subroutine dirtrans_fieldset @@ -270,7 +239,6 @@ subroutine invtrans_fieldset(this, spfields, gpfields, config) class(atlas_FieldSet), intent(in) :: spfields class(atlas_FieldSet), intent(inout) :: gpfields class(atlas_Config), intent(in), optional :: config -#if ATLAS_HAVE_TRANS type(atlas_Config) :: p if( present(config) ) then @@ -287,13 +255,6 @@ subroutine invtrans_fieldset(this, spfields, gpfields, config) if( .not. present(config) ) then call p%final() endif -#else - THROW_ERROR - FCKIT_SUPPRESS_UNUSED( this ) - FCKIT_SUPPRESS_UNUSED( spfields ) - FCKIT_SUPPRESS_UNUSED( gpfields ) - FCKIT_SUPPRESS_UNUSED( config ) -#endif end subroutine invtrans_fieldset subroutine dirtrans_field(this, gpfield, spfield, config) @@ -302,7 +263,6 @@ subroutine dirtrans_field(this, gpfield, spfield, config) class(atlas_Field), intent(in) :: gpfield class(atlas_Field), intent(inout) :: spfield class(atlas_Config), intent(in), optional :: config -#if ATLAS_HAVE_TRANS type(atlas_Config) :: p if( present(config) ) then @@ -319,13 +279,6 @@ subroutine dirtrans_field(this, gpfield, spfield, config) if( .not. present(config) ) then call p%final() endif -#else - THROW_ERROR - FCKIT_SUPPRESS_UNUSED( this ) - FCKIT_SUPPRESS_UNUSED( gpfield ) - FCKIT_SUPPRESS_UNUSED( spfield ) - FCKIT_SUPPRESS_UNUSED( config ) -#endif end subroutine dirtrans_field subroutine dirtrans_wind2vordiv_field(this, gpwind, spvor, spdiv, config) @@ -335,7 +288,6 @@ subroutine dirtrans_wind2vordiv_field(this, gpwind, spvor, spdiv, config) type(atlas_Field), intent(inout) :: spvor type(atlas_Field), intent(inout) :: spdiv type(atlas_Config), intent(in), optional :: config -#if ATLAS_HAVE_TRANS type(atlas_Config) :: p if( present(config) ) then @@ -353,14 +305,6 @@ subroutine dirtrans_wind2vordiv_field(this, gpwind, spvor, spdiv, config) if( .not. present(config) ) then call p%final() endif -#else - THROW_ERROR - FCKIT_SUPPRESS_UNUSED( this ) - FCKIT_SUPPRESS_UNUSED( gpwind ) - FCKIT_SUPPRESS_UNUSED( spvor ) - FCKIT_SUPPRESS_UNUSED( spdiv ) - FCKIT_SUPPRESS_UNUSED( config ) -#endif end subroutine dirtrans_wind2vordiv_field @@ -371,7 +315,6 @@ subroutine invtrans_field(this, spfield, gpfield, config) class(atlas_Field), intent(in) :: spfield class(atlas_Field), intent(inout) :: gpfield class(atlas_Config), intent(in), optional :: config -#if ATLAS_HAVE_TRANS type(atlas_Config) :: p if( present(config) ) then @@ -388,13 +331,6 @@ subroutine invtrans_field(this, spfield, gpfield, config) if( .not. present(config) ) then call p%final() endif -#else - THROW_ERROR - FCKIT_SUPPRESS_UNUSED( this ) - FCKIT_SUPPRESS_UNUSED( spfield ) - FCKIT_SUPPRESS_UNUSED( gpfield ) - FCKIT_SUPPRESS_UNUSED( config ) -#endif end subroutine invtrans_field @@ -405,7 +341,6 @@ subroutine invtrans_vordiv2wind_field(this, spvor, spdiv, gpwind, config) class(atlas_Field), intent(in) :: spdiv class(atlas_Field), intent(inout) :: gpwind class(atlas_Config), intent(in), optional :: config -#if ATLAS_HAVE_TRANS type(atlas_Config) :: p if( present(config) ) then @@ -423,14 +358,6 @@ subroutine invtrans_vordiv2wind_field(this, spvor, spdiv, gpwind, config) if( .not. present(config) ) then call p%final() endif -#else - THROW_ERROR - FCKIT_SUPPRESS_UNUSED( this ) - FCKIT_SUPPRESS_UNUSED( spvor ) - FCKIT_SUPPRESS_UNUSED( spdiv ) - FCKIT_SUPPRESS_UNUSED( gpwind ) - FCKIT_SUPPRESS_UNUSED( config ) -#endif end subroutine invtrans_vordiv2wind_field @@ -440,7 +367,6 @@ subroutine invtrans_grad_field(this, spfield, gpfield) class(atlas_Trans), intent(in) :: this class(atlas_Field), intent(in) :: spfield class(atlas_Field), intent(inout) :: gpfield -#if ATLAS_HAVE_TRANS type(atlas_Config) :: config config = atlas_Config() call atlas__Trans__invtrans_grad_field( this%CPTR_PGIBUG_A, & @@ -448,102 +374,8 @@ subroutine invtrans_grad_field(this, spfield, gpfield) & gpfield%CPTR_PGIBUG_A, & & config%CPTR_PGIBUG_B) call config%final() -#else - THROW_ERROR - FCKIT_SUPPRESS_UNUSED( this ) - FCKIT_SUPPRESS_UNUSED( spfield ) - FCKIT_SUPPRESS_UNUSED( gpfield ) -#endif end subroutine invtrans_grad_field - - -subroutine gathspec_r1(this, local, global) - use atlas_trans_c_binding - use, intrinsic :: iso_c_binding, only : c_double - class(atlas_Trans), intent(in) :: this - real(c_double), intent(in) :: local(:) - real(c_double), intent(inout) :: global(:) -#if ATLAS_HAVE_TRANS - call atlas__Trans__gathspec(this%CPTR_PGIBUG_A, 1, (/1/), local, global ) -#else - THROW_ERROR - FCKIT_SUPPRESS_UNUSED( this ) - FCKIT_SUPPRESS_UNUSED( local ) - FCKIT_SUPPRESS_UNUSED( global ) -#endif -end subroutine gathspec_r1 - -subroutine gathspec_r2(this, local, global) - use, intrinsic :: iso_c_binding, only : c_double - use fckit_array_module, only: array_view1d - use atlas_trans_c_binding - class(atlas_Trans), intent(in) :: this - real(c_double), intent(in) :: local(:,:) - real(c_double), intent(inout) :: global(:,:) -#if ATLAS_HAVE_TRANS - real(c_double), pointer :: local_view(:), global_view(:) - integer :: destination(size(local,1)) - destination(:) = 1 - local_view => array_view1d(local) - global_view => array_view1d(global) - call atlas__Trans__gathspec(this%CPTR_PGIBUG_A, size(local,1), destination, local_view, global_view ) -#else - THROW_ERROR - FCKIT_SUPPRESS_UNUSED( this ) - FCKIT_SUPPRESS_UNUSED( local ) - FCKIT_SUPPRESS_UNUSED( global ) -#endif -end subroutine gathspec_r2 - - -subroutine specnorm_r1_scalar(this, spectra, norm, rank) - use atlas_trans_c_binding - use, intrinsic :: iso_c_binding, only : c_double - class(atlas_Trans), intent(in) :: this - real(c_double), intent(in) :: spectra(:) - real(c_double), intent(out) :: norm - integer, optional :: rank ! MPI rank -#if ATLAS_HAVE_TRANS - integer :: rank_opt - real(c_double) :: norms(1) - rank_opt = 0 - if( present(rank) ) rank_opt = rank - call atlas__Trans__specnorm(this%CPTR_PGIBUG_A, 1, spectra, norms, rank_opt ) - norm = norms(1) -#else - norm=0 - THROW_ERROR - FCKIT_SUPPRESS_UNUSED( this ) - FCKIT_SUPPRESS_UNUSED( spectra ) - FCKIT_SUPPRESS_UNUSED( rank ) -#endif -end subroutine - -subroutine specnorm_r2(this, spectra, norm, rank) - use, intrinsic :: iso_c_binding, only : c_double - use fckit_array_module, only: array_view1d - use atlas_trans_c_binding - class(atlas_Trans), intent(in) :: this - real(c_double), intent(in) :: spectra(:,:) - real(c_double), intent(inout) :: norm(:) - integer, optional :: rank ! MPI rank -#if ATLAS_HAVE_TRANS - integer :: rank_opt - real(c_double), pointer :: spectra_view(:) - rank_opt = 0 - if( present(rank) ) rank_opt = rank - spectra_view => array_view1d(spectra) - call atlas__Trans__specnorm(this%CPTR_PGIBUG_A, size(spectra,1), spectra_view, norm, rank_opt ) -#else - THROW_ERROR - FCKIT_SUPPRESS_UNUSED( this ) - FCKIT_SUPPRESS_UNUSED( spectra ) - FCKIT_SUPPRESS_UNUSED( norm ) - FCKIT_SUPPRESS_UNUSED( rank ) -#endif -end subroutine - !------------------------------------------------------------------------------- ATLAS_FINAL subroutine atlas_Trans__final_auto(this) 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 86372547e..c0f46bc61 100644 --- a/src/sandbox/benchmark_ifs_setup/atlas-benchmark-ifs-setup.cc +++ b/src/sandbox/benchmark_ifs_setup/atlas-benchmark-ifs-setup.cc @@ -44,7 +44,7 @@ using eckit::PathName; //------------------------------------------------------------------------------ class Tool : public AtlasTool { - virtual void execute( const Args& args ); + virtual int execute( const Args& args ); virtual std::string briefDescription() { return "Tool to generate a python script that plots the grid-distribution " "of a given grid"; @@ -75,13 +75,15 @@ Tool::Tool( int argc, char** argv ) : AtlasTool( argc, argv ) { //----------------------------------------------------------------------------- -void Tool::execute( const Args& args ) { +int Tool::execute( const Args& args ) { Trace timer( Here(), displayName() ); key = ""; args.get( "grid", key ); std::string path_in_str = ""; - if ( args.get( "grid", path_in_str ) ) path_in = path_in_str; + if ( args.get( "grid", path_in_str ) ) { + path_in = path_in_str; + } StructuredGrid grid; if ( key.size() ) { @@ -95,7 +97,9 @@ void Tool::execute( const Args& args ) { Log::error() << "No grid specified." << std::endl; } - if ( !grid ) return; + if ( !grid ) { + return failed(); + } size_t halo = args.getLong( "halo", halo_default() ); @@ -118,6 +122,7 @@ void Tool::execute( const Args& args ) { } timer.stop(); Log::info() << Trace::report() << std::endl; + return success(); } //------------------------------------------------------------------------------ diff --git a/src/sandbox/benchmark_sorting/atlas-benchmark-sorting.cc b/src/sandbox/benchmark_sorting/atlas-benchmark-sorting.cc index 7c91c6208..b526b2bd9 100644 --- a/src/sandbox/benchmark_sorting/atlas-benchmark-sorting.cc +++ b/src/sandbox/benchmark_sorting/atlas-benchmark-sorting.cc @@ -90,19 +90,22 @@ void make_nodes_global_index_human_readable( const mesh::actions::BuildHalo& bui if ( do_all ) { points_to_edit.resize( nodes_glb_idx.size() ); - for ( idx_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 { glb_idx_max = nodes.global_index().metadata().getLong( "max", 0 ); points_to_edit.resize( build_halo.periodic_points_local_index_.size() ); - for ( size_t i = 0; i < points_to_edit.size(); ++i ) + for ( size_t i = 0; i < points_to_edit.size(); ++i ) { points_to_edit[i] = build_halo.periodic_points_local_index_[i]; + } } std::vector glb_idx( points_to_edit.size() ); - for ( size_t i = 0; i < points_to_edit.size(); ++i ) + for ( size_t i = 0; i < points_to_edit.size(); ++i ) { glb_idx[i] = nodes_glb_idx( i ); + } ATLAS_DEBUG_VAR( points_to_edit ); ATLAS_DEBUG_VAR( points_to_edit.size() ); @@ -148,7 +151,9 @@ void make_nodes_global_index_human_readable( const mesh::actions::BuildHalo& bui gidx_t gid = glb_idx_max; for ( size_t jnode = 0; jnode < node_sort.size(); ++jnode ) { - if ( jnode == 0 ) { ++gid; } + if ( jnode == 0 ) { + ++gid; + } else if ( node_sort[jnode].g != node_sort[jnode - 1].g ) { ++gid; } @@ -174,7 +179,7 @@ void make_nodes_global_index_human_readable( const mesh::actions::BuildHalo& bui //----------------------------------------------------------------------------- class Tool : public AtlasTool { - virtual void execute( const Args& args ); + virtual int execute( const Args& args ); virtual std::string briefDescription() { return "Tool to generate a python script that plots the grid-distribution " "of a given grid"; @@ -201,14 +206,16 @@ Tool::Tool( int argc, char** argv ) : AtlasTool( argc, argv ) { //----------------------------------------------------------------------------- -void Tool::execute( const Args& args ) { +int Tool::execute( const Args& args ) { Trace t( Here(), "main" ); key = ""; args.get( "grid", key ); std::string path_in_str = ""; - if ( args.get( "grid", path_in_str ) ) path_in = path_in_str; + if ( args.get( "grid", path_in_str ) ) { + path_in = path_in_str; + } StructuredGrid grid; if ( key.size() ) { @@ -222,7 +229,9 @@ void Tool::execute( const Args& args ) { Log::error() << "No grid specified." << std::endl; } - if ( !grid ) return; + if ( !grid ) { + return failed(); + } Log::debug() << "Domain: " << grid.domain() << std::endl; Log::debug() << "Periodic: " << grid.periodic() << std::endl; @@ -257,6 +266,7 @@ void Tool::execute( const Args& args ) { Log::info() << Trace::report( Config( "indent", 2 )( "decimals", 2 ) // ("depth",5) ); + return success(); } //------------------------------------------------------------------------------ diff --git a/src/sandbox/grid_distribution/atlas-grid-distribution.cc b/src/sandbox/grid_distribution/atlas-grid-distribution.cc index 071cf1fa4..fffe13b6a 100644 --- a/src/sandbox/grid_distribution/atlas-grid-distribution.cc +++ b/src/sandbox/grid_distribution/atlas-grid-distribution.cc @@ -40,7 +40,7 @@ using eckit::PathName; //------------------------------------------------------------------------------ class Tool : public AtlasTool { - virtual void execute( const Args& args ); + virtual int execute( const Args& args ); virtual std::string briefDescription() { return "Tool to generate a python script that plots the grid-distribution " "of a given grid"; @@ -68,12 +68,14 @@ Tool::Tool( int argc, char** argv ) : AtlasTool( argc, argv ) { //----------------------------------------------------------------------------- -void Tool::execute( const Args& args ) { +int Tool::execute( const Args& args ) { key = ""; args.get( "grid.name", key ); std::string path_in_str = ""; - if ( args.get( "grid.json", path_in_str ) ) path_in = path_in_str; + if ( args.get( "grid.json", path_in_str ) ) { + path_in = path_in_str; + } StructuredGrid grid; if ( key.size() ) { @@ -96,13 +98,17 @@ void Tool::execute( const Args& args ) { Log::error() << "No grid specified." << std::endl; } - if ( !grid ) return; + if ( !grid ) { + return failed(); + } Log::debug() << "Domain: " << grid.domain() << std::endl; Log::debug() << "Periodic: " << grid.periodic() << std::endl; std::string partitioner_type; - if ( not args.get( "partitioner", partitioner_type ) ) partitioner_type = "equal_regions"; + if ( not args.get( "partitioner", partitioner_type ) ) { + partitioner_type = "equal_regions"; + } long N = mpi::comm().size(); args.get( "partitions", N ); @@ -188,6 +194,7 @@ void Tool::execute( const Args& args ) { "\n" "plt.show()"; } + return success(); } //------------------------------------------------------------------------------ diff --git a/src/sandbox/interpolation/PartitionedMesh.cc b/src/sandbox/interpolation/PartitionedMesh.cc index 57b221fa2..094e51c9f 100644 --- a/src/sandbox/interpolation/PartitionedMesh.cc +++ b/src/sandbox/interpolation/PartitionedMesh.cc @@ -37,7 +37,9 @@ void PartitionedMesh::writeGmsh( const std::string& fileName, const FieldSet& fi output::Gmsh out( fileName, output_config ); out.write( mesh_ ); - if ( not fields.empty() ) { out.write( fields ); } + if ( not fields.empty() ) { + out.write( fields ); + } } void PartitionedMesh::partition( const Grid& grid ) { diff --git a/src/sandbox/interpolation/atlas-parallel-interpolation.cc b/src/sandbox/interpolation/atlas-parallel-interpolation.cc index 61d46516d..71a12b6a3 100644 --- a/src/sandbox/interpolation/atlas-parallel-interpolation.cc +++ b/src/sandbox/interpolation/atlas-parallel-interpolation.cc @@ -38,13 +38,15 @@ auto vortex_rollup = []( double lon, double lat, double t ) { 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; } + 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 ); + int execute( const AtlasTool::Args& args ); std::string briefDescription() { return "Demonstration of parallel interpolation"; } std::string usage() { return name() + @@ -99,7 +101,7 @@ class AtlasParallelInterpolation : public AtlasTool { } }; -void AtlasParallelInterpolation::execute( const AtlasTool::Args& args ) { +int AtlasParallelInterpolation::execute( const AtlasTool::Args& args ) { // Get user options std::string option; bool trigs = false; @@ -111,13 +113,17 @@ void AtlasParallelInterpolation::execute( const AtlasTool::Args& args ) { idx_t log_rank = 0; args.get( "log-rank", log_rank ); - if ( idx_t( 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 ); } + if ( args.get( "backend", option ) ) { + eckit::linalg::LinearAlgebra::backend( option ); + } // Generate and partition source & target mesh // source mesh is partitioned on its own, the target mesh uses @@ -194,7 +200,9 @@ void AtlasParallelInterpolation::execute( const AtlasTool::Args& args ) { Interpolation( option::type( backward_interpolation_method ), tgt_functionspace, src_functionspace ); } - if ( args.getBool( "forward-interpolator-output", false ) ) { interpolator_forward.print( Log::info() ); } + if ( args.getBool( "forward-interpolator-output", false ) ) { + interpolator_forward.print( Log::info() ); + } // Create source FunctionSpace and fields @@ -292,6 +300,7 @@ void AtlasParallelInterpolation::execute( const AtlasTool::Args& args ) { Log::info() << "Writing backward interpolation results to src-back.msh" << std::endl; src.writeGmsh( "src-back.msh", src_fields ); } + return success(); } int main( int argc, char* argv[] ) { diff --git a/src/tests/AtlasTestEnvironment.h b/src/tests/AtlasTestEnvironment.h index 779d1aab5..76bb532a3 100644 --- a/src/tests/AtlasTestEnvironment.h +++ b/src/tests/AtlasTestEnvironment.h @@ -77,7 +77,8 @@ using eckit::types::is_approximately_equal; if ( ( _num_subsections - 1 ) == _subsection ) { \ atlas::Log::info() << "Running section \"" << _test_subsection << "\" ..." << std::endl; \ } \ - if ( ( _num_subsections - 1 ) == _subsection ) ATLAS_TRACE_SCOPE( _test_subsection ) + if ( ( _num_subsections - 1 ) == _subsection ) \ + ATLAS_TRACE_SCOPE( _test_subsection ) #ifndef SETUP #define SETUP( name ) @@ -97,7 +98,9 @@ static int barrier_timeout( double seconds ) { watch.start(); std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) ); watch.stop(); - if ( watch.elapsed() > seconds ) { return 1; } + if ( watch.elapsed() > seconds ) { + return 1; + } } return 0; } @@ -128,7 +131,8 @@ void debug_addTarget( eckit::LogTarget* target ) { lib.debugChannel().addTarget( new eckit::PrefixTarget( debug_prefix( libname ), target ) ); } } - if ( eckit::Log::debug() ) eckit::Log::debug().addTarget( target ); + if ( eckit::Log::debug() ) + eckit::Log::debug().addTarget( target ); } void debug_setTarget( eckit::LogTarget* target ) { @@ -138,24 +142,32 @@ void debug_setTarget( eckit::LogTarget* target ) { lib.debugChannel().setTarget( new eckit::PrefixTarget( debug_prefix( libname ), target ) ); } } - if ( eckit::Log::debug() ) eckit::Log::debug().setTarget( target ); + if ( eckit::Log::debug() ) + eckit::Log::debug().setTarget( target ); } void debug_reset() { for ( std::string libname : eckit::system::Library::list() ) { const eckit::system::Library& lib = eckit::system::Library::lookup( libname ); - if ( lib.debug() ) { lib.debugChannel().reset(); } + if ( lib.debug() ) { + lib.debugChannel().reset(); + } } - if ( eckit::Log::debug() ) eckit::Log::debug().reset(); + if ( eckit::Log::debug() ) + eckit::Log::debug().reset(); } bool getEnv( const std::string& env, bool default_value ) { - if (::getenv( env.c_str() ) ) { return eckit::Translator()(::getenv( env.c_str() ) ); } + if ( ::getenv( env.c_str() ) ) { + return eckit::Translator()( ::getenv( env.c_str() ) ); + } return default_value; } int getEnv( const std::string& env, int default_value ) { - if (::getenv( env.c_str() ) ) { return eckit::Translator()(::getenv( env.c_str() ) ); } + if ( ::getenv( env.c_str() ) ) { + return eckit::Translator()( ::getenv( env.c_str() ) ); + } return default_value; } diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 705a39a73..007189bc9 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -38,9 +38,9 @@ endif() # Envisioned to become part of ecbuild_add_test with a CUDA option # in a future ecbuild release macro( atlas_add_cuda_test ) - set( options BOOST ) + set( options "" ) set( single_value_args TARGET ) - set( multi_value_args SOURCES LIBS ) + set( multi_value_args SOURCES LIBS ENVIRONMENT ) cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} ) if(_PAR_UNPARSED_ARGUMENTS) @@ -68,6 +68,11 @@ macro( atlas_add_cuda_test ) else() add_test ( NAME ${_PAR_TARGET} COMMAND ${_PAR_TARGET} ) endif() + + list( APPEND _PAR_ENVIRONMENT "ATLAS_RUN_NGPUS=1" ) + list( REMOVE_DUPLICATES _PAR_ENVIRONMENT ) + set_property( TEST ${_PAR_TARGET} APPEND PROPERTY ENVIRONMENT "${_PAR_ENVIRONMENT}" ) + endif() endmacro() @@ -79,6 +84,10 @@ if( TRANSI_VERSION VERSION_LESS 0.6 )# transi not yet ported to CMake3 include_directories( ${TRANSI_INCLUDE_DIRS} ) endif() +if( ATLAS_GRIDTOOLS_STORAGE_BACKEND_CUDA ) + set( ATLAS_TEST_ENVIRONMENT "ATLAS_RUN_NGPUS=1" ) +endif() + add_subdirectory( acc ) add_subdirectory( array ) add_subdirectory( util ) diff --git a/src/tests/acc/CMakeLists.txt b/src/tests/acc/CMakeLists.txt index 1ddee108e..2ef6cdcce 100644 --- a/src/tests/acc/CMakeLists.txt +++ b/src/tests/acc/CMakeLists.txt @@ -19,6 +19,7 @@ if( ATLAS_HAVE_GRIDTOOLS_STORAGE AND GRIDTOOLS_HAVE_CUDA AND ENABLE_TESTS AND HA fctest_unified_memory_with_openacc_cxx.cc LIBS atlas_f LINKER_LANGUAGE Fortran + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ATLAS_RUN_NGPUS=1 ) target_link_libraries( atlas_test_unified_memory_with_openacc ${ACC_Fortran_FLAGS} gridtools::storage ) @@ -28,6 +29,7 @@ if( ATLAS_HAVE_GRIDTOOLS_STORAGE AND GRIDTOOLS_HAVE_CUDA AND ENABLE_TESTS AND HA SOURCES fctest_connectivity_openacc.F90 LIBS atlas_f LINKER_LANGUAGE Fortran + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ATLAS_RUN_NGPUS=1 ) target_link_libraries( atlas_test_connectivity_openacc ${ACC_Fortran_FLAGS} ) set_target_properties( atlas_test_connectivity_openacc PROPERTIES COMPILE_FLAGS "${ACC_Fortran_FLAGS_STR}" ) diff --git a/src/tests/acceptance_tests/CMakeLists.txt b/src/tests/acceptance_tests/CMakeLists.txt index fa230989b..70a85d54e 100644 --- a/src/tests/acceptance_tests/CMakeLists.txt +++ b/src/tests/acceptance_tests/CMakeLists.txt @@ -6,7 +6,97 @@ # 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 - ) +ecbuild_add_executable( + TARGET atlas-atest-mgrids + SOURCES atest_mgrids.cc + LIBS atlas +) + +set( exe_atlas-atest-mgrids $ ) +# When ECBUILD-432 is fixed (already fixed in develop on top of ecbuild 3.0.0), we don't need TARGET_FILE + + +if( HAVE_TESTS ) + ecbuild_add_option( FEATURE ACCEPTANCE_TESTS DEFAULT OFF ) +endif() + +if( HAVE_ACCEPTANCE_TESTS ) + +set( HAVE_ACCEPTANCE_TESTS_SMALL ON ) +set( HAVE_ACCEPTANCE_TESTS_LARGE ON ) + +if( TARGET atlas-atest-mgrids ) + +function( atlas_atest_mgrids category case nprocs ) + + if( HAVE_TRANS ) + set( PARTITIONER "--partitioner=trans" ) + endif() + + string(REPLACE "/" ";" case ${case} ) + list( GET case 0 gridA ) + list( GET case 1 gridB ) + unset( checksums ) + unset( case_tests ) + foreach( n ${nprocs} ) + foreach( t 1 4 12 ) + set( test_name atlas_atest_${category}_mgrids_${gridA}_to_${gridB}_n${n}_t${t} ) + ecbuild_add_test( TARGET ${test_name} + COMMAND ${exe_atlas-atest-mgrids} + ARGS --gridA=${gridA} + --gridB=${gridB} + --haloA=3 + --haloB=3 + --display-name=${test_name} + --checksum=${test_name}.checksum + --matrix-free + ${PARTITIONER} + MPI ${n} + OMP ${t} + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} + ) + list( APPEND checksums ${test_name}.checksum ) + list( APPEND case_tests ${test_name} ) + endforeach() + endforeach() + add_test( + NAME atlas_atest_mgrids_${gridA}_to_${gridB}_BitReproducible + COMMAND ${CMAKE_COMMAND} + "-DFILES=${checksums}" -P ${CMAKE_CURRENT_SOURCE_DIR}/compare.cmake + ) + foreach( dep ${case_tests} ) + set_tests_properties( atlas_atest_mgrids_${gridA}_to_${gridB}_BitReproducible PROPERTIES DEPENDS ${dep} ) + endforeach() +endfunction() + +if( HAVE_ACCEPTANCE_TESTS_SMALL ) + unset( cases ) + list( APPEND cases + O32/O16 + O32/L16 + O64/F20 + ) + list( APPEND nprocs + 1 + 4 + 32 + ) + foreach( case ${cases} ) + atlas_atest_mgrids( small ${case} "${nprocs}" ) + endforeach() +endif() + +if( HAVE_ACCEPTANCE_TESTS_LARGE ) + unset( cases ) + list( APPEND cases + O640/O320 + ) + set( nprocs 1 4 36 72 ) + foreach( case ${cases} ) + atlas_atest_mgrids( large ${case} "${nprocs}" ) + endforeach() +endif() + +endif() + +endif() diff --git a/src/tests/acceptance_tests/atest_mgrids.cc b/src/tests/acceptance_tests/atest_mgrids.cc index 837b782f5..027057d83 100644 --- a/src/tests/acceptance_tests/atest_mgrids.cc +++ b/src/tests/acceptance_tests/atest_mgrids.cc @@ -9,12 +9,11 @@ */ #include -#include #include -#include #include -#include -#include +#include + +#include "eckit/log/OStreamTarget.h" #include "atlas/field.h" #include "atlas/functionspace.h" @@ -22,22 +21,23 @@ #include "atlas/interpolation/Interpolation.h" #include "atlas/mesh.h" #include "atlas/meshgenerator.h" -#include "atlas/numerics/fvm/Method.h" #include "atlas/option.h" #include "atlas/output/Gmsh.h" #include "atlas/parallel/mpi/mpi.h" #include "atlas/runtime/AtlasTool.h" #include "atlas/runtime/Log.h" #include "atlas/util/Config.h" - -#include "atlas/mesh/actions/BuildHalo.h" +#include "atlas/util/Constants.h" +#include "atlas/util/CoordinateEnums.h" using namespace atlas; +double vortex_rollup( double lon, double lat, double t, double mean ); + //------------------------------------------------------------------------------ class Program : public AtlasTool { - virtual void execute( const Args& args ); + virtual int execute( const Args& args ); public: Program( int argc, char** argv ); @@ -49,54 +49,188 @@ Program::Program( int argc, char** argv ) : AtlasTool( argc, argv ) { add_option( new SimpleOption( "gridA", "grid A" ) ); add_option( new SimpleOption( "gridB", "grid B" ) ); add_option( new SimpleOption( "ghost", "Output ghost elements" ) ); - add_option( new SimpleOption( "haloA", "Halo size" ) ); - add_option( new SimpleOption( "haloB", "Halo size" ) ); - add_option( new SimpleOption( "no-forward", "no forward interpolation" ) ); - add_option( new SimpleOption( "no-backward", "no backward interpolation" ) ); + add_option( new SimpleOption( "haloA", "Halo size for A" ) ); + add_option( new SimpleOption( "haloB", "Halo size for B" ) ); + add_option( new SimpleOption( "matrix-free", "Interpolation without matrix" ) ); + add_option( new SimpleOption( "checksum", "File to write that will contains checksums of run" ) ); + add_option( new SimpleOption( "gmsh", "Output gmsh" ) ); + add_option( new SimpleOption( "no-validate", "Avoid validation of results to increase runtime" ) ); + add_option( new SimpleOption( "partitioner", "Partitioner for gridA (default=equal_regions)" ) ); } //----------------------------------------------------------------------------- -void Program::execute( const Args& args ) { - auto ghost = util::Config( "ghost", args.getBool( "ghost", false ) ); - auto haloA = option::halo( args.getLong( "haloA", 1 ) ); - auto haloB = option::halo( args.getLong( "haloB", 1 ) ); - - auto gridA = Grid( args.getString( "gridA" ) ); - auto gridB = Grid( args.getString( "gridB" ) ); +int Program::execute( const Args& args ) { + auto matrix_free = util::Config( "matrix_free", args.getBool( "matrix-free", false ) ); + auto ghost = util::Config( "ghost", args.getBool( "ghost", false ) ); + auto haloA = option::halo( args.getLong( "haloA", 2 ) ); + auto haloB = option::halo( args.getLong( "haloB", 2 ) ); + auto checksum_filepath = args.getString( "checksum", displayName() + ".checksum" ); + auto partitioner = args.getString( "partitioner", "equal_regions" ); + auto gridA = Grid( args.getString( "gridA" ) ); + auto gridB = Grid( args.getString( "gridB" ) ); auto meshgenerator = MeshGenerator( "structured" ); - auto distA = grid::Distribution( gridA, grid::Partitioner( "trans" ) ); - + Trace setup_A( Here(), "Setup A" ); + auto distA = grid::Distribution( gridA, grid::Partitioner( partitioner ) ); auto meshA = meshgenerator.generate( gridA, distA ); + functionspace::StructuredColumns fsA( gridA, distA, haloA ); + setup_A.stop(); - numerics::fvm::Method fvmA( meshA, haloA ); - auto gmshA = output::Gmsh( "meshA.msh", ghost ); - gmshA.write( meshA ); - + Trace setup_B( Here(), "Setup B" ); auto distB = grid::Distribution( gridB, grid::MatchingMeshPartitioner( meshA ) ); + functionspace::StructuredColumns fsB( gridB, distB, haloB ); + setup_B.stop(); + + Trace setup_interpolation_AtoB( Here(), "Setup interpolation AtoB" ); + Interpolation AtoB( option::type( "bicubic" ) | matrix_free, fsA, fsB ); + setup_interpolation_AtoB.stop(); + + Trace setup_interpolation_BtoA( Here(), "Setup interpolation BtoA" ); + Interpolation BtoA( option::type( "bicubic" ) | matrix_free, fsB, fsA ); + setup_interpolation_BtoA.stop(); + + Field fieldA = fsA.createField( option::name( "fieldA" ) ); + Field fieldB = fsB.createField( option::name( "fieldB" ) ); + + auto lonlat = array::make_view( fsA.xy() ); + auto A = array::make_view( fieldA ); + auto B = array::make_view( fieldB ); + + double meanA = 1.; + for ( idx_t n = 0; n < fsA.size(); ++n ) { + A( n ) = vortex_rollup( lonlat( n, LON ), lonlat( n, LAT ), 1., meanA ); + } + fieldA.set_dirty(); + fieldA.haloExchange(); - auto meshB = meshgenerator.generate( gridB, distB ); + Log::Channel checksums; + checksums.addStream( Log::info() ); + if ( mpi::comm().rank() == 0 ) { + checksums.addFile( checksum_filepath ); + } - numerics::fvm::Method fvmB( meshB, haloB ); + checksums << "Field A checksum before interpolation AtoB: " << fsA.checksum( fieldA ) << std::endl; - Field fieldB = fvmB.node_columns().createField(); + Trace interpolation_AtoB( Here(), "Interpolation AtoB" ); + AtoB.execute( fieldA, fieldB ); + interpolation_AtoB.stop(); - output::Gmsh gmshB( "meshB.msh", ghost ); - gmshB.write( meshB ); - gmshB.write( fieldB ); + checksums << "Field B checksum after interpolation AtoB: " << fsB.checksum( fieldB ) << std::endl; - if ( not args.getBool( "no-forward", false ) ) { - Interpolation AtoB( option::type( "finite-element" ), fvmA.node_columns(), fvmB.node_columns() ); + for ( idx_t n = 0; n < fsB.size(); ++n ) { + B( n ) = meanA - B( n ); + } + fieldB.set_dirty(); + fieldB.haloExchange(); + + Trace interpolation_BtoA( Here(), "Interpolation BtoA" ); + BtoA.execute( fieldB, fieldA ); + interpolation_BtoA.stop(); + + checksums << "Field A checksum after interpolation BtoA: " << fsA.checksum( fieldA ) << std::endl; + + Log::info() << "Timers:" << std::endl; + Log::info() << " Setup A " << setup_A.elapsed() << " s" << std::endl; + Log::info() << " Setup B " << setup_B.elapsed() << " s" << std::endl; + Log::info() << " -----------------------------------------" << std::endl; + Log::info() << " Interpolation AtoB Setup " << setup_interpolation_AtoB.elapsed() << " s" << std::endl; + Log::info() << " Interpolation BtoA Setup " << setup_interpolation_BtoA.elapsed() << " s" << std::endl; + Log::info() << " Interpolation AtoB Execute " << interpolation_AtoB.elapsed() << " s" << std::endl; + Log::info() << " Interpolation BtoA Execute " << interpolation_BtoA.elapsed() << " s" << std::endl; + Log::info() << " -----------------------------------------" << std::endl; + Log::info() << " Interpolation AtoB Total " << setup_interpolation_AtoB.elapsed() + interpolation_AtoB.elapsed() + << " s" << std::endl; + Log::info() << " Interpolation BtoA Total " << setup_interpolation_BtoA.elapsed() + interpolation_BtoA.elapsed() + << " s" << std::endl; + + int status = success(); + + Mesh meshB; + if ( not args.getBool( "no-validate", false ) ) { + double tolerance = 1.e-8; + + meshB = meshgenerator.generate( gridB, distB ); + auto norm_computerB = functionspace::NodeColumns( meshB ); + double sumB; + idx_t countB; + norm_computerB.sum( fieldB, sumB, countB ); + if ( std::abs( sumB ) < tolerance ) { + Log::info() << "Validation B correct: " << std::abs( sumB ) << " < tolerance [" << tolerance << "]" + << std::endl; + } + else { + Log::error() << "Validation B failed: " << std::abs( sumB ) << " > tolerance [" << tolerance << "]" + << std::endl; + norm_computerB.orderIndependentSum( fieldB, sumB, countB ); + Log::info() << " order_independent_sum: " << sumB << " count = " << countB << std::endl; + status = failed(); + } + + auto norm_computerA = functionspace::NodeColumns( meshA ); + double sumA; + idx_t countA; + norm_computerA.sum( fieldA, sumA, countA ); + if ( std::abs( sumA ) < tolerance ) { + Log::info() << "Validation A correct: " << std::abs( sumA ) << " < tolerance [" << tolerance << "]" + << std::endl; + } + else { + Log::error() << "Validation A failed: " << std::abs( sumA ) << " > tolerance [" << tolerance << "]" + << std::endl; + norm_computerA.orderIndependentSum( fieldA, sumA, countA ); + Log::info() << " order_independent_sum: " << sumA << " count = " << countA << std::endl; + status = failed(); + } } - if ( not args.getBool( "no-backward", false ) ) { - Interpolation BtoA( option::type( "finite-element" ), fvmB.node_columns(), fvmA.node_columns() ); + + // Gmsh output + if ( args.getBool( "gmsh", false ) ) { + if ( not meshB ) { + meshB = meshgenerator.generate( gridB, distB ); + } + + auto gmshA = output::Gmsh( displayName() + "_meshA.msh", ghost ); + gmshA.write( meshA ); + gmshA.write( fieldA ); + + auto gmshB = output::Gmsh( displayName() + "_meshB.msh", ghost ); + gmshB.write( meshB ); + gmshB.write( fieldB ); } + return status; } //------------------------------------------------------------------------------ +double vortex_rollup( double lon, double lat, double t, double mean ) { + // 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 *= util::Constants::degreesToRadians(); + lat *= util::Constants::degreesToRadians(); + + 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 = mean - std::tanh( 0.2 * rho * std::sin( lambda_prime - omega / a * t ) ); + return q; +}; + +//------------------------------------------------------------------------------ + int main( int argc, char** argv ) { Program tool( argc, argv ); return tool.start(); diff --git a/src/tests/acceptance_tests/compare.cmake b/src/tests/acceptance_tests/compare.cmake new file mode 100644 index 000000000..e3c420880 --- /dev/null +++ b/src/tests/acceptance_tests/compare.cmake @@ -0,0 +1,33 @@ +# (C) Copyright 2019 ECMWF. +# +# This file is covered by the LICENSING file in the root of this project. +# In applying this licence, ECMWF does not waive the privileges and immunities +# granted to it by virtue of its status as an intergovernmental organisation +# nor does it submit to any jurisdiction. + +function( run_command COMMAND ) + set( COMMAND ${ARGV} ) + string(REPLACE ";" " " PRINT_COMMAND "${COMMAND}" ) + message( "cd ${CMAKE_CURRENT_BINARY_DIR} && ${PRINT_COMMAND}" ) + execute_process( + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${COMMAND} + RESULT_VARIABLE res + ) + if(res) + message(FATAL_ERROR "[ ${COMMAND} ] failed") + endif() +endfunction() + +message( "Working directory: ${CMAKE_CURRENT_BINARY_DIR}") + +list( GET FILES 0 ref ) +foreach( file ${FILES} ) + if( EXISTS ${file} ) + if( NOT ${file} STREQUAL ${ref} ) + run_command( ${CMAKE_COMMAND} -E compare_files ${ref} ${file} ) + endif() + else() + message( STATUS "Skipping ${file} as it does not exist" ) + endif() +endforeach() diff --git a/src/tests/array/CMakeLists.txt b/src/tests/array/CMakeLists.txt index c9ed65871..c5e1a2eba 100644 --- a/src/tests/array/CMakeLists.txt +++ b/src/tests/array/CMakeLists.txt @@ -10,26 +10,32 @@ ecbuild_add_test( TARGET atlas_test_array_slicer SOURCES test_array_slicer.cc LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) ecbuild_add_test( TARGET atlas_test_array SOURCES test_array.cc LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) #ecbuild_add_test( TARGET atlas_test_table # SOURCES test_table.cc # LIBS atlas +# ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} #) ecbuild_add_test( TARGET atlas_test_svector SOURCES test_svector.cc LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} + ) ecbuild_add_test( TARGET atlas_test_array_view_util SOURCES test_array_view_util.cc LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) @@ -41,16 +47,19 @@ atlas_add_cuda_test( TARGET atlas_test_array_kernel SOURCES test_array_kernel.cu LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) atlas_add_cuda_test( TARGET atlas_test_vector_kernel SOURCES test_vector_kernel.cu LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) atlas_add_cuda_test( TARGET atlas_test_svector_kernel SOURCES test_svector_kernel.cu LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) diff --git a/src/tests/array/test_array.cc b/src/tests/array/test_array.cc index 4bf6394f1..6423c2e9e 100644 --- a/src/tests/array/test_array.cc +++ b/src/tests/array/test_array.cc @@ -255,7 +255,8 @@ CASE( "test_copy_gt_ctr" ) { ATLAS_DEBUG_VAR( dims[0] ); ATLAS_DEBUG_VAR( dims[1] ); EXPECT( dims[0] == 3 ); - if ( NOT_PADDED ) EXPECT( dims[1] == 2 ); + if ( NOT_PADDED ) + EXPECT( dims[1] == 2 ); delete ds; } #endif @@ -542,7 +543,9 @@ CASE( "test_valid" ) { CASE( "test_wrap" ) { array::ArrayT arr_t( 3, 2 ); EXPECT( arr_t.shape( 0 ) == 3 ); - if ( NOT_PADDED ) EXPECT( arr_t.stride( 0 ) == 2 ); + if ( NOT_PADDED ) { + EXPECT( arr_t.stride( 0 ) == 2 ); + } EXPECT( arr_t.shape( 1 ) == 2 ); EXPECT( arr_t.stride( 1 ) == 1 ); EXPECT( arr_t.rank() == 2 ); diff --git a/src/tests/field/CMakeLists.txt b/src/tests/field/CMakeLists.txt index 0d188fbc6..02da6d13c 100644 --- a/src/tests/field/CMakeLists.txt +++ b/src/tests/field/CMakeLists.txt @@ -12,12 +12,14 @@ if( HAVE_FCTEST ) LINKER_LANGUAGE Fortran SOURCES fctest_field.F90 LIBS atlas_f + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) add_fctest( TARGET atlas_fctest_field_wrap LINKER_LANGUAGE Fortran SOURCES fctest_field_wrap.F90 LIBS atlas_f + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) add_fctest( TARGET atlas_fctest_field_view @@ -25,6 +27,7 @@ if( HAVE_FCTEST ) SOURCES fctest_field_view.F90 LIBS atlas_f OpenMP::OpenMP_Fortran OMP 3 + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} CONDITION ATLAS_HAVE_OMP_Fortran ) @@ -33,6 +36,7 @@ if( HAVE_FCTEST ) LINKER_LANGUAGE Fortran SOURCES fctest_field_host.F90 LIBS atlas_f + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) add_fctest( TARGET atlas_fctest_field_device @@ -40,6 +44,7 @@ if( HAVE_FCTEST ) LINKER_LANGUAGE Fortran SOURCES fctest_field_gpu.F90 external_acc_routine.F90 LIBS atlas_f + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ATLAS_RUN_NGPUS=1 ) if( TARGET atlas_fctest_field_device ) diff --git a/src/tests/functionspace/CMakeLists.txt b/src/tests/functionspace/CMakeLists.txt index eda39944c..b6aa21cc4 100644 --- a/src/tests/functionspace/CMakeLists.txt +++ b/src/tests/functionspace/CMakeLists.txt @@ -18,6 +18,7 @@ if( HAVE_FCTEST ) LINKER_LANGUAGE Fortran SOURCES fctest_functionspace.F90 LIBS atlas_f + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) endif() @@ -25,28 +26,33 @@ endif() ecbuild_add_test( TARGET atlas_test_functionspace SOURCES test_functionspace.cc LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) ecbuild_add_test( TARGET atlas_test_structuredcolumns SOURCES test_structuredcolumns.cc LIBS atlas MPI 5 + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} CONDITION ECKIT_HAVE_MPI ) ecbuild_add_test( TARGET atlas_test_pointcloud SOURCES test_pointcloud.cc LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) ecbuild_add_test( TARGET atlas_test_reduced_halo SOURCES test_reduced_halo.cc LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) ecbuild_add_test( TARGET atlas_test_stencil SOURCES test_stencil.cc LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) ecbuild_add_executable( TARGET atlas_test_stencil_parallel @@ -55,15 +61,20 @@ ecbuild_add_executable( TARGET atlas_test_stencil_parallel NOINSTALL ) +set( exe_atlas_test_stencil_parallel $ ) +# When ECBUILD-432 is fixed (already fixed in develop on top of ecbuild 3.0.0), we don't need TARGET_FILE + ecbuild_add_test( TARGET atlas_test_stencil_parallel_mpi4 - COMMAND $ + COMMAND ${exe_atlas_test_stencil_parallel} MPI 4 + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} CONDITION ECKIT_HAVE_MPI ) ecbuild_add_test( TARGET atlas_test_stencil_parallel_mpi16 - COMMAND $ + COMMAND ${exe_atlas_test_stencil_parallel} MPI 16 + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} CONDITION ECKIT_HAVE_MPI ) diff --git a/src/tests/functionspace/test_functionspace.cc b/src/tests/functionspace/test_functionspace.cc index 00659cb19..6356d73cb 100644 --- a/src/tests/functionspace/test_functionspace.cc +++ b/src/tests/functionspace/test_functionspace.cc @@ -45,7 +45,9 @@ CASE( "test_functionspace_NodeColumns_no_halo" ) { array::ArrayView ghost = array::make_view( mesh.nodes().ghost() ); const size_t nb_nodes = mesh.nodes().size(); for ( size_t j = 0; j < nb_nodes; ++j ) { - if ( ghost( j ) ) { value( j ) = -1; } + if ( ghost( j ) ) { + value( j ) = -1; + } else { value( j ) = 1; } @@ -178,7 +180,9 @@ CASE( "test_functionspace_NodeColumns" ) { // glb_field->dump( Log::info() ); - if ( mpi::comm().rank() == root ) glb_field.metadata().set( "test_broadcast", 123 ); + if ( mpi::comm().rank() == root ) { + glb_field.metadata().set( "test_broadcast", 123 ); + } arr.assign( -1 ); nodes_fs.scatter( glb_field, field ); @@ -553,7 +557,8 @@ CASE( "test_SpectralFunctionSpace_trans_global" ) { EXPECT( surface_scalar_field.name() == std::string( "scalar" ) ); - if ( eckit::mpi::comm().rank() == 0 ) EXPECT( surface_scalar_field.size() == nspec2g ); + if ( eckit::mpi::comm().rank() == 0 ) + EXPECT( surface_scalar_field.size() == nspec2g ); EXPECT( surface_scalar_field.rank() == 1 ); @@ -563,12 +568,16 @@ CASE( "test_SpectralFunctionSpace_trans_global" ) { auto surface_scalar = array::make_view( surface_scalar_field ); - if ( eckit::mpi::comm().rank() == 0 ) { EXPECT( surface_scalar.shape( 0 ) == nspec2g ); } + if ( eckit::mpi::comm().rank() == 0 ) { + EXPECT( surface_scalar.shape( 0 ) == nspec2g ); + } Field columns_scalar_field = spectral_fs.createField( option::name( "scalar" ) | option::global() ); EXPECT( columns_scalar_field.name() == std::string( "scalar" ) ); - if ( eckit::mpi::comm().rank() == 0 ) { EXPECT( columns_scalar_field.size() == nspec2g * nb_levels ); } + if ( eckit::mpi::comm().rank() == 0 ) { + EXPECT( columns_scalar_field.size() == nspec2g * nb_levels ); + } else { EXPECT( columns_scalar_field.size() == 0 ); } @@ -595,12 +604,14 @@ CASE( "test_SpectralFunctionSpace_norm" ) { { auto twoD = array::make_view( twoD_field ); twoD.assign( 0. ); - if ( mpi::comm().rank() == 0 ) twoD( 0 ) = 1.; + if ( mpi::comm().rank() == 0 ) + twoD( 0 ) = 1.; auto threeD = array::make_view( threeD_field ); threeD.assign( 0. ); for ( size_t jlev = 0; jlev < nb_levels; ++jlev ) { - if ( mpi::comm().rank() == 0 ) threeD( 0, jlev ) = jlev; + if ( mpi::comm().rank() == 0 ) + threeD( 0, jlev ) = jlev; } } @@ -608,7 +619,13 @@ CASE( "test_SpectralFunctionSpace_norm" ) { std::vector threeD_norms( threeD_field.levels(), 0. ); spectral_fs.norm( twoD_field, twoD_norm ); - spectral_fs.norm( threeD_field, threeD_norms ); + if ( not threeD_field.contiguous() ) { + EXPECT_THROWS_AS( spectral_fs.norm( threeD_field, threeD_norms ), eckit::Exception ); + return; + } + else { + EXPECT_NO_THROW( spectral_fs.norm( threeD_field, threeD_norms ) ); + } if ( eckit::mpi::comm().rank() == 0 ) { EXPECT( eckit::types::is_approximately_equal( twoD_norm, diff --git a/src/tests/functionspace/test_reduced_halo.cc b/src/tests/functionspace/test_reduced_halo.cc index 5b2652186..992886ad5 100644 --- a/src/tests/functionspace/test_reduced_halo.cc +++ b/src/tests/functionspace/test_reduced_halo.cc @@ -52,7 +52,9 @@ CASE( "halo nodes" ) { for ( int h : ( reduce ? reversed( halos ) : halos ) ) { NodeColumns fs( mesh, option::halo( h ) ); - if ( mpi::comm().size() == 1 ) { EXPECT( fs.nb_nodes() == nodes[h] ); } + if ( mpi::comm().size() == 1 ) { + EXPECT( fs.nb_nodes() == nodes[h] ); + } } } } @@ -76,7 +78,9 @@ CASE( "halo edges" ) { 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 ); } + if ( mpi::comm().size() == 1 ) { + EXPECT( fs.nb_edges() == edges[h] + pole_edges ); + } } } } diff --git a/src/tests/functionspace/test_stencil.cc b/src/tests/functionspace/test_stencil.cc index 3a593063a..49754987f 100644 --- a/src/tests/functionspace/test_stencil.cc +++ b/src/tests/functionspace/test_stencil.cc @@ -216,7 +216,9 @@ CASE( "test vertical stencil" ) { 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 ); } + if ( p < vertical[0] ) { + EXPECT( stencil.k_interval() == -1 ); + } else if ( p < vertical[1] ) { EXPECT( stencil.k_interval() == 0 ); } @@ -233,7 +235,7 @@ CASE( "test vertical stencil" ) { } } - //----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #if 1 CASE( "ifs method to find nearest grid point" ) { diff --git a/src/tests/grid/CMakeLists.txt b/src/tests/grid/CMakeLists.txt index d3a80914e..31ed56be0 100644 --- a/src/tests/grid/CMakeLists.txt +++ b/src/tests/grid/CMakeLists.txt @@ -9,11 +9,12 @@ if( HAVE_FCTEST ) foreach(test fctest_griddistribution - fctest_state) + fctest_state ) - add_fctest( TARGET atlas_${test} SOURCES ${test}.F90 LINKER_LANGUAGE Fortran LIBS atlas_f ) + add_fctest( TARGET atlas_${test} SOURCES ${test}.F90 LINKER_LANGUAGE Fortran LIBS atlas_f ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) endforeach() + add_fctest( TARGET atlas_fctest_unstructuredgrid SOURCES fctest_unstructuredgrid.F90 LINKER_LANGUAGE Fortran LIBS atlas_f CONDITION HAVE_TESSELATION ) endif() foreach(test @@ -26,6 +27,18 @@ foreach(test test_state test_grid_hash) - ecbuild_add_test( TARGET atlas_${test} SOURCES ${test}.cc LIBS atlas ) + ecbuild_add_test( TARGET atlas_${test} SOURCES ${test}.cc LIBS atlas ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) endforeach() + +file( GLOB grids ${PROJECT_SOURCE_DIR}/doc/example-grids/*.yml ) + +foreach( grid ${grids} ) + get_filename_component( grid_name ${grid} NAME_WE ) + set( test_name atlas_test_grid_${grid_name} ) + ecbuild_add_test( TARGET ${test_name} + COMMAND atlas-grids + ARGS ${grid} --check --check-uid --check-boundingbox + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} + ) +endforeach() diff --git a/src/tests/grid/fctest_unstructuredgrid.F90 b/src/tests/grid/fctest_unstructuredgrid.F90 new file mode 100644 index 000000000..3de694311 --- /dev/null +++ b/src/tests/grid/fctest_unstructuredgrid.F90 @@ -0,0 +1,243 @@ +! (C) Copyright 2013 ECMWF. +! This software is licensed under the terms of the Apache Licence Version 2.0 +! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +! In applying this licence, ECMWF does not waive the privileges and immunities +! granted to it by virtue of its status as an intergovernmental organisation nor +! does it submit to any jurisdiction. + +! This File contains Unit Tests for testing the +! C++ / Fortran Interfaces to the Mesh Datastructure +! @author Willem Deconinck + +#include "fckit/fctest.h" + +! ----------------------------------------------------------------------------- + +TESTSUITE(fctest_unstructuredgrid) + +! ----------------------------------------------------------------------------- + +TESTSUITE_INIT + use atlas_module + call atlas_library%initialise() +END_TESTSUITE_INIT + +! ----------------------------------------------------------------------------- + +TESTSUITE_FINALIZE + use atlas_module + call atlas_library%finalise() +END_TESTSUITE_FINALIZE + +! ---------------------------------------------------------------------------- + +TEST( test_unstructuredgrid ) + use, intrinsic :: iso_c_binding + use atlas_module + implicit none + type(atlas_UnstructuredGrid) :: grid + type(atlas_Mesh) :: mesh + type(atlas_Output) :: gmsh + type(atlas_MeshGenerator) :: meshgenerator + type(atlas_Config) :: config + + real(c_double) :: xy(2,173) + xy(:,1) = [180,0] + xy(:,2) = [90,0] + xy(:,3) = [-90,0] + xy(:,4) = [0,90] + xy(:,5) = [0,-90] + xy(:,6) = [0,0] + xy(:,7) = [18,0] + xy(:,8) = [36,0] + xy(:,9) = [54,0] + xy(:,10) = [72,0] + xy(:,11) = [108,0] + xy(:,12) = [126,0] + xy(:,13) = [144,0] + xy(:,14) = [162,0] + xy(:,15) = [-162,0] + xy(:,16) = [-144,0] + xy(:,17) = [-126,0] + xy(:,18) = [-108,0] + xy(:,19) = [-72,0] + xy(:,20) = [-54,0] + xy(:,21) = [-36,0] + xy(:,22) = [-18,0] + xy(:,23) = [0,18] + xy(:,24) = [0,36] + xy(:,25) = [0,54] + xy(:,26) = [0,72] + xy(:,27) = [180,72] + xy(:,28) = [180,54] + xy(:,29) = [180,36] + xy(:,30) = [180,18] + xy(:,31) = [180,-18] + xy(:,32) = [180,-36] + xy(:,33) = [180,-54] + xy(:,34) = [180,-72] + xy(:,35) = [0,-72] + xy(:,36) = [0,-54] + xy(:,37) = [0,-36] + xy(:,38) = [0,-18] + xy(:,39) = [90,18] + xy(:,40) = [90,36] + xy(:,41) = [90,54] + xy(:,42) = [90,72] + xy(:,43) = [-90,72] + xy(:,44) = [-90,54] + xy(:,45) = [-90,36] + xy(:,46) = [-90,18] + xy(:,47) = [-90,-18] + xy(:,48) = [-90,-36] + xy(:,49) = [-90,-54] + xy(:,50) = [-90,-72] + xy(:,51) = [90,-72] + xy(:,52) = [90,-54] + xy(:,53) = [90,-36] + xy(:,54) = [90,-18] + xy(:,55) = [123.974,-58.6741] + xy(:,56) = [154.087,-16.9547] + xy(:,57) = [154.212,-58.8675] + xy(:,58) = [114.377,-41.9617] + xy(:,59) = [125.567,-23.5133] + xy(:,60) = [137.627,-40.8524] + xy(:,61) = [106.162,-24.5874] + xy(:,62) = [158.508,-38.55] + xy(:,63) = [137.826,-72.8109] + xy(:,64) = [142.103,-26.799] + xy(:,65) = [138.256,-13.8871] + xy(:,66) = [168.39,-24.3266] + xy(:,67) = [168.954,-12.0094] + xy(:,68) = [117.333,-12.35] + xy(:,69) = [102.254,-11.1537] + xy(:,70) = [120.307,59.7167] + xy(:,71) = [107.196,26.0167] + xy(:,72) = [144.768,28.3721] + xy(:,73) = [150.891,60.0343] + xy(:,74) = [164.566,25.5053] + xy(:,75) = [116.851,14.0295] + xy(:,76) = [124.84,28.3978] + xy(:,77) = [157.901,42.042] + xy(:,78) = [111.41,43.1056] + xy(:,79) = [134.333,44.6677] + xy(:,80) = [103.277,11.707] + xy(:,81) = [135.358,73.2119] + xy(:,82) = [135.349,14.2311] + xy(:,83) = [153.48,13.386] + xy(:,84) = [168.071,11.5344] + xy(:,85) = [-162.99,26.3775] + xy(:,86) = [-147.519,56.1313] + xy(:,87) = [-122.579,27.4824] + xy(:,88) = [-117.909,59.2376] + xy(:,89) = [-104.052,27.3616] + xy(:,90) = [-153.107,14.9717] + xy(:,91) = [-110.833,41.7436] + xy(:,92) = [-144.847,32.8534] + xy(:,93) = [-161.546,42.1031] + xy(:,94) = [-129.866,44.5201] + xy(:,95) = [-133.883,72.4163] + xy(:,96) = [-166.729,11.8907] + xy(:,97) = [-135.755,15.2529] + xy(:,98) = [-106.063,14.4869] + xy(:,99) = [-119.452,11.7037] + xy(:,100) = [-146.026,-58.6741] + xy(:,101) = [-115.913,-16.9547] + xy(:,102) = [-115.788,-58.8675] + xy(:,103) = [-155.623,-41.9617] + xy(:,104) = [-144.433,-23.5133] + xy(:,105) = [-132.373,-40.8524] + xy(:,106) = [-163.838,-24.5874] + xy(:,107) = [-111.492,-38.55] + xy(:,108) = [-132.174,-72.8109] + xy(:,109) = [-127.897,-26.799] + xy(:,110) = [-131.744,-13.8871] + xy(:,111) = [-101.61,-24.3266] + xy(:,112) = [-101.046,-12.0094] + xy(:,113) = [-152.667,-12.35] + xy(:,114) = [-167.746,-11.1537] + xy(:,115) = [-14.0127,-27.2963] + xy(:,116) = [-59.193,-57.0815] + xy(:,117) = [-56.465,-19.5751] + xy(:,118) = [-27.056,-59.3077] + xy(:,119) = [-57.124,-35.9752] + xy(:,120) = [-33.4636,-28.3914] + xy(:,121) = [-74.8037,-46.8602] + xy(:,122) = [-40.089,-45.1376] + xy(:,123) = [-74.8149,-28.3136] + xy(:,124) = [-21.3072,-42.2177] + xy(:,125) = [-44.0778,-72.6353] + xy(:,126) = [-19.6969,-12.8527] + xy(:,127) = [-40.1318,-12.1601] + xy(:,128) = [-72.691,-11.4129] + xy(:,129) = [-56.0261,58.6741] + xy(:,130) = [-25.9127,16.9547] + xy(:,131) = [-25.7876,58.8675] + xy(:,132) = [-65.6229,41.9617] + xy(:,133) = [-54.4335,23.5133] + xy(:,134) = [-42.373,40.8524] + xy(:,135) = [-73.838,24.5874] + xy(:,136) = [-21.4917,38.55] + xy(:,137) = [-42.1744,72.8109] + xy(:,138) = [-37.8974,26.799] + xy(:,139) = [-41.7437,13.8871] + xy(:,140) = [-11.6095,24.3266] + xy(:,141) = [-11.0459,12.0094] + xy(:,142) = [-62.667,12.35] + xy(:,143) = [-77.7456,11.1537] + xy(:,144) = [30.3071,59.7167] + xy(:,145) = [17.1956,26.0167] + xy(:,146) = [54.7676,28.3721] + xy(:,147) = [60.8915,60.0343] + xy(:,148) = [74.5657,25.5053] + xy(:,149) = [26.8506,14.0295] + xy(:,150) = [34.8398,28.3978] + xy(:,151) = [67.9014,42.042] + xy(:,152) = [21.41,43.1056] + xy(:,153) = [44.3335,44.6677] + xy(:,154) = [13.2772,11.707] + xy(:,155) = [45.3579,73.2119] + xy(:,156) = [45.3492,14.2311] + xy(:,157) = [63.4799,13.386] + xy(:,158) = [78.0714,11.5344] + xy(:,159) = [17.01,-26.3775] + xy(:,160) = [32.4806,-56.1313] + xy(:,161) = [57.4213,-27.4824] + xy(:,162) = [62.0912,-59.2376] + xy(:,163) = [75.9483,-27.3616] + xy(:,164) = [26.893,-14.9717] + xy(:,165) = [69.1672,-41.7436] + xy(:,166) = [35.1527,-32.8534] + xy(:,167) = [18.4543,-42.1031] + xy(:,168) = [50.1344,-44.5201] + xy(:,169) = [46.1172,-72.4163] + xy(:,170) = [13.2711,-11.8907] + xy(:,171) = [44.2448,-15.2529] + xy(:,172) = [73.9368,-14.4869] + xy(:,173) = [60.5478,-11.7037] + + grid = atlas_UnstructuredGrid(xy) + + FCTEST_CHECK_EQUAL( grid%owners(), 1 ) + + meshgenerator = atlas_MeshGenerator("delaunay") + mesh = meshgenerator%generate(grid) + FCTEST_CHECK_EQUAL( mesh%owners(), 1 ) + + FCTEST_CHECK_EQUAL( grid%owners(), 2 ) + + gmsh = atlas_output_Gmsh("atlas_fctest_unstructuredgrid.msh",coordinates="xyz") + call gmsh%write(mesh) + + + call mesh%final() + FCTEST_CHECK_EQUAL( grid%owners(), 1 ) + call gmsh%final() + call grid%final() + call meshgenerator%final() +END_TEST + +! ----------------------------------------------------------------------------- + +END_TESTSUITE + diff --git a/src/tests/grid/test_grid_hash.cc b/src/tests/grid/test_grid_hash.cc index 8b70287fc..d94f6463c 100644 --- a/src/tests/grid/test_grid_hash.cc +++ b/src/tests/grid/test_grid_hash.cc @@ -29,10 +29,10 @@ 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" ), + std::make_tuple( Grid( "O32" ), "e8d76a652ea937615276383aba43c912" ), + std::make_tuple( Grid( "O32", Domain() ), "e8d76a652ea937615276383aba43c912" ), + std::make_tuple( Grid( "O32", RectangularDomain( {0, 360}, {90, -90} ) ), "e8d76a652ea937615276383aba43c912" ), + std::make_tuple( Grid( "O32", ZonalBandDomain( {90, -90} ) ), "e8d76a652ea937615276383aba43c912" ), }; int c{0}; @@ -42,7 +42,9 @@ CASE( "test_global" ) { SECTION( "grid: " + std::to_string( c ) ) { Hash h; grid.hash( h ); - if ( hash.empty() ) { Log::info() << "grid " << c << " hash = " << std::string( h ) << std::endl; } + if ( hash.empty() ) { + Log::info() << "grid " << c << " hash = " << std::string( h ) << std::endl; + } EXPECT( std::string( h ) == hash ); } c++; diff --git a/src/tests/grid/test_grid_ptr.cc b/src/tests/grid/test_grid_ptr.cc index eaf68f2db..067ba013c 100644 --- a/src/tests/grid/test_grid_ptr.cc +++ b/src/tests/grid/test_grid_ptr.cc @@ -187,7 +187,9 @@ CASE( "test_iterator_with_predicate" ) { auto filter = []( long n ) { bool b = ( n >= 5 && n < 10 ); - if ( b ) Log::debug() << "n = " << n << std::endl; + if ( b ) { + Log::debug() << "n = " << n << std::endl; + } return b; }; diff --git a/src/tests/grid/test_state.cc b/src/tests/grid/test_state.cc index c9b2955f9..fa91a235b 100644 --- a/src/tests/grid/test_state.cc +++ b/src/tests/grid/test_state.cc @@ -48,7 +48,9 @@ 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_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 ) ) { @@ -58,10 +60,14 @@ void MyStateGenerator::generate( State& state, const eckit::Parametrisation& p ) std::string grid_uid; if ( geometry.get( "grid", grid_uid ) ) { Grid grid( grid_uid ); - if ( !geometry.has( "ngptot" ) ) { geometry.set( "ngptot", grid.size() ); } + if ( !geometry.has( "ngptot" ) ) { + geometry.set( "ngptot", grid.size() ); + } } - if ( !geometry.has( "ngptot" ) ) { throw_Exception( "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 ) ) { diff --git a/src/tests/interpolation/CMakeLists.txt b/src/tests/interpolation/CMakeLists.txt index 738b75bdf..67e72b624 100644 --- a/src/tests/interpolation/CMakeLists.txt +++ b/src/tests/interpolation/CMakeLists.txt @@ -10,16 +10,19 @@ ecbuild_add_test( TARGET atlas_test_Quad3D CONDITION ECKIT_HAVE_EIGEN SOURCES test_Quad3D.cc LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) ecbuild_add_test( TARGET atlas_test_interpolation_finite_element SOURCES test_interpolation_finite_element.cc LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) ecbuild_add_test( TARGET atlas_test_interpolation_cubic_prototype SOURCES test_interpolation_cubic_prototype.cc CubicInterpolationPrototype.h LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) ecbuild_add_executable( TARGET atlas_test_interpolation_structured2D @@ -28,15 +31,47 @@ ecbuild_add_executable( TARGET atlas_test_interpolation_structured2D NOINSTALL ) +if( ECBUILD-432-fixed ) +# When ECBUILD-432 is fixed (already fixed in develop on top of ecbuild 3.0.0), we don't need TARGET_FILE ecbuild_add_test( TARGET atlas_test_interpolation_bilinear COMMAND atlas_test_interpolation_structured2D ARGS --scheme linear + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) ecbuild_add_test( TARGET atlas_test_interpolation_bicubic COMMAND atlas_test_interpolation_structured2D ARGS --scheme cubic + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) ecbuild_add_test( TARGET atlas_test_interpolation_biquasicubic COMMAND atlas_test_interpolation_structured2D ARGS --scheme quasicubic + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) +else() + # TO BE REMOVED! + + set( exe_atlas_test_interpolation_structured2D $ ) + if( CMAKE_CROSSCOMPILING_EMULATOR ) + set( exe_atlas_test_interpolation_structured2D ${CMAKE_CROSSCOMPILING_EMULATOR} ) + set( arg_atlas_test_interpolation_structured2D $ ) + endif() + + ecbuild_add_test( TARGET atlas_test_interpolation_bilinear + COMMAND ${exe_atlas_test_interpolation_structured2D} ARGS ${arg_atlas_test_interpolation_structured2D} --scheme linear + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} + ) + + ecbuild_add_test( TARGET atlas_test_interpolation_bicubic + COMMAND ${exe_atlas_test_interpolation_structured2D} ARGS ${arg_atlas_test_interpolation_structured2D} --scheme cubic + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} + ) + + ecbuild_add_test( TARGET atlas_test_interpolation_biquasicubic + COMMAND ${exe_atlas_test_interpolation_structured2D} ARGS ${arg_atlas_test_interpolation_structured2D} --scheme quasicubic + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} + ) +endif() + + + diff --git a/src/tests/interpolation/CubicInterpolationPrototype.h b/src/tests/interpolation/CubicInterpolationPrototype.h index 545d8687d..28780b573 100644 --- a/src/tests/interpolation/CubicInterpolationPrototype.h +++ b/src/tests/interpolation/CubicInterpolationPrototype.h @@ -157,7 +157,9 @@ class CubicVerticalInterpolation { if ( limiter_ ) { idx_t k = stencil.k_interval(); idx_t k1, k2; - if ( k < 0 ) { k1 = k2 = 0; } + if ( k < 0 ) { + k1 = k2 = 0; + } else if ( k > 2 ) { k1 = k2 = 3; } @@ -272,7 +274,9 @@ class CubicHorizontalInterpolation { } } - if ( limiter_ ) { limit( output, index, input ); } + if ( limiter_ ) { + limit( output, index, input ); + } } template diff --git a/src/tests/interpolation/test_interpolation_cubic_prototype.cc b/src/tests/interpolation/test_interpolation_cubic_prototype.cc index 3808f3053..37a27b965 100644 --- a/src/tests/interpolation/test_interpolation_cubic_prototype.cc +++ b/src/tests/interpolation/test_interpolation_cubic_prototype.cc @@ -135,9 +135,15 @@ CASE( "test horizontal cubic interpolation" ) { //----------------------------------------------------------------------------- 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; + 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; } @@ -145,9 +151,13 @@ bool operator!=( const eckit::linalg::Triplet& t1, const eckit::linalg::Triplet& return !( t1 == t2 ); } bool operator==( const std::vector& t1, const std::vector& t2 ) { - if ( t1.size() != t2.size() ) return false; + if ( t1.size() != t2.size() ) { + return false; + } for ( size_t i = 0; i < t1.size(); ++i ) { - if ( t1[i] != t2[i] ) return false; + if ( t1[i] != t2[i] ) { + return false; + } } return true; } @@ -155,7 +165,9 @@ 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 << ","; } + if ( i < array.size() - 1 ) { + out << ","; + } out << " "; } out << "}"; diff --git a/src/tests/interpolation/test_interpolation_structured2D.cc b/src/tests/interpolation/test_interpolation_structured2D.cc index 2a766cc50..177418385 100644 --- a/src/tests/interpolation/test_interpolation_structured2D.cc +++ b/src/tests/interpolation/test_interpolation_structured2D.cc @@ -133,7 +133,9 @@ double vortex_rollup( double lon, double lat, double t ) { 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; } + 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; }; diff --git a/src/tests/io/CMakeLists.txt b/src/tests/io/CMakeLists.txt index 05bc36850..114666c98 100644 --- a/src/tests/io/CMakeLists.txt +++ b/src/tests/io/CMakeLists.txt @@ -9,11 +9,13 @@ ecbuild_add_test( TARGET atlas_test_gmsh SOURCES test_gmsh.cc ../TestMeshes.h LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) ecbuild_add_test( TARGET atlas_test_pointcloud_io SOURCES test_pointcloud_io.cc LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) if( HAVE_FCTEST ) @@ -22,6 +24,7 @@ add_fctest( TARGET atlas_fctest_gmsh LINKER_LANGUAGE Fortran SOURCES fctest_gmsh.F90 LIBS atlas_f + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) endif() diff --git a/src/tests/io/test_pointcloud_io.cc b/src/tests/io/test_pointcloud_io.cc index 29cbe9106..1ff2cf963 100644 --- a/src/tests/io/test_pointcloud_io.cc +++ b/src/tests/io/test_pointcloud_io.cc @@ -69,7 +69,9 @@ const std::vector fnames( test_arrays::fnames, test_arrays::fnames } // namespace test_vectors bool test_write_file( const std::string& file_path, const size_t& nb_pts, const size_t& nb_columns ) { - if ( !nb_pts ) return false; + if ( !nb_pts ) { + return false; + } std::ofstream f( file_path.c_str() ); return ( f && f << "PointCloudIO " << nb_pts << " " << nb_columns << " lon lat f_1 " diff --git a/src/tests/mesh/CMakeLists.txt b/src/tests/mesh/CMakeLists.txt index 838c8b7a6..87a3a7778 100644 --- a/src/tests/mesh/CMakeLists.txt +++ b/src/tests/mesh/CMakeLists.txt @@ -13,6 +13,7 @@ if( HAVE_FCTEST ) CONDITION NOT atlas_fctest_mesh_DISABLED SOURCES fctest_mesh.F90 LIBS atlas_f + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) add_fctest( TARGET atlas_fctest_meshgen @@ -20,18 +21,21 @@ if( HAVE_FCTEST ) CONDITION ON SOURCES fctest_meshgen.F90 LIBS atlas_f + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) add_fctest( TARGET atlas_fctest_connectivity LINKER_LANGUAGE Fortran SOURCES fctest_connectivity.F90 LIBS atlas_f + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) add_fctest( TARGET atlas_fctest_elements LINKER_LANGUAGE Fortran SOURCES fctest_elements.F90 LIBS atlas_f + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) endif() @@ -41,6 +45,7 @@ ecbuild_add_test( TARGET atlas_test_parfields CONDITION ECKIT_HAVE_MPI SOURCES test_parfields.cc LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) ecbuild_add_test( TARGET atlas_test_halo @@ -48,6 +53,7 @@ ecbuild_add_test( TARGET atlas_test_halo CONDITION ECKIT_HAVE_MPI SOURCES test_halo.cc ../TestMeshes.h LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) ecbuild_add_test( TARGET atlas_test_distmesh @@ -55,6 +61,7 @@ ecbuild_add_test( TARGET atlas_test_distmesh CONDITION ECKIT_HAVE_MPI SOURCES test_distmesh.cc ../TestMeshes.h LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) ecbuild_add_test( @@ -62,12 +69,14 @@ ecbuild_add_test( SOURCES test_cgal_mesh_gen_from_points.cc CONDITION ATLAS_HAVE_TESSELATION LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) ecbuild_add_test( TARGET atlas_test_accumulate_facets SOURCES test_accumulate_facets.cc LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) ecbuild_add_test( TARGET atlas_test_mesh_node2cell @@ -75,13 +84,15 @@ ecbuild_add_test( TARGET atlas_test_mesh_node2cell CONDITION ECKIT_HAVE_MPI SOURCES test_mesh_node2cell.cc LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) -foreach( test connectivity elements ll meshgen3d rgg ) +foreach( test connectivity stream_connectivity elements ll meshgen3d rgg ) ecbuild_add_test( TARGET atlas_test_${test} SOURCES test_${test}.cc LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) endforeach() @@ -89,4 +100,5 @@ atlas_add_cuda_test( TARGET atlas_test_connectivity_kernel SOURCES test_connectivity_kernel.cu LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) diff --git a/src/tests/mesh/test_distmesh.cc b/src/tests/mesh/test_distmesh.cc index 3cb896f1c..5ff6f3fa2 100644 --- a/src/tests/mesh/test_distmesh.cc +++ b/src/tests/mesh/test_distmesh.cc @@ -52,7 +52,9 @@ double dual_volume( Mesh& mesh ) { double area = 0; for ( idx_t node = 0; node < nb_nodes; ++node ) { - if ( !is_ghost_node( node ) ) { area += dual_volumes( node ); } + if ( !is_ghost_node( node ) ) { + area += dual_volumes( node ); + } } ATLAS_TRACE_MPI( ALLREDUCE ) { mpi::comm().allReduceInPlace( area, eckit::mpi::sum() ); } @@ -94,7 +96,9 @@ CASE( "test_distribute_t63" ) { double computed_dual_volume = test::dual_volume( m ); EXPECT( eckit::types::is_approximately_equal( computed_dual_volume, 360. * 180., 0.0001 ) ); double difference = 360. * 180. - computed_dual_volume; - if ( difference > 1e-8 ) { std::cout << "difference = " << difference << std::endl; } + if ( difference > 1e-8 ) { + std::cout << "difference = " << difference << std::endl; + } Gmsh( "dist.msh" ).write( m ); diff --git a/src/tests/mesh/test_halo.cc b/src/tests/mesh/test_halo.cc index e6ab04457..bff82541a 100644 --- a/src/tests/mesh/test_halo.cc +++ b/src/tests/mesh/test_halo.cc @@ -49,7 +49,9 @@ double dual_volume( Mesh& mesh ) { array::ArrayView dual_volumes = array::make_view( nodes.field( "dual_volumes" ) ); double area = 0; for ( int node = 0; node < nb_nodes; ++node ) { - if ( !is_ghost_node( node ) ) { area += dual_volumes( node ); } + if ( !is_ghost_node( node ) ) { + area += dual_volumes( node ); + } } ATLAS_TRACE_MPI( ALLREDUCE ) { mpi::comm().allReduceInPlace( area, eckit::mpi::sum() ); } diff --git a/src/tests/mesh/test_parfields.cc b/src/tests/mesh/test_parfields.cc index dfd2460be..68756dfae 100644 --- a/src/tests/mesh/test_parfields.cc +++ b/src/tests/mesh/test_parfields.cc @@ -49,8 +49,12 @@ class IsGhost { mypart_( mpi::comm().rank() ) {} bool operator()( idx_t idx ) const { - if ( part_( idx ) != mypart_ ) return true; - if ( ridx_( idx ) != idx ) return true; + if ( part_( idx ) != mypart_ ) { + return true; + } + if ( ridx_( idx ) != idx ) { + return true; + } return false; } @@ -202,26 +206,37 @@ CASE( "test2" ) { idx_t nb_ghost = 0; for ( idx_t jnode = 0; jnode < nodes.size(); ++jnode ) { - if ( is_ghost( jnode ) ) ++nb_ghost; + if ( is_ghost( jnode ) ) { + ++nb_ghost; + } } ATLAS_DEBUG_VAR( nb_ghost ); - if ( mpi::comm().rank() == 0 ) EXPECT( nb_ghost == 128 ); // South boundary of Northern hemisphere - if ( mpi::comm().rank() == 1 ) EXPECT( nb_ghost == 0 ); // Southern hemisphere has no ghosts + if ( mpi::comm().rank() == 0 ) { + EXPECT( nb_ghost == 128 ); // South boundary of Northern hemisphere + } + if ( mpi::comm().rank() == 1 ) { + EXPECT( nb_ghost == 0 ); // Southern hemisphere has no ghosts + } mesh::actions::build_periodic_boundaries( m ); int nb_periodic = -nb_ghost; for ( idx_t jnode = 0; jnode < nodes.size(); ++jnode ) { - if ( is_ghost( jnode ) ) ++nb_periodic; + if ( is_ghost( jnode ) ) { + ++nb_periodic; + } } ATLAS_DEBUG_VAR( nb_periodic ); - if ( mpi::comm().rank() == 0 ) - EXPECT( nb_periodic == 33 ); // Periodic East boundary of Northern hemisphere - // (plus one point south) - if ( mpi::comm().rank() == 1 ) EXPECT( nb_periodic == 32 ); // Periodic East boundary of Southern hemisphere + if ( mpi::comm().rank() == 0 ) { + EXPECT( nb_periodic == 33 ); // Periodic East boundary of Northern hemisphere + } + // (plus one point south) + if ( mpi::comm().rank() == 1 ) { + EXPECT( nb_periodic == 32 ); // Periodic East boundary of Southern hemisphere + } Gmsh( "periodic.msh", util::Config( "info", true ) ).write( m ); } diff --git a/src/tests/mesh/test_rgg.cc b/src/tests/mesh/test_rgg.cc index cdbd43c44..a5567b0cd 100644 --- a/src/tests/mesh/test_rgg.cc +++ b/src/tests/mesh/test_rgg.cc @@ -373,8 +373,9 @@ ASSERT(0); const mesh::HybridElements::Connectivity& cell_node_connectivity = m.cells().node_connectivity(); for ( idx_t jelem = 0; jelem < static_cast( m.cells().size() ); ++jelem ) { - for ( idx_t jnode = 0; jnode < cell_node_connectivity.cols( jelem ); ++jnode ) + for ( idx_t jnode = 0; jnode < cell_node_connectivity.cols( jelem ); ++jnode ) { node_elem_connections[cell_node_connectivity( jelem, jnode )]++; + } } for ( idx_t jnode = 0; jnode < nb_nodes; ++jnode ) { if ( node_elem_connections[jnode] == 0 ) { @@ -390,9 +391,10 @@ ASSERT(0); if ( gidx( n ) <= grid.size() ) { if ( part( n ) == p ) { ++nb_owned; - if ( all_owned[gidx( n ) - 1] != -1 ) + if ( all_owned[gidx( n ) - 1] != -1 ) { std::cout << "node " << gidx( n ) << " already visited by " << all_owned[gidx( n ) - 1] << std::endl; + } EXPECT( all_owned[gidx( n ) - 1] == -1 ); all_owned[gidx( n ) - 1] = part( n ); } @@ -401,7 +403,9 @@ ASSERT(0); } for ( size_t gid = 1; gid <= all_owned.size(); ++gid ) { - if ( all_owned[gid - 1] == -1 ) { Log::error() << "node " << gid << " is not owned by anyone" << std::endl; } + if ( all_owned[gid - 1] == -1 ) { + Log::error() << "node " << gid << " is not owned by anyone" << std::endl; + } } EXPECT( nb_owned == grid.size() ); diff --git a/src/tests/mesh/test_shapefunctions.cc b/src/tests/mesh/test_shapefunctions.cc index 823ae51bf..97c5e9027 100644 --- a/src/tests/mesh/test_shapefunctions.cc +++ b/src/tests/mesh/test_shapefunctions.cc @@ -100,7 +100,8 @@ class Polynomial { public: Polynomial& add( const monomial_type& mononomial ) { - if ( mononomial.coeff != 0 ) mononomials_.push_back( mononomial ); + if ( mononomial.coeff != 0 ) + mononomials_.push_back( mononomial ); return *this; } @@ -169,7 +170,9 @@ class Polynomial { static std::vector curl( const std::vector& pvec ) { std::vector p( 3 ); - if ( NDIM == 2 ) { p[2] = pvec[1].deriv( 0 ) - pvec[0].deriv( 1 ); } + if ( NDIM == 2 ) { + p[2] = pvec[1].deriv( 0 ) - pvec[0].deriv( 1 ); + } if ( NDIM == 3 ) { p[0] = pvec[2].deriv( 1 ) - pvec[1].deriv( 2 ); p[1] = pvec[0].deriv( 2 ) - pvec[2].deriv( 0 ); @@ -215,7 +218,9 @@ class Polynomial { } } for ( size_t j = 0; j < other.mononomials_.size(); ++j ) { - if ( !matched[j] ) { add( other.mononomials_[j] ); } + if ( !matched[j] ) { + add( other.mononomials_[j] ); + } } return *this; } @@ -421,7 +426,8 @@ class NewFunctionSpace { /// @brief Set the total number of nodes in FunctionSpace void set_nb_nodes( int nb_nodes ) { nb_nodes_ = nb_nodes; - if ( nproma_ == 0 ) nproma_ = 1; + if ( nproma_ == 0 ) + nproma_ = 1; ATLAS_ASSERT( nb_nodes_ % nproma_ == 0 ); nblk_ = nb_nodes_ / nproma_; } @@ -441,12 +447,18 @@ class NewFunctionSpace { /// @brief Add elements const ElementType& add_elements( const std::string& element_type, int nelem ) { - if ( element_type == "Polygon" ) element_types_.push_back( ElementType::Ptr( new Polygon() ) ); - if ( element_type == "QuadP1" ) element_types_.push_back( ElementType::Ptr( new QuadP1 ) ); - if ( element_type == "TriagP1" ) element_types_.push_back( ElementType::Ptr( new TriagP1 ) ); - if ( element_type == "LineP0" ) element_types_.push_back( ElementType::Ptr( new LineP0 ) ); - if ( element_type == "LineP1" ) element_types_.push_back( ElementType::Ptr( new LineP1 ) ); - if ( element_type == "LineP2" ) element_types_.push_back( ElementType::Ptr( new LineP2 ) ); + if ( element_type == "Polygon" ) + element_types_.push_back( ElementType::Ptr( new Polygon() ) ); + if ( element_type == "QuadP1" ) + element_types_.push_back( ElementType::Ptr( new QuadP1 ) ); + if ( element_type == "TriagP1" ) + element_types_.push_back( ElementType::Ptr( new TriagP1 ) ); + if ( element_type == "LineP0" ) + element_types_.push_back( ElementType::Ptr( new LineP0 ) ); + if ( element_type == "LineP1" ) + element_types_.push_back( ElementType::Ptr( new LineP1 ) ); + if ( element_type == "LineP2" ) + element_types_.push_back( ElementType::Ptr( new LineP2 ) ); index_[element_type] = nelem_per_type_.size(); nelem_per_type_.push_back( nelem ); @@ -475,13 +487,20 @@ class NewFunctionSpace { int idx7 = IDX_NOTUSED ) { atlas::array::ArrayShape shape; shape.reserve( 7 ); - if ( idx1 != IDX_NOTUSED ) shape.push_back( range( idx1 ) ); - if ( idx2 != IDX_NOTUSED ) shape.push_back( range( idx2 ) ); - if ( idx3 != IDX_NOTUSED ) shape.push_back( range( idx3 ) ); - if ( idx4 != IDX_NOTUSED ) shape.push_back( range( idx4 ) ); - if ( idx5 != IDX_NOTUSED ) shape.push_back( range( idx5 ) ); - if ( idx6 != IDX_NOTUSED ) shape.push_back( range( idx6 ) ); - if ( idx7 != IDX_NOTUSED ) shape.push_back( range( idx7 ) ); + if ( idx1 != IDX_NOTUSED ) + shape.push_back( range( idx1 ) ); + if ( idx2 != IDX_NOTUSED ) + shape.push_back( range( idx2 ) ); + if ( idx3 != IDX_NOTUSED ) + shape.push_back( range( idx3 ) ); + if ( idx4 != IDX_NOTUSED ) + shape.push_back( range( idx4 ) ); + if ( idx5 != IDX_NOTUSED ) + shape.push_back( range( idx5 ) ); + if ( idx6 != IDX_NOTUSED ) + shape.push_back( range( idx6 ) ); + if ( idx7 != IDX_NOTUSED ) + shape.push_back( range( idx7 ) ); atlas::array::ArrayT field( shape ); return field; } @@ -498,7 +517,8 @@ class NewFunctionSpace { case IDX_NPROMA: return nproma(); default: - if ( idx_type >= 0 ) return idx_type; + if ( idx_type >= 0 ) + return idx_type; } throw_Exception( "idx_type not recognized" ); return 0; diff --git a/src/tests/mesh/test_stream_connectivity.cc b/src/tests/mesh/test_stream_connectivity.cc new file mode 100644 index 000000000..565631e2d --- /dev/null +++ b/src/tests/mesh/test_stream_connectivity.cc @@ -0,0 +1,179 @@ +/* + * (C) Copyright 2013 ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not 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/io/ResizableBuffer.h" +#include "eckit/serialisation/ResizableMemoryStream.h" + +#include "atlas/mesh/Connectivity.h" +#include "tests/AtlasTestEnvironment.h" + +using namespace atlas::mesh; + +namespace atlas { +namespace test { + +//----------------------------------------------------------------------------- + +CASE( "test_stream_irregular_connectivity" ) { + eckit::ResizableBuffer b{0}; + eckit::ResizableMemoryStream s{b}; + + // Create stream + { + IrregularConnectivity conn( "bla" ); + + constexpr idx_t vals[4] = {2, 3, 5, 6}; + conn.add( 1, 4, vals, /* fortran-array = */ false ); + + constexpr idx_t vals2[6] = {1, 3, 4, 3, 7, 8}; + conn.add( 2, 3, vals2, /* fortran-array = */ false ); + s << conn; + } + + + s.rewind(); + // Read from stream + { + IrregularConnectivity conn( s ); + EXPECT( conn.rows() == 3 ); + EXPECT( conn.cols( 0 ) == 4 ); + EXPECT( conn.cols( 1 ) == 3 ); + EXPECT( conn.cols( 2 ) == 3 ); + EXPECT( conn( 0, 0 ) == 2 ); + EXPECT( conn( 0, 1 ) == 3 ); + EXPECT( conn( 0, 2 ) == 5 ); + EXPECT( conn( 0, 3 ) == 6 ); + EXPECT( conn( 1, 0 ) == 1 ); + EXPECT( conn( 1, 1 ) == 3 ); + EXPECT( conn( 1, 2 ) == 4 ); + EXPECT( conn( 2, 0 ) == 3 ); + EXPECT( conn( 2, 1 ) == 7 ); + EXPECT( conn( 2, 2 ) == 8 ); + EXPECT( conn.name() == "bla" ); + } + + + s.rewind(); + // Read from stream + { + IrregularConnectivity conn; + s >> conn; + EXPECT( conn.rows() == 3 ); + EXPECT( conn.cols( 0 ) == 4 ); + EXPECT( conn.cols( 1 ) == 3 ); + EXPECT( conn.cols( 2 ) == 3 ); + EXPECT( conn( 0, 0 ) == 2 ); + EXPECT( conn( 0, 1 ) == 3 ); + EXPECT( conn( 0, 2 ) == 5 ); + EXPECT( conn( 0, 3 ) == 6 ); + EXPECT( conn( 1, 0 ) == 1 ); + EXPECT( conn( 1, 1 ) == 3 ); + EXPECT( conn( 1, 2 ) == 4 ); + EXPECT( conn( 2, 0 ) == 3 ); + EXPECT( conn( 2, 1 ) == 7 ); + EXPECT( conn( 2, 2 ) == 8 ); + EXPECT( conn.name() == "bla" ); + } +} + +//----------------------------------------------------------------------------- + +CASE( "test_stream_block_connectivity" ) { + eckit::ResizableBuffer b{0}; + eckit::ResizableMemoryStream s{b}; + + // Create stream + { + BlockConnectivity conn( 2, 3, {1, 3, 4, 3, 7, 8} ); + s << conn; + } + + + s.rewind(); + // Read from stream + { + BlockConnectivity conn( s ); + EXPECT( conn.rows() == 2 ); + EXPECT( conn.cols() == 3 ); + EXPECT( conn( 0, 0 ) == 1 ); + EXPECT( conn( 0, 1 ) == 3 ); + EXPECT( conn( 0, 2 ) == 4 ); + EXPECT( conn( 1, 0 ) == 3 ); + EXPECT( conn( 1, 1 ) == 7 ); + EXPECT( conn( 1, 2 ) == 8 ); + } + + + s.rewind(); + // Read from stream + { + BlockConnectivity conn; + s >> conn; + EXPECT( conn.rows() == 2 ); + EXPECT( conn.cols() == 3 ); + EXPECT( conn( 0, 0 ) == 1 ); + EXPECT( conn( 0, 1 ) == 3 ); + EXPECT( conn( 0, 2 ) == 4 ); + EXPECT( conn( 1, 0 ) == 3 ); + EXPECT( conn( 1, 1 ) == 7 ); + EXPECT( conn( 1, 2 ) == 8 ); + } +} + +CASE( "test_stream_multiblock_connectivity" ) { + eckit::ResizableBuffer b{0}; + eckit::ResizableMemoryStream s{b}; + + // Create stream + { + MultiBlockConnectivity conn( "mbc" ); + conn.add( BlockConnectivity{3, 5, {3, 7, 1, 4, 5, 6, 4, 56, 8, 4, 1, 3, 76, 4, 3}} ); + conn.add( BlockConnectivity{3, 2, {4, 75, 65, 45, 51, 35}} ); + s << conn; + } + + s.rewind(); + // Read from stream + { + MultiBlockConnectivity conn{s}; + EXPECT( conn.name() == "mbc" ); + EXPECT( conn.blocks() == 2 ); + EXPECT( conn( 3, 1 ) == 75 ); + EXPECT( conn( 4, 1 ) == 45 ); + EXPECT( conn( 5, 0 ) == 51 ); + EXPECT( conn( 1, 0, 1 ) == 75 ); + EXPECT( conn( 1, 1, 1 ) == 45 ); + EXPECT( conn( 1, 2, 0 ) == 51 ); + } + + s.rewind(); + // Read from stream + { + MultiBlockConnectivity conn; + s >> conn; + EXPECT( conn.name() == "mbc" ); + EXPECT( conn.blocks() == 2 ); + EXPECT( conn( 3, 1 ) == 75 ); + EXPECT( conn( 4, 1 ) == 45 ); + EXPECT( conn( 5, 0 ) == 51 ); + EXPECT( conn( 1, 0, 1 ) == 75 ); + EXPECT( conn( 1, 1, 1 ) == 45 ); + EXPECT( conn( 1, 2, 0 ) == 51 ); + } +} + +//----------------------------------------------------------------------------- + +} // namespace test +} // namespace atlas + +int main( int argc, char** argv ) { + return atlas::test::run( argc, argv ); +} diff --git a/src/tests/numerics/CMakeLists.txt b/src/tests/numerics/CMakeLists.txt index 4a4d32683..9995f5cba 100644 --- a/src/tests/numerics/CMakeLists.txt +++ b/src/tests/numerics/CMakeLists.txt @@ -9,6 +9,7 @@ ecbuild_add_test( TARGET atlas_test_fvm_nabla SOURCES test_fvm_nabla.cc LIBS atlas ${OMP_CXX} + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) if( HAVE_FCTEST) @@ -16,11 +17,13 @@ if( HAVE_FCTEST) LINKER_LANGUAGE Fortran SOURCES fctest_fvm_nabla.F90 LIBS atlas_f ${OMP_Fortran} + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) add_fctest( TARGET atlas_fctest_ifs_setup LINKER_LANGUAGE Fortran SOURCES fctest_ifs_setup.F90 LIBS atlas_f + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) endif() diff --git a/src/tests/numerics/test_fvm_nabla.cc b/src/tests/numerics/test_fvm_nabla.cc index 0238dea07..dd55679d8 100644 --- a/src/tests/numerics/test_fvm_nabla.cc +++ b/src/tests/numerics/test_fvm_nabla.cc @@ -50,7 +50,9 @@ double dual_volume( const Mesh& mesh ) { const array::ArrayView is_ghost = array::make_view( nodes.ghost() ); double area = 0; for ( int node = 0; node < nb_nodes; ++node ) { - if ( !is_ghost( node ) ) { area += dual_volumes( node ); } + if ( !is_ghost( node ) ) { + area += dual_volumes( node ); + } } mpi::comm().allReduceInPlace( area, eckit::mpi::sum() ); @@ -101,8 +103,9 @@ void rotated_flow_magnitude( const fvm::Method& fvm, Field& field, const double& 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 ( idx_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 ); + } } } diff --git a/src/tests/parallel/CMakeLists.txt b/src/tests/parallel/CMakeLists.txt index 5841f725b..b66a2ad54 100644 --- a/src/tests/parallel/CMakeLists.txt +++ b/src/tests/parallel/CMakeLists.txt @@ -11,6 +11,7 @@ ecbuild_add_test( TARGET atlas_test_haloexchange CONDITION ECKIT_HAVE_MPI SOURCES test_haloexchange.cc LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) ecbuild_add_test( TARGET atlas_test_gather @@ -18,5 +19,6 @@ ecbuild_add_test( TARGET atlas_test_gather CONDITION ECKIT_HAVE_MPI SOURCES test_gather.cc LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) diff --git a/src/tests/projection/CMakeLists.txt b/src/tests/projection/CMakeLists.txt index cc5c63b5c..bca0bf4a7 100644 --- a/src/tests/projection/CMakeLists.txt +++ b/src/tests/projection/CMakeLists.txt @@ -7,9 +7,10 @@ # does it submit to any jurisdiction. foreach(test - test_rotation - test_projection_LAEA ) + test_bounding_box + test_projection_LAEA + test_rotation ) - ecbuild_add_test( TARGET atlas_${test} SOURCES ${test}.cc LIBS atlas ) + ecbuild_add_test( TARGET atlas_${test} SOURCES ${test}.cc LIBS atlas ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) endforeach() diff --git a/src/tests/projection/FindGoodWest.h b/src/tests/projection/FindGoodWest.h index 740d31c51..016a7895f 100644 --- a/src/tests/projection/FindGoodWest.h +++ b/src/tests/projection/FindGoodWest.h @@ -111,7 +111,8 @@ struct WestFinder { auto top_bottom = std::array{0, grid.ny() - 1}; for ( idx_t j : top_bottom ) { for ( idx_t i = 0; i < grid.nx( j ); ++i ) { - if ( !in_bounds( i, j ) ) return false; + if ( !in_bounds( i, j ) ) + return false; } } } @@ -120,7 +121,8 @@ struct WestFinder { for ( idx_t j = 0; j < grid.ny(); ++j ) { auto left_right = std::array{0, grid.nx( j ) - 1}; for ( idx_t i : left_right ) { - if ( !in_bounds( i, j ) ) return false; + if ( !in_bounds( i, j ) ) + return false; } } } diff --git a/src/tests/projection/test_bounding_box.cc b/src/tests/projection/test_bounding_box.cc new file mode 100644 index 000000000..16f82907f --- /dev/null +++ b/src/tests/projection/test_bounding_box.cc @@ -0,0 +1,251 @@ +/* + * (C) Copyright 1996- ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not 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 "eckit/geometry/Point2.h" +#include "eckit/log/Plural.h" +#include "eckit/types/FloatCompare.h" + +#include "atlas/domain.h" +#include "atlas/domain/detail/GlobalDomain.h" // FIXME not included by atlas/domain.h +#include "atlas/grid.h" +#include "atlas/runtime/Log.h" +#include "atlas/util/Point.h" +#include "atlas/util/Rotation.h" +#include "tests/AtlasTestEnvironment.h" + + +namespace atlas { +namespace test { + +//----------------------------------------------------------------------------- + +double normalise( double weird, double minimum ) { + double lon = weird; + + double GLOBE = 360.; + while ( lon < minimum ) { + lon += GLOBE; + } + while ( lon >= minimum + GLOBE ) { + lon -= GLOBE; + } + + return lon; +} + + +struct BoundingBox : public std::array { + BoundingBox( double n, double w, double s, double e ) : std::array( {n, w, s, e} ) {} + BoundingBox() : BoundingBox( 90, 0, -90, 360 ) {} + + double north() const { return operator[]( 0 ); } + double south() const { return operator[]( 2 ); } + double west() const { return operator[]( 1 ); } + double east() const { return operator[]( 3 ); } + + operator RectangularDomain() const { return {{{west(), east()}}, {{south(), north()}}}; } + + bool contains( const double& lat, const double& lon ) const { + return ( lat <= north() ) && ( lat >= south() ) && ( normalise( lon, west() ) <= east() ); + } + + bool contains( const BoundingBox& other ) const { + bool otherEmpty = !eckit::types::is_strictly_greater( other.north(), other.south() ) || + !eckit::types::is_strictly_greater( other.east(), other.west() ); + + if ( otherEmpty ) { + return contains( other.south(), other.west() ); + } + + // check for West/East range (if non-periodic), then other's corners + if ( east() - west() < other.east() - other.west() || east() < normalise( other.east(), west() ) ) { + return false; + } + + return contains( other.north(), other.west() ) && contains( other.north(), other.east() ) && + contains( other.south(), other.west() ) && contains( other.south(), other.east() ); + } +}; + + +struct Rotation : std::array { + Rotation( double lat, double lon ) : std::array( {lon, lat} ) {} + double south_pole_latitude() const { return operator[]( 1 ); } + double south_pole_longitude() const { return normalise( operator[]( 0 ), 0. ); } + BoundingBox rotate( const BoundingBox& box ) const { + util::Config config; + config.set( "type", "rotated_lonlat" ); + config.set( "south_pole", std::vector( {south_pole_longitude(), south_pole_latitude()} ) ); + atlas::Projection p( config ); + + RectangularDomain before( {box.west(), box.east()}, {box.south(), box.north()} ); + Domain after = p.lonlatBoundingBox( before ); + ATLAS_ASSERT( after ); + + RectangularLonLatDomain r( after ); + ATLAS_ASSERT( r ); + + return {r.north(), r.west(), r.south(), r.east()}; + } +}; + + +using NiNj = std::array; + + +struct test_poles_t { +public: + test_poles_t( const NiNj& ninj, const Rotation& rotation, const BoundingBox& bbox, bool includesNorthPole = false, + bool includesSouthPole = false ) : + ninj_( ninj ), + rotation_( rotation ), + bbox_( bbox ), + includesNorthPole_( includesNorthPole ), + includesSouthPole_( includesSouthPole ) {} + + const NiNj ninj_; + const Rotation rotation_; + const BoundingBox bbox_; + const bool includesNorthPole_; + const bool includesSouthPole_; + +private: + friend std::ostream& operator<<( std::ostream& out, const test_poles_t& test ) { + return ( out << "test:" + << "\n\t" + << "NiNj = " << test.ninj_ << "\n\t" + << "Rotation = " << test.rotation_ << "\n\t" + << "BoundingBox = " << test.bbox_ << "\n\t" + << "includesNorthPole? " << test.includesNorthPole_ << "\n\t" + << "includesSouthPole? " << test.includesSouthPole_ ); + } +}; + + +//----------------------------------------------------------------------------- + +CASE( "MIR-282" ) { + auto old = Log::info().precision( 16 ); + + + std::vector test_poles{ + {NiNj{124, 118}, Rotation( -35., 0. ), BoundingBox{12, -14.5, -17.25, 16.25}}, + {NiNj{360, 181}, Rotation( -90., 0. ), BoundingBox(), true, true}, + {NiNj{81, 56}, Rotation( -75., 15. ), BoundingBox{75.1, -35., 20., 45.}, true}, + {NiNj{111, 86}, Rotation( -35., 15. ), BoundingBox{40., -55., -45., 55.}, true}, + {NiNj{91, 76}, Rotation( -30., -15. ), BoundingBox{35., -40., -40., 50.}, true}, + {NiNj{101, 81}, Rotation( -25., 0. ), BoundingBox{40., -50., -40., 50.}, true}, + {NiNj{56, 61}, Rotation( -15., 45. ), BoundingBox{30., -50., -30., 5.}, true}, + {NiNj{96, 91}, Rotation( 0., 80. ), BoundingBox{50., -65., -40., 30.}, true}, + + {NiNj{178, 143}, Rotation( -40., 10. ), BoundingBox{22.7, -13.6, -5.9, 21.8}}, + {NiNj{117, 79}, Rotation( -43., 10. ), BoundingBox{3.4, -6.8, -4.4, 4.8}}, + {NiNj{776, 492}, Rotation( -30., 0. ), BoundingBox{18.1, -37.6, -31., 39.9}}, + {NiNj{149, 105}, Rotation( -76., 14. ), BoundingBox{72., -32., 20., 42.}}, + {NiNj{240, 240}, Rotation( -30., -5. ), BoundingBox{9.875, -15., -20., 14.875}}, + + {NiNj{13, 12}, Rotation( -15., 45. ), BoundingBox{27.5, -46.5, -28, 1.5}, true}, + {NiNj{321, 370}, Rotation( -15., 45. ), BoundingBox{27.5, -46.5, -28, 1.5}, true}, + + {NiNj{202, 235}, Rotation( 0., 130. ), BoundingBox{32.75, -86.75, -37.75, -26.15}, false}, + {NiNj{409, 309}, Rotation( -35., 15. ), BoundingBox{36., -51., -41., 51.}, true}, + + {NiNj{171, 6}, Rotation( -35., 160. ), BoundingBox{80., 30., 75., 200.}}, + {NiNj{81, 11}, Rotation( 30., -30. ), BoundingBox{70., 120., 60., 200.}}, + {NiNj{261, 66}, Rotation( 45., -120. ), BoundingBox{55., -120., -10., 140.}}, + + {NiNj{4, 4}, Rotation( 50., 100. ), BoundingBox{10., 70., -20., 100.}}, + }; + + + SECTION( "MIR-282: rotated_ll covering North/South poles" ) { + for ( auto& test : test_poles ) { + Log::info() << '\n' << test << std::endl; + + const PointLonLat southPole( test.rotation_.south_pole_longitude(), test.rotation_.south_pole_latitude() ); + + const util::Rotation r( southPole ); + + // check bbox including poles (in the unrotated frame) + PointLonLat NP{r.unrotate( {0., 90.} )}; + PointLonLat SP{r.unrotate( {0., -90.} )}; + + bool includesNorthPole = test.bbox_.contains( NP.lat(), NP.lon() ); + bool includesSouthPole = test.bbox_.contains( SP.lat(), SP.lon() ); + + Log::info() << "check:" + << "\n\t" + << "NP = " << NP << "\n\t" + << "SP = " << SP << "\n\t" + << "includesNorthPole? " << includesNorthPole << "\n\t" + << "includesSouthPole? " << includesSouthPole << std::endl; + + EXPECT( includesNorthPole == test.includesNorthPole_ ); + EXPECT( includesSouthPole == test.includesSouthPole_ ); + } + } + + + SECTION( "MIR-282: rotated_ll contained by cropping" ) { + for ( auto& test : test_poles ) { + Log::info() << '\n' << test << std::endl; + + double n = test.bbox_.north(); + double s = test.bbox_.south(); + double w = test.bbox_.west(); + double e = test.bbox_.east(); + + RectangularDomain dom( test.bbox_ ); + + using grid::LinearSpacing; + StructuredGrid::XSpace xspace( LinearSpacing( w, e, test.ninj_[0], !ZonalBandDomain( dom ) ) ); + StructuredGrid::YSpace yspace( LinearSpacing( n, s, test.ninj_[1] ) ); + + util::Config config; + config.set( "type", "rotated_lonlat" ); + config.set( "south_pole", std::vector( {test.rotation_.south_pole_longitude(), + test.rotation_.south_pole_latitude()} ) ); + Projection rotation( config ); + + Grid g = StructuredGrid( xspace, yspace, rotation, dom ); + ATLAS_ASSERT( g ); + + BoundingBox crop( test.rotation_.rotate( test.bbox_ ) ); + + Log::info() << "contained by cropping" + << "\n\t " << test.bbox_ << "\n\t + " << test.rotation_ << "\n\t = " << crop << std::endl; + + for ( PointLonLat p : g.lonlat() ) { + EXPECT( crop.contains( p.lat(), p.lon() ) ); + } + Log::info() << "checked " << eckit::Plural( g.size(), "point" ) << std::endl; + } + } + + + Log::info().precision( old ); +} + +//----------------------------------------------------------------------------- + +} // namespace test +} // namespace atlas + + +int main( int argc, char** argv ) { + return atlas::test::run( argc, argv ); +} diff --git a/src/tests/projection/test_projection_LAEA.cc b/src/tests/projection/test_projection_LAEA.cc index e1b563995..ccd89be76 100644 --- a/src/tests/projection/test_projection_LAEA.cc +++ b/src/tests/projection/test_projection_LAEA.cc @@ -96,7 +96,7 @@ CASE( "test_grid_creation_from_GRIB" ) { gridspec.set( "dx", dx ); gridspec.set( "dy", dy ); gridspec.set( firstPointLoc, firstPointLonLat ); - gridspec.set( "y_increasing", false ); // Always decrease y for MIR + gridspec.set( "y_numbering", -1 ); // Always decrease y for MIR gridspec.set( "projection", [&]() { Grid::Spec projection; projection.set( "type", "lambert_azimuthal_equal_area" ); @@ -144,62 +144,17 @@ CASE( "test_grid_creation_from_GRIB" ) { EXPECT( n == g.size() ); } - // Get circumscribed LonLat bounding box ( Could be turned into memberfunction of StructuredGrid ) + // Check if bounding box is correct { - auto regulargrid = RegularGrid( g ); - NormaliseLongitude normalised( find_good_west( regulargrid ) ); - double maxlat = -90.; - double minlat = 90.; - double minlon = 360.; - double maxlon = -360.; - // top - { - idx_t j = 0; - for ( idx_t i = 0; i < regulargrid.nx(); ++i ) { - auto p = regulargrid.lonlat( i, j ); - minlon = std::min( minlon, normalised( p.lon() ) ); - maxlon = std::max( maxlon, normalised( p.lon() ) ); - minlat = std::min( minlat, p.lat() ); - maxlat = std::max( maxlat, p.lat() ); - } - } - // bottom - { - idx_t j = regulargrid.ny() - 1; - for ( idx_t i = 0; i < regulargrid.nx(); ++i ) { - auto p = regulargrid.lonlat( i, j ); - minlon = std::min( minlon, normalised( p.lon() ) ); - maxlon = std::max( maxlon, normalised( p.lon() ) ); - minlat = std::min( minlat, p.lat() ); - maxlat = std::max( maxlat, p.lat() ); - } - } - // left - { - idx_t i = 0; - for ( idx_t j = 0; j < regulargrid.ny(); ++j ) { - auto p = regulargrid.lonlat( i, j ); - minlon = std::min( minlon, normalised( p.lon() ) ); - maxlon = std::max( maxlon, normalised( p.lon() ) ); - minlat = std::min( minlat, p.lat() ); - maxlat = std::max( maxlat, p.lat() ); - } - } - // right - { - idx_t i = regulargrid.nx() - 1; - for ( idx_t j = 0; j < regulargrid.ny(); ++j ) { - auto p = regulargrid.lonlat( i, j ); - minlon = std::min( minlon, normalised( p.lon() ) ); - maxlon = std::max( maxlon, normalised( p.lon() ) ); - minlat = std::min( minlat, p.lat() ); - maxlat = std::max( maxlat, p.lat() ); - } + RectangularLonLatDomain bb{g.lonlatBoundingBox()}; + const double tolerance = 1.e-6; + EXPECT( is_approximately_equal( bb.west(), -90.001, tolerance ) ); + EXPECT( is_approximately_equal( bb.east(), 41.883045, tolerance ) ); + EXPECT( is_approximately_equal( bb.south(), 3.817356, tolerance ) ); + EXPECT( is_approximately_equal( bb.north(), 76.041386, tolerance ) ); + for ( PointLonLat p : g.lonlat() ) { + EXPECT( bb.contains( p ) ); } - Log::info() << "n = " << maxlat << std::endl; - Log::info() << "s = " << minlat << std::endl; - Log::info() << "w = " << minlon << std::endl; - Log::info() << "e = " << maxlon << std::endl; } } diff --git a/src/tests/projection/test_rotation.cc b/src/tests/projection/test_rotation.cc index 071d6c797..1dc42feb8 100644 --- a/src/tests/projection/test_rotation.cc +++ b/src/tests/projection/test_rotation.cc @@ -9,6 +9,7 @@ */ #include +#include #include "eckit/types/FloatCompare.h" @@ -28,21 +29,19 @@ namespace test { //----------------------------------------------------------------------------- -constexpr double eps() { - return 1.e-5; +constexpr double eps = 1.e-5; +constexpr double d2r = atlas::util::Constants::degreesToRadians(); +constexpr double r2d = atlas::util::Constants::radiansToDegrees(); + +bool equivalent( const PointLonLat& p1, const PointLonLat& p2 ) { + using eckit::types::is_approximately_equal; + auto f = [=]( double lon ) { return 10. + std::cos( lon * d2r ); }; + + return is_approximately_equal( p1.lat(), p2.lat(), eps ) && + ( std::abs( p2.lat() ) == 90. || is_approximately_equal( f( p1.lon() ), f( p2.lon() ), eps ) ); } -const double d2r = atlas::util::Constants::degreesToRadians(); -const double r2d = atlas::util::Constants::radiansToDegrees(); - -#define EXPECT_EQUIVALENT( p1, p2 ) \ - if ( std::abs( p2.lat() ) == 90. ) \ - EXPECT( eckit::types::is_approximately_equal( p1.lat(), p2.lat(), eps() ) ); \ - else { \ - EXPECT( eckit::types::is_approximately_equal( 10. + std::cos( p1.lon() * d2r ), \ - 10. + std::cos( p2.lon() * d2r ), eps() ) ); \ - EXPECT( eckit::types::is_approximately_equal( 10. + std::sin( p1.lat() * d2r ), \ - 10. + std::sin( p2.lat() * d2r ), eps() ) ); \ - } + +#define EXPECT_EQUIVALENT( p1, p2 ) EXPECT( equivalent( p1, p2 ) ) //----------------------------------------------------------------------------- @@ -89,7 +88,9 @@ class MagicsRotation { double PXROT = std::acos( ZCXROT ) * r2d; - if ( ZSXROT < 0.0 ) PXROT = -PXROT; + if ( ZSXROT < 0.0 ) { + PXROT = -PXROT; + } return PointLonLat( PXROT, PYROT ); } @@ -111,7 +112,9 @@ class MagicsRotation { ZCXMXC = std::max( std::min( ZCXMXC, +1.0 ), -1.0 ); double ZSXMXC = cos_lat * sin_lat / ZCYREG; double ZXMXC = std::acos( ZCXMXC ) * r2d; - if ( ZSXMXC < 0.0 ) ZXMXC = -ZXMXC; + if ( ZSXMXC < 0.0 ) { + ZXMXC = -ZXMXC; + } double PXREG = ZXMXC + south_pole_.lon(); return PointLonLat( PXREG, PYREG ); @@ -120,6 +123,23 @@ class MagicsRotation { //----------------------------------------------------------------------------- +CASE( "test_rotation_construction" ) { + static const PointLonLat SP{0., -90.}; + static const PointLonLat NP{180., 90.}; + + std::vector rotation_poles = {SP, NP, {0., -90.1}, {0., 90.1}}; + + for ( auto& p : rotation_poles ) { + Rotation s( Config( "south_pole", std::vector{p.lon(), p.lat()} ) ); + Log::info() << "rotate_south_pole=" << s << std::endl; + EXPECT( s.rotated() == ( p != SP ) ); + + Rotation n( Config( "north_pole", std::vector{p.lon(), p.lat()} ) ); + Log::info() << "rotate_north_pole=" << n << std::endl; + EXPECT( n.rotated() == ( p != NP ) ); + } +} + CASE( "test_rotation" ) { Config config; config.set( "north_pole", std::vector{-176, 40} ); diff --git a/src/tests/runtime/CMakeLists.txt b/src/tests/runtime/CMakeLists.txt index 34a7b252b..26b4dcd87 100644 --- a/src/tests/runtime/CMakeLists.txt +++ b/src/tests/runtime/CMakeLists.txt @@ -9,7 +9,7 @@ ecbuild_add_test( TARGET atlas_test_trace SOURCES test_trace.cc LIBS atlas ${OMP_CXX} - ENVIRONMENT ATLAS_TRACE_REPORT=1 + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ATLAS_TRACE_REPORT=1 OMP 2 ) @@ -19,7 +19,7 @@ add_fctest( TARGET atlas_fctest_trace SOURCES fctest_trace.fypp LINKER_LANGUAGE Fortran LIBS atlas_f ${OMP_Fortran} - ENVIRONMENT ATLAS_TRACE_REPORT=1 + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ATLAS_TRACE_REPORT=1 ) endif() diff --git a/src/tests/runtime/test_trace.cc b/src/tests/runtime/test_trace.cc index f67e2226e..bcb347f08 100644 --- a/src/tests/runtime/test_trace.cc +++ b/src/tests/runtime/test_trace.cc @@ -45,7 +45,9 @@ CASE( "test trace OpenMP" ) { auto trace = Trace( Here(), "loop" ); if ( ATLAS_HAVE_OMP ) { trace.stop(); - if ( atlas_omp_get_thread_num() > 0 ) { EXPECT( trace.elapsed() == 0. ); } + if ( atlas_omp_get_thread_num() > 0 ) { + EXPECT( trace.elapsed() == 0. ); + } else { EXPECT( trace.elapsed() != 0. ); } diff --git a/src/tests/trans/CMakeLists.txt b/src/tests/trans/CMakeLists.txt index adf10ef87..d21a0d5cd 100644 --- a/src/tests/trans/CMakeLists.txt +++ b/src/tests/trans/CMakeLists.txt @@ -15,6 +15,7 @@ if( HAVE_FCTEST ) LIBS atlas_f CONDITION ECKIT_HAVE_MPI AND TRANSI_HAVE_MPI MPI 4 + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) endif() @@ -23,9 +24,16 @@ if( HAVE_FCTEST ) LINKER_LANGUAGE Fortran SOURCES fctest_trans_invtrans_grad.F90 LIBS atlas_f + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) endif() + add_fctest( TARGET atlas_fctest_trans_unstructured + LINKER_LANGUAGE Fortran + SOURCES fctest_trans_unstructured.F90 + LIBS atlas_f + ) + endif() ecbuild_add_test( TARGET atlas_test_trans @@ -33,18 +41,21 @@ ecbuild_add_test( TARGET atlas_test_trans SOURCES test_trans.cc CONDITION ATLAS_HAVE_TRANS AND ECKIT_HAVE_MPI AND TRANSI_HAVE_MPI LIBS atlas transi + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) ecbuild_add_test( TARGET atlas_test_trans_serial SOURCES test_trans.cc CONDITION ATLAS_HAVE_TRANS LIBS atlas transi + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) ecbuild_add_test( TARGET atlas_test_trans_invtrans_grad SOURCES test_trans_invtrans_grad.cc CONDITION ATLAS_HAVE_TRANS LIBS atlas transi + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) # Note: This duplication is needed because transi is a private library of atlas, @@ -54,14 +65,14 @@ if( ATLAS_HAVE_TRANS ) ecbuild_add_test( TARGET atlas_test_transgeneral SOURCES test_transgeneral.cc LIBS atlas transi - ENVIRONMENT ATLAS_TRACE_REPORT=1 + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ATLAS_TRACE_REPORT=1 CONDITION ATLAS_HAVE_FFTW ) else() ecbuild_add_test( TARGET atlas_test_transgeneral SOURCES test_transgeneral.cc LIBS atlas - ENVIRONMENT ATLAS_TRACE_REPORT=1 + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ATLAS_TRACE_REPORT=1 CONDITION ATLAS_HAVE_FFTW ) endif() @@ -70,6 +81,6 @@ endif() ecbuild_add_test( TARGET atlas_test_trans_localcache SOURCES test_trans_localcache.cc LIBS atlas - ENVIRONMENT ATLAS_TRACE_REPORT=1 + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ATLAS_TRACE_REPORT=1 ) diff --git a/src/tests/trans/fctest_trans.F90 b/src/tests/trans/fctest_trans.F90 index 523e5d90f..6e8778222 100644 --- a/src/tests/trans/fctest_trans.F90 +++ b/src/tests/trans/fctest_trans.F90 @@ -44,6 +44,19 @@ end module fctest_atlas_trans_fixture ! ----------------------------------------------------------------------------- +TEST( test_trans_backend ) + type(atlas_Trans) :: trans + FCTEST_CHECK( trans%has_backend("local") ) + FCTEST_CHECK( trans%has_backend("ifs") ) + if( trans%has_backend("ifs") ) then + FCTEST_CHECK_EQUAL( trans%backend(), "ifs" ) + else + FCTEST_CHECK_EQUAL( trans%backend(), "local" ) + endif +END_TEST + +! ----------------------------------------------------------------------------- + TEST( test_trans ) type(atlas_StructuredGrid) :: grid type(atlas_StructuredGrid) :: trans_grid @@ -52,7 +65,7 @@ end module fctest_atlas_trans_fixture type(atlas_Trans) :: trans type(atlas_mesh_Nodes) :: nodes type(atlas_functionspace_NodeColumns) :: nodes_fs - type(atlas_functionspace_Spectral) :: spectral_fs + type(atlas_functionspace_Spectral) :: spectral_fs, trans_spectral type(atlas_Field) :: scalarfield1, scalarfield2 type(atlas_Field) :: windfield type(atlas_Field) :: vorfield,divfield @@ -86,14 +99,16 @@ end module fctest_atlas_trans_fixture trans = atlas_Trans(grid,truncation) FCTEST_CHECK_EQUAL( grid%owners(), 3 ) ! trans tracks grid - FCTEST_CHECK_EQUAL( trans%nb_gridpoints_global(), int(grid%size()) ) + ! FCTEST_CHECK_EQUAL( trans%nb_gridpoints_global(), int(grid%size()) ) trans_grid = trans%grid() FCTEST_CHECK_EQUAL( trans_grid%owners(), 4 ) FCTEST_CHECK( .not. trans%is_null() ) FCTEST_CHECK_EQUAL( trans%truncation(), truncation ) - FCTEST_CHECK_EQUAL( trans%nb_spectral_coefficients_global(), (truncation+1)*(truncation+2) ) + + trans_spectral = trans%spectral() + FCTEST_CHECK_EQUAL( trans_spectral%nb_spectral_coefficients_global(), (truncation+1)*(truncation+2) ) nodes = mesh%nodes() nodes_fs = atlas_functionspace_NodeColumns(mesh,0) @@ -109,6 +124,8 @@ end module fctest_atlas_trans_fixture spectral_fs = atlas_functionspace_Spectral(trans) write(msg,*) "spectral_fs%owners()",spectral_fs%owners(); call fckit_log%info(msg) + FCTEST_CHECK_EQUAL( spectral_fs%nb_spectral_coefficients_global(), (truncation+1)*(truncation+2) ) + spectralfield1 = spectral_fs%create_field(name="spectral1",kind=atlas_real(c_double),levels=nlev) write(msg,*) "spectral_fs%owners()",spectral_fs%owners(); call fckit_log%info(msg) @@ -184,6 +201,12 @@ end module fctest_atlas_trans_fixture call trans%invtrans_vordiv2wind(vorfield,divfield,windfield) glb_vorfield = spectral_fs%create_field(name="vorticity",kind=atlas_real(c_double),levels=nlev,global=.true.) + + if( .not. vorfield%contiguous() ) then + call fckit_log%error("No support for gather if fields are not contiguous") + return + endif + call spectral_fs%gather(vorfield,glb_vorfield) call spectral_fs%scatter(glb_vorfield,vorfield) @@ -361,6 +384,10 @@ end module fctest_atlas_trans_fixture do jfld=1,spfields%size() field = spfields%field(jfld) write(msg,*) "spectral field ",field%name(); call atlas_log%info(msg) + if( .not. field%contiguous() ) then + call fckit_log%error("No support for norm if fields are not contiguous") + return + endif call spectral%norm(field,norm) write(msg,*) "norm = ",norm; call atlas_log%info(msg) enddo @@ -420,6 +447,11 @@ end module fctest_atlas_trans_fixture enddo enddo +if( .not. field%contiguous() ) then + call fckit_log%error("No support for gather if fields are not contiguous") + return +endif + fieldg = spectral%create_field(atlas_real(c_double),global=.true.) call spectral%gather(field,fieldg) diff --git a/src/tests/trans/fctest_trans_unstructured.F90 b/src/tests/trans/fctest_trans_unstructured.F90 new file mode 100644 index 000000000..5d9fdf559 --- /dev/null +++ b/src/tests/trans/fctest_trans_unstructured.F90 @@ -0,0 +1,100 @@ +! (C) Copyright 2013 ECMWF. +! This software is licensed under the terms of the Apache Licence Version 2.0 +! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +! In applying this licence, ECMWF does not 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" + +! ----------------------------------------------------------------------------- + + +TESTSUITE(fctest_atlas_trans_unstr) + +! ----------------------------------------------------------------------------- + +TESTSUITE_INIT + use atlas_module + type(atlas_Trans) :: trans + call atlas_library%initialise() + call trans%set_backend("local") +END_TESTSUITE_INIT + +! ----------------------------------------------------------------------------- + +TESTSUITE_FINALIZE + use atlas_module + call atlas_library%finalise() +END_TESTSUITE_FINALIZE + +! ----------------------------------------------------------------------------- + +TEST( test_trans ) + use atlas_module + implicit none + type(atlas_UnstructuredGrid) :: grid + type(atlas_Trans) :: trans + type(atlas_functionspace_Spectral) :: spectral + type(atlas_Field) :: gp_scal_field, gp_wind_field + type(atlas_Field) :: sp_scal_field, sp_vor_field, sp_div_field + type(atlas_Config) :: config + integer :: truncation + + real(c_double) :: xy(2,10) + + xy(:,1) = [107.196,26.0167] + xy(:,2) = [144.768,28.3721] + xy(:,3) = [150.891,60.0343] + xy(:,4) = [164.566,25.5053] + xy(:,5) = [116.851,14.0295] + xy(:,6) = [124.84,28.3978] + xy(:,7) = [157.901,42.042] + xy(:,8) = [111.41,43.1056] + xy(:,9) = [134.333,44.6677] + xy(:,10) = [120.307,59.7167] + + grid = atlas_UnstructuredGrid( xy ) + + truncation = 21; + + trans = atlas_Trans(grid,truncation) + + FCTEST_CHECK_EQUAL( trans%truncation(), truncation ) + + spectral = trans%spectral() + + sp_scal_field = spectral%create_field(name="spectral_scalar",kind=atlas_real(8)) + sp_vor_field = spectral%create_field(name="spectral_vorticity",kind=atlas_real(8)) + sp_div_field = spectral%create_field(name="spectral_divergence",kind=atlas_real(8)) + + gp_scal_field = atlas_Field(name="gridpoint_scalar",kind=atlas_real(8),shape=[10]) + gp_wind_field = atlas_Field(name="gridpoint_wind",kind=atlas_real(8),shape=[10,2]) + + call set_zero( sp_scal_field ) + call set_zero( sp_vor_field ) + call set_zero( sp_div_field ) + + config = atlas_Config() + call config%set("warning",0) ! turn off warnings for unstructured grids + + call trans%invtrans( sp_scal_field, gp_scal_field, config ) + call trans%invtrans_vordiv2wind( sp_vor_field, sp_div_field, gp_wind_field, config ) + +contains + + subroutine set_zero( field ) + use, intrinsic :: iso_c_binding + type(atlas_Field) :: field + real(c_double), pointer :: data(:) + call field%data(data) + data(:) = 0. + end subroutine + +END_TEST + + +END_TESTSUITE + diff --git a/src/tests/trans/test_trans.cc b/src/tests/trans/test_trans.cc index 43a96d247..75693a9f3 100644 --- a/src/tests/trans/test_trans.cc +++ b/src/tests/trans/test_trans.cc @@ -54,7 +54,8 @@ namespace test { struct AtlasTransEnvironment : public AtlasTestEnvironment { AtlasTransEnvironment( int argc, char* argv[] ) : AtlasTestEnvironment( argc, argv ) { - if ( mpi::comm().size() == 1 ) trans_use_mpi( false ); + if ( mpi::comm().size() == 1 ) + trans_use_mpi( false ); trans_init(); } @@ -63,12 +64,12 @@ struct AtlasTransEnvironment : public AtlasTestEnvironment { //----------------------------------------------------------------------------- -void read_rspecg( trans::TransImpl& trans, std::vector& rspecg, std::vector& nfrom, int& nfld ) { +void read_rspecg( const trans::TransImpl& trans, std::vector& rspecg, std::vector& nfrom, int& nfld ) { Log::info() << "read_rspecg ...\n"; nfld = 2; if ( mpi::comm().rank() == 0 ) { - rspecg.resize( nfld * trans.spectralCoefficients() ); - for ( size_t i = 0; i < trans.spectralCoefficients(); ++i ) { + rspecg.resize( nfld * trans.nb_spectral_coefficients_global() ); + for ( size_t i = 0; i < trans.nb_spectral_coefficients_global(); ++i ) { rspecg[i * nfld + 0] = ( i == 0 ? 1. : 0. ); // scalar field 1 rspecg[i * nfld + 1] = ( i == 0 ? 2. : 0. ); // scalar field 2 } @@ -89,6 +90,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 ); + ATLAS_ASSERT( view.shape( 0 ) == nb_spectral_coefficients_global ); 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 @@ -100,6 +102,8 @@ void read_rspecg( Field spec ) { //----------------------------------------------------------------------------- +#if 1 + CASE( "test_trans_distribution_matches_atlas" ) { EXPECT( grid::Partitioner::exists( "trans" ) ); @@ -186,6 +190,9 @@ CASE( "test_write_read_cache" ) { } #endif +#endif + +#if 1 CASE( "test_distspec" ) { trans::TransIFS trans( Grid( "F80" ), 159 ); Log::info() << "Trans initialized" << std::endl; @@ -207,6 +214,8 @@ CASE( "test_distspec" ) { trans.gathgrid( nfld, nto.data(), rgp.data(), rgpg.data() ); if ( mpi::comm().rank() == 0 ) { + ATLAS_DEBUG_VAR( specnorms[0] ); + ATLAS_DEBUG_VAR( specnorms[1] ); EXPECT( eckit::types::is_approximately_equal( specnorms[0], 1., 1.e-10 ) ); EXPECT( eckit::types::is_approximately_equal( specnorms[1], 2., 1.e-10 ) ); } @@ -214,6 +223,8 @@ CASE( "test_distspec" ) { Log::info() << "end test_distspec" << std::endl; } +#endif + CASE( "test_distspec_speconly" ) { functionspace::Spectral fs( 159 ); int nfld = 2; @@ -224,16 +235,30 @@ CASE( "test_distspec_speconly" ) { Field dist = fs.createField( glb ); - fs.scatter( glb, dist ); - fs.norm( dist, specnorms ); + if ( not dist.contiguous() ) { + EXPECT_THROWS_AS( fs.scatter( glb, dist ), eckit::Exception ); + if ( mpi::comm().size() == 1 ) { + dist = glb; + EXPECT_THROWS_AS( fs.norm( dist, specnorms ), eckit::Exception ); + } + return; + } + else { + EXPECT_NO_THROW( fs.scatter( glb, dist ) ); + EXPECT_NO_THROW( fs.norm( dist, specnorms ) ); + } + if ( mpi::comm().rank() == 0 ) { + ATLAS_DEBUG_VAR( specnorms[0] ); + ATLAS_DEBUG_VAR( specnorms[1] ); EXPECT( eckit::types::is_approximately_equal( specnorms[0], 1., 1.e-10 ) ); EXPECT( eckit::types::is_approximately_equal( specnorms[1], 2., 1.e-10 ) ); } Log::info() << "end test_distspec_only" << std::endl; } +#if 1 CASE( "test_distribution" ) { Grid g( "O80" ); @@ -334,7 +359,18 @@ CASE( "test_nomesh" ) { spg( imag ) = ( n == 0 ? 0 : -m * spectral.truncation() + n ); } ); - EXPECT_NO_THROW( spectral.scatter( spfg, spf ) ); + if ( not spf.contiguous() ) { + EXPECT_THROWS_AS( spectral.scatter( spfg, spf ), eckit::Exception ); + if ( mpi::comm().size() == 1 ) { + spf = spfg; + } + else { + return; + } + } + else { + EXPECT_NO_THROW( spectral.scatter( spfg, spf ) ); + } array::ArrayView sp = array::make_view( spf ); @@ -362,7 +398,18 @@ CASE( "test_nomesh" ) { EXPECT_NO_THROW( trans.dirtrans( gpf, spf ) ); - EXPECT_NO_THROW( spectral.gather( spf, spfg ) ); + if ( not spf.contiguous() ) { + EXPECT_THROWS_AS( spectral.gather( spf, spfg ), eckit::Exception ); + if ( mpi::comm().size() == 1 ) { + spfg = spf; + } + else { + return; + } + } + else { + EXPECT_NO_THROW( spectral.gather( spf, spfg ) ); + } spectral.parallel_for( option::global(), [&]( idx_t real, idx_t imag, int n ) { EXPECT( is_approximately_equal( spg( real ), ( n == 0 ? 4. : 0. ), 0.001 ) ); @@ -543,6 +590,7 @@ CASE( "test_trans_VorDivToUV" ) { } } } +#endif //----------------------------------------------------------------------------- diff --git a/src/tests/trans/test_trans_invtrans_grad.cc b/src/tests/trans/test_trans_invtrans_grad.cc index 52e994cea..f464ac88b 100644 --- a/src/tests/trans/test_trans_invtrans_grad.cc +++ b/src/tests/trans/test_trans_invtrans_grad.cc @@ -43,7 +43,8 @@ namespace test { struct AtlasTransEnvironment : public AtlasTestEnvironment { AtlasTransEnvironment( int argc, char* argv[] ) : AtlasTestEnvironment( argc, argv ) { - if ( mpi::comm().size() == 1 ) trans_use_mpi( false ); + if ( mpi::comm().size() == 1 ) + trans_use_mpi( false ); trans_init(); } diff --git a/src/tests/trans/test_trans_localcache.cc b/src/tests/trans/test_trans_localcache.cc index 636e01461..65be88cb7 100644 --- a/src/tests/trans/test_trans_localcache.cc +++ b/src/tests/trans/test_trans_localcache.cc @@ -46,7 +46,9 @@ using LinearSpacing = grid::LinearSpacing; eckit::PathName CacheFile( const std::string& path ) { eckit::PathName cachefile( path ); - if ( cachefile.exists() ) cachefile.unlink(); + if ( cachefile.exists() ) { + cachefile.unlink(); + } return cachefile; } @@ -111,7 +113,9 @@ CASE( "test_global_grids" ) { EXPECT( cache_creator.supported() ); auto cachefile = CacheFile( "leg_" + cache_creator.uid() + ".bin" ); cache_creator.create( cachefile ); - if ( GaussianGrid( grid ) ) { EXPECT( hash( cachefile ) == F_cache_hash ); } + if ( GaussianGrid( grid ) ) { + EXPECT( hash( cachefile ) == F_cache_hash ); + } ATLAS_TRACE_SCOPE( "create without cache" ) Trans( grid, truncation ); diff --git a/src/tests/trans/test_transgeneral.cc b/src/tests/trans/test_transgeneral.cc index 01ba01753..f8db91c13 100644 --- a/src/tests/trans/test_transgeneral.cc +++ b/src/tests/trans/test_transgeneral.cc @@ -87,8 +87,12 @@ double sphericalharmonics_analytic_point( double a = util::Earth::radius(); // Fourier part of the spherical harmonics: double rft = 1.; - if ( m > 0 ) rft *= 2.; // the famous factor 2 that noone really understands - if ( imag == 0 ) { rft *= loncos; } + if ( m > 0 ) { + rft *= 2.; // the famous factor 2 that noone really understands + } + if ( imag == 0 ) { + rft *= loncos; + } else { rft *= -lonsin; } @@ -105,88 +109,164 @@ double sphericalharmonics_analytic_point( // scalar: if ( ivar_in == 2 ) { if ( ivar_out == 2 ) { - if ( m == 0 && n == 0 ) return rft; - if ( m == 0 && n == 1 ) return std::sqrt( 3. ) * latsin * rft; - if ( m == 0 && n == 2 ) return std::sqrt( 5. ) / 2. * ( 3. * latsin * latsin - 1. ) * rft; // sign? - if ( m == 0 && n == 3 ) + if ( m == 0 && n == 0 ) { + return rft; + } + if ( m == 0 && n == 1 ) { + return std::sqrt( 3. ) * latsin * rft; + } + if ( m == 0 && n == 2 ) { + return std::sqrt( 5. ) / 2. * ( 3. * latsin * latsin - 1. ) * rft; // sign? + } + if ( m == 0 && n == 3 ) { return std::sqrt( 7. ) / 2. * ( 5. * latsin * latsin - 3. ) * latsin * rft; // sign? - if ( m == 1 && n == 1 ) return std::sqrt( 3. / 2. ) * latcos * rft; // sign? - if ( m == 1 && n == 2 ) return std::sqrt( 15. / 2. ) * latsin * latcos * rft; // sign? - if ( m == 1 && n == 3 ) + } + if ( m == 1 && n == 1 ) { + return std::sqrt( 3. / 2. ) * latcos * rft; // sign? + } + if ( m == 1 && n == 2 ) { + return std::sqrt( 15. / 2. ) * latsin * latcos * rft; // sign? + } + if ( m == 1 && n == 3 ) { return std::sqrt( 21. ) / 4. * latcos * ( 5. * latsin * latsin - 1. ) * rft; // sign? - if ( m == 2 && n == 2 ) return std::sqrt( 15. / 2. ) / 2. * latcos * latcos * rft; - if ( m == 2 && n == 3 ) return std::sqrt( 105. / 2. ) / 2. * latcos * latcos * latsin * rft; - if ( m == 3 && n == 3 ) return std::sqrt( 35. ) / 4. * latcos * latcos * latcos * rft; // sign? - if ( m == 4 && n == 4 ) return ( 3 * std::sqrt( 17.5 ) * std::pow( latcos, 4 ) ) / 8. * rft; - if ( m == 5 && n == 5 ) return ( 3 * std::sqrt( 77 ) * std::pow( latcos, 5 ) ) / 16. * rft; - if ( m == 6 && n == 6 ) return ( std::sqrt( 3003 ) * std::pow( latcos, 6 ) ) / 32. * rft; - if ( m == 7 && n == 7 ) return ( 3 * std::sqrt( 357.5 ) * std::pow( latcos, 7 ) ) / 32. * rft; - if ( m == 8 && n == 8 ) return ( 3 * std::sqrt( 6077.5 ) * std::pow( latcos, 8 ) ) / 128. * rft; - if ( m == 9 && n == 9 ) return ( std::sqrt( 230945 ) * std::pow( latcos, 9 ) ) / 256. * rft; - if ( m == 10 && n == 10 ) return ( std::sqrt( 969969 ) * std::pow( latcos, 10 ) ) / 512. * rft; - if ( m == 11 && n == 11 ) return ( std::sqrt( 1.0140585e6 ) * std::pow( latcos, 11 ) ) / 512. * rft; - if ( m == 12 && n == 12 ) return ( 5 * std::sqrt( 676039 ) * std::pow( latcos, 12 ) ) / 2048. * rft; - if ( m == 13 && n == 13 ) return ( 15 * std::sqrt( 78004.5 ) * std::pow( latcos, 13 ) ) / 2048. * rft; - if ( m == 14 && n == 14 ) return ( 15 * std::sqrt( 323161.5 ) * std::pow( latcos, 14 ) ) / 4096. * rft; - if ( m == 15 && n == 15 ) return ( 3 * std::sqrt( 33393355 ) * std::pow( latcos, 15 ) ) / 8192. * rft; - if ( m == 16 && n == 16 ) return ( 3 * std::sqrt( 5.509903575e8 ) * std::pow( latcos, 16 ) ) / 32768. * rft; - if ( m == 17 && n == 17 ) return ( 15 * std::sqrt( 90751353 ) * std::pow( latcos, 17 ) ) / 65536. * rft; - if ( m == 18 && n == 18 ) return ( 5 * std::sqrt( 3357800061 ) * std::pow( latcos, 18 ) ) / 131072. * rft; - if ( m == 19 && n == 19 ) + } + if ( m == 2 && n == 2 ) { + return std::sqrt( 15. / 2. ) / 2. * latcos * latcos * rft; + } + if ( m == 2 && n == 3 ) { + return std::sqrt( 105. / 2. ) / 2. * latcos * latcos * latsin * rft; + } + if ( m == 3 && n == 3 ) { + return std::sqrt( 35. ) / 4. * latcos * latcos * latcos * rft; // sign? + } + if ( m == 4 && n == 4 ) { + return ( 3 * std::sqrt( 17.5 ) * std::pow( latcos, 4 ) ) / 8. * rft; + } + if ( m == 5 && n == 5 ) { + return ( 3 * std::sqrt( 77 ) * std::pow( latcos, 5 ) ) / 16. * rft; + } + if ( m == 6 && n == 6 ) { + return ( std::sqrt( 3003 ) * std::pow( latcos, 6 ) ) / 32. * rft; + } + if ( m == 7 && n == 7 ) { + return ( 3 * std::sqrt( 357.5 ) * std::pow( latcos, 7 ) ) / 32. * rft; + } + if ( m == 8 && n == 8 ) { + return ( 3 * std::sqrt( 6077.5 ) * std::pow( latcos, 8 ) ) / 128. * rft; + } + if ( m == 9 && n == 9 ) { + return ( std::sqrt( 230945 ) * std::pow( latcos, 9 ) ) / 256. * rft; + } + if ( m == 10 && n == 10 ) { + return ( std::sqrt( 969969 ) * std::pow( latcos, 10 ) ) / 512. * rft; + } + if ( m == 11 && n == 11 ) { + return ( std::sqrt( 1.0140585e6 ) * std::pow( latcos, 11 ) ) / 512. * rft; + } + if ( m == 12 && n == 12 ) { + return ( 5 * std::sqrt( 676039 ) * std::pow( latcos, 12 ) ) / 2048. * rft; + } + if ( m == 13 && n == 13 ) { + return ( 15 * std::sqrt( 78004.5 ) * std::pow( latcos, 13 ) ) / 2048. * rft; + } + if ( m == 14 && n == 14 ) { + return ( 15 * std::sqrt( 323161.5 ) * std::pow( latcos, 14 ) ) / 4096. * rft; + } + if ( m == 15 && n == 15 ) { + return ( 3 * std::sqrt( 33393355 ) * std::pow( latcos, 15 ) ) / 8192. * rft; + } + if ( m == 16 && n == 16 ) { + return ( 3 * std::sqrt( 5.509903575e8 ) * std::pow( latcos, 16 ) ) / 32768. * rft; + } + if ( m == 17 && n == 17 ) { + return ( 15 * std::sqrt( 90751353 ) * std::pow( latcos, 17 ) ) / 65536. * rft; + } + if ( m == 18 && n == 18 ) { + return ( 5 * std::sqrt( 3357800061 ) * std::pow( latcos, 18 ) ) / 131072. * rft; + } + if ( m == 19 && n == 19 ) { return ( 15 * std::sqrt( 3.829070245e8 ) * std::pow( latcos, 19 ) ) / 131072. * rft; - if ( m == 20 && n == 20 ) return ( 3 * std::sqrt( 156991880045 ) * std::pow( latcos, 20 ) ) / 524288. * rft; - if ( m == 21 && n == 21 ) + } + if ( m == 20 && n == 20 ) { + return ( 3 * std::sqrt( 156991880045 ) * std::pow( latcos, 20 ) ) / 524288. * rft; + } + if ( m == 21 && n == 21 ) { return ( std::sqrt( 1.4465680375575e12 ) * std::pow( latcos, 21 ) ) / 524288. * rft; - if ( m == 22 && n == 22 ) + } + if ( m == 22 && n == 22 ) { return ( 15 * std::sqrt( 2.63012370465e10 ) * std::pow( latcos, 22 ) ) / 1.048576e6 * rft; - if ( m == 23 && n == 23 ) + } + if ( m == 23 && n == 23 ) { return ( 15 * std::sqrt( 107492012277 ) * std::pow( latcos, 23 ) ) / 2.097152e6 * rft; - if ( m == 24 && n == 24 ) + } + if ( m == 24 && n == 24 ) { return ( 105 * std::sqrt( 35830670759 ) * std::pow( latcos, 24 ) ) / 8.388608e6 * rft; - if ( m == 25 && n == 25 ) + } + if ( m == 25 && n == 25 ) { return ( 21 * std::sqrt( 9.136821043545e11 ) * std::pow( latcos, 25 ) ) / 8.388608e6 * rft; - if ( m == 26 && n == 26 ) + } + if ( m == 26 && n == 26 ) { return ( 21 * std::sqrt( 3.7250116562145e12 ) * std::pow( latcos, 26 ) ) / 1.6777216e7 * rft; - if ( m == 27 && n == 27 ) + } + if ( m == 27 && n == 27 ) { return ( 7 * std::sqrt( 136583760727865. ) * std::pow( latcos, 27 ) ) / 3.3554432e7 * rft; - if ( m == 28 && n == 28 ) + } + if ( m == 28 && n == 28 ) { return ( std::sqrt( 2.7248460265209068e16 ) * std::pow( latcos, 28 ) ) / 6.7108864e7 * rft; - if ( m == 29 && n == 29 ) + } + if ( m == 29 && n == 29 ) { return ( std::sqrt( 110873045217057585. ) * std::pow( latcos, 29 ) ) / 1.34217728e8 * rft; - if ( m == 30 && n == 30 ) + } + if ( m == 30 && n == 30 ) { return ( std::sqrt( 450883717216034179. ) * std::pow( latcos, 30 ) ) / 2.68435456e8 * rft; - if ( m == 31 && n == 31 ) + } + if ( m == 31 && n == 31 ) { return ( 21 * std::sqrt( 1.0389025742304935e15 ) * std::pow( latcos, 31 ) ) / 2.68435456e8 * rft; - if ( m == 32 && n == 32 ) + } + if ( m == 32 && n == 32 ) { return ( 21 * std::sqrt( 6.752866732498208e16 ) * std::pow( latcos, 32 ) ) / 2.147483648e9 * rft; - if ( m == 33 && n == 33 ) + } + if ( m == 33 && n == 33 ) { return ( 7 * std::sqrt( 2467865842240254105. ) * std::pow( latcos, 33 ) ) / 4.294967296e9 * rft; - if ( m == 34 && n == 34 ) + } + if ( m == 34 && n == 34 ) { return ( 21 * std::sqrt( 1112959105324036165. ) * std::pow( latcos, 34 ) ) / 8.589934592e9 * rft; - if ( m == 35 && n == 35 ) + } + if ( m == 35 && n == 35 ) { return ( 3 * std::sqrt( 5.53140675346046e19 ) * std::pow( latcos, 35 ) ) / 8.589934592e9 * rft; - if ( m == 36 && n == 36 ) + } + if ( m == 36 && n == 36 ) { return ( std::sqrt( 8075853860052271220473. ) * std::pow( latcos, 36 ) ) / 3.4359738368e10 * rft; - if ( m == 37 && n == 37 ) + } + if ( m == 37 && n == 37 ) { return ( 5 * std::sqrt( 3.2739948081292994e20 ) * std::pow( latcos, 37 ) ) / 3.4359738368e10 * rft; - if ( m == 38 && n == 38 ) + } + if ( m == 38 && n == 38 ) { return ( 35 * std::sqrt( 2.707815254843781e19 ) * std::pow( latcos, 38 ) ) / 6.8719476736e10 * rft; - if ( m == 39 && n == 39 ) + } + if ( m == 39 && n == 39 ) { return ( 35 * std::sqrt( 109701233401363445369. ) * std::pow( latcos, 39 ) ) / 1.37438953472e11 * rft; - if ( m == 40 && n == 40 ) + } + if ( m == 40 && n == 40 ) { return ( 63 * std::sqrt( 548506167006817226845. ) * std::pow( latcos, 40 ) ) / 5.49755813888e11 * rft; - if ( m == 41 && n == 41 ) + } + if ( m == 41 && n == 41 ) { return ( 63 * std::sqrt( 5.551952666044613e20 ) * std::pow( latcos, 41 ) ) / 5.49755813888e11 * rft; - if ( m == 42 && n == 42 ) + } + if ( m == 42 && n == 42 ) { return ( 15 * std::sqrt( 3.964094203555854e22 ) * std::pow( latcos, 42 ) ) / 1.099511627776e12 * rft; - if ( m == 43 && n == 43 ) + } + if ( m == 43 && n == 43 ) { return ( 45 * std::sqrt( 17823059209786010066579. ) * std::pow( latcos, 43 ) ) / 2.199023255552e12 * rft; - if ( m == 44 && n == 44 ) + } + if ( m == 44 && n == 44 ) { return ( 45 * std::sqrt( 7.210237589413431e22 ) * std::pow( latcos, 44 ) ) / 4.398046511104e12 * rft; - if ( m == 45 && n == 45 ) + } + if ( m == 45 && n == 45 ) { return ( 21 * std::sqrt( 1339044123748208678378695. ) * std::pow( latcos, 45 ) ) / 8.796093022208e12 * rft; + } // return // std::pow(latcos,45)*rft*21.*std::sqrt(1339044123748208678378695.)/8796093022208.; // // sign? @@ -202,25 +282,37 @@ double sphericalharmonics_analytic_point( // vorticity: if ( ivar_in == 0 ) { if ( ivar_out == 0 ) { // u: - if ( m == 0 && n == 0 ) return 0.; + if ( m == 0 && n == 0 ) { + return 0.; + } if ( m == 0 && n == 1 ) { - if ( imag == 0 ) { return std::sqrt( 3. ) * a / 2. * latcos; } + if ( imag == 0 ) { + return std::sqrt( 3. ) * a / 2. * latcos; + } else { return 0.; } } if ( m == 1 && n == 1 ) { - if ( imag == 0 ) { return -a * std::sqrt( 3. / 2. ) * loncos * latsin; } + if ( imag == 0 ) { + return -a * std::sqrt( 3. / 2. ) * loncos * latsin; + } else { return a * std::sqrt( 3. / 2. ) * lonsin * latsin; } } } else if ( ivar_out == 1 ) { // v: - if ( m == 0 && n == 0 ) return 0.; - if ( m == 0 && n == 1 ) return 0.; + if ( m == 0 && n == 0 ) { + return 0.; + } + if ( m == 0 && n == 1 ) { + return 0.; + } if ( m == 1 && n == 1 ) { - if ( imag == 0 ) { return a * std::sqrt( 3. / 2. ) * lonsin; } + if ( imag == 0 ) { + return a * std::sqrt( 3. / 2. ) * lonsin; + } else { return a * std::sqrt( 3. / 2. ) * loncos; } @@ -234,25 +326,37 @@ double sphericalharmonics_analytic_point( // divergence: if ( ivar_in == 1 ) { if ( ivar_out == 0 ) { // u: - if ( m == 0 && n == 0 ) return 0.; - if ( m == 0 && n == 1 ) return 0.; + if ( m == 0 && n == 0 ) { + return 0.; + } + if ( m == 0 && n == 1 ) { + return 0.; + } if ( m == 1 && n == 1 ) { - if ( imag == 0 ) { return a * std::sqrt( 3. / 2. ) * lonsin; } + if ( imag == 0 ) { + return a * std::sqrt( 3. / 2. ) * lonsin; + } else { return a * std::sqrt( 3. / 2. ) * loncos; } } } else if ( ivar_out == 1 ) { // v: - if ( m == 0 && n == 0 ) return 0.; + if ( m == 0 && n == 0 ) { + return 0.; + } if ( m == 0 && n == 1 ) { - if ( imag == 0 ) { return -std::sqrt( 3. ) * a / 2. * latcos; } + if ( imag == 0 ) { + return -std::sqrt( 3. ) * a / 2. * latcos; + } else { return 0.; } } if ( m == 1 && n == 1 ) { - if ( imag == 0 ) { return a * std::sqrt( 3. / 2. ) * loncos * latsin; } + if ( imag == 0 ) { + return a * std::sqrt( 3. / 2. ) * loncos * latsin; + } else { return -a * std::sqrt( 3. / 2. ) * lonsin * latsin; // sign? } @@ -287,8 +391,9 @@ void spectral_transform_grid_analytic( const int ivar_out ) // variable returned by this function. 0: u, 1: v, 2: scalar { int N = ( trc + 2 ) * ( trc + 1 ) / 2; - for ( int jm = 0; jm < 2 * N; jm++ ) + for ( int jm = 0; jm < 2 * N; jm++ ) { rspecg[jm] = 0.; + } int k = 0; for ( int jm = 0; jm <= trc; jm++ ) { for ( int jn = jm; jn <= trc; jn++ ) { @@ -300,8 +405,9 @@ void spectral_transform_grid_analytic( } } - for ( int jm = 0; jm < grid.size(); jm++ ) + for ( int jm = 0; jm < grid.size(); jm++ ) { rgp[jm] = 0.; + } if ( StructuredGrid( grid ) ) { StructuredGrid g( grid ); @@ -313,7 +419,9 @@ void spectral_transform_grid_analytic( gs_global = StructuredGrid( gridGlobal ); int nlatsGlobal = gs_global.ny(); for ( int jlat = 0; jlat < nlatsGlobal; jlat++ ) { - if ( gs_global.y( jlat ) > g.y( 0 ) ) { jlatMin++; }; + if ( gs_global.y( jlat ) > g.y( 0 ) ) { + jlatMin++; + }; } } @@ -369,7 +477,9 @@ double compute_rms( const size_t N, // length of the arrays rms += diff * diff; rmax = std::max( rmax, std::abs( array2[idx] ) ); } - if ( rmax == 0. ) { rms = 0.; } + if ( rmax == 0. ) { + rms = 0.; + } else { rms = std::sqrt( rms / N ) / rmax; } @@ -440,9 +550,15 @@ CASE( "test_trans_vordiv_with_translib" ) { vor[j] = 0.; div[j] = 0.; } - if ( ivar_in == 0 ) vor[k * nb_vordiv + jfld] = 1.; - if ( ivar_in == 1 ) div[k * nb_vordiv + jfld] = 1.; - if ( ivar_in == 2 ) sp[k * nb_scalar + jfld] = 1.; + if ( ivar_in == 0 ) { + vor[k * nb_vordiv + jfld] = 1.; + } + if ( ivar_in == 1 ) { + div[k * nb_vordiv + jfld] = 1.; + } + if ( ivar_in == 2 ) { + sp[k * nb_scalar + jfld] = 1.; + } for ( int j = 0; j < nb_all * g.size(); j++ ) { gp[j] = 0.; @@ -642,7 +758,9 @@ CASE( "test_trans_domain" ) { int trc = 63; //Log::info() << "rgp1:" << std::endl; - if ( eckit::PathName( "legcache.bin" ).exists() ) eckit::PathName( "legcache.bin" ).unlink(); + if ( eckit::PathName( "legcache.bin" ).exists() ) { + eckit::PathName( "legcache.bin" ).unlink(); + } Trace t1( Here(), "translocal1 construction" ); trans::Trans transLocal1( global_grid, g1.domain(), trc, option::type( "local" ) | option::write_legendre( "legcache.bin" ) ); @@ -707,9 +825,15 @@ CASE( "test_trans_domain" ) { vor[j] = 0.; div[j] = 0.; } - if ( ivar_in == 0 ) vor[k * nb_vordiv + jfld] = 1.; - if ( ivar_in == 1 ) div[k * nb_vordiv + jfld] = 1.; - if ( ivar_in == 2 ) sp[k * nb_scalar + jfld] = 1.; + if ( ivar_in == 0 ) { + vor[k * nb_vordiv + jfld] = 1.; + } + if ( ivar_in == 1 ) { + div[k * nb_vordiv + jfld] = 1.; + } + if ( ivar_in == 2 ) { + sp[k * nb_scalar + jfld] = 1.; + } for ( int j = 0; j < nb_all * g1.size(); j++ ) { rgp1[j] = 0.; @@ -887,9 +1011,15 @@ CASE( "test_trans_pole" ) { vor[j] = 0.; div[j] = 0.; } - if ( ivar_in == 0 ) vor[k * nb_vordiv + jfld] = 1.; - if ( ivar_in == 1 ) div[k * nb_vordiv + jfld] = 1.; - if ( ivar_in == 2 ) sp[k * nb_scalar + jfld] = 1.; + if ( ivar_in == 0 ) { + vor[k * nb_vordiv + jfld] = 1.; + } + if ( ivar_in == 1 ) { + div[k * nb_vordiv + jfld] = 1.; + } + if ( ivar_in == 2 ) { + sp[k * nb_scalar + jfld] = 1.; + } for ( int j = 0; j < nb_all * g1.size(); j++ ) { rgp1[j] = 0.; @@ -1072,9 +1202,15 @@ CASE( "test_trans_southpole" ) { vor[j] = 0.; div[j] = 0.; } - if ( ivar_in == 0 ) vor[k * nb_vordiv + jfld] = 1.; - if ( ivar_in == 1 ) div[k * nb_vordiv + jfld] = 1.; - if ( ivar_in == 2 ) sp[k * nb_scalar + jfld] = 1.; + if ( ivar_in == 0 ) { + vor[k * nb_vordiv + jfld] = 1.; + } + if ( ivar_in == 1 ) { + div[k * nb_vordiv + jfld] = 1.; + } + if ( ivar_in == 2 ) { + sp[k * nb_scalar + jfld] = 1.; + } for ( int j = 0; j < nb_all * g1.size(); j++ ) { rgp1[j] = 0.; @@ -1243,9 +1379,15 @@ CASE( "test_trans_unstructured" ) { vor[j] = 0.; div[j] = 0.; } - if ( ivar_in == 0 ) vor[k * nb_vordiv + jfld] = 1.; - if ( ivar_in == 1 ) div[k * nb_vordiv + jfld] = 1.; - if ( ivar_in == 2 ) sp[k * nb_scalar + jfld] = 1.; + if ( ivar_in == 0 ) { + vor[k * nb_vordiv + jfld] = 1.; + } + if ( ivar_in == 1 ) { + div[k * nb_vordiv + jfld] = 1.; + } + if ( ivar_in == 2 ) { + sp[k * nb_scalar + jfld] = 1.; + } for ( int j = 0; j < nb_all * g.size(); j++ ) { gp[j] = 0.; @@ -1319,7 +1461,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 fc72e9f75..5d8e91470 100644 --- a/src/tests/util/CMakeLists.txt +++ b/src/tests/util/CMakeLists.txt @@ -13,6 +13,7 @@ if( HAVE_FCTEST ) LINKER_LANGUAGE Fortran SOURCES fctest_logging.F90 LIBS atlas_f + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) add_fctest( TARGET atlas_fctest_parametrisation @@ -20,12 +21,14 @@ if( HAVE_FCTEST ) LINKER_LANGUAGE Fortran SOURCES fctest_parametrisation.F90 LIBS atlas_f + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) add_fctest( TARGET atlas_fctest_metadata LINKER_LANGUAGE Fortran SOURCES fctest_metadata.F90 LIBS atlas_f + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) endif() @@ -34,6 +37,7 @@ foreach( test earth flags footprint indexview polygon point ) ecbuild_add_test( TARGET atlas_test_${test} SOURCES test_${test}.cc LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) endforeach() @@ -41,6 +45,7 @@ ecbuild_add_test( TARGET atlas_test_vector SOURCES test_vector.cc LIBS atlas CONDITION ATLAS_HAVE_GRIDTOOLS_STORAGE + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) ecbuild_add_test( TARGET atlas_test_metadata @@ -48,5 +53,6 @@ ecbuild_add_test( TARGET atlas_test_metadata CONDITION ECKIT_HAVE_MPI SOURCES test_metadata.cc LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) diff --git a/src/tests/util/test_indexview.cc b/src/tests/util/test_indexview.cc index c62cfa00c..6aece5631 100644 --- a/src/tests/util/test_indexview.cc +++ b/src/tests/util/test_indexview.cc @@ -33,14 +33,15 @@ namespace test { template std::string pos( Iterator& it ) { std::stringstream ss; - for ( size_t i = 0; i < it.pos().size(); ++i ) + for ( size_t i = 0; i < it.pos().size(); ++i ) { ss << it.pos()[i] << " "; + } return ss.str(); } - //----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- - /* +/* CASE( "test_array" ) { array::ArrayT _array (3,1,4); diff --git a/src/tests/util/test_metadata.cc b/src/tests/util/test_metadata.cc index 4730eac5c..b617f6caf 100644 --- a/src/tests/util/test_metadata.cc +++ b/src/tests/util/test_metadata.cc @@ -25,13 +25,17 @@ namespace test { CASE( "test_broadcast_to_self" ) { Metadata metadata; - if ( mpi::comm().rank() == 0 ) { metadata.set( "paramID", 128 ); } + if ( mpi::comm().rank() == 0 ) { + metadata.set( "paramID", 128 ); + } // broadcast metadata.broadcast(); EXPECT( metadata.has( "paramID" ) ); - if ( metadata.has( "paramID" ) ) EXPECT( metadata.get( "paramID" ) == 128 ); + if ( metadata.has( "paramID" ) ) { + EXPECT( metadata.get( "paramID" ) == 128 ); + } } // ----------------------------------------------------------------------------- @@ -39,7 +43,9 @@ CASE( "test_broadcast_to_self" ) { CASE( "test_broadcast_to_other" ) { size_t root = 0; Metadata global; - if ( mpi::comm().rank() == root ) { global.set( "paramID", 128 ); } + if ( mpi::comm().rank() == root ) { + global.set( "paramID", 128 ); + } Metadata local; @@ -47,9 +53,13 @@ CASE( "test_broadcast_to_other" ) { global.broadcast( local ); EXPECT( local.has( "paramID" ) ); - if ( local.has( "paramID" ) ) EXPECT( local.get( "paramID" ) == 128 ); + if ( local.has( "paramID" ) ) { + EXPECT( local.get( "paramID" ) == 128 ); + } - if ( mpi::comm().rank() != root ) EXPECT( !global.has( "paramID" ) ); + if ( mpi::comm().rank() != root ) { + EXPECT( !global.has( "paramID" ) ); + } } //----------------------------------------------------------------------------- diff --git a/tools/apply-clang-format.sh b/tools/apply-clang-format.sh index 4494e5dac..4b01a8162 100755 --- a/tools/apply-clang-format.sh +++ b/tools/apply-clang-format.sh @@ -8,6 +8,19 @@ # granted to it by virtue of its status as an intergovernmental organisation nor # does it submit to any jurisdiction. +_REQUIRED_CLANG_VERSION='7.0.1' + +if ! [ -x "$(command -v clang-format)" ]; then + echo 'Error: clang-format is not installed.' >&2 + exit 1 +fi + +if ! [[ $(clang-format --version) =~ ${_REQUIRED_CLANG_VERSION} ]]; then + echo "Error: Require clang-format version: ${_REQUIRED_CLANG_VERSION}" + echo " > $(which clang-format) --version" + echo " $(clang-format --version)" + exit 1 +fi SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $SCRIPTDIR/../src diff --git a/tools/atlas-run b/tools/atlas-run new file mode 100755 index 000000000..abec4c045 --- /dev/null +++ b/tools/atlas-run @@ -0,0 +1,90 @@ +#!/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. + + +set -e + +while test $# -gt 0; do + + case "$1" in + --*) + ATLAS_RUN_MPI_ARGS="${ATLAS_RUN_MPI_ARGS} $1" + shift # past argument + ;; + -n|-np) + ATLAS_RUN_NPROCS="$2" + shift # past argument + shift # past value + ;; + *) # unknown option + break + ;; + esac +done + +command_exists() { + type "$1" &> /dev/null ; +} + +if [ -n "${ATLAS_RUN_NTHREADS}" ]; then + export OMP_NUM_THREADS=${ATLAS_RUN_NTHREADS} +fi + +if command_exists aprun && \ + [[ ${EC_queue:-unset} != "nf" ]] && \ + [[ ${EC_queue:-unset} != "ns" ]] +then + LAUNCH="aprun ${ATLAS_RUN_MPI_ARGS}" + if [ -z "${ATLAS_RUN_NPROCS}" ]; then + LAUNCH="${LAUNCH} -n 1" + else + LAUNCH="${LAUNCH} -n ${ATLAS_RUN_NPROCS}" + fi + if [ -n "${OMP_NUM_THREADS}" ]; then + LAUNCH="${LAUNCH} -d ${OMP_NUM_THREADS}" + fi + +elif command_exists srun ; then + LAUNCH="srun ${ATLAS_RUN_MPI_ARGS}" + if [ -n "${ATLAS_RUN_NGPUS}" ]; then + LAUNCH="${LAUNCH} --gres=gpu:${ATLAS_RUN_NGPUS}" + fi + if [ -z "${ATLAS_RUN_NPROCS}" ]; then + LAUNCH="${LAUNCH} -n 1" + else + LAUNCH="${LAUNCH} -n ${ATLAS_RUN_NPROCS}" + fi + SLURM_EXPORT_ENV=ALL # Required to propagate environment variables to srun'd program + +else + if [[ ${ARCH:-unset} == "cray" ]]; then + echo + module load cray-snplauncher + module load cray-snplauncher + fi + if [ -z "${ATLAS_RUN_NPROCS}" ]; then + unset LAUNCH + elif command_exists mpirun ; then + LAUNCH="mpirun ${ATLAS_RUN_MPI_ARGS} -np ${ATLAS_RUN_NPROCS}" + elif command_exists mpiexec; then + LAUNCH="mpiexec ${ATLAS_RUN_MPI_ARGS} -n ${ATLAS_RUN_NPROCS}" + else + echo "No MPI driver found (mpirun,mpiexec,aprun,srun)" + exit 1 + fi +fi + +if [ -z "${ATLAS_RUN_NPROCS}" ]; then + echo + export ECKIT_MPI_FORCE=serial + export ECKIT_MPI_FORCE=serial +fi + +echo + $LAUNCH "$@" +$LAUNCH "$@" +