diff --git a/cmake/SetupDoxygen.cmake b/cmake/SetupDoxygen.cmake index 50d746ec..a05357be 100644 --- a/cmake/SetupDoxygen.cmake +++ b/cmake/SetupDoxygen.cmake @@ -1,40 +1,59 @@ -# Distributed under the MIT License. -# See LICENSE.txt for details. - -log_info("Finding Doxygen") - +message(STATUS "Finding Doxygen") find_package(Doxygen REQUIRED) -if (DOXYGEN_FOUND) - log_debug("DOXYGEN_VERSION: ${DOXYGEN_VERSION}") - - set(ELASTICA_DOX_GENERATE_HTML "YES") - set(ELASTICA_DOX_GENERATE_XML "NO") - - configure_file( - docs/Doxyfile.in - ${PROJECT_BINARY_DIR}/docs/DoxyfileHtml @ONLY IMMEDIATE - ) - - # Construct the command that calls Doxygen - set( - GENERATE_DOCS_COMMAND - "${DOXYGEN_EXECUTABLE} ${PROJECT_BINARY_DIR}/docs/DoxyfileHtml" - ) - - # Parse the command into a CMake list for the `add_custom_target` - separate_arguments(GENERATE_DOCS_COMMAND) - - add_custom_target( - doc - COMMAND ${GENERATE_DOCS_COMMAND} - DEPENDS - ${PROJECT_BINARY_DIR}/docs/DoxyfileHtml - COMMENT - "Generating API documentation with Doxygen" - VERBATIM - ) - -else (DOXYGEN_FOUND) - message(WARNING "Doxygen is needed to build the documentation.") -endif (DOXYGEN_FOUND) +set(ELASTICA_DOCS_OUTPUT_DIR "${PROJECT_BINARY_DIR}/docs/html") +set(ELASTICA_DOCS_DOXYFILE "${PROJECT_BINARY_DIR}/docs/Doxyfile") +set(ELASTICA_DOCS_THEME_DIR "${PROJECT_BINARY_DIR}/docs/doxygen-awesome-css") +set(ELASTICA_DOCS_WARN_LOG "${PROJECT_BINARY_DIR}/docs/doxygen-warnings.log") +set(ELASTICA_DOCS_TARGET_OUTPUT_ROOT "${PROJECT_BINARY_DIR}") + +set(ELASTICA_DOXYGEN_HTML_EXTRA_STYLESHEETS "") +set(ELASTICA_DOXYGEN_HTML_EXTRA_FILES "") + +include(FetchContent) +FetchContent_Declare( + doxygen-awesome-css + URL https://github.com/jothepro/doxygen-awesome-css/archive/refs/heads/main.zip + DOWNLOAD_EXTRACT_TIMESTAMP TRUE) +FetchContent_MakeAvailable(doxygen-awesome-css) +FetchContent_GetProperties(doxygen-awesome-css SOURCE_DIR AWESOME_CSS_DIR) + +string(JOIN " \\\n " ELASTICA_DOXYGEN_HTML_EXTRA_STYLESHEETS + "doxygen-awesome-css/doxygen-awesome.css" + "doxygen-awesome-css/doxygen-awesome-sidebar-only.css" + "doxygen-awesome-css/doxygen-awesome-sidebar-only-darkmode-toggle.css") + +string(JOIN " \\\n " ELASTICA_DOXYGEN_HTML_EXTRA_FILES + "${ELASTICA_DOCS_THEME_DIR}/doxygen-awesome-darkmode-toggle.js" + "${ELASTICA_DOCS_THEME_DIR}/doxygen-awesome-fragment-copy-button.js" + "${ELASTICA_DOCS_THEME_DIR}/doxygen-awesome-interactive-toc.js") + +file(MAKE_DIRECTORY "${ELASTICA_DOCS_THEME_DIR}") +file(COPY + "${AWESOME_CSS_DIR}/doxygen-awesome.css" + "${AWESOME_CSS_DIR}/doxygen-awesome-sidebar-only.css" + "${AWESOME_CSS_DIR}/doxygen-awesome-sidebar-only-darkmode-toggle.css" + "${AWESOME_CSS_DIR}/doxygen-awesome-darkmode-toggle.js" + "${AWESOME_CSS_DIR}/doxygen-awesome-fragment-copy-button.js" + "${AWESOME_CSS_DIR}/doxygen-awesome-interactive-toc.js" + DESTINATION "${ELASTICA_DOCS_THEME_DIR}") + +configure_file( + "${PROJECT_SOURCE_DIR}/docs/Doxyfile.in" + "${ELASTICA_DOCS_DOXYFILE}" + @ONLY) + +add_custom_target( + doc + COMMAND "${CMAKE_COMMAND}" -E echo "[doc] Starting Doxygen build." + COMMAND "${CMAKE_COMMAND}" -E echo "[doc] Warnings will be written to: ${ELASTICA_DOCS_WARN_LOG}" + COMMAND "${CMAKE_COMMAND}" -E echo "[doc] HTML output: ${ELASTICA_DOCS_OUTPUT_DIR}" + COMMAND "${DOXYGEN_EXECUTABLE}" "${ELASTICA_DOCS_DOXYFILE}" + WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/docs" + DEPENDS "${ELASTICA_DOCS_DOXYFILE}" + COMMENT "Generating API documentation with Doxygen" + USES_TERMINAL + VERBATIM) + +message(STATUS "Documentation target enabled") +message(STATUS "Documentation output directory: ${ELASTICA_DOCS_OUTPUT_DIR}") diff --git a/docs/CoreConcepts.md b/docs/CoreConcepts.md new file mode 100644 index 00000000..9d28f5bc --- /dev/null +++ b/docs/CoreConcepts.md @@ -0,0 +1,177 @@ +\page core_concepts_page Core Concepts + +[TOC] + +This page introduces the main ideas you need before modifying or creating a +simulation. + +## Simulator and configuration + +An Elastica++ simulation is assembled around a simulator object plus a +configuration that determines: + +- which systems are allowed +- how systems are grouped into blocks +- how iteration is performed +- which domain, parallel, and module-level settings are active + +The basic pattern looks like this: + +\code{.cpp} +using ::elastica::cosserat_rod::CosseratRod; +namespace ec = elastica::configuration; + +auto system_config = ec::make_systems_configuration>( + ec::make_blocking_policy(ec::RestrictSizeAcrossBlockTypes{50UL}), + ec::make_iteration_policy(ec::iterate_across_system_types_in(ec::seq), + ec::iterate_over_systems_in(ec::seq))); + +auto simulator_config = ec::make_simulator_configuration( + ec::DefaultDomainConfiguration{}, + system_config, + ec::DefaultParallelConfiguration{}); + +auto simulator = elastica::make_simulator<>(simulator_config); +\endcode + +Start with: + +- `elastica::make_simulator` +- simulator configuration helpers in the `configuration` namespace + +## Systems and plugins + +The systems module defines the physical entities that participate in the +simulation, such as Cosserat rods and rigid bodies. + +Important ideas: + +- a simulation declares which system types it will contain +- systems are added to the simulator and later finalized +- plugins, tags, and traits shape what data and behavior a system exposes + +For most first simulations, the main starting point is +\ref elastica::cosserat_rod. + +A minimal system-emplacement pattern looks like: + +\code{.cpp} +auto rod_ref = simulator->emplace_back( + straight_initializer.initialize()); +\endcode + +The returned value is a wrapped reference, which lets you safely keep access to +the created system. + +## Rods, materials, initializers, tags, and blocks + +Cosserat rods are the most common entry point for new users. + +The typical flow is: + +1. create or choose a material +2. choose an initializer such as a straight-rod initializer +3. initialize the rod state +4. add the rod to the simulator +5. access rod data through member functions, free functions, or tags + +Material and initializer setup usually looks like: + +\code{.cpp} +elastica::MaterialID material = elastica::create_material( + 7.874, 0.24, 200, 200.0 / 1.24, 200, 1e-10, 1e-10, 0.1, 0.1); + +using StraightInit = ::elastica::cosserat_rod::StraightCosseratRodInitializer; +StraightInit initializer{ + StraightInit::NElement{10UL}, + StraightInit::Material{material}, + StraightInit::Radius{0.007522}, + StraightInit::Length{0.18}, + StraightInit::Origin{::elastica::Vec3{0.0, 0.0, 0.0}}, + StraightInit::Direction{::elastica::Vec3{0.0, 1.0, 0.0}}, + StraightInit::Normal{::elastica::Vec3{0.0, 0.0, 1.0}}, + StraightInit::ForceDampingRate{0.2}, + StraightInit::TorqueDampingRate{0.2}, +}; +\endcode + +Optional initialization can be overridden at construction time: + +\code{.cpp} +simulator->emplace_back( + initializer.initialize( + ::blocks::initialize<::elastica::tags::Velocity>( + [](std::size_t index) { + return 0.1 + 0.002 * static_cast(index); + }))); +\endcode + +The tutorial examples show three access patterns for rod state: + +\code{.cpp} +auto &rod = rod_ref.get(); + +auto member_position = rod.get_position(); +auto free_position = ::elastica::position(rod); +auto tagged_position = ::elastica::get<::elastica::tags::Position>(rod); +\endcode + +Blocks are the execution and storage grouping mechanism used by the simulator. +They become more important when you start reasoning about performance, +parallelism, and multi-system simulations. + +## Iteration and time stepping + +Time stepping drives the simulation forward. + +When reading or writing simulation code, keep these concepts separate: + +- current simulation state +- the stepper or time integration algorithm +- callbacks or callables run at each step +- stopping conditions such as total time or iteration count + +The case-study tutorials introduce the split between setup, run, and step: + +\code{.cpp} +void setup(); +void run(); +void step(const double time, const double dt); +\endcode + +For onboarding, the important point is not every stepping detail but the fact +that simulation setup and simulation advancement are distinct phases. + +## Environments, constraints, connections, and IO + +Most personal simulations are built by starting with a rod or rigid body and +then layering on behavior: + +- environments for effects such as gravity or collision context +- constraints for fixed or time-varying restrictions +- connections or joints for linked systems +- IO for metadata, HDF5, YAML, CSV, or restart workflows + +The practical workflow usually looks like: + +\code{.cpp} +// 1. Create simulator +auto simulator = elastica::make_simulator<>(simulator_config); + +// 2. Add systems +auto rod_ref = simulator->emplace_back( + initializer.initialize()); + +// 3. Layer in extra behavior in the style of the closest reference example +// (constraints, forcing, joints, environments, IO) + +// 4. Finalize and run +\endcode + +When choosing an example to copy from, it is usually best to choose based on +which of these behaviors you need first. + +## Suggested next reading + +- \ref examples_page "Case Examples" +- Tutorial programs under `examples/` (see repository `examples/README.md`) diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index 698db259..cd802bbd 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -6,7 +6,9 @@ OUTPUT_DIRECTORY = "@ELASTICA_DOCS_TARGET_OUTPUT_ROOT@" CREATE_SUBDIRS = NO ALLOW_UNICODE_NAMES = YES -INPUT = @ELASTICA_DOXYGEN_INPUTS@ +INPUT = @PROJECT_SOURCE_DIR@/docs \ + @PROJECT_SOURCE_DIR@/examples \ + @PROJECT_SOURCE_DIR@/elastica INPUT_ENCODING = UTF-8 FILE_PATTERNS = *.hpp \ *.cpp \ @@ -14,7 +16,7 @@ FILE_PATTERNS = *.hpp \ RECURSIVE = YES EXCLUDE_PATTERNS = */build/* \ */.git/* \ - */PythonBindings/* \ + */PythonBindings/* # Markdown files inside our source code for developers get listed # which is not what we want. So filter them out EXCLUDE_PATTERNS += @PROJECT_SOURCE_DIR@/elastica/*.md @@ -25,9 +27,12 @@ EXCLUDE_SYMBOLS = *brigand* \ std* \ YAML* EXAMPLE_PATH = @PROJECT_SOURCE_DIR@/tests/ \ + @PROJECT_SOURCE_DIR@/tests/Unit \ + @PROJECT_SOURCE_DIR@/elastica \ @PROJECT_SOURCE_DIR@/examples -EXAMPLE_RECURSIVE = NO -IMAGE_PATH = @ELASTICA_DOXYGEN_IMAGE_PATHS@ +EXAMPLE_RECURSIVE = YES +CITE_BIB_FILES = @PROJECT_SOURCE_DIR@/docs/refs.bib +IMAGE_PATH = @PROJECT_SOURCE_DIR@/docs USE_MDFILE_AS_MAINPAGE = "@PROJECT_SOURCE_DIR@/docs/Main.md" STRIP_FROM_PATH = "@PROJECT_SOURCE_DIR@" @@ -120,11 +125,11 @@ STRIP_CODE_COMMENTS = NO SHOW_USED_FILES = YES VERBATIM_HEADERS = NO -QUIET = @ELASTICA_DOXYGEN_QUIET@ +QUIET = YES GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html -HTML_HEADER = "@ELASTICA_DOCS_HTML_HEADER@" +HTML_HEADER = @PROJECT_SOURCE_DIR@/docs/header.html.in HTML_COLORSTYLE = LIGHT HTML_COLORSTYLE_HUE = 209 HTML_COLORSTYLE_SAT = 255 @@ -166,12 +171,11 @@ GENERATE_RTF = NO GENERATE_MAN = NO HIDE_UNDOC_RELATIONS = YES -HAVE_DOT = @ELASTICA_DOXYGEN_HAVE_DOT@ +HAVE_DOT = NO DOT_NUM_THREADS = 0 DOT_MULTI_TARGETS = YES -CLASS_DIAGRAMS = NO -CALL_GRAPH = @ELASTICA_DOXYGEN_CALL_GRAPH@ -CALLER_GRAPH = @ELASTICA_DOXYGEN_CALLER_GRAPH@ +CALL_GRAPH = NO +CALLER_GRAPH = NO CLASS_GRAPH = NO COLLABORATION_GRAPH = NO GROUP_GRAPHS = NO @@ -188,7 +192,7 @@ DOT_IMAGE_FORMAT = png MAX_DOT_GRAPH_DEPTH = 0 GENERATE_LEGEND = NO INTERACTIVE_SVG = YES -DOT_PATH = @ELASTICA_DOXYGEN_DOT_PATH@ +DOT_PATH = DOTFILE_DIRS = MSCFILE_DIRS = DIAFILE_DIRS = diff --git a/docs/DoxygenGroups.hpp b/docs/DoxygenGroups.hpp new file mode 100644 index 00000000..f97ada4c --- /dev/null +++ b/docs/DoxygenGroups.hpp @@ -0,0 +1,177 @@ +//============================================================================== +/*! + * \file DoxygenGroups.hpp + * \brief Central Doxygen module groups (documentation only; not compiled). + * + * These definitions register module group IDs used with the ingroup command + * across the library. The docs directory is listed first in Doxygen INPUT so + * groups here are registered early. + */ +//============================================================================== + +#pragma once + +//****************************************************************************** +/*!\defgroup utils Utilities + * \brief Umbrella for general-purpose helpers (geometry, logging, traits, etc.) + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup util Low-level utilities + * \ingroup utils + * \brief Small helpers (memory, CRTP, non-copyable, etc.) + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup utilities Utilities (alternate id) + * \ingroup utils + * \brief Alternate spelling used by some headers. + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup UtilitiesGroup Utilities (legacy name) + * \ingroup utils + * \brief Legacy module id; prefer \ref utils where possible. + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup type_traits Type traits + * \ingroup utils + * \brief Type traits and metaprogramming helpers (alongside \c type_traits_group). + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup interface Simulator interfaces + * \ingroup simulator + * \brief Abstract interfaces to the simulator core. + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup io Input and output + * \ingroup simulator + * \brief File, HDF5, YAML, and related I/O interfaces. + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup environment Environment (singular) + * \ingroup environments + * \brief Supplemental group id for headers that use the singular name alongside + * the main environments module. + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup customization Customization hooks + * \ingroup environments + * \brief Transfer and primitive customization traits. + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup core Collision / DEM core + * \ingroup collision_system + * \brief Core collision and DEM solver documentation group. + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup rigid_body RigidBody + * \ingroup systems + * \brief Data, operations and helpers for manipulating rigid bodies. + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup rigid_body_component Rigid body components + * \ingroup rigid_body + * \brief Geometry, kinematics, and related rigid-body components. + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup OptionParsingGroup Command-line options + * \ingroup modules + * \brief Option parsing and parameters. + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup ErrorHandlingGroup Error handling + * \brief Assertions, errors, and contract checking. + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup TimeSteppersGroup Time stepping + * \ingroup time + * \brief History buffers and stepper-related helpers. + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup symplectic Symplectic integrators + * \ingroup time + * \brief Symplectic time integration algorithms. + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup math Math helpers + * \ingroup utils + * \brief Vector length, normalize, and similar math utilities. + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup math_shims Math shims + * \ingroup math + * \brief Thin wrappers around math operations. + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup fine_detection Fine collision kernels + * \ingroup fine_collision_detection + * \brief Narrow-phase collision detection helpers. + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup cosserat_rods Cosserat rods (plural id) + * \ingroup cosserat_rod + * \brief Legacy group id; see \ref cosserat_rod. + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup vtk VTK output + * \ingroup serialization + * \brief VTK writers and related I/O. + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup extension_environments Example environment extensions + * \brief Field profiles and extensions used by example programs. + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup extension Example extensions + * \brief Adapters and helpers for example-specific code. + */ +//****************************************************************************** + +//****************************************************************************** +/*!\defgroup joints Joints + * \ingroup simulator + * \brief Interfaces for coupled forces and torques between systems. + */ +//****************************************************************************** diff --git a/docs/Examples.md b/docs/Examples.md new file mode 100644 index 00000000..0a1ed6b9 --- /dev/null +++ b/docs/Examples.md @@ -0,0 +1,43 @@ +\page examples_page Case Examples + +This page is a short chooser for the case-study and tutorial example tree. + +For the complete automatically generated example list, use the `Examples` tab +in the Doxygen navigation. For a source-tree overview, see +[examples/README.md](../examples/README.md). + +If you are still onboarding, start with \ref installation "Installation", then +return here to pick an example program. + +## Best first choices + +- [tutorial_single_rod.cpp](../examples/tutorial_single_rod/tutorial_single_rod.cpp) + Read rod state, tags, and array shapes. +- [tutorial_rod_construction.cpp](../examples/tutorial_rod_construction/tutorial_rod_construction.cpp) + Build and initialize a rod inside a simulator. +- [tutorial_casestudy_setup](../examples/tutorial_casestudy_setup/CMakeLists.txt) + Learn the case-study structure for reusable simulations. +- [AxialStretchingCaseStudy.cpp](../examples/axial_stretching/AxialStretchingCaseStudy.cpp) + Good first parameterized personal simulation. + +## Choose by need + +- Need a single-rod starting point: + [tutorial_rod_construction.cpp](../examples/tutorial_rod_construction/tutorial_rod_construction.cpp) +- Need joints or coupled systems: + [HingeJointCaseStudy.cpp](../examples/hinge_joint/HingeJointCaseStudy.cpp) +- Need collision/contact: + [RodCollisionCaseStudy.cpp](../examples/rod_collision/CaseStudy/RodCollisionCaseStudy.cpp) + or [RodPlaneCollisionCaseStudy.cpp](../examples/rod_plane_collision/plane/RodPlaneCollisionCaseStudy.cpp) +- Need parallel or runtime tuning: + [examples/parallelism/main.cpp](../examples/parallelism/main.cpp) + or [parallel_butterfly/main.cpp](../examples/parallel_butterfly/main.cpp) + +## Advanced collections + +- [examples/active_matter](../examples/active_matter/CMakeLists.txt) +- [examples/magnetism](../examples/magnetism/README.md) +- [examples/nest](../examples/nest/CMakeLists.txt) + +Treat these as reference collections after you already have a working base +simulation. diff --git a/docs/Installation.md b/docs/Installation.md new file mode 100644 index 00000000..fa15f71d --- /dev/null +++ b/docs/Installation.md @@ -0,0 +1,130 @@ +\page installation Installation + +[TOC] + +This page describes the standard local build for Elastica++ on macOS and Linux. +For Python package installation after the build, see the **Python Bindings** +section on this page. +For a first end-to-end local run after installation, continue with the +\ref examples_page "Case Examples" page and the tutorial sources under `examples/`. + +## Requirements + +Elastica++ is built with CMake and uses `vcpkg` manifest mode for C++ +dependencies. + +- A C++20 compiler +- CMake 3.17 or newer +- Ninja or Make +- Python 3 +- `vcpkg` + +## Configure + +Bootstrap `vcpkg` if it is not already available in your environment. +We recommend installing dependencies through `vcpkg`, although you may install dependencies yourself: +- `blaze` and `blaze-tensor`: linear-algebra +- `tbb`: shared-memory-parallelism +- `brigand`: meta-programming +- `catch2`: unit-test +- `yaml-cpp`, `cxxopts` + +For some example cases, extra dependency might be needed: +- `pybind11` +- `spline` +- `HighFive` with `HDF5-mpi`: I/O + +Configure Elastica++ with the `vcpkg` toolchain: + +\code{.sh} +cmake -B build -G Ninja \ + -D CMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" \ + -D BUILD_TESTING=ON \ + -D ELASTICA_BUILD_BENCHMARKS=OFF \ + -D ELASTICA_BUILD_EXAMPLES=OFF \ + -D ELASTICA_BUILD_PYTHON_BINDINGS=OFF +\endcode + +## Build + +Build the project with: + +\code{.sh} +cmake --build build --parallel +\endcode + +## Python Bindings + +Python bindings are optional and can be enabled with +`-D ELASTICA_BUILD_PYTHON_BINDINGS=ON`. + +After building, the editable Python package lives in `build/bin/python` and can +be installed with: + +```bash +cd build/bin/python +python3 -m pip install --editable . +``` + +This installs the `elasticapp` package in editable mode. + +## Build documentation + +Generate the Doxygen documentation without configuring the main package build: + +\code{.sh} +cmake -B build-docs -G Ninja \ + -D ELASTICA_BUILD_DOCUMENTATION=ON +cmake --build build-docs --target doc --parallel +\endcode + +If you enabled documentation in the main build, you can also build the docs +from that existing build tree. + +## Test + +Run the unit test suite from the build directory: + +\code{.sh} +cd build +ctest --output-on-failure +\endcode + +## Next steps + +- \ref examples_page "Case Examples" for the first runnable examples and for + building a personal simulation +- Tutorial sources under `examples/` (for example `tutorial_single_rod` and + `tutorial_casestudy_setup`) + +## Advanced debugging build + +For local debugging, development, or dependency troubleshooting, it can be +useful to configure a fuller build with extra diagnostics enabled: + +\code{.sh} +cmake -B build-debug -G Ninja \ + -D CMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" \ + -D CMAKE_CXX_COMPILER=/usr/bin/clang++ \ + -D CMAKE_BUILD_TYPE=Debug \ + -D BUILD_TESTING=ON \ + -D ELASTICA_BUILD_DOCUMENTATION=OFF \ + -D ELASTICA_BUILD_EXAMPLES=ON \ + -D ELASTICA_BUILD_BENCHMARKS=ON \ + -D ELASTICA_BUILD_PYTHON_BINDINGS=ON \ + -D Python_FIND_VIRTUALENV=FIRST \ + -D ELASTICA_ENABLE_PROFILING=ON \ + -D ELASTICA_SMP=ON \ + -D USE_SLEEF=OFF \ + -D DEBUG_SYMBOLS=ON \ + -D ENABLE_WARNINGS=ON \ + -D ASAN=OFF \ + -D UBSAN_UNDEFINED=OFF \ + -D UBSAN_INTEGER=OFF \ + -D PY_DEV_MODE=OFF +cmake --build build-debug --parallel +\endcode + +This is not the recommended default for everyday builds, but it is a useful +starting point when debugging configuration issues, running a broader local +check, or working on examples and Python bindings at the same time. diff --git a/docs/Installation/Installation.md b/docs/Installation/Installation.md deleted file mode 100644 index 1e3a7da0..00000000 --- a/docs/Installation/Installation.md +++ /dev/null @@ -1,7 +0,0 @@ -\cond NEVER Distributed under the MIT License. See LICENSE.txt for details. \endcond - -# Installation {#installation} - -This page details the installation procedure for Elastica on personal computers. For instructions on installing the -python bindings generated by Elastica please refer to the \subpage python_installation page. - diff --git a/docs/Installation/InstallationPython.md b/docs/Installation/InstallationPython.md deleted file mode 100644 index 53165e26..00000000 --- a/docs/Installation/InstallationPython.md +++ /dev/null @@ -1,12 +0,0 @@ -\cond NEVER Distributed under the MIT License. See LICENSE.txt for details. \endcond - -# Installation of Python-bound case studies {#python_installation} - -To generate and install the Python bindings for case studies: - -1. Configure and build the project with `ELASTICA_BUILD_PYTHON_BINDINGS=ON`. -2. Change into the build tree's `bin/python` directory. -3. Run `python3 -m pip install --editable .`. - -This installs the `elasticapp` package in editable mode. Add `--user` if you want -to install it for only the current user. diff --git a/docs/Main.md b/docs/Main.md index 9dc890aa..03e8c57b 100644 --- a/docs/Main.md +++ b/docs/Main.md @@ -1,24 +1,57 @@ -\cond NEVER Distributed under the MIT License. See LICENSE.txt for details. \endcond - \mainpage Introduction -
-Table of Contents - -
- # What is Elastica++? {#intro_sec} -`Elastica++` is a `C++` package to simulate the dynamics of soft-filaments that, at every cross-section, can undergo all -six possible modes of deformation, allowing the filament to bend, twist, stretch and shear. Such slender structures are -ubiquitous in natural and artificial systems across scales, from DNA strands to flagella and space tethers. They also -make up a variety of complex systems, from birds’ nests made of twigs to living creatures made of bones, tendons, fibers -and muscles. - -`Elastica++` models these filaments using Cosserat rod theory which allows for modeling assemblies of such rods while -interacting with complex exogenous (surface contact, friction and hydrodynamics) and endogenous (muscular activity) -effects. `Elastica++` maps such assemblies efficiently to multicore processors using a novel Block architecture which -allows it to scale from laptops to computing clusters. More information about `Elastica++` is available at the -Elastica [project website](https://cosseratrods.org) +[TOC] + +> [!note] +> If you are new to the elastica project, we recommend to first look into python-implementation [PyElastica](https://github.com/GazzolaLab/PyElastica) to experience Cosserat-rod simulation and its applications. **Elastica++** is an optimized solver for **problems at scale**. In small problems where compute is CPU-bounded, this CPP implementation may not provide much advantages. + +`Elastica++` is a `C++` package to simulate the dynamics of soft-filaments that, at every cross-section, can undergo all six possible modes of deformation, allowing the filament to bend, twist, stretch and shear. Such slender structures are ubiquitous in natural and artificial systems across scales, from DNA strands to flagella and space tethers. They also make up a variety of complex systems, from birds’ nests made of twigs to living creatures made of bones, tendons, fibers and muscles. + +`Elastica++` models these filaments using Cosserat rod theory which allows for modeling assemblies of such rods while interacting with complex exogenous (surface contact, friction and hydrodynamics) and endogenous (muscular activity) effects. `Elastica++` maps such assemblies efficiently to multicore processors using a novel Block architecture which allows it to scale from laptops to computing clusters. More information about `Elastica++` is available at the Elastica [project website](https://cosseratrods.org) + +# Getting started {#getting_started_sec} + +For build and installation guidance, start with the \ref installation page. + +# Learn the codebase {#learn_sec} + +Use the narrative guides to understand the core abstractions before diving into +the API reference: + +- \ref core_concepts_page "Core Concepts" + +# Build your own simulation {#build_your_own_sec} + +If your goal is to adapt Elastica++ for personal use, start here: + +- \ref examples_page "Case Examples" + +# Case Examples {#examples_sec} + +Start with the curated \ref examples_page "Case Examples" page for grouped example programs and +recommended entry points. Use the examples as runnable companions to the +tutorial and setup guides rather than as a flat catalog. + +# Roadmap {#roadmap_sec} + +For outstanding architectural and implementation work, see the +\ref todo_page "Project TODO". + +# Documentation map {#documentation_map_sec} + +The generated documentation is organized around the following entry points: + +- Learn: \ref installation "Installation", + \ref core_concepts_page "Core Concepts" +- Browse runnable examples: \ref examples_page "Case Examples" +- API reference: +- \ref todo_page "Project TODO" +- \ref systems "Physical systems" +- \ref elastica::cosserat_rod "Cosserat rods" +- \ref rigid_body "Rigid bodies" +- \ref blocks "Blocks" +- \ref system_tags "System tags" + +For API browsing, use the navigation tabs above. diff --git a/docs/TODO.md b/docs/TODO.md new file mode 100644 index 00000000..72f315bc --- /dev/null +++ b/docs/TODO.md @@ -0,0 +1,61 @@ +\page todo_page Project TODO + +[TOC] + +This page tracks longer-term technical work that still appears to be open. +Items that already have clear implementations in the current codebase, such as +time-stepping infrastructure, serialization support, reset support, metadata +introspection, and existing collision backends, have been removed from this +list. + +## Bugs To Be Fixed + +- Review open correctness and stability issues discovered during active + development. + +## Memory And Data Layout + +- Revisit block memory kernels for dimension- and system-specific layouts. +- Explore fixed-span block variants with tunable maximum size. +- Explore free-span block variants better suited for BVH-style structures. +- Evaluate movable versus non-movable block storage for spatial hashing and + related data structures. +- Decide whether a global vector of blocks or a different aggregate layout is + the right long-term container strategy. + +## Space Adaptation + +- Add a space-adaptation interface that can operate on aggregates and their + history/state data together. +- Introduce block creation, deletion, split, and merge policies for adaptive + storage. +- Investigate Eulerian tree-based adaptation for fixed blocks. +- Investigate Lagrangian BVH-style adaptation for free blocks. +- Study combined space-time reordering, including occasional memory reordering + for hierarchy- and contact-aware access patterns. + +## Time Integration + +- Add a timestep adapter and timestep chooser strategy for more flexible + integration control. + +## Application UX + +- Design rendering/output customization points with sensible defaults and + object-specific specializations. +- Add a callback model that supports both stateful functors and lightweight + stateless lambdas. + +## Parallelism And Performance + +- Investigate dynamic SIMD backends such as ISPC where they provide a real + benefit. +- Add a NUMA-aware execution/storage layer if the workload justifies it. +- Evaluate whether selective SoA/AoS transformations would improve collision + processing performance. + +## Collision Detection + +- Add a sweep-and-prune broad-phase strategy. +- Add callback hooks for features such as reference counting or time-of-impact + estimation. diff --git a/docs/commands.tex b/docs/commands.tex new file mode 100644 index 00000000..c2e8a1b6 --- /dev/null +++ b/docs/commands.tex @@ -0,0 +1,7 @@ +\newcommand{\gv}[1]{\ensuremath{\mbox{\boldmath$ #1 $}}} +\newcommand{\bv}[1]{\ensuremath{\boldsymbol{#1}}} +\newcommand{\norm}[1]{\left\lVert#1\right\rVert} +\newcommand{\imag}[1]{\mathrm{Im} \left[ #1 \right]} +\newcommand{\RN}[1]{\textup{\uppercase\expandafter{\romannumeral#1}}} +\newcommand{\order}[1]{\mathcal O \left( #1 \right)} +\newcommand{\state}[1]{\gv{#1}} diff --git a/docs/config/MathJax.js b/docs/config/MathJax.js new file mode 100644 index 00000000..bf1fdede --- /dev/null +++ b/docs/config/MathJax.js @@ -0,0 +1,22 @@ +window.MathJax = { + tex: { + tags: "ams", + packages: ['base', 'ams', 'bbox', 'color', 'physics', 'newcommand', + 'boldsymbol'] + }, + options: { + ignoreHtmlClass: 'tex2jax_ignore', + processHtmlClass: 'tex2jax_process' + }, + loader: { + load: ['[tex]/bbox', '[tex]/color', '[tex]/physics', '[tex]/newcommand', + '[tex]/boldsymbol'] + } +}; + +(function () { + var script = document.createElement('script'); + script.src = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js'; + script.async = true; + document.head.appendChild(script); +})(); diff --git a/docs/header.html.in b/docs/header.html.in new file mode 100644 index 00000000..db2f95c3 --- /dev/null +++ b/docs/header.html.in @@ -0,0 +1,66 @@ + + + + + + + + +$projectname: $title +$title + + + + + + + + + + + + +$treeview +$search +$mathjax +$darkmode + +$extrastylesheet + + + + + + + +
+ + +
+ + +
+ + + + + + + + + + + + + +
+
$projectname $projectnumber +
+
+
+ + diff --git a/docs/refs.bib b/docs/refs.bib new file mode 100644 index 00000000..d462f918 --- /dev/null +++ b/docs/refs.bib @@ -0,0 +1,10 @@ +@article{gazzola2018forward, + title = {Forward and inverse problems in the mechanics of soft filaments}, + author = {Gazzola, Mattia and others}, + journal = {Royal Society Open Science}, + year = {2018}, + volume = {5}, + number = {6}, + pages = {171628}, + doi = {10.1098/rsos.171628} +} diff --git a/pyproject.toml b/pyproject.toml index f455f7e1..5f58792f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "elasticapp" -version = "0.0.2" +version = "0.1.0" description = "A performance-oriented C++ simulator for soft-filament dynamics." readme = "README.md" requires-python = ">=3.10" diff --git a/scripts/build/dev.sh b/scripts/build/dev.sh deleted file mode 100755 index 6e34001e..00000000 --- a/scripts/build/dev.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env bash - -declare -A compilers - -# Usage: compilers[compiler_nickname]="/path/to/compiler" -compilers[test]="/usr/bin/clang++" - -declare -A cmake_build_types - -cmake_build_types[debug]="Debug" -# cmake_build_types[release]="Release" -# cmake_build_types[relwithdebuginfo]="RelWithDebInfo" - -declare -A smp_options -smp_options[smp_enabled]="ON" -# smp_options[smp_disabled]="OFF" - -CMAKE="cmake" - -for compiler in "${!compilers[@]}"; do - for cmake_build_type in "${!cmake_build_types[@]}"; do - for smp_option in "${!smp_options[@]}"; do - BUILD_PATH="build_${compiler}_${cmake_build_type}_${smp_option}" - mkdir -p "${BUILD_PATH}" && cd "$_" || exit - CXX=${compilers[$compiler]} - CMAKE_BUILD_TYPE=${cmake_build_types[$cmake_build_type]} - SMP_OPTION=${smp_options[$smp_option]} - ${CMAKE} .. -DCMAKE_CXX_COMPILER="${CXX}" \ - -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" \ - -DBUILD_TESTING=ON \ - -DELASTICA_BUILD_DOCUMENTATION=OFF \ - -DELASTICA_BUILD_EXAMPLES=ON \ - -DELASTICA_BUILD_BENCHMARKS=ON \ - -DELASTICA_BUILD_PYTHON_BINDINGS=ON \ - -DPython_FIND_VIRTUALENV=FIRST \ - -DELASTICA_ENABLE_PROFILING=ON \ - -DELASTICA_SMP="${SMP_OPTION}" \ - -DUSE_SLEEF=OFF \ - -DDEBUG_SYMBOLS=ON \ - -DENABLE_WARNINGS=ON \ - -DASAN=OFF \ - -DUBSAN_UNDEFINED=OFF \ - -DUBSAN_INTEGER=OFF \ - -DPY_DEV_MODE=OFF \ - -DCMAKE_TOOLCHAIN_FILE=${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake - cd .. - done - done -done diff --git a/scripts/format/apply-format b/scripts/format/apply-format deleted file mode 100755 index 6c58a377..00000000 --- a/scripts/format/apply-format +++ /dev/null @@ -1,342 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright 2018 Undo Ltd. -# -# https://github.com/barisione/clang-format-hooks - -# Force variable declaration before access. -set -u -# Make any failure in piped commands be reflected in the exit code. -set -o pipefail - -readonly bash_source="${BASH_SOURCE[0]:-$0}" - -################## -# Misc functions # -################## - -function error_exit() { - for str in "$@"; do - echo -n "$str" >&2 - done - echo >&2 - - exit 1 -} - - -######################## -# Command line parsing # -######################## - -function show_help() { - if [ -t 1 ] && hash tput 2> /dev/null; then - local -r b=$(tput bold) - local -r i=$(tput sitm) - local -r n=$(tput sgr0) - else - local -r b= - local -r i= - local -r n= - fi - - cat << EOF -${b}SYNOPSIS${n} - - To reformat git diffs: - - ${i}$bash_source [OPTIONS] [FILES-OR-GIT-DIFF-OPTIONS]${n} - - To reformat whole files, including unchanged parts: - - ${i}$bash_source [-f | --whole-file] FILES${n} - -${b}DESCRIPTION${n} - - Reformat C or C++ code to match a specified formatting style. - - This command can either work on diffs, to reformat only changed parts of - the code, or on whole files (if -f or --whole-file is used). - - ${b}FILES-OR-GIT-DIFF-OPTIONS${n} - List of files to consider when applying clang-format to a diff. This is - passed to "git diff" as is, so it can also include extra git options or - revisions. - For example, to apply clang-format on the changes made in the last few - revisions you could use: - ${i}\$ $bash_source HEAD~3${n} - - ${b}FILES${n} - List of files to completely reformat. - - ${b}-f, --whole-file${n} - Reformat the specified files completely (including parts you didn't - change). - The fix is printed on stdout by default. Use -i if you want to modify - the files on disk. - - ${b}--staged, --cached${n} - Reformat only code which is staged for commit. - The fix is printed on stdout by default. Use -i if you want to modify - the files on disk. - - ${b}-i${n} - Reformat the code and apply the changes to the files on disk (instead - of just printing the fix on stdout). - - ${b}--apply-to-staged${n} - This is like specifying both --staged and -i, but the formatting - changes are also staged for commit (so you can just use "git commit" - to commit what you planned to, but formatted correctly). - - ${b}--style STYLE${n} - The style to use for reformatting code. - If no style is specified, then it's assumed there's a .clang-format - file in the current directory or one of its parents. - - ${b}--help, -h, -?${n} - Show this help. -EOF -} - -# getopts doesn't support long options. -# getopt mangles stuff. -# So we parse manually... -declare positionals=() -declare has_positionals=false -declare whole_file=false -declare apply_to_staged=false -declare staged=false -declare in_place=false -declare style=file -declare ignored=() -while [ $# -gt 0 ]; do - declare arg="$1" - shift # Past option. - case "$arg" in - -h | -\? | --help ) - show_help - exit 0 - ;; - -f | --whole-file ) - whole_file=true - ;; - --apply-to-staged ) - apply_to_staged=true - ;; - --cached | --staged ) - staged=true - ;; - -i ) - in_place=true - ;; - --style=* ) - style="${arg//--style=/}" - ;; - --style ) - [ $# -gt 0 ] || \ - error_exit "No argument for --style option." - style="$1" - shift - ;; - --internal-opt-ignore-regex=* ) - ignored+=("${arg//--internal-opt-ignore-regex=/}") - ;; - --internal-opt-ignore-regex ) - ignored+=("${arg//--internal-opt-ignore-regex=/}") - [ $# -gt 0 ] || \ - error_exit "No argument for --internal-opt-ignore-regex option." - ignored+=("$1") - shift - ;; - -- ) - # Stop processing further arguments. - if [ $# -gt 0 ]; then - positionals+=("$@") - has_positionals=true - fi - break - ;; - -* ) - error_exit "Unknown argument: $arg" - ;; - *) - positionals+=("$arg") - ;; - esac -done - -# Restore positional arguments, access them from "$@". -if [ ${#positionals[@]} -gt 0 ]; then - set -- "${positionals[@]}" - has_positionals=true -fi - -[ -n "$style" ] || \ - error_exit "If you use --style you need to specify a valid style." - -####################################### -# Detection of clang-format & friends # -####################################### - -# clang-format. -declare format="${CLANG_FORMAT:-}" -if [ -z "$format" ]; then - format=$(type -p clang-format) -fi - -if [ -z "$format" ]; then - error_exit \ - $'You need to install clang-format.\n' \ - $'\n' \ - $'On Ubuntu/Debian this is available in the clang-format package or, in\n' \ - $'older distro versions, clang-format-VERSION.\n' \ - $'On Fedora it\'s available in the clang package.\n' \ - $'You can also specify your own path for clang-format by setting the\n' \ - $'$CLANG_FORMAT environment variable.' -fi - -# clang-format-diff. -if [ "$whole_file" = false ]; then - invalid="/dev/null/invalid/path" - if [ "${OSTYPE:-}" = "linux-gnu" ]; then - readonly sort_version=-V - else - # On macOS, sort doesn't have -V. - readonly sort_version=-n - fi - declare paths_to_try=() - # .deb packages directly from upstream. - # We try these first as they are probably newer than the system ones. - while read -r f; do - paths_to_try+=("$f") - done < <(compgen -G "/usr/share/clang/clang-format-*/clang-format-diff.py" | sort "$sort_version" -r) - # LLVM official releases (just untarred in /usr/local). - while read -r f; do - paths_to_try+=("$f") - done < <(compgen -G "/usr/local/clang+llvm*/share/clang/clang-format-diff.py" | sort "$sort_version" -r) - # Maybe it's in the $PATH already? This is true for Ubuntu and Debian. - paths_to_try+=( \ - "$(type -p clang-format-diff 2> /dev/null || echo "$invalid")" \ - "$(type -p clang-format-diff.py 2> /dev/null || echo "$invalid")" \ - ) - # Fedora. - paths_to_try+=( \ - /usr/share/clang/clang-format-diff.py \ - ) - # Gentoo. - while read -r f; do - paths_to_try+=("$f") - done < <(compgen -G "/usr/lib/llvm/*/share/clang/clang-format-diff.py" | sort -n -r) - # Homebrew. - while read -r f; do - paths_to_try+=("$f") - done < <(compgen -G "/usr/local/Cellar/clang-format/*/share/clang/clang-format-diff.py" | sort -n -r) - - declare format_diff= - - # Did the user specify a path? - if [ -n "${CLANG_FORMAT_DIFF:-}" ]; then - format_diff="$CLANG_FORMAT_DIFF" - else - for path in "${paths_to_try[@]}"; do - if [ -e "$path" ]; then - # Found! - format_diff="$path" - if [ ! -x "$format_diff" ]; then - format_diff="python $format_diff" - fi - break - fi - done - fi - - if [ -z "$format_diff" ]; then - error_exit \ - $'Cannot find clang-format-diff which should be shipped as part of the same\n' \ - $'package where clang-format is.\n' \ - $'\n' \ - $'Please find out where clang-format-diff is in your distro and report an issue\n' \ - $'at https://github.com/barisione/clang-format-hooks/issues with details about\n' \ - $'your operating system and setup.\n' \ - $'\n' \ - $'You can also specify your own path for clang-format-diff by setting the\n' \ - $'$CLANG_FORMAT_DIFF environment variable, for instance:\n' \ - $'\n' \ - $' CLANG_FORMAT_DIFF="python /.../clang-format-diff.py" \\\n' \ - $' ' "$bash_source" - fi - - readonly format_diff -fi - - -############################ -# Actually run the command # -############################ - -if [ "$whole_file" = true ]; then - - [ "$has_positionals" = true ] || \ - error_exit "No files to reformat specified." - [ "$staged" = false ] || \ - error_exit "--staged/--cached only make sense when applying to a diff." - - read -r -a format_args <<< "$format" - format_args+=("-style=file") - [ "$in_place" = true ] && format_args+=("-i") - - "${format_args[@]}" "$@" - -else # Diff-only. - - if [ "$apply_to_staged" = true ]; then - [ "$staged" = false ] || \ - error_exit "You don't need --staged/--cached with --apply-to-staged." - [ "$in_place" = false ] || \ - error_exit "You don't need -i with --apply-to-staged." - staged=true - readonly patch_dest=$(mktemp) - trap '{ rm -f "$patch_dest"; }' EXIT - else - readonly patch_dest=/dev/stdout - fi - - declare git_args=(git diff -U0 --no-color) - [ "$staged" = true ] && git_args+=("--staged") - - # $format_diff may contain a command ("python") and the script to excute, so we - # need to split it. - read -r -a format_diff_args <<< "$format_diff" - [ "$in_place" = true ] && format_diff_args+=("-i") - - # Build the regex for paths to consider or ignore. - # We use negative lookahead assertions which preceed the list of allowed patterns - # (that is, the extensions we want). - exclusions_regex= - if [ "${#ignored[@]}" -gt 0 ]; then - for pattern in "${ignored[@]}"; do - exclusions_regex="$exclusions_regex(?!$pattern)" - done - fi - - "${git_args[@]}" "$@" \ - | "${format_diff_args[@]}" \ - -p1 \ - -style="$style" \ - -iregex="$exclusions_regex"'.*\.(c|cpp|cxx|cc|h|hpp|m|mm|js|java)' \ - > "$patch_dest" \ - || exit 1 - - if [ "$apply_to_staged" = true ]; then - if [ ! -s "$patch_dest" ]; then - echo "No formatting changes to apply." - exit 0 - fi - patch -p0 < "$patch_dest" || \ - error_exit "Cannot apply fix to local files." - git apply -p0 --cached < "$patch_dest" || \ - error_exit "Cannot apply fix to git staged changes." - fi - -fi