diff --git a/.cmake-format.py b/.cmake-format.py new file mode 100644 index 000000000..ed090568a --- /dev/null +++ b/.cmake-format.py @@ -0,0 +1,238 @@ +# ---------------------------------- +# Options affecting listfile parsing +# ---------------------------------- +with section("parse"): + # Specify structure for custom cmake functions + additional_commands = { + "foo": { + "flags": ["BAR", "BAZ"], + "kwargs": {"DEPENDS": "*", "HEADERS": "*", "SOURCES": "*"}, + } + } + + # Override configurations per-command where available + override_spec = {} + + # Specify variable tags. + vartags = [] + + # Specify property tags. + proptags = [] + +# ----------------------------- +# Options affecting formatting. +# ----------------------------- +with section("format"): + # Disable formatting entirely, making cmake-format a no-op + disable = False + + # How wide to allow formatted cmake files + line_width = 100 + + # How many spaces to tab for indent + tab_size = 2 + + # If true, lines are indented using tab characters (utf-8 0x09) instead of + # space characters (utf-8 0x20). In cases where the layout would + # require a fractional tab character, the behavior of the fractional + # indentation is governed by + use_tabchars = False + + # If is True, then the value of this variable indicates how + # fractional indentions are handled during whitespace replacement. If set to + # 'use-space', fractional indentation is left as spaces (utf-8 0x20). If set + # to `round-up` fractional indentation is replaced with a single tab character + # (utf-8 0x09) effectively shifting the column to the next tabstop + fractional_tab_policy = "use-space" + + # If an argument group contains more than this many sub-groups (parg or kwarg + # groups) then force it to a vertical layout. + max_subgroups_hwrap = 4 + + # If a positional argument group contains more than this many arguments, then + # force it to a vertical layout. + max_pargs_hwrap = 6 + + # If a cmdline positional group consumes more than this many lines without + # nesting, then invalidate the layout (and nest) + max_rows_cmdline = 2 + + # If true, separate flow control names from their parentheses with a space + separate_ctrl_name_with_space = False + + # If true, separate function names from parentheses with a space + separate_fn_name_with_space = False + + # If a statement is wrapped to more than one line, than dangle the closing + # parenthesis on its own line. + dangle_parens = False + + # If the trailing parenthesis must be 'dangled' on its on line, then align it + # to this reference: `prefix`: the start of the statement, `prefix-indent`: + # the start of the statement, plus one indentation level, `child`: align to + # the column of the arguments + dangle_align = "prefix" + + # If the statement spelling length (including space and parenthesis) is + # smaller than this amount, then force reject nested layouts. + min_prefix_chars = 4 + + # If the statement spelling length (including space and parenthesis) is larger + # than the tab width by more than this amount, then force reject un-nested + # layouts. + max_prefix_chars = 10 + + # If a candidate layout is wrapped horizontally but it exceeds this many + # lines, then reject the layout. + max_lines_hwrap = 2 + + # What style line endings to use in the output. + line_ending = "unix" + + # Format command names consistently as 'lower' or 'upper' case + command_case = "canonical" + + # Format keywords consistently as 'lower' or 'upper' case + keyword_case = "upper" + + # A list of command names which should always be wrapped + always_wrap = [] + + # If true, the argument lists which are known to be sortable will be sorted + # lexicographicall + enable_sort = True + + # If true, the parsers may infer whether or not an argument list is sortable + # (without annotation). + autosort = False + + # By default, if cmake-format cannot successfully fit everything into the + # desired linewidth it will apply the last, most aggressive attempt that it + # made. If this flag is True, however, cmake-format will print error, exit + # with non-zero status code, and write-out nothing + require_valid_layout = False + + # A dictionary mapping layout nodes to a list of wrap decisions. See the + # documentation for more information. + layout_passes = {} + +# ------------------------------------------------ +# Options affecting comment reflow and formatting. +# ------------------------------------------------ +with section("markup"): + # What character to use for bulleted lists + bullet_char = "*" + + # What character to use as punctuation after numerals in an enumerated list + enum_char = "." + + # If comment markup is enabled, don't reflow the first comment block in each + # listfile. Use this to preserve formatting of your copyright/license + # statements. + first_comment_is_literal = False + + # If comment markup is enabled, don't reflow any comment block which matches + # this (regex) pattern. Default is `None` (disabled). + literal_comment_pattern = None + + # Regular expression to match preformat fences in comments default= + # ``r'^\s*([`~]{3}[`~]*)(.*)$'`` + fence_pattern = "^\\s*([`~]{3}[`~]*)(.*)$" + + # Regular expression to match rulers in comments default= + # ``r'^\s*[^\w\s]{3}.*[^\w\s]{3}$'`` + ruler_pattern = "^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$" + + # If a comment line matches starts with this pattern then it is explicitly a + # trailing comment for the preceding argument. Default is '#<' + explicit_trailing_pattern = "#<" + + # If a comment line starts with at least this many consecutive hash + # characters, then don't lstrip() them off. This allows for lazy hash rulers + # where the first hash char is not separated by space + hashruler_min_length = 10 + + # If true, then insert a space between the first hash char and remaining hash + # chars in a hash ruler, and normalize its length to fill the column + canonicalize_hashrulers = True + + # enable comment markup parsing and reflow + enable_markup = True + +# ---------------------------- +# Options affecting the linter +# ---------------------------- +with section("lint"): + # a list of lint codes to disable + disabled_codes = [] + + # regular expression pattern describing valid function names + function_pattern = "[0-9a-z_]+" + + # regular expression pattern describing valid macro names + macro_pattern = "[0-9A-Z_]+" + + # regular expression pattern describing valid names for variables with global + # (cache) scope + global_var_pattern = "[A-Z][0-9A-Z_]+" + + # regular expression pattern describing valid names for variables with global + # scope (but internal semantic) + internal_var_pattern = "_[A-Z][0-9A-Z_]+" + + # regular expression pattern describing valid names for variables with local + # scope + local_var_pattern = "[a-z][a-z0-9_]+" + + # regular expression pattern describing valid names for privatedirectory + # variables + private_var_pattern = "_[0-9a-z_]+" + + # regular expression pattern describing valid names for public directory + # variables + public_var_pattern = "[A-Z][0-9A-Z_]+" + + # regular expression pattern describing valid names for function/macro + # arguments and loop variables. + argument_var_pattern = "[a-z][a-z0-9_]+" + + # regular expression pattern describing valid names for keywords used in + # functions or macros + keyword_pattern = "[A-Z][0-9A-Z_]+" + + # In the heuristic for C0201, how many conditionals to match within a loop in + # before considering the loop a parser. + max_conditionals_custom_parser = 2 + + # Require at least this many newlines between statements + min_statement_spacing = 1 + + # Require no more than this many newlines between statements + max_statement_spacing = 2 + max_returns = 6 + max_branches = 12 + max_arguments = 5 + max_localvars = 15 + max_statements = 50 + +# ------------------------------- +# Options affecting file encoding +# ------------------------------- +with section("encode"): + # If true, emit the unicode byte-order mark (BOM) at the start of the file + emit_byteorder_mark = False + + # Specify the encoding of the input file. Defaults to utf-8 + input_encoding = "utf-8" + + # Specify the encoding of the output file. Defaults to utf-8. Note that cmake + # only claims to support utf-8 so be careful when using anything else + output_encoding = "utf-8" + +# ------------------------------------- +# Miscellaneous configurations options. +# ------------------------------------- +with section("misc"): + # A dictionary containing any per-command configuration overrides. Currently + # only `command_case` is supported. + per_command = {} diff --git a/.github/workflows/clang_format.yml b/.github/workflows/clang_format.yml new file mode 100644 index 000000000..1fc1122f0 --- /dev/null +++ b/.github/workflows/clang_format.yml @@ -0,0 +1,17 @@ +name: clang-format + +on: + merge_group: + pull_request: + push: + branches: [master] + +jobs: + formatting-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - name: Check formatting + uses: jidicula/clang-format-action@v4.15.0 + with: + clang-format-version: '18' diff --git a/.gitignore b/.gitignore index e37b449eb..33bf9be72 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ manual/ippl_user_guide.pdf build*/ *~ *.~ +*.orig # ignore build directories build*/ diff --git a/CMakeLists.txt b/CMakeLists.txt index a8721b63e..a6c037b23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,37 @@ -cmake_minimum_required(VERSION 3.20) - -project(IPPL LANGUAGES CXX VERSION 3.0.2) - -include(GNUInstallDirs) - -list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +# ------------------------------------------------------------------------------ +# CMake version requirement +# ------------------------------------------------------------------------------ +cmake_minimum_required(VERSION 3.24) + +# ------------------------------------------------------------------------------ +# Policies - use the latest of everything +# ------------------------------------------------------------------------------ +cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) + +# but disable c++20 module scanning until we have better support for it this seems to cause some +# problems when using gcc@14 +cmake_policy(SET CMP0155 OLD) + +# ------------------------------------------------------------------------------ +# Project declaration and version +# ------------------------------------------------------------------------------ +project(IPPL VERSION 3.2 LANGUAGES CXX) + +# ------------------------------------------------------------------------------ +# Module path, setup before including any cmake modules +# ------------------------------------------------------------------------------ +list(PREPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" "${PROJECT_SOURCE_DIR}/CMakeModules") + +# ------------------------------------------------------------------------------ +# Project setup +# ------------------------------------------------------------------------------ +include(ProjectSetup) +# ------------------------------------------------------------------------------ +# Primary IPPL options +# ------------------------------------------------------------------------------ +set(IPPL_PLATFORMS "Platforms to build IPPL for" CACHE STRING "OPENMP;CUDA") +option(BUILD_SHARED_LIBS "Build IPPL as a shared library" OFF) option(IPPL_ENABLE_UNIT_TESTS "Enable unit tests using GoogleTest" OFF) option(IPPL_ENABLE_FFT "Enable FFT support" OFF) option(IPPL_ENABLE_SOLVERS "Enable IPPL solvers" OFF) @@ -13,31 +39,67 @@ option(IPPL_ENABLE_ALPINE "Enable building the Alpine module" OFF) option(IPPL_ENABLE_COSMOLOGY "Enable building the Cosmology module" OFF) option(IPPL_ENABLE_EXAMPLES "Enable building the Example module" OFF) option(IPPL_ENABLE_TESTS "Build integration tests in test/ directory" OFF) -option(BUILD_SHARED_LIBS "Build libraries as shared" OFF) -option(IPPL_DYL "Build IPPL as a shared library (compat shim for BUILD_SHARED_LIBS)" OFF) -if(IPPL_DYL) - set(BUILD_SHARED_LIBS ON CACHE BOOL "" FORCE) - message(WARNING "IPPL_DYL is deprecated; use -DBUILD_SHARED_LIBS=ON instead.") -endif() option(IPPL_ENABLE_COVERAGE "Enable code coverage" OFF) option(IPPL_ENABLE_NSYS_PROFILER "Enable Nvidia Nsys Profiler" OFF) option(IPPL_ENABLE_SANITIZER "Enable sanitizer(s)" OFF) -option(USE_ALTERNATIVE_VARIANT "Use modified variant implementation (required for CUDA 12.2 + GCC 12.3.0)" OFF) - - -add_compile_options( - $<$:-ffile-prefix-map=${CMAKE_SOURCE_DIR}=.> - $<$:-ffile-prefix-map=${CMAKE_SOURCE_DIR}=.> -) - -include(ProjectSetup) -include(Version) -include(Dependencies) +option(IPPL_USE_ALTERNATIVE_VARIANT + "Use modified variant implementation (required for CUDA 12.2 + GCC 12.3.0)" OFF) +option(IPPL_USE_STANDARD_FOLDERS "Put all generated binaries in bin/lib folders" OFF) +option(IPPL_SKIP_FAILING_TESTS "Do not build/test tests that are currently marked as failing" OFF) +# option(IPPL_DYL "Build IPPL as a shared library (ON) or static library (OFF)" OFF) if(IPPL_DYL) +# set(BUILD_SHARED_LIBS ON CACHE BOOL "" FORCE) message(WARNING "IPPL_DYL is deprecated; use +# -DBUILD_SHARED_LIBS=ON instead.") endif() + +# ------------------------------------------------------------------------------ +# Setup Output directories +# ------------------------------------------------------------------------------ +if(IPPL_USE_STANDARD_FOLDERS) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin + CACHE PATH "Single Directory for all Executables.") + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib + CACHE PATH "Single Directory for all Libraries") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib + CACHE PATH "Single Directory for all static libraries.") +else() + unset(CMAKE_RUNTIME_OUTPUT_DIRECTORY CACHE) + unset(CMAKE_LIBRARY_OUTPUT_DIRECTORY CACHE) + unset(CMAKE_ARCHIVE_OUTPUT_DIRECTORY CACHE) +endif() -add_subdirectory(src) +# ------------------------------------------------------------------------------ +# cmake modules +# ------------------------------------------------------------------------------ +# cmake supplied modules +include(GNUInstallDirs) +include(FetchContent) +include(CMakePackageConfigHelpers) +include(ExternalProject) +include(CTest) +# custom modules +include(Messages) include(CompilerOptions) include(Platforms) +include(Dependencies) +include(FailingTests) + +# ------------------------------------------------------------------------------ +# Deprecated vars +# ------------------------------------------------------------------------------ +if(DEFINED USE_ALTERNATIVE_VARIANT) + colour_message( + WARNING ${Red} + "USE_ALTERNATIVE_VARIANT is deprecated. Please set IPPL_USE_ALTERNATIVE_VARIANT instead.") + set(IPPL_USE_ALTERNATIVE_VARIANT ${USE_ALTERNATIVE_VARIANT} CACHE BOOL "" FORCE) +endif() + +# ------------------------------------------------------------------------------ +# Debug: This tells the compiler to replace occurrences of ${} with in debug info and error +# messages. +# ------------------------------------------------------------------------------ +add_compile_options( + $<$:-ffile-prefix-map=${CMAKE_SOURCE_DIR}=.> + $<$:-ffile-prefix-map=${CMAKE_SOURCE_DIR}=.>) if(DEFINED FETCHCONTENT_BASE_DIR) add_compile_options( @@ -46,16 +108,19 @@ if(DEFINED FETCHCONTENT_BASE_DIR) ) endif() -if(NOT DEFINED BUILD_TESTING) - set(BUILD_TESTING OFF CACHE BOOL "Enable tests via CTest") -endif() +# ------------------------------------------------------------------------------ +# Define sources for project +# ------------------------------------------------------------------------------ +add_subdirectory(src) +# ------------------------------------------------------------------------------ +# Include testing related material (BUILD_TESTING is defined in CTest module) +# ------------------------------------------------------------------------------ if(IPPL_ENABLE_UNIT_TESTS OR IPPL_ENABLE_TESTS) set(BUILD_TESTING ON CACHE BOOL "" FORCE) endif() if(PROJECT_IS_TOP_LEVEL AND BUILD_TESTING) - include(CTest) if(IPPL_ENABLE_UNIT_TESTS) add_subdirectory(unit_tests) endif() @@ -64,14 +129,17 @@ if(PROJECT_IS_TOP_LEVEL AND BUILD_TESTING) endif() endif() +# ------------------------------------------------------------------------------ +# Include optional source directories +# ------------------------------------------------------------------------------ if(IPPL_ENABLE_ALPINE) - add_subdirectory(alpine) + add_subdirectory(alpine) endif() if(IPPL_ENABLE_COSMOLOGY) - add_subdirectory(cosmology) + add_subdirectory(cosmology) endif() if(IPPL_ENABLE_EXAMPLES) - add_subdirectory(examples) + add_subdirectory(examples) endif() diff --git a/CMakeUserPresets.json b/CMakeUserPresets.json new file mode 100644 index 000000000..30f4ab2e0 --- /dev/null +++ b/CMakeUserPresets.json @@ -0,0 +1,90 @@ +{ + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 24, + "patch": 0 + }, + "configurePresets": [ + { + "name": "testing", + "hidden": true, + "cacheVariables": { + "IPPL_ENABLE_TESTS": "ON", + "IPPL_ENABLE_UNIT_TESTS": "ON" + } + }, + { + "name": "default", + "displayName": "Default", + "description": "Default build, release mode with most common options", + "generator": "Unix Makefiles", + "cacheVariables": { + "BUILD_SHARED_LIBS": "ON", + "CMAKE_BUILD_TYPE": "Release", + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", + "Kokkos_VERSION_DEFAULT": "4.5.01", + "Heffte_VERSION_DEFAULT": "2.4.0", + "IPPL_PLATFORMS": "OPENMP;CUDA", + "IPPL_ENABLE_FFT": "ON", + "IPPL_ENABLE_ALPINE": "ON", + "IPPL_ENABLE_COSMOLOGY": "ON", + "IPPL_ENABLE_TESTS": "OFF", + "IPPL_ENABLE_UNIT_TESTS": "OFF", + "IPPL_USE_STANDARD_FOLDERS": "OFF" + } + }, + { + "name": "fetch", + "displayName": "ForceDownload", + "description": "Always downloads dependencies", + "inherits": [ + "default" + ], + "cacheVariables": { + "Kokkos_VERSION": "git.4.6.02", + "Heffte_VERSION": "git.v2.4.1" + } + }, + { + "name": "release-testing", + "displayName": "Testing(Release)", + "description": "Enables building test in release mode", + "inherits": [ + "testing", + "default" + ] + }, + { + "name": "debug-testing", + "displayName": "Testing(Debug)", + "description": "Enables building test in debug mode", + "inherits": [ + "testing", + "default" + ], + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "IPPL_ENABLE_SANITIZER": "ON", + "IPPL_PLATFORMS": "SERIAL" + } + }, + { + "name": "alps-gh200", + "displayName": "Alps-GH200-defaults", + "description": "Enables building test in debug mode", + "inherits": [ + "testing", + "default" + ], + "cacheVariables": { + "MPIEXEC_PREFLAGS": "--gpus-per-task=1;/user-environment/wrapper-mpi.sh", + "IPPL_PLATFORMS": "OPENMP;CUDA", + "CMAKE_CUDA_ARCHITECTURES": "90", + "MPIEXEC_EXECUTABLE": "/usr/bin/srun", + "Kokkos_VERSION_DEFAULT": "4.7", + "Heffte_VERSION_DEFAULT": "2.4.1" + } + } + ] +} diff --git a/README.md b/README.md index 83c20e150..ea4532e6f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,34 @@ [![License](https://img.shields.io/github/license/IPPL-framework/ippl)](https://github.com/IPPL-framework/ippl/blob/master/LICENSE) # Independent Parallel Particle Layer (IPPL) -Independent Parallel Particle Layer (IPPL) is a performance portable C++ library for Particle-Mesh methods. IPPL makes use of Kokkos (https://github.com/kokkos/kokkos), HeFFTe (https://github.com/icl-utk-edu/heffte), and MPI (Message Passing Interface) to deliver a portable, massively parallel toolkit for particle-mesh methods. IPPL supports simulations in one to six dimensions, mixed precision, and asynchronous execution in different execution spaces (e.g. CPUs and GPUs). + +## Table of Contents +- [Independent Parallel Particle Layer (IPPL)](#independent-parallel-particle-layer-ippl) + - [Table of Contents](#table-of-contents) +- [CI/CD](#cicd) +- [Installing IPPL and its dependencies](#installing-ippl-and-its-dependencies) + - [Requirements](#requirements) + - [Optional requirements](#optional-requirements) + - [Compilation](#compilation) + - [None of the options have to be set explicitly, all have a default.](#none-of-the-options-have-to-be-set-explicitly-all-have-a-default) + - [Examples](#examples) + - [CMakeUserPresets](#cmakeuserpresets) + - [Serial debug build with tests and newest Kokkos](#serial-debug-build-with-tests-and-newest-kokkos) + - [OpenMP release build with alpine and FFTW](#openmp-release-build-with-alpine-and-fftw) + - [Cuda alpine release build](#cuda-alpine-release-build) + - [HIP release build (LUMI)](#hip-release-build-lumi) +- [Contributions](#contributions) + - [Citing IPPL](#citing-ippl) +- [Job scripts for running on Merlin and Gwendolen (at PSI)](#job-scripts-for-running-on-merlin-and-gwendolen-at-psi) + - [Merlin CPU (MPI + OpenMP)](#merlin-cpu-mpi--openmp) + - [Gwendolen GPU](#gwendolen-gpu) + - [LUMI GPU partition](#lumi-gpu-partition) +- [Profiling IPPL MPI calls](#profiling-ippl-mpi-calls) +- [Build Instructions](#build-instructions) + - [MERLIN 7 (PSI)](#merlin-7-psi) + - [ALPS (CSCS)](#alps-cscs) + +Independent Parallel Particle Layer (IPPL) is a performance portable C++ library for Particle-Mesh methods. IPPL makes use of Kokkos (https://github.com/kokkos/kokkos), HeFFTe (https://github.com/icl-utk-edu/heffte), and MPI (Message Passing Interface) to deliver a portable, massively parallel toolkit for particle-mesh methods. IPPL supports simulations in one to six dimensions, mixed precision, and asynchronous execution in different execution spaces (e.g. CPUs and GPUs). All IPPL releases (< 3.2.0) are available under the BSD 3-clause license. Since version 3.2.0, this repository includes a modified version of the `variant` header by GNU, created to support compilation under CUDA 12.2 with GCC 12.3.0. This header file is available under the same terms as the [GNU Standard Library](https://github.com/gcc-mirror/gcc); note the GNU runtime library exception. As long as this file is not removed, IPPL is available under GNU GPL version 3. @@ -33,8 +60,8 @@ cmake -D