Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 57 additions & 38 deletions cmake/SetupDoxygen.cmake
Original file line number Diff line number Diff line change
@@ -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}")
177 changes: 177 additions & 0 deletions docs/CoreConcepts.md
Original file line number Diff line number Diff line change
@@ -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<tmpl::list<CosseratRod>>(
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<CosseratRod>(
straight_initializer.initialize<CosseratRod>());
\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<CosseratRod>(
initializer.initialize<CosseratRod>(
::blocks::initialize<::elastica::tags::Velocity>(
[](std::size_t index) {
return 0.1 + 0.002 * static_cast<double>(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<CosseratRod>(
initializer.initialize<CosseratRod>());

// 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`)
26 changes: 15 additions & 11 deletions docs/Doxyfile.in
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ 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 \
*.md
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
Expand All @@ -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@"

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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 =
Loading
Loading