From 4a14fadd410c228c01ffef3a5c809492db9c6af9 Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Sat, 7 Mar 2026 15:42:35 +0900 Subject: [PATCH 01/39] Add magnetohydrodynamics cpp-hlld benchmark scaffold --- benchmarks/magnetohydrodynamics/README.md | 15 + .../magnetohydrodynamics/cpp-hlld/eval/run.sh | 27 ++ .../cpp-hlld/eval/tests/cpp/test_hidden.cpp | 135 ++++++ .../cpp-hlld/eval/tests/test_hidden.py | 36 ++ .../magnetohydrodynamics/cpp-hlld/spec.md | 36 ++ .../magnetohydrodynamics/cpp-hlld/task.toml | 7 + .../cpp-hlld/workspace/CMakeLists.txt | 69 +++ .../cpp-hlld/workspace/pyproject.toml | 7 + .../cpp-hlld/workspace/src/hlld.cpp | 31 ++ .../cpp-hlld/workspace/src/hlld.hpp | 13 + .../workspace/tests/cpp/test_public.cpp | 121 +++++ .../cpp-hlld/workspace/tests/test_public.py | 24 + .../shared/eval/README.md | 3 + .../shared/workspace/basic_equations.md | 139 ++++++ .../shared/workspace/hlld.md | 416 ++++++++++++++++++ 15 files changed, 1079 insertions(+) create mode 100644 benchmarks/magnetohydrodynamics/README.md create mode 100755 benchmarks/magnetohydrodynamics/cpp-hlld/eval/run.sh create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/test_hidden.cpp create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/test_hidden.py create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld/spec.md create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld/task.toml create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld/workspace/CMakeLists.txt create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld/workspace/pyproject.toml create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.cpp create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.hpp create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/cpp/test_public.cpp create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/test_public.py create mode 100644 benchmarks/magnetohydrodynamics/shared/eval/README.md create mode 100644 benchmarks/magnetohydrodynamics/shared/workspace/basic_equations.md create mode 100644 benchmarks/magnetohydrodynamics/shared/workspace/hlld.md diff --git a/benchmarks/magnetohydrodynamics/README.md b/benchmarks/magnetohydrodynamics/README.md new file mode 100644 index 0000000..79baee8 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/README.md @@ -0,0 +1,15 @@ +# Magnetohydrodynamics Benchmarks + +This suite contains benchmark tasks for ideal magnetohydrodynamics solvers. + +## Directory layout + +- `shared/workspace/basic_equations.md`: suite-wide notation and flux conventions. +- `shared/workspace/hlld.md`: HLLD algorithm notes for solver tasks. +- `cpp-hlld/`: C++ HLLD approximate Riemann solver task. + +## Notes + +- Shared workspace files are visible to the agent during benchmark runs. +- Keep maintainer-only derivations, generators, and hidden fixtures outside the + shared workspace. diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/eval/run.sh b/benchmarks/magnetohydrodynamics/cpp-hlld/eval/run.sh new file mode 100755 index 0000000..c95929f --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/eval/run.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -u -o pipefail + +cd /work + +status="passed" +score="1.0" + +python3 -m pytest -q /eval/tests +rc=$? +if [ "$rc" -ne 0 ]; then + status="failed" + score="0.0" +fi + +python3 - <) +#include +#else +#include "/usr/local/include/catch2/catch_test_macros.hpp" +#endif + +#include + +namespace +{ + +constexpr double kTolerance = 1e-12; + +ConservativeState primitive_to_conservative(const PrimitiveState& state, double bx, double gamma) +{ + const double rho = state[0]; + const double u = state[1]; + const double v = state[2]; + const double w = state[3]; + const double p = state[4]; + const double by = state[5]; + const double bz = state[6]; + + const double kinetic = 0.5 * rho * (u * u + v * v + w * w); + const double magnetic = 0.5 * (bx * bx + by * by + bz * bz); + const double energy = p / (gamma - 1.0) + kinetic + magnetic; + + return ConservativeState{ + rho, rho * u, rho * v, rho * w, energy, by, bz, + }; +} + +FluxState physical_flux_x(const ConservativeState& state, double bx, double gamma) +{ + const double rho = state[0]; + const double mx = state[1]; + const double my = state[2]; + const double mz = state[3]; + const double energy = state[4]; + const double by = state[5]; + const double bz = state[6]; + + const double u = mx / rho; + const double v = my / rho; + const double w = mz / rho; + const double kinetic = 0.5 * rho * (u * u + v * v + w * w); + const double magnetic = 0.5 * (bx * bx + by * by + bz * bz); + const double pressure = (gamma - 1.0) * (energy - kinetic - magnetic); + const double total_pressure = pressure + magnetic; + + return FluxState{ + rho * u, + rho * u * u + total_pressure - bx * bx, + rho * v * u - bx * by, + rho * w * u - bx * bz, + (energy + total_pressure) * u - bx * (u * bx + v * by + w * bz), + by * u - bx * v, + bz * u - bx * w, + }; +} + +void require_close(const FluxState& actual, const FluxState& expected) +{ + for (std::size_t i = 0; i < actual.size(); ++i) { + REQUIRE(std::abs(actual[i] - expected[i]) <= kTolerance); + } +} + +} // namespace + +TEST_CASE("equal conservative states reduce to the physical flux") +{ + const double bx = 0.35; + const double gamma = 1.4; + const PrimitiveState primitive{0.9, -0.45, 0.2, 0.15, 0.8, -0.3, 0.55}; + const ConservativeState state = primitive_to_conservative(primitive, bx, gamma); + + const FluxState actual = hlld_flux_from_conservative(state, state, bx, gamma); + const FluxState expected = physical_flux_x(state, bx, gamma); + + require_close(actual, expected); +} + +TEST_CASE("nontrivial primitive solve returns finite values") +{ + const double bx = -0.65; + const double gamma = 5.0 / 3.0; + + const PrimitiveState left{1.08, 0.45, -0.12, 0.08, 0.95, 0.4, -0.3}; + const PrimitiveState right{0.72, -0.25, 0.16, -0.05, 0.58, -0.2, 0.35}; + + const FluxState flux = hlld_flux_from_primitive(left, right, bx, gamma); + + for (double value : flux) { + REQUIRE(std::isfinite(value)); + } +} + +TEST_CASE("hidden reference flux case 1 matches expected HLLD result") +{ + const double bx = -0.65; + const double gamma = 5.0 / 3.0; + + const PrimitiveState left{1.08, 0.45, -0.12, 0.08, 0.95, 0.4, -0.3}; + const PrimitiveState right{0.72, -0.25, 0.16, -0.05, 0.58, -0.2, 0.35}; + const FluxState expected{ + 0.3324233585009154, 1.3204052114557712, 0.06638064166463348, -0.022436684783467387, + 0.7427148869798962, 0.20070323090296055, -0.18527478786984644, + }; + + const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("hidden reference flux case 2 matches expected HLLD result") +{ + const double bx = 0.35; + const double gamma = 1.4; + + const PrimitiveState left{0.9, -0.45, 0.2, 0.15, 0.8, -0.3, 0.55}; + const PrimitiveState right{1.15, 0.18, -0.12, -0.08, 1.05, 0.22, -0.4}; + const FluxState expected{ + -0.15164205717520077, 0.6302921311068539, 0.025882982020760857, 0.06707828676255045, + -0.35658597023319155, -0.06350044448634364, 0.14687345745300118, + }; + + const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/test_hidden.py b/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/test_hidden.py new file mode 100644 index 0000000..2f5ae82 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/test_hidden.py @@ -0,0 +1,36 @@ +import subprocess +from pathlib import Path + + +def _build_hidden_tests() -> Path: + hidden_source = Path("/eval/tests/cpp/test_hidden.cpp") + subprocess.run( + [ + "cmake", + "-S", + ".", + "-B", + "build", + "-DSCIBENCH_ENABLE_HIDDEN_TESTS=ON", + f"-DSCIBENCH_HIDDEN_TEST_SOURCE={hidden_source}", + ], + check=True, + ) + subprocess.run( + ["cmake", "--build", "build", "--target", "hlld_hidden_tests"], check=True + ) + exe = Path("build/tests/hlld_hidden_tests") + assert exe.exists() + return exe + + +def test_hidden_catch2_suite() -> None: + exe = _build_hidden_tests() + proc = subprocess.run( + [str(exe), "--reporter", "compact"], + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + check=False, + ) + assert proc.returncode == 0, proc.stdout + proc.stderr diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/spec.md b/benchmarks/magnetohydrodynamics/cpp-hlld/spec.md new file mode 100644 index 0000000..aaa8704 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/spec.md @@ -0,0 +1,36 @@ +# cpp-hlld + +Implement the HLLD approximate Riemann solver for 1D ideal MHD in C++. + +## Read first + +- `/work/basic_equations.md` +- `/work/hlld.md` + +## Task + +Edit `src/hlld.cpp` so that these functions are implemented correctly: + +- `hlld_flux_from_primitive(...)` +- `hlld_flux_from_conservative(...)` + +The benchmark uses: + +- primitive-state ordering: `[rho, u, v, w, p, By, Bz]` +- conservative-state ordering: `[rho, mx, my, mz, E, By, Bz]` +- flux ordering: `[F_rho, F_mx, F_my, F_mz, F_E, F_By, F_Bz]` +- Lorentz-Heaviside units +- `Bx` passed separately from the state vectors + +Do not change the public function signatures in `src/hlld.hpp`. + +## Standards + +- C++17 +- Use `std::array` for the public API + +## Local dev + +```bash +pytest -q +``` diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/task.toml b/benchmarks/magnetohydrodynamics/cpp-hlld/task.toml new file mode 100644 index 0000000..4f60d04 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/task.toml @@ -0,0 +1,7 @@ +id = "cpp-hlld" +suite = "magnetohydrodynamics" +language = "cpp" +time_limit_sec = 300 +eval_cmd = "/eval/run.sh" +prompt = "Read /run/spec.md, /work/basic_equations.md, and /work/hlld.md, then solve the task in /work." +use_shared_workspace = true diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/CMakeLists.txt b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/CMakeLists.txt new file mode 100644 index 0000000..0ca3a2e --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/CMakeLists.txt @@ -0,0 +1,69 @@ +cmake_minimum_required(VERSION 3.16) + +project(cpp_hlld LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +include(FetchContent) + +option(SCIBENCH_ENABLE_HIDDEN_TESTS "Build hidden Catch2 tests" OFF) +set( + SCIBENCH_HIDDEN_TEST_SOURCE + "" + CACHE FILEPATH + "Path to hidden Catch2 test source" +) + +find_package(Catch2 3 QUIET) + +if(NOT Catch2_FOUND) + FetchContent_Declare( + Catch2 + GIT_REPOSITORY https://github.com/catchorg/Catch2.git + GIT_TAG v3.13.0 + GIT_SHALLOW TRUE + ) + FetchContent_MakeAvailable(Catch2) +endif() + +add_library(hlld_solver + src/hlld.cpp +) + +target_include_directories(hlld_solver PUBLIC + src +) + +add_executable(hlld_public_tests + tests/cpp/test_public.cpp +) + +target_link_libraries(hlld_public_tests PRIVATE + hlld_solver + Catch2::Catch2WithMain +) + +set_target_properties(hlld_public_tests PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests" +) + +if(SCIBENCH_ENABLE_HIDDEN_TESTS) + if(NOT EXISTS "${SCIBENCH_HIDDEN_TEST_SOURCE}") + message(FATAL_ERROR "Hidden test source not found: ${SCIBENCH_HIDDEN_TEST_SOURCE}") + endif() + + add_executable(hlld_hidden_tests + "${SCIBENCH_HIDDEN_TEST_SOURCE}" + ) + + target_link_libraries(hlld_hidden_tests PRIVATE + hlld_solver + Catch2::Catch2WithMain + ) + + set_target_properties(hlld_hidden_tests PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests" + ) +endif() diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/pyproject.toml b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/pyproject.toml new file mode 100644 index 0000000..66bd2af --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/pyproject.toml @@ -0,0 +1,7 @@ +[project] +name = "magnetohydrodynamics-cpp-hlld" +version = "0.0.0" +requires-python = ">=3.10" + +[tool.pytest.ini_options] +testpaths = ["tests"] diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.cpp b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.cpp new file mode 100644 index 0000000..b5698a6 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.cpp @@ -0,0 +1,31 @@ +#include "hlld.hpp" + +namespace +{ + +FluxState zero_flux() +{ + return FluxState{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; +} + +} // namespace + +FluxState hlld_flux_from_primitive(const PrimitiveState& left, const PrimitiveState& right, + double bx, double gamma) +{ + (void)left; + (void)right; + (void)bx; + (void)gamma; + return zero_flux(); +} + +FluxState hlld_flux_from_conservative(const ConservativeState& left, const ConservativeState& right, + double bx, double gamma) +{ + (void)left; + (void)right; + (void)bx; + (void)gamma; + return zero_flux(); +} diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.hpp b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.hpp new file mode 100644 index 0000000..a5640cb --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include + +using PrimitiveState = std::array; +using ConservativeState = std::array; +using FluxState = std::array; + +FluxState hlld_flux_from_primitive(const PrimitiveState& left, const PrimitiveState& right, + double bx, double gamma); + +FluxState hlld_flux_from_conservative(const ConservativeState& left, const ConservativeState& right, + double bx, double gamma); diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/cpp/test_public.cpp b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/cpp/test_public.cpp new file mode 100644 index 0000000..f97af36 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/cpp/test_public.cpp @@ -0,0 +1,121 @@ +#if __has_include("hlld.hpp") +#include "hlld.hpp" +#else +#include "../../src/hlld.hpp" +#endif + +#if __has_include() +#include +#else +#include "/usr/local/include/catch2/catch_test_macros.hpp" +#endif + +#include + +namespace +{ + +constexpr double kTolerance = 1e-12; + +ConservativeState primitive_to_conservative(const PrimitiveState& state, double bx, double gamma) +{ + const double rho = state[0]; + const double u = state[1]; + const double v = state[2]; + const double w = state[3]; + const double p = state[4]; + const double by = state[5]; + const double bz = state[6]; + + const double kinetic = 0.5 * rho * (u * u + v * v + w * w); + const double magnetic = 0.5 * (bx * bx + by * by + bz * bz); + const double energy = p / (gamma - 1.0) + kinetic + magnetic; + + return ConservativeState{ + rho, rho * u, rho * v, rho * w, energy, by, bz, + }; +} + +FluxState physical_flux_x(const ConservativeState& state, double bx, double gamma) +{ + const double rho = state[0]; + const double mx = state[1]; + const double my = state[2]; + const double mz = state[3]; + const double energy = state[4]; + const double by = state[5]; + const double bz = state[6]; + + const double u = mx / rho; + const double v = my / rho; + const double w = mz / rho; + const double kinetic = 0.5 * rho * (u * u + v * v + w * w); + const double magnetic = 0.5 * (bx * bx + by * by + bz * bz); + const double pressure = (gamma - 1.0) * (energy - kinetic - magnetic); + const double total_pressure = pressure + magnetic; + + return FluxState{ + rho * u, + rho * u * u + total_pressure - bx * bx, + rho * v * u - bx * by, + rho * w * u - bx * bz, + (energy + total_pressure) * u - bx * (u * bx + v * by + w * bz), + by * u - bx * v, + bz * u - bx * w, + }; +} + +void require_close(const FluxState& actual, const FluxState& expected) +{ + for (std::size_t i = 0; i < actual.size(); ++i) { + REQUIRE(std::abs(actual[i] - expected[i]) <= kTolerance); + } +} + +} // namespace + +TEST_CASE("equal primitive states reduce to the physical flux") +{ + const double bx = 0.75; + const double gamma = 1.4; + const PrimitiveState state{1.1, 0.2, -0.3, 0.4, 0.9, 0.5, -0.6}; + const ConservativeState conservative = primitive_to_conservative(state, bx, gamma); + + const FluxState actual = hlld_flux_from_primitive(state, state, bx, gamma); + const FluxState expected = physical_flux_x(conservative, bx, gamma); + + require_close(actual, expected); +} + +TEST_CASE("primitive and conservative entry points agree") +{ + const double bx = -0.4; + const double gamma = 5.0 / 3.0; + + const PrimitiveState left{1.0, 0.3, 0.1, -0.2, 1.0, 0.7, -0.5}; + const PrimitiveState right{0.8, -0.1, -0.4, 0.25, 0.7, -0.2, 0.3}; + + const ConservativeState left_cons = primitive_to_conservative(left, bx, gamma); + const ConservativeState right_cons = primitive_to_conservative(right, bx, gamma); + + const FluxState from_primitive = hlld_flux_from_primitive(left, right, bx, gamma); + const FluxState from_conservative = hlld_flux_from_conservative(left_cons, right_cons, bx, gamma); + + require_close(from_primitive, from_conservative); +} + +TEST_CASE("nontrivial public reference flux matches expected HLLD result") +{ + const double bx = 0.75; + const double gamma = 1.4; + + const PrimitiveState left{1.0, 0.3, 0.1, -0.2, 1.0, 0.7, -0.5}; + const PrimitiveState right{0.8, -0.1, -0.4, 0.25, 0.7, -0.2, 0.3}; + const FluxState expected{ + 0.2959755324688338, 1.1841244172856562, -0.17006720148138638, 0.020437274707554964, + 1.1895179713786177, 0.4579156493939873, -0.29354464377682116, + }; + + const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/test_public.py b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/test_public.py new file mode 100644 index 0000000..69b5cfa --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/test_public.py @@ -0,0 +1,24 @@ +import subprocess +from pathlib import Path + + +def _build_public_tests() -> Path: + subprocess.run(["cmake", "-S", ".", "-B", "build"], check=True) + subprocess.run( + ["cmake", "--build", "build", "--target", "hlld_public_tests"], check=True + ) + exe = Path("build/tests/hlld_public_tests") + assert exe.exists() + return exe + + +def test_catch2_public_suite() -> None: + exe = _build_public_tests() + proc = subprocess.run( + [str(exe), "--reporter", "compact"], + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + check=False, + ) + assert proc.returncode == 0, proc.stdout + proc.stderr diff --git a/benchmarks/magnetohydrodynamics/shared/eval/README.md b/benchmarks/magnetohydrodynamics/shared/eval/README.md new file mode 100644 index 0000000..9216b9f --- /dev/null +++ b/benchmarks/magnetohydrodynamics/shared/eval/README.md @@ -0,0 +1,3 @@ +# Shared eval assets + +This directory is reserved for future suite-wide hidden-eval helpers. diff --git a/benchmarks/magnetohydrodynamics/shared/workspace/basic_equations.md b/benchmarks/magnetohydrodynamics/shared/workspace/basic_equations.md new file mode 100644 index 0000000..7bca609 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/shared/workspace/basic_equations.md @@ -0,0 +1,139 @@ +# Ideal MHD Equations + +Below we summarize the ideal magnetohydrodynamics (MHD) equations in 1D along the x direction. +The normal magnetic field $B_x$ is constant and can be separated from the 7-component state vectors. +Multidimensional extensions are straightforward and are not discussed here. + +## Units and conventions + +We use Lorentz-Heaviside units, so no explicit $4\pi$ or $\mu_0$ factors appear. + +## Primitive variables + +The primitive-state ordering in this suite is + +```math +\mathbf{W} = +\begin{bmatrix} +\rho & u & v & w & p & B_y & B_z +\end{bmatrix}^{\mathsf T}. +``` + +## Conservative variables + +The conservative-state ordering in this suite is + +```math +\mathbf{U} = +\begin{bmatrix} +\rho & m_x & m_y & m_z & E & B_y & B_z +\end{bmatrix}^{\mathsf T}, +``` + +where + +```math +m_x = \rho u, +\qquad +m_y = \rho v, +\qquad +m_z = \rho w. +``` + +## Equation of state and derived quantities + +We use an ideal-gas equation of state with ratio of specific heats $\gamma$. + +The total energy density is + +```math +E = +\frac{p}{\gamma - 1} ++ \frac{1}{2}\rho\left(u^2 + v^2 + w^2\right) ++ \frac{1}{2}\left(B_x^2 + B_y^2 + B_z^2\right). +``` + +Given a conservative state, the gas pressure is recovered as + +```math +p = +(\gamma - 1) +\left[ +E +- \frac{1}{2}\rho\left(u^2 + v^2 + w^2\right) +- \frac{1}{2}\left(B_x^2 + B_y^2 + B_z^2\right) +\right]. +``` + +The total pressure is + +```math +p_T = p + \frac{1}{2}\left(B_x^2 + B_y^2 + B_z^2\right). +``` + +## Physical flux in the x direction + +For the conservative state + +```math +\mathbf{U} = +\begin{bmatrix} +\rho & m_x & m_y & m_z & E & B_y & B_z +\end{bmatrix}^{\mathsf T}, +``` + +with + +```math +u = \frac{m_x}{\rho}, +\qquad +v = \frac{m_y}{\rho}, +\qquad +w = \frac{m_z}{\rho}, +``` + +the physical $x$-flux is + +```math +\mathbf{F}_x(\mathbf{U}) = +\begin{bmatrix} +\rho u \\ +\rho u^2 + p_T - B_x^2 \\ +\rho v u - B_x B_y \\ +\rho w u - B_x B_z \\ +(E + p_T)u - B_x(u B_x + v B_y + w B_z) \\ +B_y u - B_x v \\ +B_z u - B_x w +\end{bmatrix}. +``` + +## Fast magnetosonic speed + +Define + +```math +a^2 = \frac{\gamma p}{\rho}, +\qquad +b_x^2 = \frac{B_x^2}{\rho}, +\qquad +b_t^2 = \frac{B_y^2 + B_z^2}{\rho}, +\qquad +b^2 = b_x^2 + b_t^2. +``` + +Then the fast magnetosonic speed in the $x$ direction is + +```math +c_f^2 = +\frac{1}{2} +\left[ +a^2 + b^2 + +\sqrt{\left(a^2 + b^2\right)^2 - 4 a^2 b_x^2} +\right]. +``` + +Use + +```math +c_f = \sqrt{c_f^2}. +``` diff --git a/benchmarks/magnetohydrodynamics/shared/workspace/hlld.md b/benchmarks/magnetohydrodynamics/shared/workspace/hlld.md new file mode 100644 index 0000000..082a2bf --- /dev/null +++ b/benchmarks/magnetohydrodynamics/shared/workspace/hlld.md @@ -0,0 +1,416 @@ +# HLLD Riemann Solver Algorithm + +This note documents the HLLD approximate Riemann solver used in this suite. +It focuses on the implementation formulas and branch structure. + +## Wave structure + +For left and right states $L$ and $R$, the HLLD fan uses five waves: + +```math +S_L, +\qquad +S_L^\ast, +\qquad +S_M, +\qquad +S_R^\ast, +\qquad +S_R. +``` + +These waves separate four intermediate states: + +```math +\mathbf{U}_L^\ast, +\qquad +\mathbf{U}_L^{\ast\ast}, +\qquad +\mathbf{U}_R^{\ast\ast}, +\qquad +\mathbf{U}_R^\ast. +``` + +Within the HLLD fan, the normal velocity and total pressure are assumed +constant: + +```math +u^\ast = S_M, +\qquad +p_T^\ast = \text{constant}. +``` + +## Outer wave speeds + +Use the standard HLL estimate + +```math +S_L = \min(u_L - c_{f,L},\, u_R - c_{f,R}), +\qquad +S_R = \max(u_L + c_{f,L},\, u_R + c_{f,R}). +``` + +If + +```math +0 \le S_L, +``` + +return the left physical flux. +If + +```math +S_R \le 0, +``` + +return the right physical flux. + +## Contact speed and total pressure + +The contact-wave speed is + +```math +S_M = +\frac{ +(S_R-u_R)\rho_R u_R - (S_L-u_L)\rho_L u_L - p_{T,R} + p_{T,L} +}{ +(S_R-u_R)\rho_R - (S_L-u_L)\rho_L +}. +``` + +The common total pressure in the star region is + +```math +p_T^\ast += +p_{T,L} + \rho_L (S_L-u_L)(S_M-u_L) += +p_{T,R} + \rho_R (S_R-u_R)(S_M-u_R). +``` + +## Single-star states + +For $\alpha \in \{L,R\}$, define + +```math +\rho_\alpha^\ast += +\rho_\alpha +\frac{S_\alpha-u_\alpha}{S_\alpha-S_M}. +``` + +Also define the denominator + +```math +D_\alpha = +\rho_\alpha (S_\alpha-u_\alpha)(S_\alpha-S_M) - B_x^2. +``` + +Then the transverse velocity components are + +```math +v_\alpha^\ast += +v_\alpha +- +B_x B_{y,\alpha} +\frac{S_M-u_\alpha}{D_\alpha}, +``` + +```math +w_\alpha^\ast += +w_\alpha +- +B_x B_{z,\alpha} +\frac{S_M-u_\alpha}{D_\alpha}, +``` + +and the transverse magnetic-field components are + +```math +B_{y,\alpha}^\ast += +B_{y,\alpha} +\frac{\rho_\alpha (S_\alpha-u_\alpha)^2 - B_x^2}{D_\alpha}, +``` + +```math +B_{z,\alpha}^\ast += +B_{z,\alpha} +\frac{\rho_\alpha (S_\alpha-u_\alpha)^2 - B_x^2}{D_\alpha}. +``` + +The normal momentum in the star state is + +```math +m_{x,\alpha}^\ast = \rho_\alpha^\ast S_M, +``` + +and the transverse momenta are + +```math +m_{y,\alpha}^\ast = \rho_\alpha^\ast v_\alpha^\ast, +\qquad +m_{z,\alpha}^\ast = \rho_\alpha^\ast w_\alpha^\ast. +``` + +The star-region energy is + +```math +E_\alpha^\ast += +\frac{ +(S_\alpha-u_\alpha)E_\alpha +- p_{T,\alpha} u_\alpha ++ p_T^\ast S_M ++ B_x\left( +\mathbf{v}_\alpha\cdot\mathbf{B}_\alpha +- +\mathbf{v}_\alpha^\ast\cdot\mathbf{B}_\alpha^\ast +\right) +}{ +S_\alpha-S_M +}, +``` + +where + +```math +\mathbf{v}_\alpha = (u_\alpha, v_\alpha, w_\alpha), +\qquad +\mathbf{B}_\alpha = (B_x, B_{y,\alpha}, B_{z,\alpha}). +``` + +For the starred-state dot product in the energy formula, use + +```math +\mathbf{v}_\alpha^\ast = (S_M, v_\alpha^\ast, w_\alpha^\ast), +\qquad +\mathbf{B}_\alpha^\ast = (B_x, B_{y,\alpha}^\ast, B_{z,\alpha}^\ast). +``` + +So the full conservative single-star state is + +```math +\mathbf{U}_\alpha^\ast = +\begin{bmatrix} +\rho_\alpha^\ast \\ +\rho_\alpha^\ast S_M \\ +\rho_\alpha^\ast v_\alpha^\ast \\ +\rho_\alpha^\ast w_\alpha^\ast \\ +E_\alpha^\ast \\ +B_{y,\alpha}^\ast \\ +B_{z,\alpha}^\ast +\end{bmatrix}. +``` + +## Double-star states + +The rotational-wave speeds are + +```math +S_L^\ast = S_M - \frac{|B_x|}{\sqrt{\rho_L^\ast}}, +\qquad +S_R^\ast = S_M + \frac{|B_x|}{\sqrt{\rho_R^\ast}}. +``` + +The density and normal momentum are unchanged across the rotational waves: + +```math +\rho_L^{\ast\ast} = \rho_L^\ast, +\qquad +\rho_R^{\ast\ast} = \rho_R^\ast, +``` + +```math +m_{x,L}^{\ast\ast} = \rho_L^\ast S_M, +\qquad +m_{x,R}^{\ast\ast} = \rho_R^\ast S_M. +``` + +The transverse velocity and magnetic field are shared across the contact: + +```math +v_L^{\ast\ast} = v_R^{\ast\ast} \equiv v^{\ast\ast}, +\qquad +w_L^{\ast\ast} = w_R^{\ast\ast} \equiv w^{\ast\ast}, +``` + +```math +B_{y,L}^{\ast\ast} = B_{y,R}^{\ast\ast} \equiv B_y^{\ast\ast}, +\qquad +B_{z,L}^{\ast\ast} = B_{z,R}^{\ast\ast} \equiv B_z^{\ast\ast}. +``` + +Use + +```math +v^{\ast\ast} += +\frac{ +\sqrt{\rho_L^\ast} v_L^\ast ++ +\sqrt{\rho_R^\ast} v_R^\ast ++ +(B_{y,R}^\ast - B_{y,L}^\ast)\operatorname{sgn}(B_x) +}{ +\sqrt{\rho_L^\ast} + \sqrt{\rho_R^\ast} +}, +``` + +```math +w^{\ast\ast} += +\frac{ +\sqrt{\rho_L^\ast} w_L^\ast ++ +\sqrt{\rho_R^\ast} w_R^\ast ++ +(B_{z,R}^\ast - B_{z,L}^\ast)\operatorname{sgn}(B_x) +}{ +\sqrt{\rho_L^\ast} + \sqrt{\rho_R^\ast} +}, +``` + +```math +B_y^{\ast\ast} += +\frac{ +\sqrt{\rho_L^\ast} B_{y,R}^\ast ++ +\sqrt{\rho_R^\ast} B_{y,L}^\ast ++ +\sqrt{\rho_L^\ast\rho_R^\ast}(v_R^\ast - v_L^\ast)\operatorname{sgn}(B_x) +}{ +\sqrt{\rho_L^\ast} + \sqrt{\rho_R^\ast} +}, +``` + +```math +B_z^{\ast\ast} += +\frac{ +\sqrt{\rho_L^\ast} B_{z,R}^\ast ++ +\sqrt{\rho_R^\ast} B_{z,L}^\ast ++ +\sqrt{\rho_L^\ast\rho_R^\ast}(w_R^\ast - w_L^\ast)\operatorname{sgn}(B_x) +}{ +\sqrt{\rho_L^\ast} + \sqrt{\rho_R^\ast} +}. +``` + +The double-star energies are + +```math +E_L^{\ast\ast} += +E_L^\ast +- +\sqrt{\rho_L^\ast} +\left( +\mathbf{v}_L^\ast\cdot\mathbf{B}_L^\ast +- +\mathbf{v}^{\ast\ast}\cdot\mathbf{B}^{\ast\ast} +\right)\operatorname{sgn}(B_x), +``` + +```math +E_R^{\ast\ast} += +E_R^\ast ++ +\sqrt{\rho_R^\ast} +\left( +\mathbf{v}_R^\ast\cdot\mathbf{B}_R^\ast +- +\mathbf{v}^{\ast\ast}\cdot\mathbf{B}^{\ast\ast} +\right)\operatorname{sgn}(B_x). +``` + +Here + +```math +\mathbf{v}^{\ast\ast} = (S_M, v^{\ast\ast}, w^{\ast\ast}), +\qquad +\mathbf{B}^{\ast\ast} = (B_x, B_y^{\ast\ast}, B_z^{\ast\ast}). +``` + +The double-star conservative states are therefore + +```math +\mathbf{U}_L^{\ast\ast} = +\begin{bmatrix} +\rho_L^\ast \\ +\rho_L^\ast S_M \\ +\rho_L^\ast v^{\ast\ast} \\ +\rho_L^\ast w^{\ast\ast} \\ +E_L^{\ast\ast} \\ +B_y^{\ast\ast} \\ +B_z^{\ast\ast} +\end{bmatrix}, +\qquad +\mathbf{U}_R^{\ast\ast} = +\begin{bmatrix} +\rho_R^\ast \\ +\rho_R^\ast S_M \\ +\rho_R^\ast v^{\ast\ast} \\ +\rho_R^\ast w^{\ast\ast} \\ +E_R^{\ast\ast} \\ +B_y^{\ast\ast} \\ +B_z^{\ast\ast} +\end{bmatrix}. +``` + +## Fluxes for intermediate states + +For any wave speed $S$ and corresponding state $\mathbf{U}$ reached from side +state $\mathbf{U}_0$ with physical flux $\mathbf{F}_0$, the Rankine-Hugoniot +flux update is + +```math +\mathbf{F} = \mathbf{F}_0 + S(\mathbf{U} - \mathbf{U}_0). +``` + +In particular, + +```math +\mathbf{F}_L^\ast = \mathbf{F}_L + S_L(\mathbf{U}_L^\ast - \mathbf{U}_L), +\qquad +\mathbf{F}_R^\ast = \mathbf{F}_R + S_R(\mathbf{U}_R^\ast - \mathbf{U}_R), +``` + +```math +\mathbf{F}_L^{\ast\ast} = \mathbf{F}_L^\ast + S_L^\ast(\mathbf{U}_L^{\ast\ast} - \mathbf{U}_L^\ast), +\qquad +\mathbf{F}_R^{\ast\ast} = \mathbf{F}_R^\ast + S_R^\ast(\mathbf{U}_R^{\ast\ast} - \mathbf{U}_R^\ast). +``` + +## Flux selection + +After constructing all intermediate states, choose the interface flux according +to the location of zero in the wave fan: + +```math +\mathbf{F}^\ast = +\begin{cases} +\mathbf{F}_L, & 0 \le S_L, \\ +\mathbf{F}_L^\ast, & S_L \le 0 \le S_L^\ast, \\ +\mathbf{F}_L^{\ast\ast}, & S_L^\ast \le 0 \le S_M, \\ +\mathbf{F}_R^{\ast\ast}, & S_M \le 0 \le S_R^\ast, \\ +\mathbf{F}_R^\ast, & S_R^\ast \le 0 \le S_R, \\ +\mathbf{F}_R, & S_R \le 0. +\end{cases} +``` + +All fluxes use the conservative component ordering defined in +`basic_equations.md`. + +## Robustness expectations + +- Assume all benchmark inputs are admissible physical states. +- Keep arithmetic finite and deterministic on the benchmark cases. +- The primitive-state entry point and conservative-state entry point should + return the same numerical flux for equivalent left/right states. From 9d80fb75fa3e0c7521472207c3b513c00a4875ac Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Sat, 7 Mar 2026 15:46:13 +0900 Subject: [PATCH 02/39] Fix GitHub math rendering in HLLD doc --- .../magnetohydrodynamics/shared/workspace/hlld.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/benchmarks/magnetohydrodynamics/shared/workspace/hlld.md b/benchmarks/magnetohydrodynamics/shared/workspace/hlld.md index 082a2bf..2cf4b4d 100644 --- a/benchmarks/magnetohydrodynamics/shared/workspace/hlld.md +++ b/benchmarks/magnetohydrodynamics/shared/workspace/hlld.md @@ -254,7 +254,7 @@ v^{\ast\ast} + \sqrt{\rho_R^\ast} v_R^\ast + -(B_{y,R}^\ast - B_{y,L}^\ast)\operatorname{sgn}(B_x) +(B_{y,R}^\ast - B_{y,L}^\ast)\mathrm{sgn}(B_x) }{ \sqrt{\rho_L^\ast} + \sqrt{\rho_R^\ast} }, @@ -268,7 +268,7 @@ w^{\ast\ast} + \sqrt{\rho_R^\ast} w_R^\ast + -(B_{z,R}^\ast - B_{z,L}^\ast)\operatorname{sgn}(B_x) +(B_{z,R}^\ast - B_{z,L}^\ast)\mathrm{sgn}(B_x) }{ \sqrt{\rho_L^\ast} + \sqrt{\rho_R^\ast} }, @@ -282,7 +282,7 @@ B_y^{\ast\ast} + \sqrt{\rho_R^\ast} B_{y,L}^\ast + -\sqrt{\rho_L^\ast\rho_R^\ast}(v_R^\ast - v_L^\ast)\operatorname{sgn}(B_x) +\sqrt{\rho_L^\ast\rho_R^\ast}(v_R^\ast - v_L^\ast)\mathrm{sgn}(B_x) }{ \sqrt{\rho_L^\ast} + \sqrt{\rho_R^\ast} }, @@ -296,7 +296,7 @@ B_z^{\ast\ast} + \sqrt{\rho_R^\ast} B_{z,L}^\ast + -\sqrt{\rho_L^\ast\rho_R^\ast}(w_R^\ast - w_L^\ast)\operatorname{sgn}(B_x) +\sqrt{\rho_L^\ast\rho_R^\ast}(w_R^\ast - w_L^\ast)\mathrm{sgn}(B_x) }{ \sqrt{\rho_L^\ast} + \sqrt{\rho_R^\ast} }. @@ -314,7 +314,7 @@ E_L^\ast \mathbf{v}_L^\ast\cdot\mathbf{B}_L^\ast - \mathbf{v}^{\ast\ast}\cdot\mathbf{B}^{\ast\ast} -\right)\operatorname{sgn}(B_x), +\right)\mathrm{sgn}(B_x), ``` ```math @@ -327,7 +327,7 @@ E_R^\ast \mathbf{v}_R^\ast\cdot\mathbf{B}_R^\ast - \mathbf{v}^{\ast\ast}\cdot\mathbf{B}^{\ast\ast} -\right)\operatorname{sgn}(B_x). +\right)\mathrm{sgn}(B_x). ``` Here From b5be13f723f7eb0918a17bfb82354ee210b33d66 Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Sun, 8 Mar 2026 18:45:33 +0900 Subject: [PATCH 03/39] Strengthen cpp-hlld benchmark guidance and tests --- benchmarks/magnetohydrodynamics/README.md | 5 + .../eval/tests/cpp/hlld_reference.hpp | 238 ++++++++++++++++++ .../cpp-hlld/eval/tests/cpp/test_hidden.cpp | 42 +++- .../magnetohydrodynamics/cpp-hlld/spec.md | 4 + .../magnetohydrodynamics/cpp-hlld/task.toml | 2 +- .../workspace/tests/cpp/test_public.cpp | 123 ++++++++- .../shared/workspace/hlld.md | 49 ++-- 7 files changed, 425 insertions(+), 38 deletions(-) create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/hlld_reference.hpp diff --git a/benchmarks/magnetohydrodynamics/README.md b/benchmarks/magnetohydrodynamics/README.md index 79baee8..86f3848 100644 --- a/benchmarks/magnetohydrodynamics/README.md +++ b/benchmarks/magnetohydrodynamics/README.md @@ -13,3 +13,8 @@ This suite contains benchmark tasks for ideal magnetohydrodynamics solvers. - Shared workspace files are visible to the agent during benchmark runs. - Keep maintainer-only derivations, generators, and hidden fixtures outside the shared workspace. + +## Reference credit + +- The hidden HLLD reference implementation is adapted closely from + `https://github.com/chiba-aplab/cansplus` diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/hlld_reference.hpp b/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/hlld_reference.hpp new file mode 100644 index 0000000..8206bf8 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/hlld_reference.hpp @@ -0,0 +1,238 @@ +#pragma once + +#if __has_include("hlld.hpp") +#include "hlld.hpp" +#else +#include "../../../workspace/src/hlld.hpp" +#endif + +#include + +namespace hidden_reference +{ + +inline FluxState hlld_flux_from_primitive(const PrimitiveState& left, const PrimitiveState& right, + double bx, double gamma) +{ + constexpr double eps = 1.0e-40; + + const double rol = left[0]; + const double vxl = left[1]; + const double vyl = left[2]; + const double vzl = left[3]; + const double prl = left[4]; + const double byl = left[5]; + const double bzl = left[6]; + + const double ror = right[0]; + const double vxr = right[1]; + const double vyr = right[2]; + const double vzr = right[3]; + const double prr = right[4]; + const double byr = right[5]; + const double bzr = right[6]; + + const double igm = 1.0 / (gamma - 1.0); + const double bxs = bx; + const double bxsq = bxs * bxs; + + const double pbl = 0.5 * (bxsq + byl * byl + bzl * bzl); + const double pbr = 0.5 * (bxsq + byr * byr + bzr * bzr); + const double ptl = prl + pbl; + const double ptr = prr + pbr; + + const double rxl = rol * vxl; + const double ryl = rol * vyl; + const double rzl = rol * vzl; + const double rxr = ror * vxr; + const double ryr = ror * vyr; + const double rzr = ror * vzr; + + const double eel = prl * igm + 0.5 * (rxl * vxl + ryl * vyl + rzl * vzl) + pbl; + const double eer = prr * igm + 0.5 * (rxr * vxr + ryr * vyr + rzr * vzr) + pbr; + + const double gmpl = gamma * prl; + const double gmpr = gamma * prr; + const double gpbl = gmpl + 2.0 * pbl; + const double gpbr = gmpr + 2.0 * pbr; + + const double cfl = std::sqrt((gpbl + std::sqrt((gmpl - 2.0 * pbl) * (gmpl - 2.0 * pbl) + + 4.0 * gmpl * (byl * byl + bzl * bzl))) * + 0.5 / rol); + const double cfr = std::sqrt((gpbr + std::sqrt((gmpr - 2.0 * pbr) * (gmpr - 2.0 * pbr) + + 4.0 * gmpr * (byr * byr + bzr * bzr))) * + 0.5 / ror); + + const double sl = std::min(vxl, vxr) - std::max(cfl, cfr); + const double sr = std::max(vxl, vxr) + std::max(cfl, cfr); + + const FluxState fql{rxl, + rxl * vxl + ptl - bxsq, + rxl * vyl - bxs * byl, + rxl * vzl - bxs * bzl, + vxl * (eel + ptl - bxsq) - bxs * (vyl * byl + vzl * bzl), + byl * vxl - bxs * vyl, + bzl * vxl - bxs * vzl}; + const FluxState fqr{rxr, + rxr * vxr + ptr - bxsq, + rxr * vyr - bxs * byr, + rxr * vzr - bxs * bzr, + vxr * (eer + ptr - bxsq) - bxs * (vyr * byr + vzr * bzr), + byr * vxr - bxs * vyr, + bzr * vxr - bxs * vzr}; + + const double sdl = sl - vxl; + const double sdr = sr - vxr; + const double rosdl = rol * sdl; + const double rosdr = ror * sdr; + const double temp = 1.0 / (rosdr - rosdl); + const double sm = (rosdr * vxr - rosdl * vxl - ptr + ptl) * temp; + const double sdml = sl - sm; + const double sdmr = sr - sm; + const double ptst = (rosdr * ptl - rosdl * ptr + rosdl * rosdr * (vxr - vxl)) * temp; + + const auto sign_unit = [](double x) { return (x >= 0.0) ? 1.0 : -1.0; }; + + const double temp_fst_l = rosdl * sdml - bxsq; + const double sign1_l = sign_unit(std::abs(temp_fst_l) - eps); + const double maxs1_l = std::max(0.0, sign1_l); + const double mins1_l = std::min(0.0, sign1_l); + const double itf_l = 1.0 / (temp_fst_l + mins1_l); + const double isdml = 1.0 / sdml; + + const double temp_l = bxs * (sdl - sdml) * itf_l; + const double rolst = maxs1_l * (rosdl * isdml) - mins1_l * rol; + const double vxlst = maxs1_l * sm - mins1_l * vxl; + const double rxlst = rolst * vxlst; + const double vylst = maxs1_l * (vyl - byl * temp_l) - mins1_l * vyl; + const double rylst = rolst * vylst; + const double vzlst = maxs1_l * (vzl - bzl * temp_l) - mins1_l * vzl; + const double rzlst = rolst * vzlst; + const double temp_l_b = (rosdl * sdl - bxsq) * itf_l; + const double bylst = maxs1_l * (byl * temp_l_b) - mins1_l * byl; + const double bzlst = maxs1_l * (bzl * temp_l_b) - mins1_l * bzl; + const double vdbstl = vxlst * bxs + vylst * bylst + vzlst * bzlst; + const double eelst = maxs1_l * ((sdl * eel - ptl * vxl + ptst * sm + + bxs * (vxl * bxs + vyl * byl + vzl * bzl - vdbstl)) * + isdml) - + mins1_l * eel; + + const double temp_fst_r = rosdr * sdmr - bxsq; + const double sign1_r = sign_unit(std::abs(temp_fst_r) - eps); + const double maxs1_r = std::max(0.0, sign1_r); + const double mins1_r = std::min(0.0, sign1_r); + const double itf_r = 1.0 / (temp_fst_r + mins1_r); + const double isdmr = 1.0 / sdmr; + + const double temp_r = bxs * (sdr - sdmr) * itf_r; + const double rorst = maxs1_r * (rosdr * isdmr) - mins1_r * ror; + const double vxrst = maxs1_r * sm - mins1_r * vxr; + const double rxrst = rorst * vxrst; + const double vyrst = maxs1_r * (vyr - byr * temp_r) - mins1_r * vyr; + const double ryrst = rorst * vyrst; + const double vzrst = maxs1_r * (vzr - bzr * temp_r) - mins1_r * vzr; + const double rzrst = rorst * vzrst; + const double temp_r_b = (rosdr * sdr - bxsq) * itf_r; + const double byrst = maxs1_r * (byr * temp_r_b) - mins1_r * byr; + const double bzrst = maxs1_r * (bzr * temp_r_b) - mins1_r * bzr; + const double vdbstr = vxrst * bxs + vyrst * byrst + vzrst * bzrst; + const double eerst = maxs1_r * ((sdr * eer - ptr * vxr + ptst * sm + + bxs * (vxr * bxs + vyr * byr + vzr * bzr - vdbstr)) * + isdmr) - + mins1_r * eer; + + const double sqrtrol = std::sqrt(rolst); + const double sqrtror = std::sqrt(rorst); + const double abbx = std::abs(bxs); + const double slst = sm - abbx / sqrtrol; + const double srst = sm + abbx / sqrtror; + const double signbx = sign_unit(bxs); + const double sign1_b = sign_unit(abbx - eps); + const double maxs1_b = std::max(0.0, sign1_b); + const double mins1_b = -std::min(0.0, sign1_b); + const double invsumro = maxs1_b / (sqrtrol + sqrtror); + + const double roldst = rolst; + const double rordst = rorst; + const double rxldst = rxlst; + const double rxrdst = rxrst; + const double vxldst = vxlst; + const double vxrdst = vxrst; + + const double vy_shared = + invsumro * (sqrtrol * vylst + sqrtror * vyrst + signbx * (byrst - bylst)); + const double vyldst = vylst * mins1_b + vy_shared; + const double vyrdst = vyrst * mins1_b + vy_shared; + const double ryldst = rylst * mins1_b + roldst * vy_shared; + const double ryrdst = ryrst * mins1_b + rordst * vy_shared; + + const double vz_shared = + invsumro * (sqrtrol * vzlst + sqrtror * vzrst + signbx * (bzrst - bzlst)); + const double vzldst = vzlst * mins1_b + vz_shared; + const double vzrdst = vzrst * mins1_b + vz_shared; + const double rzldst = rzlst * mins1_b + roldst * vz_shared; + const double rzrdst = rzrst * mins1_b + rordst * vz_shared; + + const double by_shared = + invsumro * (sqrtrol * byrst + sqrtror * bylst + signbx * sqrtrol * sqrtror * (vyrst - vylst)); + const double byldst = bylst * mins1_b + by_shared; + const double byrdst = byrst * mins1_b + by_shared; + + const double bz_shared = + invsumro * (sqrtrol * bzrst + sqrtror * bzlst + signbx * sqrtrol * sqrtror * (vzrst - vzlst)); + const double bzldst = bzlst * mins1_b + bz_shared; + const double bzrdst = bzrst * mins1_b + bz_shared; + + const double temp_dst = sm * bxs + vyldst * byldst + vzldst * bzldst; + const double eeldst = eelst - sqrtrol * signbx * (vdbstl - temp_dst) * maxs1_b; + const double eerdst = eerst + sqrtror * signbx * (vdbstr - temp_dst) * maxs1_b; + + const double sign1 = sign_unit(sm); + const double maxs1 = std::max(0.0, sign1); + const double mins1 = -std::min(0.0, sign1); + const double msl = std::min(sl, 0.0); + const double mslst = std::min(slst, 0.0); + const double msrst = std::max(srst, 0.0); + const double msr = std::max(sr, 0.0); + const double temp_flux_l = mslst - msl; + const double temp_flux_r = msrst - msr; + + return FluxState{ + (fql[0] - msl * rol - rolst * temp_flux_l + roldst * mslst) * maxs1 + + (fqr[0] - msr * ror - rorst * temp_flux_r + rordst * msrst) * mins1, + (fql[1] - msl * rxl - rxlst * temp_flux_l + rxldst * mslst) * maxs1 + + (fqr[1] - msr * rxr - rxrst * temp_flux_r + rxrdst * msrst) * mins1, + (fql[2] - msl * ryl - rylst * temp_flux_l + ryldst * mslst) * maxs1 + + (fqr[2] - msr * ryr - ryrst * temp_flux_r + ryrdst * msrst) * mins1, + (fql[3] - msl * rzl - rzlst * temp_flux_l + rzldst * mslst) * maxs1 + + (fqr[3] - msr * rzr - rzrst * temp_flux_r + rzrdst * msrst) * mins1, + (fql[4] - msl * eel - eelst * temp_flux_l + eeldst * mslst) * maxs1 + + (fqr[4] - msr * eer - eerst * temp_flux_r + eerdst * msrst) * mins1, + (fql[5] - msl * byl - bylst * temp_flux_l + byldst * mslst) * maxs1 + + (fqr[5] - msr * byr - byrst * temp_flux_r + byrdst * msrst) * mins1, + (fql[6] - msl * bzl - bzlst * temp_flux_l + bzldst * mslst) * maxs1 + + (fqr[6] - msr * bzr - bzrst * temp_flux_r + bzrdst * msrst) * mins1, + }; +} + +inline FluxState hlld_flux_from_conservative(const ConservativeState& left, + const ConservativeState& right, double bx, + double gamma) +{ + const auto to_primitive = [bx, gamma](const ConservativeState& state) { + const double rho = state[0]; + const double u = state[1] / rho; + const double v = state[2] / rho; + const double w = state[3] / rho; + const double by = state[5]; + const double bz = state[6]; + const double kinetic = 0.5 * rho * (u * u + v * v + w * w); + const double magnetic = 0.5 * (bx * bx + by * by + bz * bz); + const double p = (gamma - 1.0) * (state[4] - kinetic - magnetic); + return PrimitiveState{rho, u, v, w, p, by, bz}; + }; + + return hlld_flux_from_primitive(to_primitive(left), to_primitive(right), bx, gamma); +} + +} // namespace hidden_reference diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/test_hidden.cpp b/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/test_hidden.cpp index 86959df..4781c2a 100644 --- a/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/test_hidden.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/test_hidden.cpp @@ -10,6 +10,8 @@ #include "/usr/local/include/catch2/catch_test_macros.hpp" #endif +#include "hlld_reference.hpp" + #include namespace @@ -102,33 +104,53 @@ TEST_CASE("nontrivial primitive solve returns finite values") } } -TEST_CASE("hidden reference flux case 1 matches expected HLLD result") +TEST_CASE("hidden reference flux case 1 matches reference implementation") { const double bx = -0.65; const double gamma = 5.0 / 3.0; const PrimitiveState left{1.08, 0.45, -0.12, 0.08, 0.95, 0.4, -0.3}; const PrimitiveState right{0.72, -0.25, 0.16, -0.05, 0.58, -0.2, 0.35}; - const FluxState expected{ - 0.3324233585009154, 1.3204052114557712, 0.06638064166463348, -0.022436684783467387, - 0.7427148869798962, 0.20070323090296055, -0.18527478786984644, - }; + const FluxState expected = hidden_reference::hlld_flux_from_primitive(left, right, bx, gamma); const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } -TEST_CASE("hidden reference flux case 2 matches expected HLLD result") +TEST_CASE("hidden reference flux case 2 matches reference implementation") { const double bx = 0.35; const double gamma = 1.4; const PrimitiveState left{0.9, -0.45, 0.2, 0.15, 0.8, -0.3, 0.55}; const PrimitiveState right{1.15, 0.18, -0.12, -0.08, 1.05, 0.22, -0.4}; - const FluxState expected{ - -0.15164205717520077, 0.6302921311068539, 0.025882982020760857, 0.06707828676255045, - -0.35658597023319155, -0.06350044448634364, 0.14687345745300118, - }; + const FluxState expected = hidden_reference::hlld_flux_from_primitive(left, right, bx, gamma); + + const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("small Bx near-degenerate reference case matches reference implementation") +{ + const double bx = 1.0e-6; + const double gamma = 1.4; + + const PrimitiveState left{1.0, 0.4, 0.2, -0.1, 1.0, 0.5, -0.4}; + const PrimitiveState right{0.85, -0.3, -0.15, 0.25, 0.8, -0.35, 0.45}; + const FluxState expected = hidden_reference::hlld_flux_from_primitive(left, right, bx, gamma); + + const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("second Bx equals zero hydro case matches reference implementation") +{ + const double bx = 0.0; + const double gamma = 1.4; + + const PrimitiveState left{0.4, -1.1, 0.0, 0.0, 0.4, 0.0, 0.0}; + const PrimitiveState right{1.2, -0.2, 0.0, 0.0, 1.3, 0.0, 0.0}; + const FluxState expected = hidden_reference::hlld_flux_from_primitive(left, right, bx, gamma); const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/spec.md b/benchmarks/magnetohydrodynamics/cpp-hlld/spec.md index aaa8704..4fbd5e6 100644 --- a/benchmarks/magnetohydrodynamics/cpp-hlld/spec.md +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/spec.md @@ -21,6 +21,10 @@ The benchmark uses: - flux ordering: `[F_rho, F_mx, F_my, F_mz, F_E, F_By, F_Bz]` - Lorentz-Heaviside units - `Bx` passed separately from the state vectors +- the test suite includes `Bx = 0` hydro and magnetized degenerate cases +- the test suite also includes a small-`Bx` near-degenerate case, so handle + `Bx = 0`, small denominators in the starred-state formulas, and related + square-root/discriminant edge cases carefully Do not change the public function signatures in `src/hlld.hpp`. diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/task.toml b/benchmarks/magnetohydrodynamics/cpp-hlld/task.toml index 4f60d04..f58f5d8 100644 --- a/benchmarks/magnetohydrodynamics/cpp-hlld/task.toml +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/task.toml @@ -1,7 +1,7 @@ id = "cpp-hlld" suite = "magnetohydrodynamics" language = "cpp" -time_limit_sec = 300 +time_limit_sec = 600 eval_cmd = "/eval/run.sh" prompt = "Read /run/spec.md, /work/basic_equations.md, and /work/hlld.md, then solve the task in /work." use_shared_workspace = true diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/cpp/test_public.cpp b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/cpp/test_public.cpp index f97af36..fc17d25 100644 --- a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/cpp/test_public.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/cpp/test_public.cpp @@ -104,16 +104,127 @@ TEST_CASE("primitive and conservative entry points agree") require_close(from_primitive, from_conservative); } -TEST_CASE("nontrivial public reference flux matches expected HLLD result") +TEST_CASE("right-going contact discontinuity is resolved exactly") { - const double bx = 0.75; + const double bx = 0.8; + const double gamma = 5.0 / 3.0; + + const PrimitiveState left{1.0, 0.3, 0.2, -0.15, 1.0, 0.6, -0.3}; + const PrimitiveState right{0.7, 0.3, 0.2, -0.15, 1.0, 0.6, -0.3}; + + const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + require_close(actual, physical_flux_x(primitive_to_conservative(left, bx, gamma), bx, gamma)); +} + +TEST_CASE("left-going contact discontinuity is resolved exactly") +{ + const double bx = 0.8; + const double gamma = 5.0 / 3.0; + + const PrimitiveState left{1.0, -0.25, 0.2, -0.15, 1.0, 0.6, -0.3}; + const PrimitiveState right{0.7, -0.25, 0.2, -0.15, 1.0, 0.6, -0.3}; + + const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + require_close(actual, physical_flux_x(primitive_to_conservative(right, bx, gamma), bx, gamma)); +} + +TEST_CASE("right-going rotational discontinuity is resolved exactly") +{ + const double bx = 1.0; + const double gamma = 5.0 / 3.0; + + const PrimitiveState left{1.0, 0.2, 0.1, -0.2, 1.0, 1.0, 0.0}; + const PrimitiveState right{1.0, 0.2, 0.5, -1.0, 1.0, 0.6, 0.8}; + + const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + require_close(actual, physical_flux_x(primitive_to_conservative(left, bx, gamma), bx, gamma)); +} + +TEST_CASE("left-going rotational discontinuity is resolved exactly") +{ + const double bx = 1.0; + const double gamma = 5.0 / 3.0; + + const PrimitiveState left{1.0, 0.2, 0.1, -0.2, 1.0, 1.0, 0.0}; + const PrimitiveState right{1.0, 0.2, -0.3, 0.6, 1.0, 0.6, 0.8}; + + const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + require_close(actual, physical_flux_x(primitive_to_conservative(right, bx, gamma), bx, gamma)); +} + +TEST_CASE("Bx equals zero hydro case matches reference flux") +{ + const double bx = 0.0; const double gamma = 1.4; - const PrimitiveState left{1.0, 0.3, 0.1, -0.2, 1.0, 0.7, -0.5}; - const PrimitiveState right{0.8, -0.1, -0.4, 0.25, 0.7, -0.2, 0.3}; + const PrimitiveState left{1.0, 0.75, 0.0, 0.0, 1.0, 0.0, 0.0}; + const PrimitiveState right{0.125, 0.0, 0.0, 0.0, 0.1, 0.0, 0.0}; + const FluxState expected{ + 0.92274146439449267, 1.3581095429585437, 0.0, 0.0, 3.1282919538345322, 0.0, 0.0, + }; + + const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("Bx equals zero magnetized case matches reference flux") +{ + const double bx = 0.0; + const double gamma = 5.0 / 3.0; + + const PrimitiveState left{1.0, 0.6, 0.1, -0.2, 1.0, 0.7, -0.5}; + const PrimitiveState right{0.7, -0.3, -0.15, 0.25, 0.5, -0.2, 0.4}; + const FluxState expected{ + 0.44815524807196727, 2.011116795062418, 0.044815524807196722, -0.089631049614393443, + 1.6980640537315086, 0.31370867365037713, -0.22407762403598386, + }; + + const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("small Bx near-degenerate case matches reference flux") +{ + const double bx = 1.0e-6; + const double gamma = 1.4; + + const PrimitiveState left{1.0, 0.4, 0.2, -0.1, 1.0, 0.5, -0.4}; + const PrimitiveState right{0.85, -0.3, -0.15, 0.25, 0.8, -0.35, 0.45}; + const FluxState expected{ + 0.16298732855830989, 1.7549717390289374, 0.032596899426565185, -0.016298279827753587, + 0.72345786285986069, 0.081493464279122407, -0.065194831423298072, + }; + + const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("generic coupled MHD case 1 matches reference flux") +{ + const double bx = -0.65; + const double gamma = 5.0 / 3.0; + + const PrimitiveState left{1.08, 0.45, -0.12, 0.08, 0.95, 0.4, -0.3}; + const PrimitiveState right{0.72, -0.25, 0.16, -0.05, 0.58, -0.2, 0.35}; + const FluxState expected{ + 0.33341182495747945, 1.3232304013056353, 0.06667172041085781, -0.02277204332310151, + 0.88458241136476201, 0.20058802344338272, -0.18511862133859658, + }; + + const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("generic coupled MHD case 2 matches reference flux") +{ + const double bx = 0.35; + const double gamma = 1.4; + + const PrimitiveState left{0.9, -0.45, 0.2, 0.15, 0.8, -0.3, 0.55}; + const PrimitiveState right{1.15, 0.18, -0.12, -0.08, 1.05, 0.22, -0.4}; const FluxState expected{ - 0.2959755324688338, 1.1841244172856562, -0.17006720148138638, 0.020437274707554964, - 1.1895179713786177, 0.4579156493939873, -0.29354464377682116, + -0.14227120841958368, 0.6095322640180193, 0.028703852070217931, 0.063723510257583313, + -0.40524273615789225, -0.065690714628438368, 0.14700372046240096, }; const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); diff --git a/benchmarks/magnetohydrodynamics/shared/workspace/hlld.md b/benchmarks/magnetohydrodynamics/shared/workspace/hlld.md index 2cf4b4d..cd59d58 100644 --- a/benchmarks/magnetohydrodynamics/shared/workspace/hlld.md +++ b/benchmarks/magnetohydrodynamics/shared/workspace/hlld.md @@ -42,28 +42,15 @@ p_T^\ast = \text{constant}. ## Outer wave speeds -Use the standard HLL estimate +Use the following wave-speed estimate for the outer waves $S_L$ and $S_R$. ```math -S_L = \min(u_L - c_{f,L},\, u_R - c_{f,R}), +S_L=\min(u_L,u_R)-\max(c_{f,L},c_{f,R}) \qquad -S_R = \max(u_L + c_{f,L},\, u_R + c_{f,R}). +S_R=\max(u_L,u_R)+\max(c_{f,L},c_{f,R}) ``` -If - -```math -0 \le S_L, -``` - -return the left physical flux. -If - -```math -S_R \le 0, -``` - -return the right physical flux. +This wave-speed estimate is part of the benchmark convention. ## Contact speed and total pressure @@ -408,9 +395,29 @@ to the location of zero in the wave fan: All fluxes use the conservative component ordering defined in `basic_equations.md`. -## Robustness expectations +## Implementation notes + +- This benchmark follows one specific HLLD implementation convention rather than + an arbitrary mathematically equivalent variant. + +- Small starred-state denominator + If $|D_\alpha|$ is extremely small, do not apply the raw starred-state update + by dividing through that value. Instead, replace the starred transverse + updates with: + ```math + v_\alpha^\ast = v_\alpha, \quad + w_\alpha^\ast = w_\alpha, \quad + B_{y,\alpha}^\ast = B_{y,\alpha}, \quad + B_{z,\alpha}^\ast = B_{z,\alpha}. + ``` + +- Small $B_x$ + When $B_x=0$, the rotational waves collapse and the double-star regions become + unnecessary. In that case, do not use the double-star states for flux + calculation. + + For this benchmark, a merely small nonzero $|B_x|$ should still be treated as + a nondegenerate case unless some other guarded quantity, such as $D_\alpha$, + becomes numerically singular. - Assume all benchmark inputs are admissible physical states. -- Keep arithmetic finite and deterministic on the benchmark cases. -- The primitive-state entry point and conservative-state entry point should - return the same numerical flux for equivalent left/right states. From bf251b9bf25c923e5ebc2448e834a47d39e000a1 Mon Sep 17 00:00:00 2001 From: Takanobu Amano <46679145+amanotk@users.noreply.github.com> Date: Sun, 8 Mar 2026 18:50:25 +0900 Subject: [PATCH 04/39] Update formatting of starred-state update equations Reformatted math equations for better readability. --- .../magnetohydrodynamics/shared/workspace/hlld.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/benchmarks/magnetohydrodynamics/shared/workspace/hlld.md b/benchmarks/magnetohydrodynamics/shared/workspace/hlld.md index cd59d58..d6822fa 100644 --- a/benchmarks/magnetohydrodynamics/shared/workspace/hlld.md +++ b/benchmarks/magnetohydrodynamics/shared/workspace/hlld.md @@ -404,12 +404,13 @@ All fluxes use the conservative component ordering defined in If $|D_\alpha|$ is extremely small, do not apply the raw starred-state update by dividing through that value. Instead, replace the starred transverse updates with: - ```math - v_\alpha^\ast = v_\alpha, \quad - w_\alpha^\ast = w_\alpha, \quad - B_{y,\alpha}^\ast = B_{y,\alpha}, \quad - B_{z,\alpha}^\ast = B_{z,\alpha}. - ``` + +```math +v_\alpha^\ast = v_\alpha, \quad +w_\alpha^\ast = w_\alpha, \quad +B_{y,\alpha}^\ast = B_{y,\alpha}, \quad +B_{z,\alpha}^\ast = B_{z,\alpha}. +``` - Small $B_x$ When $B_x=0$, the rotational waves collapse and the double-star regions become From 6215af3cd3b7c47ce253d7cf679d489892c864a4 Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Sat, 28 Mar 2026 16:54:31 +0900 Subject: [PATCH 05/39] Fix hidden test merge artifact --- .../magnetohydrodynamics/cpp-hlld/eval/tests/test_hidden.py | 1 - 1 file changed, 1 deletion(-) diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/test_hidden.py b/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/test_hidden.py index 8d10be9..c0e0187 100644 --- a/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/test_hidden.py +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/test_hidden.py @@ -11,7 +11,6 @@ def _build_hidden_tests() -> Path: ".", "-B", "build", -<<<<<<< HEAD "-DSIMBENCH_ENABLE_HIDDEN_TESTS=ON", f"-DSIMBENCH_HIDDEN_TEST_SOURCE={hidden_source}", ], From 7c982caa4f25e0fb79133ff416429efdac00b81d Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Sat, 28 Mar 2026 19:01:05 +0900 Subject: [PATCH 06/39] Strengthen HLLD coverage and fix Docker OpenCode setup --- .github/workflows/toolchain-image.yml | 1 + .gitignore | 2 + agents_default.toml | 4 +- .../eval/tests/cpp/hlld_reference.hpp | 43 ++-- .../cpp-hlld/eval/tests/cpp/test_hidden.cpp | 60 ++--- .../cpp-hlld/workspace/src/hlld.cpp | 238 ++++++++++++++++-- .../cpp-hlld/workspace/src/hlld.hpp | 12 +- .../workspace/tests/cpp/test_public.cpp | 194 +++++++++----- docker/Dockerfile | 3 +- runner/execution_agent.py | 2 +- runner/metrics_helpers.py | 2 +- scripts/build_image.py | 3 + tests/test_runner_cli_flow.py | 4 +- 13 files changed, 428 insertions(+), 140 deletions(-) diff --git a/.github/workflows/toolchain-image.yml b/.github/workflows/toolchain-image.yml index 8e8a626..9cc1d69 100644 --- a/.github/workflows/toolchain-image.yml +++ b/.github/workflows/toolchain-image.yml @@ -51,6 +51,7 @@ jobs: labels: ${{ steps.meta.outputs.labels }} build-args: | FLAP_VERSION=1.2.16 + OPENCODE_VERSION=1.3.3 CATCH2_REF=v3.13.0 MDSPAN_REF=mdspan-0.6.0 XTL_REF=0.8.2 diff --git a/.gitignore b/.gitignore index 5ed28a7..0d4faa8 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ __pycache__/ .venv/ venv/ .DS_Store +benchmarks/*/*/workspace/build/ +benchmarks/*/*/workspace/build-review/ diff --git a/agents_default.toml b/agents_default.toml index 2f85a21..30651bd 100644 --- a/agents_default.toml +++ b/agents_default.toml @@ -10,8 +10,10 @@ pass_env = [ ] pre = [ "mkdir -p \"$HOME/.local/share/opencode\"", + "mkdir -p \"$HOME/.config/opencode\"", "if [ -f /opencode-auth.json ]; then cp /opencode-auth.json \"$HOME/.local/share/opencode/auth.json\"; fi", - "if [ -f /opencode-config.json ]; then export OPENCODE_CONFIG=/opencode-config.json; elif [ -f /opencode-config.jsonc ]; then export OPENCODE_CONFIG=/opencode-config.jsonc; fi", + "if [ -f /opencode-config.json ]; then cp /opencode-config.json \"$HOME/.config/opencode/opencode.json\"; fi", + "if [ -f /opencode-config.jsonc ]; then cp /opencode-config.jsonc \"$HOME/.config/opencode/opencode.jsonc\"; fi", ] cmd = "stdbuf -oL -eL opencode run -m \"$BENCH_MODEL\" $BENCH_MODEL_OPTIONS_ARGS --thinking --dir / \"$(cat \"$BENCH_PROMPT_FILE\")\" -f \"$BENCH_SPEC_FILE\"" diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/hlld_reference.hpp b/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/hlld_reference.hpp index 8206bf8..1849a16 100644 --- a/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/hlld_reference.hpp +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/hlld_reference.hpp @@ -11,8 +11,8 @@ namespace hidden_reference { -inline FluxState hlld_flux_from_primitive(const PrimitiveState& left, const PrimitiveState& right, - double bx, double gamma) +inline StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, + double bx, double gamma) { constexpr double eps = 1.0e-40; @@ -66,20 +66,20 @@ inline FluxState hlld_flux_from_primitive(const PrimitiveState& left, const Prim const double sl = std::min(vxl, vxr) - std::max(cfl, cfr); const double sr = std::max(vxl, vxr) + std::max(cfl, cfr); - const FluxState fql{rxl, - rxl * vxl + ptl - bxsq, - rxl * vyl - bxs * byl, - rxl * vzl - bxs * bzl, - vxl * (eel + ptl - bxsq) - bxs * (vyl * byl + vzl * bzl), - byl * vxl - bxs * vyl, - bzl * vxl - bxs * vzl}; - const FluxState fqr{rxr, - rxr * vxr + ptr - bxsq, - rxr * vyr - bxs * byr, - rxr * vzr - bxs * bzr, - vxr * (eer + ptr - bxsq) - bxs * (vyr * byr + vzr * bzr), - byr * vxr - bxs * vyr, - bzr * vxr - bxs * vzr}; + const StateVector fql{rxl, + rxl * vxl + ptl - bxsq, + rxl * vyl - bxs * byl, + rxl * vzl - bxs * bzl, + vxl * (eel + ptl - bxsq) - bxs * (vyl * byl + vzl * bzl), + byl * vxl - bxs * vyl, + bzl * vxl - bxs * vzl}; + const StateVector fqr{rxr, + rxr * vxr + ptr - bxsq, + rxr * vyr - bxs * byr, + rxr * vzr - bxs * bzr, + vxr * (eer + ptr - bxsq) - bxs * (vyr * byr + vzr * bzr), + byr * vxr - bxs * vyr, + bzr * vxr - bxs * vzr}; const double sdl = sl - vxl; const double sdr = sr - vxr; @@ -197,7 +197,7 @@ inline FluxState hlld_flux_from_primitive(const PrimitiveState& left, const Prim const double temp_flux_l = mslst - msl; const double temp_flux_r = msrst - msr; - return FluxState{ + return StateVector{ (fql[0] - msl * rol - rolst * temp_flux_l + roldst * mslst) * maxs1 + (fqr[0] - msr * ror - rorst * temp_flux_r + rordst * msrst) * mins1, (fql[1] - msl * rxl - rxlst * temp_flux_l + rxldst * mslst) * maxs1 + @@ -215,11 +215,10 @@ inline FluxState hlld_flux_from_primitive(const PrimitiveState& left, const Prim }; } -inline FluxState hlld_flux_from_conservative(const ConservativeState& left, - const ConservativeState& right, double bx, - double gamma) +inline StateVector hlld_flux_from_conservative(const StateVector& left, const StateVector& right, + double bx, double gamma) { - const auto to_primitive = [bx, gamma](const ConservativeState& state) { + const auto to_primitive = [bx, gamma](const StateVector& state) { const double rho = state[0]; const double u = state[1] / rho; const double v = state[2] / rho; @@ -229,7 +228,7 @@ inline FluxState hlld_flux_from_conservative(const ConservativeState& left, const double kinetic = 0.5 * rho * (u * u + v * v + w * w); const double magnetic = 0.5 * (bx * bx + by * by + bz * bz); const double p = (gamma - 1.0) * (state[4] - kinetic - magnetic); - return PrimitiveState{rho, u, v, w, p, by, bz}; + return StateVector{rho, u, v, w, p, by, bz}; }; return hlld_flux_from_primitive(to_primitive(left), to_primitive(right), bx, gamma); diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/test_hidden.cpp b/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/test_hidden.cpp index 4781c2a..265fb1c 100644 --- a/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/test_hidden.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/test_hidden.cpp @@ -19,7 +19,7 @@ namespace constexpr double kTolerance = 1e-12; -ConservativeState primitive_to_conservative(const PrimitiveState& state, double bx, double gamma) +StateVector primitive_to_conservative(const StateVector& state, double bx, double gamma) { const double rho = state[0]; const double u = state[1]; @@ -33,12 +33,12 @@ ConservativeState primitive_to_conservative(const PrimitiveState& state, double const double magnetic = 0.5 * (bx * bx + by * by + bz * bz); const double energy = p / (gamma - 1.0) + kinetic + magnetic; - return ConservativeState{ + return StateVector{ rho, rho * u, rho * v, rho * w, energy, by, bz, }; } -FluxState physical_flux_x(const ConservativeState& state, double bx, double gamma) +StateVector physical_flux_x(const StateVector& state, double bx, double gamma) { const double rho = state[0]; const double mx = state[1]; @@ -56,7 +56,7 @@ FluxState physical_flux_x(const ConservativeState& state, double bx, double gamm const double pressure = (gamma - 1.0) * (energy - kinetic - magnetic); const double total_pressure = pressure + magnetic; - return FluxState{ + return StateVector{ rho * u, rho * u * u + total_pressure - bx * bx, rho * v * u - bx * by, @@ -67,7 +67,7 @@ FluxState physical_flux_x(const ConservativeState& state, double bx, double gamm }; } -void require_close(const FluxState& actual, const FluxState& expected) +void require_close(const StateVector& actual, const StateVector& expected) { for (std::size_t i = 0; i < actual.size(); ++i) { REQUIRE(std::abs(actual[i] - expected[i]) <= kTolerance); @@ -78,13 +78,13 @@ void require_close(const FluxState& actual, const FluxState& expected) TEST_CASE("equal conservative states reduce to the physical flux") { - const double bx = 0.35; - const double gamma = 1.4; - const PrimitiveState primitive{0.9, -0.45, 0.2, 0.15, 0.8, -0.3, 0.55}; - const ConservativeState state = primitive_to_conservative(primitive, bx, gamma); + const double bx = 0.35; + const double gamma = 1.4; + const StateVector primitive{0.9, -0.45, 0.2, 0.15, 0.8, -0.3, 0.55}; + const StateVector state = primitive_to_conservative(primitive, bx, gamma); - const FluxState actual = hlld_flux_from_conservative(state, state, bx, gamma); - const FluxState expected = physical_flux_x(state, bx, gamma); + const StateVector actual = hlld_flux_from_conservative(state, state, bx, gamma); + const StateVector expected = physical_flux_x(state, bx, gamma); require_close(actual, expected); } @@ -94,10 +94,10 @@ TEST_CASE("nontrivial primitive solve returns finite values") const double bx = -0.65; const double gamma = 5.0 / 3.0; - const PrimitiveState left{1.08, 0.45, -0.12, 0.08, 0.95, 0.4, -0.3}; - const PrimitiveState right{0.72, -0.25, 0.16, -0.05, 0.58, -0.2, 0.35}; + const StateVector left{1.08, 0.45, -0.12, 0.08, 0.95, 0.4, -0.3}; + const StateVector right{0.72, -0.25, 0.16, -0.05, 0.58, -0.2, 0.35}; - const FluxState flux = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector flux = hlld_flux_from_primitive(left, right, bx, gamma); for (double value : flux) { REQUIRE(std::isfinite(value)); @@ -109,11 +109,11 @@ TEST_CASE("hidden reference flux case 1 matches reference implementation") const double bx = -0.65; const double gamma = 5.0 / 3.0; - const PrimitiveState left{1.08, 0.45, -0.12, 0.08, 0.95, 0.4, -0.3}; - const PrimitiveState right{0.72, -0.25, 0.16, -0.05, 0.58, -0.2, 0.35}; - const FluxState expected = hidden_reference::hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector left{1.08, 0.45, -0.12, 0.08, 0.95, 0.4, -0.3}; + const StateVector right{0.72, -0.25, 0.16, -0.05, 0.58, -0.2, 0.35}; + const StateVector expected = hidden_reference::hlld_flux_from_primitive(left, right, bx, gamma); - const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } @@ -122,11 +122,11 @@ TEST_CASE("hidden reference flux case 2 matches reference implementation") const double bx = 0.35; const double gamma = 1.4; - const PrimitiveState left{0.9, -0.45, 0.2, 0.15, 0.8, -0.3, 0.55}; - const PrimitiveState right{1.15, 0.18, -0.12, -0.08, 1.05, 0.22, -0.4}; - const FluxState expected = hidden_reference::hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector left{0.9, -0.45, 0.2, 0.15, 0.8, -0.3, 0.55}; + const StateVector right{1.15, 0.18, -0.12, -0.08, 1.05, 0.22, -0.4}; + const StateVector expected = hidden_reference::hlld_flux_from_primitive(left, right, bx, gamma); - const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } @@ -135,11 +135,11 @@ TEST_CASE("small Bx near-degenerate reference case matches reference implementat const double bx = 1.0e-6; const double gamma = 1.4; - const PrimitiveState left{1.0, 0.4, 0.2, -0.1, 1.0, 0.5, -0.4}; - const PrimitiveState right{0.85, -0.3, -0.15, 0.25, 0.8, -0.35, 0.45}; - const FluxState expected = hidden_reference::hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector left{1.0, 0.4, 0.2, -0.1, 1.0, 0.5, -0.4}; + const StateVector right{0.85, -0.3, -0.15, 0.25, 0.8, -0.35, 0.45}; + const StateVector expected = hidden_reference::hlld_flux_from_primitive(left, right, bx, gamma); - const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } @@ -148,10 +148,10 @@ TEST_CASE("second Bx equals zero hydro case matches reference implementation") const double bx = 0.0; const double gamma = 1.4; - const PrimitiveState left{0.4, -1.1, 0.0, 0.0, 0.4, 0.0, 0.0}; - const PrimitiveState right{1.2, -0.2, 0.0, 0.0, 1.3, 0.0, 0.0}; - const FluxState expected = hidden_reference::hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector left{0.4, -1.1, 0.0, 0.0, 0.4, 0.0, 0.0}; + const StateVector right{1.2, -0.2, 0.0, 0.0, 1.3, 0.0, 0.0}; + const StateVector expected = hidden_reference::hlld_flux_from_primitive(left, right, bx, gamma); - const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.cpp b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.cpp index b5698a6..c56aedc 100644 --- a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.cpp @@ -1,31 +1,237 @@ #include "hlld.hpp" +#include +#include + namespace { -FluxState zero_flux() +constexpr double kEps = 1.0e-40; + +double sign_unit(double x) +{ + return (x >= 0.0) ? 1.0 : -1.0; +} + +StateVector primitive_from_conservative(const StateVector& state, double bx, double gamma) { - return FluxState{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + const double rho = state[0]; + const double u = state[1] / rho; + const double v = state[2] / rho; + const double w = state[3] / rho; + const double by = state[5]; + const double bz = state[6]; + + const double kinetic = 0.5 * rho * (u * u + v * v + w * w); + const double magnetic = 0.5 * (bx * bx + by * by + bz * bz); + const double p = (gamma - 1.0) * (state[4] - kinetic - magnetic); + + return StateVector{rho, u, v, w, p, by, bz}; } } // namespace -FluxState hlld_flux_from_primitive(const PrimitiveState& left, const PrimitiveState& right, - double bx, double gamma) +StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, + double gamma) { - (void)left; - (void)right; - (void)bx; - (void)gamma; - return zero_flux(); + const double rol = left[0]; + const double vxl = left[1]; + const double vyl = left[2]; + const double vzl = left[3]; + const double prl = left[4]; + const double byl = left[5]; + const double bzl = left[6]; + + const double ror = right[0]; + const double vxr = right[1]; + const double vyr = right[2]; + const double vzr = right[3]; + const double prr = right[4]; + const double byr = right[5]; + const double bzr = right[6]; + + const double igm = 1.0 / (gamma - 1.0); + const double bxs = bx; + const double bxsq = bxs * bxs; + + const double pbl = 0.5 * (bxsq + byl * byl + bzl * bzl); + const double pbr = 0.5 * (bxsq + byr * byr + bzr * bzr); + const double ptl = prl + pbl; + const double ptr = prr + pbr; + + const double rxl = rol * vxl; + const double ryl = rol * vyl; + const double rzl = rol * vzl; + const double rxr = ror * vxr; + const double ryr = ror * vyr; + const double rzr = ror * vzr; + + const double eel = prl * igm + 0.5 * (rxl * vxl + ryl * vyl + rzl * vzl) + pbl; + const double eer = prr * igm + 0.5 * (rxr * vxr + ryr * vyr + rzr * vzr) + pbr; + + const double gmpl = gamma * prl; + const double gmpr = gamma * prr; + const double gpbl = gmpl + 2.0 * pbl; + const double gpbr = gmpr + 2.0 * pbr; + + const double cfl = std::sqrt((gpbl + std::sqrt((gmpl - 2.0 * pbl) * (gmpl - 2.0 * pbl) + + 4.0 * gmpl * (byl * byl + bzl * bzl))) * + 0.5 / rol); + const double cfr = std::sqrt((gpbr + std::sqrt((gmpr - 2.0 * pbr) * (gmpr - 2.0 * pbr) + + 4.0 * gmpr * (byr * byr + bzr * bzr))) * + 0.5 / ror); + + const double sl = std::min(vxl, vxr) - std::max(cfl, cfr); + const double sr = std::max(vxl, vxr) + std::max(cfl, cfr); + + const StateVector fql{rxl, + rxl * vxl + ptl - bxsq, + rxl * vyl - bxs * byl, + rxl * vzl - bxs * bzl, + vxl * (eel + ptl - bxsq) - bxs * (vyl * byl + vzl * bzl), + byl * vxl - bxs * vyl, + bzl * vxl - bxs * vzl}; + const StateVector fqr{rxr, + rxr * vxr + ptr - bxsq, + rxr * vyr - bxs * byr, + rxr * vzr - bxs * bzr, + vxr * (eer + ptr - bxsq) - bxs * (vyr * byr + vzr * bzr), + byr * vxr - bxs * vyr, + bzr * vxr - bxs * vzr}; + + const double sdl = sl - vxl; + const double sdr = sr - vxr; + const double rosdl = rol * sdl; + const double rosdr = ror * sdr; + const double temp = 1.0 / (rosdr - rosdl); + const double sm = (rosdr * vxr - rosdl * vxl - ptr + ptl) * temp; + const double sdml = sl - sm; + const double sdmr = sr - sm; + const double ptst = (rosdr * ptl - rosdl * ptr + rosdl * rosdr * (vxr - vxl)) * temp; + + const double temp_fst_l = rosdl * sdml - bxsq; + const double sign1_l = sign_unit(std::abs(temp_fst_l) - kEps); + const double maxs1_l = std::max(0.0, sign1_l); + const double mins1_l = std::min(0.0, sign1_l); + const double itf_l = 1.0 / (temp_fst_l + mins1_l); + const double isdml = 1.0 / sdml; + + const double temp_l = bxs * (sdl - sdml) * itf_l; + const double rolst = maxs1_l * (rosdl * isdml) - mins1_l * rol; + const double vxlst = maxs1_l * sm - mins1_l * vxl; + const double rxlst = rolst * vxlst; + const double vylst = maxs1_l * (vyl - byl * temp_l) - mins1_l * vyl; + const double rylst = rolst * vylst; + const double vzlst = maxs1_l * (vzl - bzl * temp_l) - mins1_l * vzl; + const double rzlst = rolst * vzlst; + const double temp_l_b = (rosdl * sdl - bxsq) * itf_l; + const double bylst = maxs1_l * (byl * temp_l_b) - mins1_l * byl; + const double bzlst = maxs1_l * (bzl * temp_l_b) - mins1_l * bzl; + const double vdbstl = vxlst * bxs + vylst * bylst + vzlst * bzlst; + const double eelst = maxs1_l * ((sdl * eel - ptl * vxl + ptst * sm + + bxs * (vxl * bxs + vyl * byl + vzl * bzl - vdbstl)) * + isdml) - + mins1_l * eel; + + const double temp_fst_r = rosdr * sdmr - bxsq; + const double sign1_r = sign_unit(std::abs(temp_fst_r) - kEps); + const double maxs1_r = std::max(0.0, sign1_r); + const double mins1_r = std::min(0.0, sign1_r); + const double itf_r = 1.0 / (temp_fst_r + mins1_r); + const double isdmr = 1.0 / sdmr; + + const double temp_r = bxs * (sdr - sdmr) * itf_r; + const double rorst = maxs1_r * (rosdr * isdmr) - mins1_r * ror; + const double vxrst = maxs1_r * sm - mins1_r * vxr; + const double rxrst = rorst * vxrst; + const double vyrst = maxs1_r * (vyr - byr * temp_r) - mins1_r * vyr; + const double ryrst = rorst * vyrst; + const double vzrst = maxs1_r * (vzr - bzr * temp_r) - mins1_r * vzr; + const double rzrst = rorst * vzrst; + const double temp_r_b = (rosdr * sdr - bxsq) * itf_r; + const double byrst = maxs1_r * (byr * temp_r_b) - mins1_r * byr; + const double bzrst = maxs1_r * (bzr * temp_r_b) - mins1_r * bzr; + const double vdbstr = vxrst * bxs + vyrst * byrst + vzrst * bzrst; + const double eerst = maxs1_r * ((sdr * eer - ptr * vxr + ptst * sm + + bxs * (vxr * bxs + vyr * byr + vzr * bzr - vdbstr)) * + isdmr) - + mins1_r * eer; + + const double sqrtrol = std::sqrt(rolst); + const double sqrtror = std::sqrt(rorst); + const double abbx = std::abs(bxs); + const double slst = sm - abbx / sqrtrol; + const double srst = sm + abbx / sqrtror; + const double signbx = sign_unit(bxs); + const double sign1_b = sign_unit(abbx - kEps); + const double maxs1_b = std::max(0.0, sign1_b); + const double mins1_b = -std::min(0.0, sign1_b); + const double invsumro = maxs1_b / (sqrtrol + sqrtror); + + const double roldst = rolst; + const double rordst = rorst; + const double rxldst = rxlst; + const double rxrdst = rxrst; + + const double vy_shared = + invsumro * (sqrtrol * vylst + sqrtror * vyrst + signbx * (byrst - bylst)); + const double ryldst = rylst * mins1_b + roldst * vy_shared; + const double ryrdst = ryrst * mins1_b + rordst * vy_shared; + + const double vz_shared = + invsumro * (sqrtrol * vzlst + sqrtror * vzrst + signbx * (bzrst - bzlst)); + const double rzldst = rzlst * mins1_b + roldst * vz_shared; + const double rzrdst = rzrst * mins1_b + rordst * vz_shared; + + const double by_shared = + invsumro * (sqrtrol * byrst + sqrtror * bylst + signbx * sqrtrol * sqrtror * (vyrst - vylst)); + const double byldst = bylst * mins1_b + by_shared; + const double byrdst = byrst * mins1_b + by_shared; + + const double bz_shared = + invsumro * (sqrtrol * bzrst + sqrtror * bzlst + signbx * sqrtrol * sqrtror * (vzrst - vzlst)); + const double bzldst = bzlst * mins1_b + bz_shared; + const double bzrdst = bzrst * mins1_b + bz_shared; + + const double vyldst = vylst * mins1_b + vy_shared; + const double vyrdst = vyrst * mins1_b + vy_shared; + const double vzldst = vzlst * mins1_b + vz_shared; + const double vzrdst = vzrst * mins1_b + vz_shared; + const double temp_dst = sm * bxs + vyldst * byldst + vzldst * bzldst; + const double eeldst = eelst - sqrtrol * signbx * (vdbstl - temp_dst) * maxs1_b; + const double eerdst = eerst + sqrtror * signbx * (vdbstr - temp_dst) * maxs1_b; + + const double sign1 = sign_unit(sm); + const double maxs1 = std::max(0.0, sign1); + const double mins1 = -std::min(0.0, sign1); + const double msl = std::min(sl, 0.0); + const double mslst = std::min(slst, 0.0); + const double msrst = std::max(srst, 0.0); + const double msr = std::max(sr, 0.0); + const double temp_flux_l = mslst - msl; + const double temp_flux_r = msrst - msr; + + return StateVector{ + (fql[0] - msl * rol - rolst * temp_flux_l + roldst * mslst) * maxs1 + + (fqr[0] - msr * ror - rorst * temp_flux_r + rordst * msrst) * mins1, + (fql[1] - msl * rxl - rxlst * temp_flux_l + rxldst * mslst) * maxs1 + + (fqr[1] - msr * rxr - rxrst * temp_flux_r + rxrdst * msrst) * mins1, + (fql[2] - msl * ryl - rylst * temp_flux_l + ryldst * mslst) * maxs1 + + (fqr[2] - msr * ryr - ryrst * temp_flux_r + ryrdst * msrst) * mins1, + (fql[3] - msl * rzl - rzlst * temp_flux_l + rzldst * mslst) * maxs1 + + (fqr[3] - msr * rzr - rzrst * temp_flux_r + rzrdst * msrst) * mins1, + (fql[4] - msl * eel - eelst * temp_flux_l + eeldst * mslst) * maxs1 + + (fqr[4] - msr * eer - eerst * temp_flux_r + eerdst * msrst) * mins1, + (fql[5] - msl * byl - bylst * temp_flux_l + byldst * mslst) * maxs1 + + (fqr[5] - msr * byr - byrst * temp_flux_r + byrdst * msrst) * mins1, + (fql[6] - msl * bzl - bzlst * temp_flux_l + bzldst * mslst) * maxs1 + + (fqr[6] - msr * bzr - bzrst * temp_flux_r + bzrdst * msrst) * mins1, + }; } -FluxState hlld_flux_from_conservative(const ConservativeState& left, const ConservativeState& right, - double bx, double gamma) +StateVector hlld_flux_from_conservative(const StateVector& left, const StateVector& right, + double bx, double gamma) { - (void)left; - (void)right; - (void)bx; - (void)gamma; - return zero_flux(); + return hlld_flux_from_primitive(primitive_from_conservative(left, bx, gamma), + primitive_from_conservative(right, bx, gamma), bx, gamma); } diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.hpp b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.hpp index a5640cb..08d1c64 100644 --- a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.hpp +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.hpp @@ -2,12 +2,10 @@ #include -using PrimitiveState = std::array; -using ConservativeState = std::array; -using FluxState = std::array; +using StateVector = std::array; -FluxState hlld_flux_from_primitive(const PrimitiveState& left, const PrimitiveState& right, - double bx, double gamma); +StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, + double gamma); -FluxState hlld_flux_from_conservative(const ConservativeState& left, const ConservativeState& right, - double bx, double gamma); +StateVector hlld_flux_from_conservative(const StateVector& left, const StateVector& right, + double bx, double gamma); diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/cpp/test_public.cpp b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/cpp/test_public.cpp index fc17d25..abb9bf1 100644 --- a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/cpp/test_public.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/cpp/test_public.cpp @@ -16,8 +16,9 @@ namespace { constexpr double kTolerance = 1e-12; +constexpr double kPi = 3.14159265358979323846; -ConservativeState primitive_to_conservative(const PrimitiveState& state, double bx, double gamma) +StateVector primitive_to_conservative(const StateVector& state, double bx, double gamma) { const double rho = state[0]; const double u = state[1]; @@ -31,12 +32,12 @@ ConservativeState primitive_to_conservative(const PrimitiveState& state, double const double magnetic = 0.5 * (bx * bx + by * by + bz * bz); const double energy = p / (gamma - 1.0) + kinetic + magnetic; - return ConservativeState{ + return StateVector{ rho, rho * u, rho * v, rho * w, energy, by, bz, }; } -FluxState physical_flux_x(const ConservativeState& state, double bx, double gamma) +StateVector physical_flux_x(const StateVector& state, double bx, double gamma) { const double rho = state[0]; const double mx = state[1]; @@ -54,7 +55,7 @@ FluxState physical_flux_x(const ConservativeState& state, double bx, double gamm const double pressure = (gamma - 1.0) * (energy - kinetic - magnetic); const double total_pressure = pressure + magnetic; - return FluxState{ + return StateVector{ rho * u, rho * u * u + total_pressure - bx * bx, rho * v * u - bx * by, @@ -65,7 +66,7 @@ FluxState physical_flux_x(const ConservativeState& state, double bx, double gamm }; } -void require_close(const FluxState& actual, const FluxState& expected) +void require_close(const StateVector& actual, const StateVector& expected) { for (std::size_t i = 0; i < actual.size(); ++i) { REQUIRE(std::abs(actual[i] - expected[i]) <= kTolerance); @@ -76,13 +77,13 @@ void require_close(const FluxState& actual, const FluxState& expected) TEST_CASE("equal primitive states reduce to the physical flux") { - const double bx = 0.75; - const double gamma = 1.4; - const PrimitiveState state{1.1, 0.2, -0.3, 0.4, 0.9, 0.5, -0.6}; - const ConservativeState conservative = primitive_to_conservative(state, bx, gamma); + const double bx = 0.75; + const double gamma = 1.4; + const StateVector state{1.1, 0.2, -0.3, 0.4, 0.9, 0.5, -0.6}; + const StateVector conservative = primitive_to_conservative(state, bx, gamma); - const FluxState actual = hlld_flux_from_primitive(state, state, bx, gamma); - const FluxState expected = physical_flux_x(conservative, bx, gamma); + const StateVector actual = hlld_flux_from_primitive(state, state, bx, gamma); + const StateVector expected = physical_flux_x(conservative, bx, gamma); require_close(actual, expected); } @@ -92,14 +93,15 @@ TEST_CASE("primitive and conservative entry points agree") const double bx = -0.4; const double gamma = 5.0 / 3.0; - const PrimitiveState left{1.0, 0.3, 0.1, -0.2, 1.0, 0.7, -0.5}; - const PrimitiveState right{0.8, -0.1, -0.4, 0.25, 0.7, -0.2, 0.3}; + const StateVector left{1.0, 0.3, 0.1, -0.2, 1.0, 0.7, -0.5}; + const StateVector right{0.8, -0.1, -0.4, 0.25, 0.7, -0.2, 0.3}; - const ConservativeState left_cons = primitive_to_conservative(left, bx, gamma); - const ConservativeState right_cons = primitive_to_conservative(right, bx, gamma); + const StateVector left_cons = primitive_to_conservative(left, bx, gamma); + const StateVector right_cons = primitive_to_conservative(right, bx, gamma); - const FluxState from_primitive = hlld_flux_from_primitive(left, right, bx, gamma); - const FluxState from_conservative = hlld_flux_from_conservative(left_cons, right_cons, bx, gamma); + const StateVector from_primitive = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector from_conservative = + hlld_flux_from_conservative(left_cons, right_cons, bx, gamma); require_close(from_primitive, from_conservative); } @@ -109,10 +111,10 @@ TEST_CASE("right-going contact discontinuity is resolved exactly") const double bx = 0.8; const double gamma = 5.0 / 3.0; - const PrimitiveState left{1.0, 0.3, 0.2, -0.15, 1.0, 0.6, -0.3}; - const PrimitiveState right{0.7, 0.3, 0.2, -0.15, 1.0, 0.6, -0.3}; + const StateVector left{1.0, 0.3, 0.2, -0.15, 1.0, 0.6, -0.3}; + const StateVector right{0.7, 0.3, 0.2, -0.15, 1.0, 0.6, -0.3}; - const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); require_close(actual, physical_flux_x(primitive_to_conservative(left, bx, gamma), bx, gamma)); } @@ -121,10 +123,10 @@ TEST_CASE("left-going contact discontinuity is resolved exactly") const double bx = 0.8; const double gamma = 5.0 / 3.0; - const PrimitiveState left{1.0, -0.25, 0.2, -0.15, 1.0, 0.6, -0.3}; - const PrimitiveState right{0.7, -0.25, 0.2, -0.15, 1.0, 0.6, -0.3}; + const StateVector left{1.0, -0.25, 0.2, -0.15, 1.0, 0.6, -0.3}; + const StateVector right{0.7, -0.25, 0.2, -0.15, 1.0, 0.6, -0.3}; - const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); require_close(actual, physical_flux_x(primitive_to_conservative(right, bx, gamma), bx, gamma)); } @@ -133,11 +135,14 @@ TEST_CASE("right-going rotational discontinuity is resolved exactly") const double bx = 1.0; const double gamma = 5.0 / 3.0; - const PrimitiveState left{1.0, 0.2, 0.1, -0.2, 1.0, 1.0, 0.0}; - const PrimitiveState right{1.0, 0.2, 0.5, -1.0, 1.0, 0.6, 0.8}; + const StateVector left{1.0, 0.2, 0.1, -0.2, 1.0, 1.0, 0.0}; + const StateVector right{1.0, 0.2, 0.5, -1.0, 1.0, 0.6, 0.8}; + const StateVector expected{ + 0.2, 1.04, -0.98, -0.04, 0.609, 0.1, 0.2, + }; - const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); - require_close(actual, physical_flux_x(primitive_to_conservative(left, bx, gamma), bx, gamma)); + const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); } TEST_CASE("left-going rotational discontinuity is resolved exactly") @@ -145,11 +150,14 @@ TEST_CASE("left-going rotational discontinuity is resolved exactly") const double bx = 1.0; const double gamma = 5.0 / 3.0; - const PrimitiveState left{1.0, 0.2, 0.1, -0.2, 1.0, 1.0, 0.0}; - const PrimitiveState right{1.0, 0.2, -0.3, 0.6, 1.0, 0.6, 0.8}; + const StateVector left{1.0, 0.2, 0.1, -0.2, 1.0, 1.0, 0.0}; + const StateVector right{1.0, 0.2, -0.3, 0.6, 1.0, 0.6, 0.8}; + const StateVector expected{ + 0.2, 1.04, -0.66, -0.68, 0.449, 0.42, -0.44, + }; - const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); - require_close(actual, physical_flux_x(primitive_to_conservative(right, bx, gamma), bx, gamma)); + const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); } TEST_CASE("Bx equals zero hydro case matches reference flux") @@ -157,13 +165,13 @@ TEST_CASE("Bx equals zero hydro case matches reference flux") const double bx = 0.0; const double gamma = 1.4; - const PrimitiveState left{1.0, 0.75, 0.0, 0.0, 1.0, 0.0, 0.0}; - const PrimitiveState right{0.125, 0.0, 0.0, 0.0, 0.1, 0.0, 0.0}; - const FluxState expected{ + const StateVector left{1.0, 0.75, 0.0, 0.0, 1.0, 0.0, 0.0}; + const StateVector right{0.125, 0.0, 0.0, 0.0, 0.1, 0.0, 0.0}; + const StateVector expected{ 0.92274146439449267, 1.3581095429585437, 0.0, 0.0, 3.1282919538345322, 0.0, 0.0, }; - const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } @@ -172,14 +180,14 @@ TEST_CASE("Bx equals zero magnetized case matches reference flux") const double bx = 0.0; const double gamma = 5.0 / 3.0; - const PrimitiveState left{1.0, 0.6, 0.1, -0.2, 1.0, 0.7, -0.5}; - const PrimitiveState right{0.7, -0.3, -0.15, 0.25, 0.5, -0.2, 0.4}; - const FluxState expected{ + const StateVector left{1.0, 0.6, 0.1, -0.2, 1.0, 0.7, -0.5}; + const StateVector right{0.7, -0.3, -0.15, 0.25, 0.5, -0.2, 0.4}; + const StateVector expected{ 0.44815524807196727, 2.011116795062418, 0.044815524807196722, -0.089631049614393443, 1.6980640537315086, 0.31370867365037713, -0.22407762403598386, }; - const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } @@ -188,45 +196,111 @@ TEST_CASE("small Bx near-degenerate case matches reference flux") const double bx = 1.0e-6; const double gamma = 1.4; - const PrimitiveState left{1.0, 0.4, 0.2, -0.1, 1.0, 0.5, -0.4}; - const PrimitiveState right{0.85, -0.3, -0.15, 0.25, 0.8, -0.35, 0.45}; - const FluxState expected{ + const StateVector left{1.0, 0.4, 0.2, -0.1, 1.0, 0.5, -0.4}; + const StateVector right{0.85, -0.3, -0.15, 0.25, 0.8, -0.35, 0.45}; + const StateVector expected{ 0.16298732855830989, 1.7549717390289374, 0.032596899426565185, -0.016298279827753587, 0.72345786285986069, 0.081493464279122407, -0.065194831423298072, }; - const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } -TEST_CASE("generic coupled MHD case 1 matches reference flux") +TEST_CASE("Ryu and Jones shock tube matches reference flux") { - const double bx = -0.65; + const double bx = 4.0 / std::sqrt(4.0 * kPi); const double gamma = 5.0 / 3.0; - const PrimitiveState left{1.08, 0.45, -0.12, 0.08, 0.95, 0.4, -0.3}; - const PrimitiveState right{0.72, -0.25, 0.16, -0.05, 0.58, -0.2, 0.35}; - const FluxState expected{ - 0.33341182495747945, 1.3232304013056353, 0.06667172041085781, -0.02277204332310151, - 0.88458241136476201, 0.20058802344338272, -0.18511862133859658, + const StateVector left{ + 1.08, 1.2, 0.01, 0.5, 0.95, 3.6 / std::sqrt(4.0 * kPi), 2.0 / std::sqrt(4.0 * kPi), + }; + const StateVector right{ + 1.0, 0.0, 0.0, 0.0, 1.0, 4.0 / std::sqrt(4.0 * kPi), 2.0 / std::sqrt(4.0 * kPi), + }; + const StateVector expected{ + 0.79485593966715773, 3.5458209484697329, -1.3572358551169827, -0.22185101509215432, + 3.9950643754664625, 0.67495208799031015, -0.062307582042232856, }; - const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } -TEST_CASE("generic coupled MHD case 2 matches reference flux") +TEST_CASE("Brio and Wu shock tube matches reference flux") { - const double bx = 0.35; - const double gamma = 1.4; + const double bx = 0.75; + const double gamma = 5.0 / 3.0; + + const StateVector left{1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0}; + const StateVector right{0.125, 0.0, 0.0, 0.0, 0.1, -1.0, 0.0}; + const StateVector expected{ + 0.2063330447744266, + 0.4638678509599396, + 0.064186763013841408, + 0.0, + 0.16136546437466026, + 1.010233243594872, + 0.0, + }; + + const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("Falle switch-off shock matches reference flux") +{ + const double bx = 1.0; + const double gamma = 5.0 / 3.0; + + const StateVector left{1.368, 0.269, 1.0, 0.0, 1.769, 0.0, 0.0}; + const StateVector right{1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0}; + const StateVector expected{ + 0.29721990694355238, + 1.4932992607654056, + 0.2893229270591654, + 0.0, + 1.1427267633652525, + -1.0066552479847843, + 0.0, + }; + + const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("Falle switch-off rarefaction matches reference flux") +{ + const double bx = 1.0; + const double gamma = 5.0 / 3.0; + + const StateVector left{1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0}; + const StateVector right{0.2, 1.186, 2.967, 0.0, 0.1368, 1.6405, 0.0}; + const StateVector expected{ + 0.27717801577960577, + 0.28228035303750848, + -1.3364302412732558, + 0.0, + -1.5599793330037519, + -1.3806947854633354, + 0.0, + }; + + const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("super-fast expansion matches reference flux") +{ + const double bx = 0.0; + const double gamma = 5.0 / 3.0; - const PrimitiveState left{0.9, -0.45, 0.2, 0.15, 0.8, -0.3, 0.55}; - const PrimitiveState right{1.15, 0.18, -0.12, -0.08, 1.05, 0.22, -0.4}; - const FluxState expected{ - -0.14227120841958368, 0.6095322640180193, 0.028703852070217931, 0.063723510257583313, - -0.40524273615789225, -0.065690714628438368, 0.14700372046240096, + const StateVector left{1.0, -3.0, 0.0, 0.0, 0.45, 0.5, 0.0}; + const StateVector right{1.0, 3.0, 0.0, 0.0, 0.45, 0.5, 0.0}; + const StateVector expected{ + 0.0, -2.425, 0.0, 0.0, 0.0, 0.0, 0.0, }; - const FluxState actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } diff --git a/docker/Dockerfile b/docker/Dockerfile index 634b404..47f5d67 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -3,6 +3,7 @@ FROM debian:bookworm-slim ENV DEBIAN_FRONTEND=noninteractive ARG FLAP_VERSION=1.2.16 +ARG OPENCODE_VERSION=1.3.3 ARG CATCH2_REF=v3.13.0 ARG MDSPAN_REF=mdspan-0.6.0 ARG XTL_REF=0.8.2 @@ -97,7 +98,7 @@ RUN apt-get update \ && rm -rf /tmp/flap-build "/tmp/FLAP-v${FLAP_VERSION}" \ && curl -LsSf https://astral.sh/uv/install.sh | env UV_UNMANAGED_INSTALL=/usr/local/bin sh \ && uv pip install --system --break-system-packages --no-cache ruff fprettify \ - && npm install -g opencode-ai @anthropic-ai/claude-code @openai/codex @github/copilot \ + && npm install -g opencode-ai@${OPENCODE_VERSION} @anthropic-ai/claude-code @openai/codex @github/copilot \ && uv --version WORKDIR /work diff --git a/runner/execution_agent.py b/runner/execution_agent.py index 0b0ee9c..aa86bec 100644 --- a/runner/execution_agent.py +++ b/runner/execution_agent.py @@ -126,7 +126,7 @@ def _run_agent_in_docker( opencode_state_dir.mkdir(parents=True, exist_ok=True) docker_cmd += [ "-e", - "XDG_DATA_HOME=/opencode-data", + "HOME=/opencode-data", "-v", f"{str(opencode_state_dir)}:/opencode-data:rw", ] diff --git a/runner/metrics_helpers.py b/runner/metrics_helpers.py index e28c263..0ec9090 100644 --- a/runner/metrics_helpers.py +++ b/runner/metrics_helpers.py @@ -143,7 +143,7 @@ def _opencode_state_dir(run_dir: Path) -> Path: def _collect_opencode_usage_metrics(*, state_dir: Path) -> dict[str, Any]: env = dict(os.environ) - env["XDG_DATA_HOME"] = str(state_dir) + env["HOME"] = str(state_dir) cmd = ["opencode", "stats", "--models", "1"] try: proc = subprocess.run( diff --git a/scripts/build_image.py b/scripts/build_image.py index 6cf0d3a..a65d9a3 100755 --- a/scripts/build_image.py +++ b/scripts/build_image.py @@ -11,6 +11,7 @@ DOCKERFILE = REPO_ROOT / "docker" / "Dockerfile" FLAP_VERSION = "1.2.16" +OPENCODE_VERSION = "1.3.3" CATCH2_REF = "v3.13.0" MDSPAN_REF = "mdspan-0.6.0" XTL_REF = "0.8.2" @@ -45,6 +46,8 @@ def main(argv: list[str]) -> int: "--build-arg", f"FLAP_VERSION={FLAP_VERSION}", "--build-arg", + f"OPENCODE_VERSION={OPENCODE_VERSION}", + "--build-arg", f"CATCH2_REF={CATCH2_REF}", "--build-arg", f"MDSPAN_REF={MDSPAN_REF}", diff --git a/tests/test_runner_cli_flow.py b/tests/test_runner_cli_flow.py index 39dfbca..b397844 100644 --- a/tests/test_runner_cli_flow.py +++ b/tests/test_runner_cli_flow.py @@ -1814,7 +1814,9 @@ def fake_eval(*args, **kwargs): def fake_subprocess_run(cmd, **kwargs): if cmd == ["opencode", "stats", "--models", "1"]: - self.assertIn("XDG_DATA_HOME", kwargs["env"]) + self.assertTrue( + str(kwargs["env"].get("HOME", "")).endswith("/.opencode-data") + ) return subprocess.CompletedProcess( cmd, 0, stdout=stats_output, stderr="" ) From 1388e34f2b8ce732e1e2583d3637742ac156c8e8 Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Sat, 28 Mar 2026 23:53:49 +0900 Subject: [PATCH 07/39] Add full 1D MHD benchmark with Brio-Wu reference --- benchmarks/magnetohydrodynamics/README.md | 12 + .../cpp-full-solver1d/eval/run.sh | 28 + .../eval/tests/test_hidden.py | 49 + .../cpp-full-solver1d/spec.md | 200 ++++ .../cpp-full-solver1d/task.toml | 8 + .../workspace/CMakeLists.txt | 58 ++ .../cpp-full-solver1d/workspace/README.md | 3 + .../workspace/examples/brio_wu.toml | 28 + .../workspace/pyproject.toml | 7 + .../workspace/scripts/plot_solution.py | 95 ++ .../cpp-full-solver1d/workspace/src/main.cpp | 37 + .../cpp-full-solver1d/workspace/src/mhd1d.cpp | 572 ++++++++++++ .../cpp-full-solver1d/workspace/src/mhd1d.hpp | 72 ++ .../workspace/tests/cpp/test_public.cpp | 154 +++ .../workspace/tests/test_public.py | 57 ++ .../shared/eval/README.md | 73 +- .../shared/eval/fixtures/mhd1d/README.md | 29 + .../eval/fixtures/mhd1d/brio_wu_fixture.json | 45 + .../eval/fixtures/mhd1d/brio_wu_reference.csv | 401 ++++++++ .../shared/eval/mhd1d_reference.py | 877 ++++++++++++++++++ .../shared/eval/mhd1d_shared.py | 303 ++++++ 21 files changed, 3107 insertions(+), 1 deletion(-) create mode 100755 benchmarks/magnetohydrodynamics/cpp-full-solver1d/eval/run.sh create mode 100644 benchmarks/magnetohydrodynamics/cpp-full-solver1d/eval/tests/test_hidden.py create mode 100644 benchmarks/magnetohydrodynamics/cpp-full-solver1d/spec.md create mode 100644 benchmarks/magnetohydrodynamics/cpp-full-solver1d/task.toml create mode 100644 benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/CMakeLists.txt create mode 100644 benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/README.md create mode 100644 benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/examples/brio_wu.toml create mode 100644 benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/pyproject.toml create mode 100644 benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/scripts/plot_solution.py create mode 100644 benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp create mode 100644 benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp create mode 100644 benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp create mode 100644 benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp create mode 100644 benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/test_public.py create mode 100644 benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/README.md create mode 100644 benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_fixture.json create mode 100644 benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_reference.csv create mode 100644 benchmarks/magnetohydrodynamics/shared/eval/mhd1d_reference.py create mode 100644 benchmarks/magnetohydrodynamics/shared/eval/mhd1d_shared.py diff --git a/benchmarks/magnetohydrodynamics/README.md b/benchmarks/magnetohydrodynamics/README.md index 86f3848..4101405 100644 --- a/benchmarks/magnetohydrodynamics/README.md +++ b/benchmarks/magnetohydrodynamics/README.md @@ -7,12 +7,24 @@ This suite contains benchmark tasks for ideal magnetohydrodynamics solvers. - `shared/workspace/basic_equations.md`: suite-wide notation and flux conventions. - `shared/workspace/hlld.md`: HLLD algorithm notes for solver tasks. - `cpp-hlld/`: C++ HLLD approximate Riemann solver task. +- `cpp-full-solver1d/`: C++ full 1D ideal MHD solver (Brio-Wu benchmark). +- `shared/eval/README.md`: hidden-eval contract for shared MHD scoring assets. +- `shared/eval/mhd1d_reference.py`: hidden reference generator for the 1D + full-solver task. +- `shared/eval/mhd1d_shared.py`: shared helpers for CSV loading, score + windows, and comparison metadata. +- `shared/eval/fixtures/mhd1d/`: hidden fixtures for `cpp-full-solver1d`. ## Notes - Shared workspace files are visible to the agent during benchmark runs. - Keep maintainer-only derivations, generators, and hidden fixtures outside the shared workspace. +- `cpp-full-solver1d` scores only the interior cells, excluding two + edge-adjacent cells on each side, against the variables `rho`, `u`, `p`, and + `by` using fixture-recorded `abs_l1` and `abs_linf` tolerances. CSV fixture + headers keep the magnetic fields lowercase (`by`, `bz`) even when the code + and solver notation use `By` and `Bz`. ## Reference credit diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/eval/run.sh b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/eval/run.sh new file mode 100755 index 0000000..5132b67 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/eval/run.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -u -o pipefail + +cd /work +export PYTHONPATH="/work:/eval_shared" + +status="passed" +score="1.0" + +python3 -m pytest -q /eval/tests +rc=$? +if [ "$rc" -ne 0 ]; then + status="failed" + score="0.0" +fi + +python3 - < Path: + subprocess.run(["cmake", "-S", ".", "-B", str(build_dir)], check=True) + subprocess.run( + ["cmake", "--build", str(build_dir), "--target", SOLVER_TARGET], + check=True, + ) + + binary_name = f"{SOLVER_TARGET}.exe" if os.name == "nt" else SOLVER_TARGET + solver_path = build_dir / "bin" / binary_name + assert solver_path.exists() + return solver_path + + +def test_hidden_brio_wu_cli_matches_fixture(tmp_path: Path) -> None: + solver_path = _build_solver(tmp_path / "build") + output_csv_path = tmp_path / "brio_wu.csv" + + completed = subprocess.run( + [str(solver_path), "examples/brio_wu.toml"], + check=True, + capture_output=True, + text=True, + ) + output_csv_path.write_text(completed.stdout, encoding="utf-8") + + profile = load_mhd1d_csv_profile(output_csv_path) + assert profile.header == CSV_HEADER + + comparison = compare_mhd1d_csv_against_fixture(output_csv_path) + assert comparison.passed + + for column_name in ("v", "w", "bz"): + for row in profile.rows: + assert math.isfinite(row[column_name]) diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/spec.md b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/spec.md new file mode 100644 index 0000000..31af33a --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/spec.md @@ -0,0 +1,200 @@ +# cpp-full-solver1d + +Implement a 1D ideal MHD full solver in C++. + +## Task + +The benchmark contract is fixed around these choices: + +- domain: `[0, 1]` +- initial discontinuity: `x = 0.5` +- conservative evolution +- primitive reconstruction: MC2 +- flux function: HLLD +- time integration: SSP-RK3 +- boundary conditions: zero-gradient +- input format: TOML +- output format: CSV with columns `x,rho,u,v,w,p,by,bz` +- default problem: Brio-Wu with `gamma = 2` and `Bx = 0.75` + +## Numerical method + +The solver implements the following numerical scheme: + +1. **Reconstruction**: MC2 (minmod with centered differences) for primitive variables +2. **Riemann solver**: HLLD approximate Riemann solver for ideal MHD fluxes +3. **Time integration**: SSP-RK3 (strong stability preserving Runge-Kutta, 3rd order) +4. **Boundary conditions**: Zero-gradient ghost cells (2 cells per side) + +### State ordering + +Primitive state vector (7 components): +``` +[rho, u, v, w, p, By, Bz] +``` + +Conservative state vector (7 components): +``` +[rho, mx, my, mz, E, By, Bz] +``` + +where `mx = rho * u`, `my = rho * v`, `mz = rho * w`, and total energy +`E = p/(gamma-1) + 0.5*rho*(u^2+v^2+w^2) + 0.5*(Bx^2+By^2+Bz^2)`. + +### Default constants + +| Parameter | Value | +|-----------|-------| +| `gamma` | 2.0 | +| `Bx` | 0.75 | +| `dt` | 5.0e-4 | +| `t_final` | 0.1 | +| `nx` | 400 | + +## Building + +```bash +mkdir build && cd build +cmake .. +cmake --build . +``` + +The solver executable is placed at `build/bin/cpp_full_solver1d`. + +## Usage + +```bash +./bin/cpp_full_solver1d +``` + +The solver reads a TOML configuration file and writes CSV output to stdout. + +### Example input (Brio-Wu) + +```toml +nx = 400 +x_left = 0.0 +x_right = 1.0 +discontinuity_x = 0.5 +gamma = 2.0 +bx = 0.75 +dt = 5.0e-4 +t_final = 0.1 + +[left] +rho = 1.0 +u = 0.0 +v = 0.0 +w = 0.0 +p = 1.0 +by = 1.0 +bz = 0.0 + +[right] +rho = 0.125 +u = 0.0 +v = 0.0 +w = 0.0 +p = 0.1 +by = -1.0 +bz = 0.0 +``` + +### Running and saving output + +```bash +./bin/cpp_full_solver1d examples/brio_wu.toml > solution.csv +``` + +## Visualization + +A plot helper script is provided for quick inspection of results: + +```bash +python scripts/plot_solution.py solution.csv +``` + +This displays profiles for density (`rho`), velocity (`u`), pressure (`p`), and +magnetic field (`by`). + +## API reference + +### Core functions (`mhd1d.hpp`) + +#### `ProblemConfig make_brio_wu_example()` + +Returns a `ProblemConfig` pre-configured with the canonical Brio-Wu parameters. + +#### `StateVector primitive_to_conservative(const StateVector& primitive, double bx, double gamma)` + +Converts a primitive state vector to conservative form. + +**Parameters:** +- `primitive`: 7-component primitive state `[rho, u, v, w, p, By, Bz]` +- `bx`: Constant x-component of magnetic field +- `gamma`: Adiabatic index + +**Returns:** 7-component conservative state `[rho, mx, my, mz, E, By, Bz]` + +#### `StateVector conservative_to_primitive(const StateVector& conservative, double bx, double gamma)` + +Converts a conservative state vector to primitive form. + +**Parameters:** +- `conservative`: 7-component conservative state +- `bx`: Constant x-component of magnetic field +- `gamma`: Adiabatic index + +**Returns:** 7-component primitive state + +#### `std::pair, std::vector> reconstruct_mc2_interfaces(const std::vector& primitive_cells)` + +Performs MC2 slope-limited reconstruction at cell interfaces. + +**Parameters:** +- `primitive_cells`: Cell-centered primitive states + +**Returns:** Pair of left and right interface states + +#### `StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, double gamma)` + +Computes the HLLD numerical flux given left and right primitive states. + +**Parameters:** +- `left`: Left primitive state at interface +- `right`: Right primitive state at interface +- `bx`: Constant x-component of magnetic field +- `gamma`: Adiabatic index + +**Returns:** Numerical flux vector + +#### `std::vector run_full_simulation(const ProblemConfig& problem)` + +Runs the complete simulation from initial conditions to `t_final`. + +**Parameters:** +- `problem`: Problem configuration with initial states and parameters + +**Returns:** Final primitive state profile at `t_final` + +#### `std::vector ssp_rk3_step(const std::vector& conservative_cells, double dt, double dx, double bx, double gamma)` + +Performs one SSP-RK3 time step. + +**Parameters:** +- `conservative_cells`: Current conservative state profile +- `dt`: Time step size +- `dx`: Cell width +- `bx`: Constant x-component of magnetic field +- `gamma`: Adiabatic index + +**Returns:** Updated conservative state profile + +## Evaluation + +The hidden evaluation compares solver output against a reference solution using: + +- **Scored variables**: `rho`, `u`, `p`, `by` +- **Comparison window**: Interior cells only (excludes 2 edge-adjacent cells per side) +- **Metrics**: L1 and Linf absolute errors +- **Tolerances**: Defined in `shared/eval/fixtures/mhd1d/brio_wu_fixture.json` diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/task.toml b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/task.toml new file mode 100644 index 0000000..3c4cb26 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/task.toml @@ -0,0 +1,8 @@ +id = "cpp-full-solver1d" +suite = "magnetohydrodynamics" +language = "cpp" +time_limit_sec = 600 +eval_cmd = "/eval/run.sh" +prompt = "Read /run/spec.md and solve the task in /work." +use_shared_workspace = true +use_shared_eval = true diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/CMakeLists.txt b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/CMakeLists.txt new file mode 100644 index 0000000..01604e3 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/CMakeLists.txt @@ -0,0 +1,58 @@ +cmake_minimum_required(VERSION 3.16) + +project(cpp_full_solver1d LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +include(FetchContent) + +find_package(Catch2 3 QUIET) + +if(NOT Catch2_FOUND) + FetchContent_Declare( + Catch2 + GIT_REPOSITORY https://github.com/catchorg/Catch2.git + GIT_TAG v3.13.0 + GIT_SHALLOW TRUE + ) + FetchContent_MakeAvailable(Catch2) +endif() + +add_library(mhd1d_solver + src/mhd1d.cpp +) + +target_include_directories(mhd1d_solver PUBLIC + src +) + +add_executable(cpp_full_solver1d + src/main.cpp +) + +target_link_libraries(cpp_full_solver1d PRIVATE + mhd1d_solver +) + +set_target_properties(cpp_full_solver1d PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" +) + +add_executable(cpp_full_solver1d_public_tests + tests/cpp/test_public.cpp +) + +target_link_libraries(cpp_full_solver1d_public_tests PRIVATE + mhd1d_solver + Catch2::Catch2WithMain +) + +target_include_directories(cpp_full_solver1d_public_tests PRIVATE + src +) + +set_target_properties(cpp_full_solver1d_public_tests PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests" +) diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/README.md b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/README.md new file mode 100644 index 0000000..734c8d9 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/README.md @@ -0,0 +1,3 @@ +The public C++ workspace skeleton will be added next. + +Shared workspace docs are already mounted for this benchmark. diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/examples/brio_wu.toml b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/examples/brio_wu.toml new file mode 100644 index 0000000..38c3f1b --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/examples/brio_wu.toml @@ -0,0 +1,28 @@ +# Canonical Brio-Wu benchmark input for cpp-full-solver1d. + +nx = 400 +x_left = 0.0 +x_right = 1.0 +discontinuity_x = 0.5 +gamma = 2.0 +bx = 0.75 +dt = 5.0e-4 +t_final = 0.1 + +[left] +rho = 1.0 +u = 0.0 +v = 0.0 +w = 0.0 +p = 1.0 +by = 1.0 +bz = 0.0 + +[right] +rho = 0.125 +u = 0.0 +v = 0.0 +w = 0.0 +p = 0.1 +by = -1.0 +bz = 0.0 diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/pyproject.toml b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/pyproject.toml new file mode 100644 index 0000000..8eee297 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/pyproject.toml @@ -0,0 +1,7 @@ +[project] +name = "magnetohydrodynamics-cpp-full-solver1d" +version = "0.0.0" +requires-python = ">=3.10" + +[tool.pytest.ini_options] +testpaths = ["tests"] diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/scripts/plot_solution.py b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/scripts/plot_solution.py new file mode 100644 index 0000000..7cf2ca4 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/scripts/plot_solution.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +"""Plot a Brio-Wu solver CSV for quick inspection. + +Usage: + python scripts/plot_solution.py [path/to/solution.csv] + +If no path is provided, the script looks for ``solution.csv`` in the current +working directory. +""" + +from __future__ import annotations + +import argparse +import csv +from pathlib import Path +import sys + +import matplotlib.pyplot as plt + + +EXPECTED_FIELDS = ["x", "rho", "u", "v", "w", "p", "by", "bz"] +DEFAULT_CSV = Path("solution.csv") + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Plot the Brio-Wu solver profiles from a CSV file.", + ) + parser.add_argument( + "csv_path", + nargs="?", + type=Path, + default=DEFAULT_CSV, + help="CSV file to plot (defaults to solution.csv in the current directory).", + ) + return parser.parse_args() + + +def load_columns(csv_path: Path) -> dict[str, list[float]]: + with csv_path.open(newline="", encoding="utf-8") as handle: + reader = csv.DictReader(handle) + if reader.fieldnames != EXPECTED_FIELDS: + raise ValueError( + f"expected CSV header x,rho,u,v,w,p,by,bz; got {reader.fieldnames!r}" + ) + + columns: dict[str, list[float]] = {field: [] for field in EXPECTED_FIELDS} + for row in reader: + for field in EXPECTED_FIELDS: + columns[field].append(float(row[field])) + + return columns + + +def main() -> int: + args = parse_args() + csv_path = args.csv_path + + if not csv_path.is_file(): + print(f"error: CSV file not found: {csv_path}", file=sys.stderr) + return 1 + + try: + columns = load_columns(csv_path) + except (OSError, ValueError, KeyError) as exc: + print(f"error: {exc}", file=sys.stderr) + return 1 + + x_values = columns["x"] + + fig, axes = plt.subplots(2, 2, figsize=(10, 7), sharex=True) + plots = [ + (axes[0, 0], "rho", "Density"), + (axes[0, 1], "u", "Velocity u"), + (axes[1, 0], "p", "Pressure"), + (axes[1, 1], "by", "Magnetic field by"), + ] + + for axis, field, title in plots: + axis.plot(x_values, columns[field], linewidth=1.5) + axis.set_title(title) + axis.set_ylabel(field) + axis.grid(True, alpha=0.3) + + for axis in axes[1, :]: + axis.set_xlabel("x") + + fig.suptitle(f"Brio-Wu profiles: {csv_path}") + fig.tight_layout() + plt.show() + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp new file mode 100644 index 0000000..e94b7c3 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp @@ -0,0 +1,37 @@ +#include "mhd1d.hpp" + +#include +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + if (argc != 2) { + std::cerr << "usage: cpp_full_solver1d \n"; + return 2; + } + + const std::string input_path = argv[1]; + std::ifstream input_stream(input_path); + if (!input_stream) { + std::cerr << "cpp-full-solver1d: unable to read TOML input '" << input_path << "'\n"; + return 1; + } + + const mhd1d::ProblemConfig problem = mhd1d::make_brio_wu_example(); + const std::vector final_primitive_cells = mhd1d::run_full_simulation(problem); + const std::vector centers = + mhd1d::cell_centers(problem.nx, problem.x_left, problem.x_right); + + std::cout << "x,rho,u,v,w,p,by,bz\n"; + std::cout << std::setprecision(17); + for (std::size_t index = 0; index < final_primitive_cells.size(); ++index) { + const mhd1d::StateVector& cell = final_primitive_cells[index]; + std::cout << centers[index] << ',' << cell[0] << ',' << cell[1] << ',' << cell[2] << ',' + << cell[3] << ',' << cell[4] << ',' << cell[5] << ',' << cell[6] << '\n'; + } + + return 0; +} diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp new file mode 100644 index 0000000..548edee --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp @@ -0,0 +1,572 @@ +#include "mhd1d.hpp" + +#include +#include +#include +#include + +namespace mhd1d +{ + +namespace +{ + +constexpr double kDefaultGamma = 2.0; +constexpr double kDefaultBx = 0.75; +constexpr double kDefaultDt = 5.0e-4; +constexpr double kDefaultTFinal = 0.1; +constexpr std::size_t kDefaultNx = 400; +constexpr std::size_t kGhostWidth = 2U; +constexpr double kHlldEps = 1.0e-40; + +double sign_unit(double x) +{ + return (x >= 0.0) ? 1.0 : -1.0; +} + +double minmod3(double first, double second, double third) +{ + if (first * second > 0.0 && first * third > 0.0) { + const double limited = std::min({std::abs(first), std::abs(second), std::abs(third)}); + return std::copysign(limited, first); + } + + return 0.0; +} + +} // namespace + +namespace +{ + +std::vector +conservative_profile_to_primitive_profile(const std::vector& conservative_cells, + double bx, double gamma) +{ + std::vector primitive_cells(conservative_cells.size()); + for (std::size_t index = 0; index < conservative_cells.size(); ++index) { + primitive_cells[index] = conservative_to_primitive(conservative_cells[index], bx, gamma); + } + + return primitive_cells; +} + +} // namespace + +ProblemConfig make_brio_wu_example() +{ + return ProblemConfig{ + kDefaultNx, + 0.0, + 1.0, + 0.5, + kDefaultDt, + kDefaultTFinal, + kDefaultGamma, + kDefaultBx, + StateVector{1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0}, + StateVector{0.125, 0.0, 0.0, 0.0, 0.1, -1.0, 0.0}, + }; +} + +StateVector primitive_to_conservative(const StateVector& primitive, double bx, double gamma) +{ + const double rho = primitive[0]; + const double u = primitive[1]; + const double v = primitive[2]; + const double w = primitive[3]; + const double pressure = primitive[4]; + const double by = primitive[5]; + const double bz = primitive[6]; + + const double kinetic_energy = 0.5 * rho * (u * u + v * v + w * w); + const double magnetic_energy = 0.5 * (bx * bx + by * by + bz * bz); + + return StateVector{ + rho, rho * u, rho * v, rho * w, pressure / (gamma - 1.0) + kinetic_energy + magnetic_energy, + by, bz, + }; +} + +StateVector conservative_to_primitive(const StateVector& conservative, double bx, double gamma) +{ + const double rho = conservative[0]; + if (rho <= 0.0) { + throw std::runtime_error("density must be positive"); + } + + const double u = conservative[1] / rho; + const double v = conservative[2] / rho; + const double w = conservative[3] / rho; + const double by = conservative[5]; + const double bz = conservative[6]; + + const double kinetic_energy = 0.5 * rho * (u * u + v * v + w * w); + const double magnetic_energy = 0.5 * (bx * bx + by * by + bz * bz); + const double pressure = (gamma - 1.0) * (conservative[4] - kinetic_energy - magnetic_energy); + + return StateVector{rho, u, v, w, pressure, by, bz}; +} + +std::vector mc2_slopes(const std::vector& primitive_cells) +{ + if (primitive_cells.size() < 3U) { + throw std::runtime_error("primitive_cells must contain at least three cells"); + } + + std::vector slopes(primitive_cells.size()); + for (std::size_t index = 1; index + 1U < primitive_cells.size(); ++index) { + const StateVector& left_cell = primitive_cells[index - 1U]; + const StateVector& center_cell = primitive_cells[index]; + const StateVector& right_cell = primitive_cells[index + 1U]; + StateVector& limited_slope = slopes[index]; + + for (std::size_t component = 0; component < kStateWidth; ++component) { + const double left_difference = center_cell[component] - left_cell[component]; + const double right_difference = right_cell[component] - center_cell[component]; + const double centered_difference = 0.5 * (right_cell[component] - left_cell[component]); + limited_slope[component] = + minmod3(2.0 * left_difference, centered_difference, 2.0 * right_difference); + } + } + + return slopes; +} + +std::pair, std::vector> +reconstruct_mc2_interfaces(const std::vector& primitive_cells) +{ + const std::vector slopes = mc2_slopes(primitive_cells); + const std::size_t interface_count = primitive_cells.size() - 1U; + + std::vector left_states(interface_count); + std::vector right_states(interface_count); + + for (std::size_t index = 0; index < interface_count; ++index) { + for (std::size_t component = 0; component < kStateWidth; ++component) { + left_states[index][component] = + primitive_cells[index][component] + 0.5 * slopes[index][component]; + right_states[index][component] = + primitive_cells[index + 1U][component] - 0.5 * slopes[index + 1U][component]; + } + } + + return {left_states, right_states}; +} + +StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, + double gamma) +{ + const double rol = left[0]; + const double vxl = left[1]; + const double vyl = left[2]; + const double vzl = left[3]; + const double prl = left[4]; + const double byl = left[5]; + const double bzl = left[6]; + + const double ror = right[0]; + const double vxr = right[1]; + const double vyr = right[2]; + const double vzr = right[3]; + const double prr = right[4]; + const double byr = right[5]; + const double bzr = right[6]; + + const double igm = 1.0 / (gamma - 1.0); + const double bxs = bx; + const double bxsq = bxs * bxs; + + const double pbl = 0.5 * (bxsq + byl * byl + bzl * bzl); + const double pbr = 0.5 * (bxsq + byr * byr + bzr * bzr); + const double ptl = prl + pbl; + const double ptr = prr + pbr; + + const double rxl = rol * vxl; + const double ryl = rol * vyl; + const double rzl = rol * vzl; + const double rxr = ror * vxr; + const double ryr = ror * vyr; + const double rzr = ror * vzr; + + const double eel = prl * igm + 0.5 * (rxl * vxl + ryl * vyl + rzl * vzl) + pbl; + const double eer = prr * igm + 0.5 * (rxr * vxr + ryr * vyr + rzr * vzr) + pbr; + + const double gmpl = gamma * prl; + const double gmpr = gamma * prr; + const double gpbl = gmpl + 2.0 * pbl; + const double gpbr = gmpr + 2.0 * pbr; + + const double cfl = std::sqrt((gpbl + std::sqrt((gmpl - 2.0 * pbl) * (gmpl - 2.0 * pbl) + + 4.0 * gmpl * (byl * byl + bzl * bzl))) * + 0.5 / rol); + const double cfr = std::sqrt((gpbr + std::sqrt((gmpr - 2.0 * pbr) * (gmpr - 2.0 * pbr) + + 4.0 * gmpr * (byr * byr + bzr * bzr))) * + 0.5 / ror); + + const double sl = std::min(vxl, vxr) - std::max(cfl, cfr); + const double sr = std::max(vxl, vxr) + std::max(cfl, cfr); + + const StateVector fql{rxl, + rxl * vxl + ptl - bxsq, + rxl * vyl - bxs * byl, + rxl * vzl - bxs * bzl, + vxl * (eel + ptl - bxsq) - bxs * (vyl * byl + vzl * bzl), + byl * vxl - bxs * vyl, + bzl * vxl - bxs * vzl}; + const StateVector fqr{rxr, + rxr * vxr + ptr - bxsq, + rxr * vyr - bxs * byr, + rxr * vzr - bxs * bzr, + vxr * (eer + ptr - bxsq) - bxs * (vyr * byr + vzr * bzr), + byr * vxr - bxs * vyr, + bzr * vxr - bxs * vzr}; + + const double sdl = sl - vxl; + const double sdr = sr - vxr; + const double rosdl = rol * sdl; + const double rosdr = ror * sdr; + const double temp = 1.0 / (rosdr - rosdl); + const double sm = (rosdr * vxr - rosdl * vxl - ptr + ptl) * temp; + const double sdml = sl - sm; + const double sdmr = sr - sm; + const double ptst = (rosdr * ptl - rosdl * ptr + rosdl * rosdr * (vxr - vxl)) * temp; + + const double temp_fst_l = rosdl * sdml - bxsq; + const double sign1_l = sign_unit(std::abs(temp_fst_l) - kHlldEps); + const double maxs1_l = std::max(0.0, sign1_l); + const double mins1_l = std::min(0.0, sign1_l); + const double itf_l = 1.0 / (temp_fst_l + mins1_l); + const double isdml = 1.0 / sdml; + + const double temp_l = bxs * (sdl - sdml) * itf_l; + const double rolst = maxs1_l * (rosdl * isdml) - mins1_l * rol; + const double vxlst = maxs1_l * sm - mins1_l * vxl; + const double rxlst = rolst * vxlst; + const double vylst = maxs1_l * (vyl - byl * temp_l) - mins1_l * vyl; + const double rylst = rolst * vylst; + const double vzlst = maxs1_l * (vzl - bzl * temp_l) - mins1_l * vzl; + const double rzlst = rolst * vzlst; + const double temp_l_b = (rosdl * sdl - bxsq) * itf_l; + const double bylst = maxs1_l * (byl * temp_l_b) - mins1_l * byl; + const double bzlst = maxs1_l * (bzl * temp_l_b) - mins1_l * bzl; + const double vdbstl = vxlst * bxs + vylst * bylst + vzlst * bzlst; + const double eelst = maxs1_l * ((sdl * eel - ptl * vxl + ptst * sm + + bxs * (vxl * bxs + vyl * byl + vzl * bzl - vdbstl)) * + isdml) - + mins1_l * eel; + + const double temp_fst_r = rosdr * sdmr - bxsq; + const double sign1_r = sign_unit(std::abs(temp_fst_r) - kHlldEps); + const double maxs1_r = std::max(0.0, sign1_r); + const double mins1_r = std::min(0.0, sign1_r); + const double itf_r = 1.0 / (temp_fst_r + mins1_r); + const double isdmr = 1.0 / sdmr; + + const double temp_r = bxs * (sdr - sdmr) * itf_r; + const double rorst = maxs1_r * (rosdr * isdmr) - mins1_r * ror; + const double vxrst = maxs1_r * sm - mins1_r * vxr; + const double rxrst = rorst * vxrst; + const double vyrst = maxs1_r * (vyr - byr * temp_r) - mins1_r * vyr; + const double ryrst = rorst * vyrst; + const double vzrst = maxs1_r * (vzr - bzr * temp_r) - mins1_r * vzr; + const double rzrst = rorst * vzrst; + const double temp_r_b = (rosdr * sdr - bxsq) * itf_r; + const double byrst = maxs1_r * (byr * temp_r_b) - mins1_r * byr; + const double bzrst = maxs1_r * (bzr * temp_r_b) - mins1_r * bzr; + const double vdbstr = vxrst * bxs + vyrst * byrst + vzrst * bzrst; + const double eerst = maxs1_r * ((sdr * eer - ptr * vxr + ptst * sm + + bxs * (vxr * bxs + vyr * byr + vzr * bzr - vdbstr)) * + isdmr) - + mins1_r * eer; + + const double sqrtrol = std::sqrt(rolst); + const double sqrtror = std::sqrt(rorst); + const double abbx = std::abs(bxs); + const double slst = sm - abbx / sqrtrol; + const double srst = sm + abbx / sqrtror; + const double signbx = sign_unit(bxs); + const double sign1_b = sign_unit(abbx - kHlldEps); + const double maxs1_b = std::max(0.0, sign1_b); + const double mins1_b = -std::min(0.0, sign1_b); + const double invsumro = maxs1_b / (sqrtrol + sqrtror); + + const double roldst = rolst; + const double rordst = rorst; + const double rxldst = rxlst; + const double rxrdst = rxrst; + + const double vy_shared = + invsumro * (sqrtrol * vylst + sqrtror * vyrst + signbx * (byrst - bylst)); + const double ryldst = rylst * mins1_b + roldst * vy_shared; + const double ryrdst = ryrst * mins1_b + rordst * vy_shared; + + const double vz_shared = + invsumro * (sqrtrol * vzlst + sqrtror * vzrst + signbx * (bzrst - bzlst)); + const double rzldst = rzlst * mins1_b + roldst * vz_shared; + const double rzrdst = rzrst * mins1_b + rordst * vz_shared; + + const double by_shared = + invsumro * (sqrtrol * byrst + sqrtror * bylst + signbx * sqrtrol * sqrtror * (vyrst - vylst)); + const double byldst = bylst * mins1_b + by_shared; + const double byrdst = byrst * mins1_b + by_shared; + + const double bz_shared = + invsumro * (sqrtrol * bzrst + sqrtror * bzlst + signbx * sqrtrol * sqrtror * (vzrst - vzlst)); + const double bzldst = bzlst * mins1_b + bz_shared; + const double bzrdst = bzrst * mins1_b + bz_shared; + + const double vyldst = vylst * mins1_b + vy_shared; + const double vyrdst = vyrst * mins1_b + vy_shared; + const double vzldst = vzlst * mins1_b + vz_shared; + const double vzrdst = vzrst * mins1_b + vz_shared; + const double temp_dst = sm * bxs + vyldst * byldst + vzldst * bzldst; + const double eeldst = eelst - sqrtrol * signbx * (vdbstl - temp_dst) * maxs1_b; + const double eerdst = eerst + sqrtror * signbx * (vdbstr - temp_dst) * maxs1_b; + + const double sign1 = sign_unit(sm); + const double maxs1 = std::max(0.0, sign1); + const double mins1 = -std::min(0.0, sign1); + const double msl = std::min(sl, 0.0); + const double mslst = std::min(slst, 0.0); + const double msrst = std::max(srst, 0.0); + const double msr = std::max(sr, 0.0); + const double temp_flux_l = mslst - msl; + const double temp_flux_r = msrst - msr; + + return StateVector{ + (fql[0] - msl * rol - rolst * temp_flux_l + roldst * mslst) * maxs1 + + (fqr[0] - msr * ror - rorst * temp_flux_r + rordst * msrst) * mins1, + (fql[1] - msl * rxl - rxlst * temp_flux_l + rxldst * mslst) * maxs1 + + (fqr[1] - msr * rxr - rxrst * temp_flux_r + rxrdst * msrst) * mins1, + (fql[2] - msl * ryl - rylst * temp_flux_l + ryldst * mslst) * maxs1 + + (fqr[2] - msr * ryr - ryrst * temp_flux_r + ryrdst * msrst) * mins1, + (fql[3] - msl * rzl - rzlst * temp_flux_l + rzldst * mslst) * maxs1 + + (fqr[3] - msr * rzr - rzrst * temp_flux_r + rzrdst * msrst) * mins1, + (fql[4] - msl * eel - eelst * temp_flux_l + eeldst * mslst) * maxs1 + + (fqr[4] - msr * eer - eerst * temp_flux_r + eerdst * msrst) * mins1, + (fql[5] - msl * byl - bylst * temp_flux_l + byldst * mslst) * maxs1 + + (fqr[5] - msr * byr - byrst * temp_flux_r + byrdst * msrst) * mins1, + (fql[6] - msl * bzl - bzlst * temp_flux_l + bzldst * mslst) * maxs1 + + (fqr[6] - msr * bzr - bzrst * temp_flux_r + bzrdst * msrst) * mins1, + }; +} + +std::vector pad_zero_gradient_ghost_cells(const std::vector& cells) +{ + if (cells.empty()) { + return {}; + } + + std::vector padded; + padded.reserve(cells.size() + 4U); + padded.insert(padded.end(), 2U, cells.front()); + padded.insert(padded.end(), cells.begin(), cells.end()); + padded.insert(padded.end(), 2U, cells.back()); + return padded; +} + +std::vector cell_centers(std::size_t nx, double x_left, double x_right) +{ + if (nx == 0U) { + return {}; + } + + if (!(x_right > x_left)) { + throw std::runtime_error("x_right must be greater than x_left"); + } + + const double dx = (x_right - x_left) / static_cast(nx); + std::vector centers(nx); + for (std::size_t index = 0; index < nx; ++index) { + centers[index] = x_left + (static_cast(index) + 0.5) * dx; + } + + return centers; +} + +std::vector brio_wu_initial_profile(const ProblemConfig& problem) +{ + const std::vector centers = cell_centers(problem.nx, problem.x_left, problem.x_right); + std::vector profile(problem.nx); + + for (std::size_t index = 0; index < centers.size(); ++index) { + profile[index] = (centers[index] < problem.discontinuity_x) ? problem.left_primitive + : problem.right_primitive; + } + + return profile; +} + +std::vector run_full_simulation(const ProblemConfig& problem) +{ + if (problem.nx == 0U) { + return {}; + } + + const std::vector initial_primitive_profile = brio_wu_initial_profile(problem); + std::vector conservative_cells(initial_primitive_profile.size()); + for (std::size_t index = 0; index < initial_primitive_profile.size(); ++index) { + conservative_cells[index] = + primitive_to_conservative(initial_primitive_profile[index], problem.bx, problem.gamma); + } + + const double dx = (problem.x_right - problem.x_left) / static_cast(problem.nx); + const std::vector evolved_conservative_cells = evolve_ssp_rk3_fixed_dt( + conservative_cells, problem.t_final, problem.dt, dx, problem.bx, problem.gamma); + + std::vector final_primitive_profile(evolved_conservative_cells.size()); + for (std::size_t index = 0; index < evolved_conservative_cells.size(); ++index) { + final_primitive_profile[index] = + conservative_to_primitive(evolved_conservative_cells[index], problem.bx, problem.gamma); + } + + return final_primitive_profile; +} + +std::vector +compute_semidiscrete_rhs(const std::vector& conservative_cells, double bx, + double gamma) +{ + if (conservative_cells.empty()) { + throw std::runtime_error("conservative_cells must contain at least one cell"); + } + + const double dx = 1.0 / static_cast(conservative_cells.size()); + return compute_semidiscrete_rhs(conservative_cells, dx, bx, gamma); +} + +std::vector +compute_semidiscrete_rhs(const std::vector& conservative_cells, double dx, double bx, + double gamma) +{ + if (conservative_cells.empty()) { + throw std::runtime_error("conservative_cells must contain at least one cell"); + } + + if (dx <= 0.0) { + throw std::runtime_error("dx must be positive"); + } + + const std::vector padded_conservative = + pad_zero_gradient_ghost_cells(conservative_cells); + const std::vector padded_primitive = + conservative_profile_to_primitive_profile(padded_conservative, bx, gamma); + const std::pair, std::vector> interface_states = + reconstruct_mc2_interfaces(padded_primitive); + + const std::vector& left_interface_states = interface_states.first; + const std::vector& right_interface_states = interface_states.second; + + std::vector interface_fluxes(left_interface_states.size()); + for (std::size_t index = 0; index < left_interface_states.size(); ++index) { + interface_fluxes[index] = hlld_flux_from_primitive(left_interface_states[index], + right_interface_states[index], bx, gamma); + } + + std::vector rhs(conservative_cells.size()); + for (std::size_t index = 0; index < conservative_cells.size(); ++index) { + for (std::size_t component = 0; component < kStateWidth; ++component) { + rhs[index][component] = -(interface_fluxes[index + kGhostWidth][component] - + interface_fluxes[index + kGhostWidth - 1U][component]) / + dx; + } + } + + return rhs; +} + +std::vector ssp_rk3_step(const std::vector& conservative_cells, double dt, + double bx, double gamma) +{ + if (conservative_cells.empty()) { + throw std::runtime_error("conservative_cells must contain at least one cell"); + } + + const double dx = 1.0 / static_cast(conservative_cells.size()); + return ssp_rk3_step(conservative_cells, dt, dx, bx, gamma); +} + +std::vector ssp_rk3_step(const std::vector& conservative_cells, double dt, + double dx, double bx, double gamma) +{ + if (conservative_cells.empty()) { + throw std::runtime_error("conservative_cells must contain at least one cell"); + } + + if (dt <= 0.0) { + throw std::runtime_error("dt must be positive"); + } + + std::vector first_stage = conservative_cells; + const std::vector first_rhs = + compute_semidiscrete_rhs(conservative_cells, dx, bx, gamma); + for (std::size_t index = 0; index < first_stage.size(); ++index) { + for (std::size_t component = 0; component < kStateWidth; ++component) { + first_stage[index][component] += dt * first_rhs[index][component]; + } + } + + std::vector second_stage = conservative_cells; + const std::vector second_rhs = compute_semidiscrete_rhs(first_stage, dx, bx, gamma); + for (std::size_t index = 0; index < second_stage.size(); ++index) { + for (std::size_t component = 0; component < kStateWidth; ++component) { + second_stage[index][component] = + 0.75 * conservative_cells[index][component] + + 0.25 * (first_stage[index][component] + dt * second_rhs[index][component]); + } + } + + const std::vector third_rhs = compute_semidiscrete_rhs(second_stage, dx, bx, gamma); + std::vector next_stage = conservative_cells; + for (std::size_t index = 0; index < next_stage.size(); ++index) { + for (std::size_t component = 0; component < kStateWidth; ++component) { + next_stage[index][component] = + (1.0 / 3.0) * conservative_cells[index][component] + + (2.0 / 3.0) * (second_stage[index][component] + dt * third_rhs[index][component]); + } + } + + return next_stage; +} + +std::vector evolve_ssp_rk3_fixed_dt(const std::vector& conservative_cells, + double t_final, double dt, double bx, double gamma) +{ + if (conservative_cells.empty()) { + throw std::runtime_error("conservative_cells must contain at least one cell"); + } + + const double dx = 1.0 / static_cast(conservative_cells.size()); + return evolve_ssp_rk3_fixed_dt(conservative_cells, t_final, dt, dx, bx, gamma); +} + +std::vector evolve_ssp_rk3_fixed_dt(const std::vector& conservative_cells, + double t_final, double dt, double dx, double bx, + double gamma) +{ + if (conservative_cells.empty()) { + throw std::runtime_error("conservative_cells must contain at least one cell"); + } + + if (t_final < 0.0) { + throw std::runtime_error("t_final must be non-negative"); + } + + if (dt <= 0.0) { + throw std::runtime_error("dt must be positive"); + } + + std::vector evolved_state = conservative_cells; + double elapsed_time = 0.0; + while (elapsed_time < t_final) { + const double remaining_time = t_final - elapsed_time; + const double step_dt = std::min(dt, remaining_time); + evolved_state = ssp_rk3_step(evolved_state, step_dt, dx, bx, gamma); + elapsed_time = (step_dt < dt) ? t_final : (elapsed_time + step_dt); + } + + return evolved_state; +} + +} // namespace mhd1d diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp new file mode 100644 index 0000000..5892aee --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include +#include +#include +#include + +namespace mhd1d +{ + +constexpr std::size_t kStateWidth = 7; + +using StateVector = std::array; + +struct ProblemConfig { + std::size_t nx = 0; + double x_left = 0.0; + double x_right = 1.0; + double discontinuity_x = 0.5; + double dt = 0.0; + double t_final = 0.0; + double gamma = 0.0; + double bx = 0.0; + StateVector left_primitive{}; + StateVector right_primitive{}; +}; + +ProblemConfig make_brio_wu_example(); + +StateVector primitive_to_conservative(const StateVector& primitive, double bx, double gamma); + +StateVector conservative_to_primitive(const StateVector& conservative, double bx, double gamma); + +std::vector mc2_slopes(const std::vector& primitive_cells); + +std::pair, std::vector> +reconstruct_mc2_interfaces(const std::vector& primitive_cells); + +StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, + double gamma); + +std::vector cell_centers(std::size_t nx, double x_left, double x_right); + +std::vector pad_zero_gradient_ghost_cells(const std::vector& cells); + +std::vector brio_wu_initial_profile(const ProblemConfig& problem); + +std::vector run_full_simulation(const ProblemConfig& problem); + +std::vector +compute_semidiscrete_rhs(const std::vector& conservative_cells, double bx = 0.75, + double gamma = 2.0); + +std::vector +compute_semidiscrete_rhs(const std::vector& conservative_cells, double dx, double bx, + double gamma); + +std::vector ssp_rk3_step(const std::vector& conservative_cells, double dt, + double bx = 0.75, double gamma = 2.0); + +std::vector ssp_rk3_step(const std::vector& conservative_cells, double dt, + double dx, double bx, double gamma); + +std::vector evolve_ssp_rk3_fixed_dt(const std::vector& conservative_cells, + double t_final, double dt, double bx = 0.75, + double gamma = 2.0); + +std::vector evolve_ssp_rk3_fixed_dt(const std::vector& conservative_cells, + double t_final, double dt, double dx, double bx, + double gamma); + +} // namespace mhd1d diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp new file mode 100644 index 0000000..c58c794 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp @@ -0,0 +1,154 @@ +#include + +#include +#include + +#include "mhd1d.hpp" + +namespace +{ + +constexpr double kTolerance = 1.0e-12; + +void require_state_vector_close(const mhd1d::StateVector& actual, + const mhd1d::StateVector& expected) +{ + for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + REQUIRE(std::fabs(actual[component] - expected[component]) <= kTolerance); + } +} + +} // namespace + +TEST_CASE("primitive_to_conservative converts a known state", "[mhd1d][conversion]") +{ + const double bx = 0.75; + const double gamma = 2.0; + const auto state = mhd1d::StateVector{1.5, 2.0, -1.0, 0.5, 3.0, 0.25, -0.5}; + const auto actual = mhd1d::primitive_to_conservative(state, bx, gamma); + + const auto expected = mhd1d::StateVector{1.5, 3.0, -1.5, 0.75, 7.375, 0.25, -0.5}; + require_state_vector_close(actual, expected); +} + +TEST_CASE("conservative_to_primitive converts a known state", "[mhd1d][conversion]") +{ + const double bx = 0.75; + const double gamma = 2.0; + const auto state = mhd1d::StateVector{1.5, 3.0, -1.5, 0.75, 7.375, 0.25, -0.5}; + const auto actual = mhd1d::conservative_to_primitive(state, bx, gamma); + + const auto expected = mhd1d::StateVector{1.5, 2.0, -1.0, 0.5, 3.0, 0.25, -0.5}; + require_state_vector_close(actual, expected); +} + +TEST_CASE("primitive and conservative states round-trip", "[mhd1d][conversion]") +{ + const double bx = 0.75; + const double gamma = 2.0; + const auto input = mhd1d::StateVector{0.875, -1.25, 0.5, 0.75, 2.125, -0.2, 0.35}; + + const auto conservative = mhd1d::primitive_to_conservative(input, bx, gamma); + const auto output = mhd1d::conservative_to_primitive(conservative, bx, gamma); + + require_state_vector_close(output, input); +} + +TEST_CASE("mc2_slopes preserve a constant primitive state", "[mhd1d][reconstruction]") +{ + const auto constant_state = mhd1d::StateVector{1.25, -0.5, 0.25, -0.125, 2.75, 0.4, -0.3}; + const std::vector cells{constant_state, constant_state, constant_state, + constant_state}; + + const auto slopes = mhd1d::mc2_slopes(cells); + + REQUIRE(slopes.size() == cells.size()); + for (const auto& slope : slopes) { + require_state_vector_close(slope, mhd1d::StateVector{}); + } +} + +TEST_CASE("reconstruct_mc2_interfaces preserves a constant primitive state exactly", + "[mhd1d][reconstruction]") +{ + const auto constant_state = mhd1d::StateVector{0.9, 0.3, -0.2, 0.1, 1.8, -0.45, 0.6}; + const std::vector cells{constant_state, constant_state, constant_state, + constant_state}; + + const auto [left_states, right_states] = mhd1d::reconstruct_mc2_interfaces(cells); + + REQUIRE(left_states.size() == cells.size() - 1U); + REQUIRE(right_states.size() == cells.size() - 1U); + for (const auto& state : left_states) { + require_state_vector_close(state, constant_state); + } + for (const auto& state : right_states) { + require_state_vector_close(state, constant_state); + } +} + +TEST_CASE("hlld_flux_from_primitive matches the physical flux for identical states", + "[mhd1d][flux]") +{ + const double bx = 0.75; + const double gamma = 2.0; + const auto state = mhd1d::StateVector{1.4, -0.6, 0.25, 0.1, 1.9, -0.35, 0.5}; + const auto actual = mhd1d::hlld_flux_from_primitive(state, state, bx, gamma); + + const double rho = state[0]; + const double u = state[1]; + const double v = state[2]; + const double w = state[3]; + const double p = state[4]; + const double by = state[5]; + const double bz = state[6]; + const double bx2 = bx * bx; + const double pt = p + 0.5 * (bx2 + by * by + bz * bz); + const double e = + p / (gamma - 1.0) + 0.5 * rho * (u * u + v * v + w * w) + 0.5 * (bx2 + by * by + bz * bz); + + const auto expected = mhd1d::StateVector{ + rho * u, + rho * u * u + pt - bx2, + rho * u * v - bx * by, + rho * u * w - bx * bz, + u * (e + pt - bx2) - bx * (v * by + w * bz), + by * u - bx * v, + bz * u - bx * w, + }; + + require_state_vector_close(actual, expected); +} + +TEST_CASE("pad_zero_gradient_ghost_cells duplicates edge states on both sides", "[mhd1d][boundary]") +{ + const std::vector cells = { + mhd1d::StateVector{1.0, 0.5, -0.25, 0.125, 2.0, 0.1, -0.05}, + mhd1d::StateVector{1.2, 0.6, -0.2, 0.15, 2.2, 0.12, -0.02}, + mhd1d::StateVector{1.4, 0.7, -0.15, 0.175, 2.4, 0.14, 0.01}, + }; + + const auto padded = mhd1d::pad_zero_gradient_ghost_cells(cells); + + REQUIRE(padded.size() == cells.size() + 4U); + require_state_vector_close(padded[0], cells.front()); + require_state_vector_close(padded[1], cells.front()); + require_state_vector_close(padded[2], cells[0]); + require_state_vector_close(padded[3], cells[1]); + require_state_vector_close(padded[4], cells[2]); + require_state_vector_close(padded[5], cells.back()); + require_state_vector_close(padded[6], cells.back()); +} + +TEST_CASE("pad_zero_gradient_ghost_cells handles a single interior cell", "[mhd1d][boundary]") +{ + const auto cell = mhd1d::StateVector{1.5, -0.75, 0.25, 0.0, 3.5, -0.1, 0.2}; + const std::vector cells{cell}; + + const auto padded = mhd1d::pad_zero_gradient_ghost_cells(cells); + + REQUIRE(padded.size() == 5U); + for (const auto& padded_cell : padded) { + require_state_vector_close(padded_cell, cell); + } +} diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/test_public.py b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/test_public.py new file mode 100644 index 0000000..b15cf48 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/test_public.py @@ -0,0 +1,57 @@ +import csv +import math +import os +import subprocess +from pathlib import Path + + +PUBLIC_TEST_TARGET = "cpp_full_solver1d_public_tests" + + +def _build_public_tests() -> Path: + subprocess.run(["cmake", "-S", ".", "-B", "build"], check=True) + subprocess.run( + ["cmake", "--build", "build", "--target", PUBLIC_TEST_TARGET], + check=True, + ) + + binary_name = f"{PUBLIC_TEST_TARGET}.exe" if os.name == "nt" else PUBLIC_TEST_TARGET + executable_path = Path("build/tests") / binary_name + assert executable_path.exists() + return executable_path + + +def test_public_catch2_target_builds() -> None: + _build_public_tests() + + +def test_public_brio_wu_cli_matches_reference_grid() -> None: + _build_public_tests() + + solver_name = "cpp_full_solver1d.exe" if os.name == "nt" else "cpp_full_solver1d" + solver_path = Path("build/bin") / solver_name + assert solver_path.exists() + + completed = subprocess.run( + [str(solver_path), "examples/brio_wu.toml"], + check=True, + capture_output=True, + text=True, + ) + + rows = list(csv.reader(completed.stdout.splitlines())) + assert rows[0] == ["x", "rho", "u", "v", "w", "p", "by", "bz"] + assert len(rows) - 1 == 400 + + dx = (1.0 - 0.0) / 400.0 + for index, row in enumerate(rows[1:]): + assert len(row) == 8 + + x_value = float(row[0]) + expected_x = 0.0 + (index + 0.5) * dx + assert x_value == expected_x + + numeric_values = [float(component) for component in row[1:]] + assert all(math.isfinite(component) for component in [x_value, *numeric_values]) + assert numeric_values[0] > 0.0 + assert numeric_values[4] > 0.0 diff --git a/benchmarks/magnetohydrodynamics/shared/eval/README.md b/benchmarks/magnetohydrodynamics/shared/eval/README.md index 9216b9f..fc72403 100644 --- a/benchmarks/magnetohydrodynamics/shared/eval/README.md +++ b/benchmarks/magnetohydrodynamics/shared/eval/README.md @@ -1,3 +1,74 @@ # Shared eval assets -This directory is reserved for future suite-wide hidden-eval helpers. +This directory holds suite-wide hidden-eval documentation and helpers for +`cpp-full-solver1d`. + +## Hidden reference lifecycle + +The full-solver task uses a shared hidden-eval contract anchored by these +paths: + +- `benchmarks/magnetohydrodynamics/shared/eval/mhd1d_reference.py` +- `benchmarks/magnetohydrodynamics/shared/eval/mhd1d_shared.py` +- `benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/` + +`mhd1d_reference.py` owns the hidden reference generation and comparison +entry points. `mhd1d_shared.py` provides the shared geometry, CSV parsing, +and score-window helpers used by both the task evaluator and the maintainer +regeneration workflow. Fixture files under `fixtures/mhd1d/` store the +reference outputs and comparison metadata needed to keep scoring deterministic. + +## Fixture contract + +- CSV schema: `x,rho,u,v,w,p,by,bz` +- Scored variables: `rho`, `u`, `p`, `by` +- CSV headers use lowercase `by` and `bz`; the surrounding solver code and + notation may still refer to the magnetic components as `By` and `Bz`. +- Comparison window: interior cells only, excluding two edge-adjacent cells on + each side +- Stored tolerances: fixture metadata records `abs_l1` and `abs_linf` +- Regeneration: fixtures are regenerated from the hidden reference pipeline and + must preserve the schema, windowing rule, and tolerances above unless the + benchmark contract is intentionally revised + +## Files + +### `mhd1d_reference.py` + +Maintainer-only hidden reference implementation. Provides: + +- **Primitive/conservative conversion**: `primitive_to_conservative()`, `conservative_to_primitive()` +- **Cell geometry**: `cell_centers()`, `brio_wu_primitive_profile()`, `brio_wu_conservative_profile()` +- **Time evolution**: `evolve_brio_wu_reference_profile()`, `evolve_ssp_rk3_fixed_dt()` +- **Reconstruction**: `mc2_slopes()`, `reconstruct_mc2_interfaces()` +- **HLLD flux**: `hlld_flux_from_primitive()`, `hlld_flux_from_conservative()` +- **RHS computation**: `compute_semidiscrete_rhs()`, `brio_wu_semidiscrete_rhs()` +- **Fixture generation**: `write_brio_wu_reference_fixtures()` + +### `mhd1d_shared.py` + +Shared helpers for CSV loading and comparison: + +- **`load_mhd1d_csv_profile(csv_path)`**: Load and validate a CSV profile +- **`load_mhd1d_fixture(fixture_path)`**: Load fixture metadata and reference CSV +- **`compare_mhd1d_csv_against_fixture(solver_csv_path, fixture)`**: Compare solver output against fixture +- **`interior_cell_window_bounds(row_count, exclude_edge_adjacents_per_side)`**: Compute comparison window + +### `fixtures/mhd1d/` + +- **`brio_wu_reference.csv`**: Reference solution for the canonical Brio-Wu problem (400 cells, `t_final=0.1`) +- **`brio_wu_fixture.json`**: Metadata including tolerances, schema, and scored variables + +## Regenerating fixtures + +To regenerate the reference fixtures (maintainer only): + +```python +from mhd1d_reference import write_brio_wu_reference_fixtures +from pathlib import Path + +output_dir = Path("benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d") +write_brio_wu_reference_fixtures(output_dir) +``` + +This writes both the reference CSV and the fixture JSON with updated tolerances. diff --git a/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/README.md b/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/README.md new file mode 100644 index 0000000..bfb2141 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/README.md @@ -0,0 +1,29 @@ +# mhd1d hidden fixtures + +This directory will store the hidden reference fixtures for +`cpp-full-solver1d`. + +## Contents + +- One or more CSV fixture files with the schema `x,rho,u,v,w,p,by,bz` +- Fixture metadata that records the comparison tolerances `abs_l1` and + `abs_linf` +- Regeneration notes for maintainer use when updating the hidden reference + +CSV fixture headers intentionally stay lowercase for the magnetic fields: +`by` and `bz`. That naming matches the on-disk schema, while the code-level +state and discussion in solver docs may still use `By` and `Bz`. + +## Scoring contract + +- Scored variables: `rho`, `u`, `p`, `by` +- Window: interior cells only, excluding two edge-adjacent cells per side +- Reference comparisons use the fixture-stored `abs_l1` and `abs_linf` + tolerances + +## Regeneration expectations + +Fixtures must be regenerated from the hidden reference pipeline whenever the +benchmark contract changes. Regeneration must preserve the CSV schema, the +interior-cell window, and the stored tolerances unless the suite maintainers +explicitly revise the contract. diff --git a/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_fixture.json b/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_fixture.json new file mode 100644 index 0000000..b76068a --- /dev/null +++ b/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_fixture.json @@ -0,0 +1,45 @@ +{ + "abs_l1": { + "by": 1e-12, + "p": 1e-12, + "rho": 1e-12, + "u": 1e-12 + }, + "abs_linf": { + "by": 1e-13, + "p": 1e-13, + "rho": 1e-13, + "u": 1e-13 + }, + "bx": 0.75, + "discontinuity_x": 0.5, + "domain": [ + 0.0, + 1.0 + ], + "dt": 0.0005, + "gamma": 2.0, + "interior_cell_window": { + "exclude_edge_adjacents_per_side": 2 + }, + "name": "brio_wu", + "nx": 400, + "reference_csv": "brio_wu_reference.csv", + "schema": [ + "x", + "rho", + "u", + "v", + "w", + "p", + "by", + "bz" + ], + "scored_variables": [ + "rho", + "u", + "p", + "by" + ], + "t_final": 0.1 +} diff --git a/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_reference.csv b/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_reference.csv new file mode 100644 index 0000000..3b96ca0 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_reference.csv @@ -0,0 +1,401 @@ +x,rho,u,v,w,p,by,bz +0.00125,1,0,0,0,1,1,0 +0.0037499999999999999,1,0,0,0,1,1,0 +0.0062500000000000003,1,0,0,0,1,1,0 +0.0087500000000000008,1,0,0,0,1,1,0 +0.01125,1,0,0,0,1,1,0 +0.01375,1,0,0,0,1,1,0 +0.016250000000000001,1,0,0,0,1,1,0 +0.018749999999999999,1,0,0,0,1,1,0 +0.021250000000000002,1,0,0,0,1,1,0 +0.02375,1,0,0,0,1,1,0 +0.026249999999999999,1,0,0,0,1,1,0 +0.028750000000000001,1,0,0,0,1,1,0 +0.03125,1,0,0,0,1,1,0 +0.033750000000000002,1,0,0,0,1,1,0 +0.036249999999999998,1,0,0,0,1,1,0 +0.03875,1,0,0,0,1,1,0 +0.041250000000000002,1,0,0,0,1,1,0 +0.043750000000000004,1,0,0,0,1,1,0 +0.046249999999999999,1,0,0,0,1,1,0 +0.048750000000000002,1,0,0,0,1,1,0 +0.051250000000000004,1,0,0,0,1,1,0 +0.053749999999999999,1,0,0,0,1,1,0 +0.056250000000000001,1,0,0,0,1,1,0 +0.058750000000000004,1,0,0,0,1,1,0 +0.061249999999999999,1,0,0,0,1,1,0 +0.063750000000000001,1,0,0,0,1,1,0 +0.066250000000000003,1,0,0,0,1,1,0 +0.068750000000000006,1,0,0,0,1,1,0 +0.071250000000000008,1,0,0,0,1,1,0 +0.073749999999999996,1,0,0,0,1,1,0 +0.076249999999999998,1,0,0,0,1,1,0 +0.078750000000000001,1,0,0,0,1,1,0 +0.081250000000000003,1,0,0,0,1,1,0 +0.083750000000000005,1,0,0,0,1,1,0 +0.086250000000000007,1,0,0,0,1,1,0 +0.088749999999999996,1,0,0,0,1,1,0 +0.091249999999999998,1,0,0,0,1,1,0 +0.09375,1,0,0,0,1,1,0 +0.096250000000000002,1,0,0,0,1,1,0 +0.098750000000000004,1,0,0,0,1,1,0 +0.10125000000000001,1,0,0,0,1,1,0 +0.10375000000000001,1,0,0,0,1,1,0 +0.10625,1,0,0,0,1,1,0 +0.10875,1,0,0,0,1,1,0 +0.11125,1,0,0,0,1,1,0 +0.11375,1,0,0,0,1,1,0 +0.11625000000000001,1,0,0,0,1,1,0 +0.11875000000000001,1,0,0,0,1,1,0 +0.12125,1,0,0,0,1,1,0 +0.12375,1,0,0,0,1,1,0 +0.12625,1,0,0,0,1,1,0 +0.12875,1,0,0,0,1,1,0 +0.13125000000000001,1,0,0,0,1,1,0 +0.13375000000000001,1,0,0,0,1,1,0 +0.13625000000000001,1,0,0,0,1,1,0 +0.13875000000000001,1,0,0,0,1,1,0 +0.14125000000000001,1,0,0,0,1,1,0 +0.14375000000000002,1,0,0,0,1,1,0 +0.14624999999999999,1,0,0,0,1,1,0 +0.14874999999999999,1,0,0,0,1,1,0 +0.15125,1,0,0,0,1,1,0 +0.15375,1,0,0,0,1,1,0 +0.15625,1,0,0,0,1,1,0 +0.15875,1,0,0,0,1,1,0 +0.16125,1,0,0,0,1,1,0 +0.16375000000000001,1,0,0,0,1,1,0 +0.16625000000000001,1,0,0,0,1,1,0 +0.16875000000000001,1,0,0,0,1,1,0 +0.17125000000000001,1,0,0,0,1,1,0 +0.17375000000000002,1,0,0,0,1,1,0 +0.17624999999999999,1,0,0,0,1,1,0 +0.17874999999999999,1,0,0,0,1,1,0 +0.18124999999999999,1,0,0,0,1,1,0 +0.18375,1,0,0,0,1,1,0 +0.18625,1,0,0,0,1,1,0 +0.18875,1,0,0,0,1,1,0 +0.19125,1,0,0,0,1,1,0 +0.19375000000000001,1,0,0,0,1,1,0 +0.19625000000000001,1,0,0,0,1,1,0 +0.19875000000000001,1,0,0,0,1,1,0 +0.20125000000000001,1,0,0,0,1,1,0 +0.20375000000000001,1,0,0,0,1,1,0 +0.20625000000000002,1,0,0,0,1,1,0 +0.20874999999999999,1,0,0,0,1,1,0 +0.21124999999999999,1,0,0,0,1,1,0 +0.21375,1,0,0,0,1,1,0 +0.21625,1,0,0,0,1,1,0 +0.21875,1,0,0,0,1,1,0 +0.22125,1,0,0,0,1,1,0 +0.22375,1,0,0,0,1,1,0 +0.22625000000000001,1,0,0,0,1,1,0 +0.22875000000000001,1,0,0,0,1,1,0 +0.23125000000000001,1,0,0,0,1,1,0 +0.23375000000000001,1,0,0,0,1,1,0 +0.23625000000000002,1,0,0,0,1,1,0 +0.23875000000000002,1,0,0,0,1,1,0 +0.24124999999999999,1,0,0,0,1,1,0 +0.24374999999999999,1,0,0,0,1,1,0 +0.24625,1,0,0,0,1,1,0 +0.24875,1,0,0,0,1,1,0 +0.25125000000000003,1,0,0,0,1,1,0 +0.25375000000000003,1,0,0,0,1,1,0 +0.25624999999999998,1,0,0,0,1,1,0 +0.25874999999999998,1,0,0,0,1,1,0 +0.26124999999999998,1,0,0,0,1,1,0 +0.26374999999999998,1,0,0,0,1,1,0 +0.26624999999999999,1,0,0,0,1,1,0 +0.26874999999999999,1,0,0,0,1,1,0 +0.27124999999999999,1,0,0,0,1,1,0 +0.27374999999999999,1,0,0,0,1,1,0 +0.27625,1,0,0,0,1,1,0 +0.27875,1,0,0,0,1,1,0 +0.28125,1,0,0,0,1,1,0 +0.28375,1,0,0,0,1,1,0 +0.28625,1,0,0,0,1,1,0 +0.28875000000000001,1,0,0,0,1,1,0 +0.29125000000000001,1,0,0,0,1,1,0 +0.29375000000000001,1,0,0,0,1,1,0 +0.29625000000000001,1,0,0,0,1,1,0 +0.29875000000000002,1,0,0,0,1,1,0 +0.30125000000000002,1,0,0,0,1,1,0 +0.30375000000000002,1,0,0,0,1,1,0 +0.30625000000000002,1,0,0,0,1,1,0 +0.30875000000000002,1,0,0,0,1,1,0 +0.31125000000000003,1,0,0,0,1,1,0 +0.31375000000000003,1,0,0,0,1,1,0 +0.31625000000000003,1,0,0,0,1,1,0 +0.31875000000000003,0.99780058962396134,0.0039418906960591756,-0.0011154453241734904,0,0.99561225261243114,0.99733567707147397,0 +0.32124999999999998,0.99173977278087055,0.014827394992909993,-0.0042179802180685351,0,0.98356266355471567,0.98997992685476155,0 +0.32374999999999998,0.98408158190126227,0.028640080174583915,-0.008186565338896416,0,0.96843552308248149,0.98067103174066461,0 +0.32624999999999998,0.97581885102428656,0.043602341839540863,-0.012527557906330034,0,0.95224184930138511,0.9706093820226751,0 +0.32874999999999999,0.9673086534619818,0.059076763367010128,-0.017064614864518685,0,0.93570643492573047,0.96022723966347923,0 +0.33124999999999999,0.95869600144853218,0.074807206835931742,-0.021727022813603607,0,0.91911880282946645,0.94969857357607346,0 +0.33374999999999999,0.95004304399744044,0.090682637384932041,-0.026484836248230038,0,0.90260259674571253,0.93909829176568671,0 +0.33624999999999999,0.9413754410079106,0.10665810127729088,-0.031327232997254678,0,0.88620791115317998,0.92845621902021158,0 +0.33875,0.93270899587811373,0.12270504519506864,-0.03624752773178725,0,0.86996537982749733,0.91779125844150933,0 +0.34125,0.92405269875686513,0.13880647959038991,-0.041242256453888439,0,0.85389282701112912,0.90711462369760387,0 +0.34375,0.9154136825409287,0.15495119344114,-0.046309690150731095,0,0.83800169918738354,0.89643357043624938,0 +0.34625,0.90679699082194087,0.1711306591640914,-0.051448892458540188,0,0.82230012152488841,0.88575334869586952,0 +0.34875,0.89820651629824644,0.18733853105308285,-0.056659474531035876,0,0.80679335763251014,0.87507771377132626,0 +0.35125000000000001,0.88964446790953033,0.20356990667607194,-0.061941601414340595,0,0.79148497989669941,0.86440935577409717,0 +0.35375000000000001,0.88111284307810034,0.21982084917897435,-0.067295796388280038,0,0.77637743892286348,0.85375027049037311,0 +0.35625000000000001,0.87261362352600136,0.23608821896065768,-0.072722798578283135,0,0.76147221221794026,0.84310187986499097,0 +0.35875000000000001,0.86414845253144101,0.25236949156988764,-0.078223462833881888,0,0.74677004107769829,0.83246518929651392,0 +0.36125000000000002,0.85571868777839477,0.26866265040738607,-0.083798844143742335,0,0.73227118643443889,0.82184083376251138,0 +0.36375000000000002,0.84732496311510741,0.28496610344607487,-0.089450235711247772,0,0.71797553105924117,0.81122913890977844,0 +0.36625000000000002,0.83896778349293599,0.30127856646716628,-0.095179100441626849,0,0.70388256773647151,0.80063021301524762,0 +0.36875000000000002,0.8306478120801315,0.31759896051856901,-0.10098705469020462,0,0.68999145285900165,0.79004396131671717,0 +0.37125000000000002,0.82236584881264441,0.33392634501819063,-0.10687586239677592,0,0.67630114289001086,0.77947010645164028,0 +0.37375000000000003,0.81412256288554841,0.35025987066405678,-0.11284737308244323,0,0.66281051894930754,0.76890827004788531,0 +0.37625000000000003,0.80591829672758197,0.36659869209219098,-0.11890344385945414,0,0.64951847025460407,0.75835806846801013,0 +0.37875000000000003,0.7977533251558977,0.38294181436792768,-0.1250459153773277,0,0.63642397465987577,0.74781916579237695,0 +0.38125000000000003,0.78962821661912974,0.39928793115627925,-0.13127661071624822,0,0.62352617265709931,0.73729131884178889,0 +0.38375000000000004,0.78154397302664014,0.4156353252154189,-0.137597311365595,0,0.61082441920290476,0.72677444954932158,0 +0.38624999999999998,0.77350187664333747,0.4319818381617635,-0.14400971569167417,0,0.59831831823337123,0.71626872248566942,0 +0.38874999999999998,0.76550325157545829,0.44832485729258581,-0.15051541230315177,0,0.58600775859846921,0.70577458163502815,0 +0.39124999999999999,0.75754943880637893,0.46466125358111438,-0.15711584492844621,0,0.57389295780390692,0.69529276621051095,0 +0.39374999999999999,0.749642062019785,0.48098718289031467,-0.16381220586479228,0,0.56197455525241757,0.68482439731157485,0 +0.39624999999999999,0.74178347298350644,0.49729755518791763,-0.17060518383658033,0,0.55025391036855997,0.67437128401935453,0 +0.39874999999999999,0.73397737021860543,0.51358474386151054,-0.17749439433254424,0,0.53873391674659166,0.66393672613728749,0 +0.40125,0.72622997539659639,0.52983568010877113,-0.18447707310794387,0,0.52742087697476669,0.65352736887877549,0 +0.40375,0.71855268032257813,0.54602571955173596,-0.19154520667480535,0,0.51632840511574407,0.64315715022632924,0 +0.40625,0.71096761592194024,0.5621064499054218,-0.19867965431348364,0,0.50548500567258359,0.6328551452014316,0 +0.40875,0.70351809004436872,0.57798308169709955,-0.20583896158449672,0,0.49494776946723229,0.62268010464122547,0 +0.41125,0.69628594147097289,0.59347633160710345,-0.21293993103100095,0,0.48482478256859951,0.61274502061463976,0 +0.41375000000000001,0.68941655050596484,0.60826664970343558,-0.2198280489776889,0,0.47530692274767161,0.60325335873851049,0 +0.41625000000000001,0.68314702755279999,0.62182858255524953,-0.22624129413552949,0,0.46670271369465616,0.59454169635904308,0 +0.41875000000000001,0.67782572058125357,0.63339457769432261,-0.23178305630796459,0,0.45946103196399823,0.58710648915432451,0 +0.42125000000000001,0.67385858441141333,0.64199490957099814,-0.23596698492475343,0,0.45409808373542004,0.58156684274258463,0 +0.42375000000000002,0.67176641453700525,0.6469162308341575,-0.238218557413787,0,0.45128138130309292,0.57843540789261583,0 +0.42625000000000002,0.67078052736841931,0.64804295449248306,-0.23931535115787175,0,0.44995578425706018,0.5776695501854906,0 +0.42875000000000002,0.67093258028176295,0.64820950444476044,-0.23909517669577307,0,0.45016128034403946,0.57748103832724251,0 +0.43125000000000002,0.67221331698599318,0.64592193639342732,-0.2376161466610561,0,0.45188502884855786,0.57898748077442441,0 +0.43375000000000002,0.67477583336680169,0.64045344684033523,-0.2349806577986025,0,0.45533846144962792,0.58257702054306215,0 +0.43625000000000003,0.67693879989409655,0.63537735860005662,-0.23276478266323203,0,0.45826311431502864,0.58589598309566848,0 +0.43875000000000003,0.67818046569816726,0.63258441699362578,-0.2316835745358842,0,0.4599465488616844,0.58788185575907725,0 +0.44125000000000003,0.67847095916753464,0.63140939827029008,-0.23102942178508992,0,0.46034108071841129,0.58814312979425298,0 +0.44375000000000003,0.67871878159900201,0.63146024939639389,-0.23068318935251569,0,0.46067790212396337,0.58810935677202825,0 +0.44625000000000004,0.67853915803526677,0.63196041084427279,-0.23090732826723964,0,0.46043473249792088,0.58787073205089513,0 +0.44874999999999998,0.67803863707314427,0.6330593415786836,-0.23162869925234153,0,0.45975750456026709,0.58736622158591256,0 +0.45124999999999998,0.6774195873474379,0.6343255739755016,-0.23239706197011983,0,0.45891948202187494,0.58672848893472662,0 +0.45374999999999999,0.67688810168571512,0.63542738781445673,-0.23285843166501846,0,0.45820017218025605,0.58601807885490564,0 +0.45624999999999999,0.67650547951151974,0.63625820689185419,-0.23305952359533008,0,0.45768328142375492,0.58533372699356645,0 +0.45874999999999999,0.67624477252807902,0.63679255704404425,-0.23324253509623569,0,0.45733207413345345,0.58480268867196805,0 +0.46124999999999999,0.67604050594546095,0.63714228317088684,-0.23351779035696307,0,0.45705721760805229,0.58451139535639995,0 +0.46375,0.67595854916299569,0.63738534647931233,-0.23385855445925771,0,0.45694869192262283,0.58435845445911683,0 +0.46625,0.68086254532175094,0.63419323611509804,-0.2627490595791831,0,0.46500839952917328,0.56267418748132525,0 +0.46875,0.75828705387253315,0.56658450267562666,-0.6403332654473326,0,0.60777176667783583,0.26462111543054406,0 +0.47125,0.81542143854087634,0.46255247850130804,-1.1427907505563049,0,0.70707779939421744,-0.17802741409121203,0 +0.47375,0.78443205530850979,0.50559776659531341,-1.332519156086944,0,0.65515890375877317,-0.354497000575831,0 +0.47625000000000001,0.76277455722849596,0.55111223050629143,-1.406110791322537,0,0.61702037783610542,-0.4194427333795091,0 +0.47875000000000001,0.74404469538178764,0.55656484646456639,-1.4611410690372477,0,0.58668848068932689,-0.45267168642034472,0 +0.48125000000000001,0.7245298456798609,0.56167647024027656,-1.5074627288434979,0,0.5571761881846935,-0.47268348346610961,0 +0.48375000000000001,0.71012228623973583,0.57027999536562946,-1.543873073536012,0,0.53528590863347425,-0.49264654415374082,0 +0.48625000000000002,0.70076710390286745,0.58241431931480048,-1.5678960177704355,0,0.52117059910324071,-0.5132537526592037,0 +0.48875000000000002,0.6958138120994154,0.59253804821509259,-1.5801243124025581,0,0.51407181012863212,-0.53018918731486608,0 +0.49125000000000002,0.69634185265480064,0.60450975725843215,-1.5824609035105774,0,0.51510350342232991,-0.54159264057279222,0 +0.49375000000000002,0.69850922424214601,0.60950400813475858,-1.585266082294966,0,0.51853234952912874,-0.54291597426192384,0 +0.49625000000000002,0.69955231023329034,0.60819583311918735,-1.5848885559239814,0,0.52027069329509679,-0.54068543052621187,0 +0.49875000000000003,0.69829488634001602,0.60250392950529474,-1.5842381917356738,0,0.51860605011188388,-0.53585805694441235,0 +0.50124999999999997,0.69473126010799702,0.59400974956106756,-1.5847165912172572,0,0.51356317210852487,-0.53134363710848087,0 +0.50375000000000003,0.69253382725834534,0.59010833084815906,-1.5851121479337069,0,0.51057824154374631,-0.53011921878496304,0 +0.50624999999999998,0.69237449532735207,0.59146895693409685,-1.5858564348296551,0,0.51054249757041459,-0.53082328680938162,0 +0.50875000000000004,0.69391541373744337,0.59634222339010579,-1.5857210122073861,0,0.51315096871714994,-0.53304618751484978,0 +0.51124999999999998,0.69634148593928047,0.60301378588754684,-1.5840840117480401,0,0.5171828111968485,-0.53600443230198036,0 +0.51375000000000004,0.69696988284642125,0.60598814490820407,-1.5822803421052867,0,0.51876741128969461,-0.53768126044759668,0 +0.51624999999999999,0.69590524459691183,0.605542191027717,-1.5815913052223451,0,0.51808417485694558,-0.53738593862540907,0 +0.51875000000000004,0.69339823569240289,0.60237234278329166,-1.5824338658055286,0,0.51564230319494531,-0.53568598390826916,0 +0.52124999999999999,0.69028268100633383,0.59775928333034656,-1.5849765752973617,0,0.51233921959100215,-0.53282107449038196,0 +0.52375000000000005,0.6885408627829227,0.59563473330607197,-1.586881633696186,0,0.51091135095358142,-0.53126090526540737,0 +0.52625,0.68845991210476676,0.59576153638350393,-1.5870959718421693,0,0.51139517765564346,-0.53172734059034754,0 +0.52875000000000005,0.68913132894514517,0.59780515337360185,-1.5859257457768372,0,0.51333149786491905,-0.53324119440484385,0 +0.53125,0.69035686600602486,0.60114183287377887,-1.583761079933232,0,0.51632762277454369,-0.53561028146436995,0 +0.53375000000000006,0.69063785151444135,0.60308915950915953,-1.5825950002547069,0,0.51816477333483568,-0.5367661728665245,0 +0.53625,0.68995642603783169,0.60271623463782054,-1.5827072676591285,0,0.51817213887569635,-0.5365529040050816,0 +0.53875000000000006,0.68912674904173354,0.60080970261747135,-1.5836585612290803,0,0.5170008482178291,-0.53535672389780986,0 +0.54125000000000001,0.68900935996710411,0.59744632555053778,-1.5849988566238742,0,0.51492442266233129,-0.53339274974699291,0 +0.54375000000000007,0.68992607319859989,0.59550495144079929,-1.5855642783840616,0,0.51380892115497334,-0.53231014634052964,0 +0.54625000000000001,0.69030209756719352,0.59574669701945138,-1.5855252584440067,0,0.51389062331612756,-0.53244809173629659,0 +0.54874999999999996,0.68902173862300931,0.59740836235396289,-1.5852477103136609,0,0.5146658368665229,-0.53339030207149196,0 +0.55125000000000002,0.68189342316100054,0.60020433676255158,-1.5844249654880713,0,0.51628053637696625,-0.53477165363768919,0 +0.55374999999999996,0.65276597713910334,0.60185672139983104,-1.5836528865010249,0,0.51743177517895211,-0.53527542396206562,0 +0.55625000000000002,0.58906478526618755,0.60185519401175147,-1.583053851614638,0,0.51755849582377766,-0.53486837400458076,0 +0.55874999999999997,0.49422558600892486,0.60118766199411133,-1.5832559126839811,0,0.5172228327206092,-0.53418658367731886,0 +0.56125000000000003,0.38247103041338487,0.59990157132174105,-1.5840925292397106,0,0.51620910738423487,-0.53342595162876671,0 +0.56374999999999997,0.28025492247104017,0.59846176638276449,-1.5851622199216584,0,0.5152364728981691,-0.53275468018860095,0 +0.56625000000000003,0.22868966508824234,0.59710231685960313,-1.5860977814707127,0,0.51481122129747781,-0.53239158687234311,0 +0.56874999999999998,0.2267856507919232,0.59640620540582956,-1.5864596507885937,0,0.51481550996877012,-0.53225943769555295,0 +0.57125000000000004,0.22713175101669475,0.59631043781086113,-1.5862941490337203,0,0.51512192557837366,-0.53221446943385053,0 +0.57374999999999998,0.22832982826697543,0.59690929717637031,-1.5856945341940099,0,0.51544195200245158,-0.53214053153219976,0 +0.57625000000000004,0.23006132532598028,0.5979765390095868,-1.5850598466399157,0,0.51604401482077034,-0.53235234485917893,0 +0.57874999999999999,0.23181956629299122,0.59934757674111083,-1.5845139129375743,0,0.51687736532492834,-0.53308886162542746,0 +0.58125000000000004,0.23316522477988719,0.60072662152561196,-1.5842849795297345,0,0.51772674090669124,-0.53394457396042982,0 +0.58374999999999999,0.23391908756041113,0.60223034496795813,-1.5839684765344821,0,0.51806461631752188,-0.53457035523447027,0 +0.58625000000000005,0.23431034941216394,0.60345350170797118,-1.5841973780115437,0,0.51789119722034871,-0.53460934483436429,0 +0.58875,0.23460990828752651,0.60387631345954085,-1.5843501276762757,0,0.51757915110632757,-0.53432910759567398,0 +0.59125000000000005,0.23506825902401635,0.60282288127804684,-1.585165115162972,0,0.51773081006565902,-0.53416645772176508,0 +0.59375,0.23554392868159077,0.60057139334604759,-1.5863553588391026,0,0.51774108981529299,-0.53376740267714529,0 +0.59625000000000006,0.23574376308649053,0.59888206501796171,-1.587249000037269,0,0.51718780070000137,-0.53273061481737882,0 +0.59875,0.2357083556292047,0.59836333208440606,-1.5873845267462028,0,0.51612520155316433,-0.53158021311167569,0 +0.60125000000000006,0.23567285891449777,0.59766263969440114,-1.5877771701611647,0,0.5153079104412206,-0.53069139651429365,0 +0.60375000000000001,0.23580149297303599,0.59664353703500261,-1.5883416830586965,0,0.51563852961964063,-0.53095430707000513,0 +0.60625000000000007,0.2361263695423006,0.59461828975577724,-1.5895049849613039,0,0.51671691867389946,-0.53190837659017298,0 +0.60875000000000001,0.23631854959443394,0.59598090215208221,-1.5892842142291126,0,0.51722476899470071,-0.53244556280972177,0 +0.61124999999999996,0.23614815457146857,0.60018906680370221,-1.5879979771038979,0,0.51632413595151727,-0.53176277681989537,0 +0.61375000000000002,0.23613289789183126,0.60417970975516422,-1.5866151046667705,0,0.51643954420713611,-0.53176024605848848,0 +0.61624999999999996,0.23636461460022473,0.60239051184144632,-1.5874214851519997,0,0.51800335570916167,-0.53290555450294708,0 +0.61875000000000002,0.23685612557714375,0.59917605052507494,-1.5887974386781778,0,0.5210289610697918,-0.53516232288950649,0 +0.62124999999999997,0.236629474827142,0.59900329149184894,-1.5883523685763601,0,0.52084906032944422,-0.53504397890458888,0 +0.62375000000000003,0.23553444051781158,0.6094416366857287,-1.5832404611606701,0,0.51646465152499421,-0.53125243577613324,0 +0.62624999999999997,0.23480711426766496,0.61276659011654855,-1.5820244559454961,0,0.51359689942899112,-0.52940636364944882,0 +0.62875000000000003,0.2356805197653731,0.59981103240692546,-1.5873723560682378,0,0.51775543844125527,-0.53341880855164581,0 +0.63124999999999998,0.23665817647544471,0.58339388331467124,-1.5915886744702512,0,0.52230143300038878,-0.53706058378831778,0 +0.63375000000000004,0.23624007285922682,0.58851017476723522,-1.59323247289284,0,0.52067660348375233,-0.5344840295515112,0 +0.63624999999999998,0.23248269439745392,0.62017067097041967,-1.5860539280724555,0,0.50441116285539445,-0.52566087023161623,0 +0.63875000000000004,0.23287406771008778,0.63021607264750734,-1.5714111287249182,0,0.50610033932647758,-0.51881227330971402,0 +0.64124999999999999,0.23535665099942626,0.54552436166512541,-1.5610957972782948,0,0.51620744848479627,-0.56037653795121478,0 +0.64375000000000004,0.20465921194562456,0.43550920292588785,-1.2461151516740705,0,0.38959320083362653,-0.65081895672509904,0 +0.64624999999999999,0.14009395039150022,-0.013620789581837623,-0.52852147362552981,0,0.14893940676494133,-0.84115443834590753,0 +0.64875000000000005,0.11751273289208522,-0.22437213354109883,-0.16226723635220483,0,0.088423364818236205,-0.90651157396572613,0 +0.65125,0.1172304349686725,-0.23055950413906093,-0.15834995998342491,0,0.087980641698620188,-0.90679519491120031,0 +0.65375000000000005,0.11725471096145602,-0.23125048663034239,-0.15988967480131078,0,0.088016824468717392,-0.90623225381858352,0 +0.65625,0.11717819471904142,-0.23427702280565715,-0.16309682007195445,0,0.087901314598951896,-0.90467584906756415,0 +0.65875000000000006,0.11701473008444113,-0.23931297733336335,-0.16679190788787737,0,0.087655777579992433,-0.90262825016899195,0 +0.66125,0.11682044790275041,-0.24514922075151147,-0.17096232324746935,0,0.087364026139568063,-0.90028034756782194,0 +0.66375000000000006,0.11664990465573849,-0.25033190821458962,-0.17474981564425235,0,0.087108330784376853,-0.89817521994953109,0 +0.66625000000000001,0.11659183681487016,-0.25210877535067339,-0.17606373800900416,0,0.087021072376205377,-0.89744964551230921,0 +0.66875000000000007,0.11659565313804586,-0.25199397498810977,-0.17597732617696363,0,0.087026305831300999,-0.89749741619551415,0 +0.67125000000000001,0.11663090160109492,-0.25091377282773697,-0.17517704012828506,0,0.087078794787367686,-0.89793883874353608,0 +0.67374999999999996,0.11672569071628684,-0.24801894198896796,-0.17304243161135532,0,0.087219942612219992,-0.89911964160362412,0 +0.67625000000000002,0.11687866962961335,-0.24335351965734039,-0.16961064512063617,0,0.087448451090979984,-0.90102219304187958,0 +0.67874999999999996,0.11706716457467407,-0.23761206836584889,-0.16539777355745228,0,0.087729984963327179,-0.903363295110168,0 +0.68125000000000002,0.11725531088500578,-0.23188499457250628,-0.16120570301525269,0,0.088011625486577039,-0.90569773785665264,0 +0.68374999999999997,0.1173869096123874,-0.22787830963670686,-0.15827892017451603,0,0.088208749864432612,-0.90733063517330292,0 +0.68625000000000003,0.11740612473963735,-0.22729629509711108,-0.15785255924099278,0,0.08823710550802899,-0.90756836804359509,0 +0.68874999999999997,0.1174043024511611,-0.22735052337058989,-0.15789017932834926,0,0.08823427512892934,-0.90754730073044609,0 +0.69125000000000003,0.117385586946818,-0.22792019819914602,-0.15830312721357306,0,0.088205717689737617,-0.90731579951421071,0 +0.69374999999999998,0.11733333794868246,-0.22950618589385671,-0.15945854815582666,0,0.088127191628521229,-0.90667017955692664,0 +0.69625000000000004,0.11723047219013001,-0.23263692843712594,-0.1617427414330794,0,0.087972319470910665,-0.90539536389292952,0 +0.69874999999999998,0.11707119965622731,-0.23748283866703485,-0.16528542583275169,0,0.087733351641583468,-0.90342149850150899,0 +0.70125000000000004,0.11687031669818926,-0.24360287346583834,-0.16977049665712179,0,0.087431835729061547,-0.90092842407432894,0 +0.70374999999999999,0.11665961352933606,-0.25002473062346064,-0.17448953235454481,0,0.087116281751007274,-0.89831176039494187,0 +0.70625000000000004,0.1165165302499433,-0.25439233792360777,-0.17770571675062352,0,0.086901806565141237,-0.89653255429149881,0 +0.70874999999999999,0.11650342706556212,-0.2547927709381313,-0.17799943043788108,0,0.086882001709442935,-0.89636978909070852,0 +0.71125000000000005,0.11651313327825538,-0.25449583971560935,-0.17777892983377314,0,0.086896257833543045,-0.8964912611982403,0 +0.71375,0.11657824875283614,-0.25250868159070106,-0.17631251476880538,0,0.086993320783096961,-0.8973018533821181,0 +0.71625000000000005,0.11670669297667058,-0.24859138314712292,-0.17342577474077817,0,0.087184751921271064,-0.89889931280557489,0 +0.71875,0.11691006489352132,-0.24238906844035901,-0.16886594442826247,0,0.087488817862619084,-0.90142781444796216,0 +0.72125000000000006,0.11715696037775949,-0.23486831445080303,-0.16335344395667553,0,0.087858057823719804,-0.90449340621863428,0 +0.72375,0.1174166577876183,-0.22696879682954138,-0.15758238759684895,0,0.08824723417305036,-0.9077124481337816,0 +0.72625000000000006,0.11761203623571825,-0.22103003047499958,-0.15325677844062333,0,0.088540228534066956,-0.9101327480055359,0 +0.72875000000000001,0.11764815223606326,-0.21993423708599183,-0.15245924851833104,0,0.08859412431248137,-0.91057953155824023,0 +0.73125000000000007,0.11764295241336808,-0.2200903293627689,-0.15257160911773979,0,0.088586337286039485,-0.91051617734452983,0 +0.73375000000000001,0.11759000660142679,-0.2217003081127347,-0.15374084437403135,0,0.088506338493284042,-0.90986082609014918,0 +0.73624999999999996,0.11746031345619404,-0.22563937809188131,-0.15660719388934993,0,0.088311340736592969,-0.90825665198961858,0 +0.73875000000000002,0.11723828372065292,-0.23239420472240171,-0.16153287456890622,0,0.087977168091466496,-0.9055058428394922,0 +0.74124999999999996,0.11695405872405729,-0.24104632732416764,-0.16786313884395296,0,0.087550606026847611,-0.90198118960069906,0 +0.74375000000000002,0.11667856642422411,-0.24944335338982396,-0.17402937906226756,0,0.087137125367697799,-0.89856002823076275,0 +0.74624999999999997,0.11652142847638322,-0.25424394334264461,-0.17756382750169244,0,0.086901454460314165,-0.89660456501140007,0 +0.74875000000000003,0.11651981293218819,-0.25428866572145908,-0.17759682581079278,0,0.086899302405564094,-0.89658628316293454,0 +0.75124999999999997,0.11654384178002924,-0.2535594566735877,-0.17705849552342462,0,0.086934742960429467,-0.89688401034771859,0 +0.75375000000000003,0.11663051640593858,-0.25091355302284074,-0.17510796984102217,0,0.08706432661997765,-0.89796267762001025,0 +0.75624999999999998,0.11678404277607407,-0.24623080770483949,-0.17166114194328411,0,0.087293311528364281,-0.89987155145629427,0 +0.75875000000000004,0.11700344302198436,-0.23954347013011862,-0.16675062625144083,0,0.087621451884493884,-0.90259743709333429,0 +0.76124999999999998,0.1172431937971754,-0.23224924863937169,-0.16141064996890825,0,0.087980008633671614,-0.90557089006933678,0 +0.76375000000000004,0.11745835723684928,-0.2257014011703927,-0.15663158785569858,0,0.088302688141607355,-0.90823890147105391,0 +0.76624999999999999,0.11754312622419839,-0.22312484757638981,-0.15475473896938308,0,0.088429763359914815,-0.90928903939657357,0 +0.76875000000000004,0.11754177990704494,-0.2231668919210899,-0.15478502917437109,0,0.08842756580276423,-0.90927164832488772,0 +0.77124999999999999,0.11752467556395679,-0.22368568226609817,-0.15516209375600826,0,0.088401836341015949,-0.90906068120615424,0 +0.77375000000000005,0.11746717207168339,-0.22543397607620042,-0.15643453805452581,0,0.088315305884747231,-0.90834911199205925,0 +0.77625,0.11736654278177328,-0.2284945234234321,-0.15866471296533163,0,0.088163952024696957,-0.90710265586110195,0 +0.77875000000000005,0.11722713361337955,-0.23273201682477188,-0.16175718703284839,0,0.087954401569682927,-0.90537555931713076,0 +0.78125,0.11707778782447791,-0.23727864076599559,-0.16508186697178692,0,0.087730265510702843,-0.90352339441354335,0 +0.78375000000000006,0.11694701926702723,-0.24126444712942194,-0.16800203883568809,0,0.087533988164180898,-0.90189987769505553,0 +0.78625,0.11687743963943051,-0.24338529654596849,-0.16955784803318272,0,0.087429820942728886,-0.90103669813034792,0 +0.78875000000000006,0.11687579781052707,-0.24343592181704782,-0.16959486107747798,0,0.08742728644424369,-0.90101601254263675,0 +0.79125000000000001,0.11687539900643468,-0.24344948224066379,-0.16960462180695862,0,0.087426474749633054,-0.90100969094006977,0 +0.79375000000000007,0.11687409481764938,-0.24348129085661555,-0.16962777224760861,0,0.087424696127569423,-0.90099540369582221,0 +0.79625000000000001,0.11687218858217306,-0.24354390911756213,-0.16967348339899166,0,0.087421752667664165,-0.90097160223299655,0 +0.79875000000000007,0.116870215752296,-0.24361058874898325,-0.1697220504681374,0,0.0874184896460376,-0.90094505886224741,0 +0.80125000000000002,0.11686946136924814,-0.2436294977483163,-0.16973560439458318,0,0.087417613977942565,-0.90093824717607751,0 +0.80374999999999996,0.11686962190859448,-0.24361757731467398,-0.16972658857626485,0,0.087417870797879327,-0.90094090262231019,0 +0.80625000000000002,0.11687356980470871,-0.24350583643941545,-0.16964422423269365,0,0.087423444046079268,-0.90098768473549895,0 +0.80874999999999997,0.11688754092326054,-0.24307479305630586,-0.16932756115966405,0,0.087444533924976753,-0.90116318958274499,0 +0.81125000000000003,0.11691972536277602,-0.24209343744922968,-0.16860707128114324,0,0.087492701479890633,-0.90156325665747283,0 +0.81374999999999997,0.11697942266283615,-0.24027908101633488,-0.16727614115169526,0,0.087581830141478023,-0.90230271944561291,0 +0.81625000000000003,0.11707126156401244,-0.23747712607290974,-0.16522305705840304,0,0.08771962969895275,-0.9034445863476972,0 +0.81874999999999998,0.11720175792642251,-0.23350615420116155,-0.16231792357714034,0,0.087915217578154237,-0.9050626671429971,0 +0.82125000000000004,0.1173736571942727,-0.22828036241638489,-0.1585025661792111,0,0.088173092622349736,-0.90719178038941839,0 +0.82374999999999998,0.11758753647266376,-0.22177196496693163,-0.15376313261251445,0,0.088495041188408119,-0.90984301103522469,0 +0.82625000000000004,0.11784277533584739,-0.21402503109325074,-0.14813976728812336,0,0.088879385731000071,-0.91299811129464448,0 +0.82874999999999999,0.11813596987373072,-0.205135924121809,-0.14171096949690176,0,0.08932189551312586,-0.91661764598071116,0 +0.83125000000000004,0.11846242009804758,-0.19523667455595015,-0.13458125038057758,0,0.089816668680236189,-0.9206475711390385,0 +0.83374999999999999,0.11881836690580111,-0.18447630678794286,-0.12686686204096317,0,0.090356823064338121,-0.92502691979325369,0 +0.83625000000000005,0.1191983441793935,-0.17300551327586872,-0.11868324695390486,0,0.090935254319816416,-0.92969427790399251,0 +0.83875,0.11959717551690868,-0.16096583965923558,-0.11013805167379476,0,0.091545418685837099,-0.93459181209615316,0 +0.84125000000000005,0.12001209755915153,-0.14848356585795672,-0.10132596582677481,0,0.092181264693114717,-0.93966810954166835,0 +0.84375,0.12043877950911509,-0.13566775697809377,-0.092327068649525487,0,0.09283750209918229,-0.94487908876250215,0 +0.84625000000000006,0.12087371396585696,-0.12260927689724001,-0.083209494160765118,0,0.093509933368980058,-0.95018748674767706,0 +0.84875,0.12131567129224743,-0.1093844697747413,-0.074028085304663455,0,0.094194471653768597,-0.95556248832995694,0 +0.85125000000000006,0.12176160189020308,-0.09605840550907592,-0.064827260654986854,0,0.094888110578776108,-0.96097800205309825,0 +0.85375000000000001,0.12220959195301018,-0.082687976622211293,-0.055648874909733553,0,0.095588128076847467,-0.96641042235416763,0 +0.85625000000000007,0.12265849289683448,-0.069328350882536471,-0.046529178998104978,0,0.096291008766648978,-0.97183799626406353,0 +0.85875000000000001,0.12310492382833711,-0.056055787146077833,-0.037517888038019767,0,0.09699339953981001,-0.97722987519548088,0 +0.86125000000000007,0.12354638322994141,-0.042956407473377395,-0.028674501720487335,0,0.09769052441735504,-0.98255051087648382,0 +0.86375000000000002,0.12397571444500097,-0.030246526919572154,-0.020138158560817101,0,0.098369693309683259,-0.9877136051082076,0 +0.86624999999999996,0.12438070565716236,-0.018268628225800106,-0.012133471567233139,0,0.099013662392659962,-0.99257887118158417,0 +0.86875000000000002,0.12473720330383267,-0.0077450726851307217,-0.0051335041220790375,0,0.099581171411821656,-0.9968532001498126,0 +0.87124999999999997,0.1249700817568199,-0.00088137321149738316,-0.00058273816183469274,0,0.099952225492064839,-0.99964210622385019,0 +0.87375000000000003,0.12500000000314493,9.2678072621328777e-11,6.1313650451563421e-11,0,0.10000000000503184,-1.0000000000376423,0 +0.87624999999999997,0.12500000000313061,9.2259592555934167e-11,6.1037663810628979e-11,0,0.10000000000500853,-1.0000000000374729,0 +0.87875000000000003,0.12500000000298683,8.8026904282191698e-11,5.823759252481918e-11,0,0.10000000000477915,-1.0000000000357536,0 +0.88124999999999998,0.12500000000268974,7.9267999569953049e-11,5.2440333555909956e-11,0,0.10000000000430354,-1.0000000000321956,0 +0.88375000000000004,0.12500000000219424,6.4666272335784794e-11,4.2780682699312474e-11,0,0.1000000000035105,-1.0000000000262652,0 +0.88624999999999998,0.1250000000015753,4.6425914963663502e-11,3.071392029557768e-11,0,0.10000000000252052,-1.0000000000188565,0 +0.88875000000000004,0.12500000000090811,2.6762103644077048e-11,1.7704741376541178e-11,0,0.10000000000145282,-1.0000000000108695,0 +0.89124999999999999,0.1250000000003243,9.5565777513424923e-12,6.3224980806181864e-12,0,0.10000000000051879,-1.0000000000038816,0 +0.89375000000000004,0.12500000000000178,5.2520950551592749e-14,3.481659405223961e-14,0,0.10000000000000264,-1.0000000000000213,0 +0.89624999999999999,0.125,0,0,0,0.099999999999999867,-1,0 +0.89875000000000005,0.125,0,0,0,0.099999999999999867,-1,0 +0.90125,0.125,0,0,0,0.099999999999999867,-1,0 +0.90375000000000005,0.125,0,0,0,0.099999999999999867,-1,0 +0.90625,0.125,0,0,0,0.099999999999999867,-1,0 +0.90875000000000006,0.125,0,0,0,0.099999999999999867,-1,0 +0.91125,0.125,0,0,0,0.099999999999999867,-1,0 +0.91375000000000006,0.125,0,0,0,0.099999999999999867,-1,0 +0.91625000000000001,0.125,0,0,0,0.099999999999999867,-1,0 +0.91875000000000007,0.125,0,0,0,0.099999999999999867,-1,0 +0.92125000000000001,0.125,0,0,0,0.099999999999999867,-1,0 +0.92375000000000007,0.125,0,0,0,0.099999999999999867,-1,0 +0.92625000000000002,0.125,0,0,0,0.099999999999999867,-1,0 +0.92874999999999996,0.125,0,0,0,0.099999999999999867,-1,0 +0.93125000000000002,0.125,0,0,0,0.099999999999999867,-1,0 +0.93374999999999997,0.125,0,0,0,0.099999999999999867,-1,0 +0.93625000000000003,0.125,0,0,0,0.099999999999999867,-1,0 +0.93874999999999997,0.125,0,0,0,0.099999999999999867,-1,0 +0.94125000000000003,0.125,0,0,0,0.099999999999999867,-1,0 +0.94374999999999998,0.125,0,0,0,0.099999999999999867,-1,0 +0.94625000000000004,0.125,0,0,0,0.099999999999999867,-1,0 +0.94874999999999998,0.125,0,0,0,0.099999999999999867,-1,0 +0.95125000000000004,0.125,0,0,0,0.099999999999999867,-1,0 +0.95374999999999999,0.125,0,0,0,0.099999999999999867,-1,0 +0.95625000000000004,0.125,0,0,0,0.099999999999999867,-1,0 +0.95874999999999999,0.125,0,0,0,0.099999999999999867,-1,0 +0.96125000000000005,0.125,0,0,0,0.099999999999999867,-1,0 +0.96375,0.125,0,0,0,0.099999999999999867,-1,0 +0.96625000000000005,0.125,0,0,0,0.099999999999999867,-1,0 +0.96875,0.125,0,0,0,0.099999999999999867,-1,0 +0.97125000000000006,0.125,0,0,0,0.099999999999999867,-1,0 +0.97375,0.125,0,0,0,0.099999999999999867,-1,0 +0.97625000000000006,0.125,0,0,0,0.099999999999999867,-1,0 +0.97875000000000001,0.125,0,0,0,0.099999999999999867,-1,0 +0.98125000000000007,0.125,0,0,0,0.099999999999999867,-1,0 +0.98375000000000001,0.125,0,0,0,0.099999999999999867,-1,0 +0.98625000000000007,0.125,0,0,0,0.099999999999999867,-1,0 +0.98875000000000002,0.125,0,0,0,0.099999999999999867,-1,0 +0.99125000000000008,0.125,0,0,0,0.099999999999999867,-1,0 +0.99375000000000002,0.125,0,0,0,0.099999999999999867,-1,0 +0.99624999999999997,0.125,0,0,0,0.099999999999999867,-1,0 +0.99875000000000003,0.125,0,0,0,0.099999999999999867,-1,0 diff --git a/benchmarks/magnetohydrodynamics/shared/eval/mhd1d_reference.py b/benchmarks/magnetohydrodynamics/shared/eval/mhd1d_reference.py new file mode 100644 index 0000000..8fb1234 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/shared/eval/mhd1d_reference.py @@ -0,0 +1,877 @@ +"""Maintainer-only hidden reference helpers for 1D Brio-Wu MHD.""" + +from __future__ import annotations + +import math +import csv +import json +from pathlib import Path + +import numpy as np + + +STATE_WIDTH = 7 +DOMAIN_LEFT = 0.0 +DOMAIN_RIGHT = 1.0 +DISCONTINUITY_X = 0.5 +DEFAULT_GAMMA = 2.0 +DEFAULT_BX = 0.75 +DEFAULT_GHOST_WIDTH = 2 +BRIO_WU_REFERENCE_NX = 400 +BRIO_WU_REFERENCE_T_FINAL = 0.1 +BRIO_WU_REFERENCE_DT = 5.0e-4 +BRIO_WU_REFERENCE_CSV_NAME = "brio_wu_reference.csv" +BRIO_WU_FIXTURE_JSON_NAME = "brio_wu_fixture.json" +BRIO_WU_REFERENCE_HEADER = ("x", "rho", "u", "v", "w", "p", "by", "bz") +BRIO_WU_SCORING_VARIABLES = ("rho", "u", "p", "by") +BRIO_WU_INNER_WINDOW_EXCLUDE = 2 + +PRIMITIVE_ORDER = ("rho", "u", "v", "w", "p", "By", "Bz") +CONSERVATIVE_ORDER = ("rho", "mx", "my", "mz", "E", "By", "Bz") + +BRIO_WU_LEFT_PRIMITIVE = np.array([1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0], dtype=np.float64) +BRIO_WU_RIGHT_PRIMITIVE = np.array( + [0.125, 0.0, 0.0, 0.0, 0.1, -1.0, 0.0], dtype=np.float64 +) + + +def _require_state_width(state: np.ndarray, *, name: str) -> np.ndarray: + array = np.asarray(state, dtype=np.float64) + if array.shape[-1] != STATE_WIDTH: + raise ValueError(f"{name} must have last dimension {STATE_WIDTH}") + return array + + +def _sign_unit(number: float) -> float: + return 1.0 if number >= 0.0 else -1.0 + + +def primitive_to_conservative( + primitive_state: np.ndarray, + bx: float = DEFAULT_BX, + gamma: float = DEFAULT_GAMMA, +) -> np.ndarray: + primitive = _require_state_width(primitive_state, name="primitive_state") + + rho = primitive[..., 0] + u = primitive[..., 1] + v = primitive[..., 2] + w = primitive[..., 3] + pressure = primitive[..., 4] + by = primitive[..., 5] + bz = primitive[..., 6] + + conservative = np.empty_like(primitive, dtype=np.float64) + conservative[..., 0] = rho + conservative[..., 1] = rho * u + conservative[..., 2] = rho * v + conservative[..., 3] = rho * w + conservative[..., 4] = pressure / (gamma - 1.0) + 0.5 * rho * ( + u * u + v * v + w * w + ) + conservative[..., 4] += 0.5 * (bx * bx + by * by + bz * bz) + conservative[..., 5] = by + conservative[..., 6] = bz + return conservative + + +def conservative_to_primitive( + conservative_state: np.ndarray, + bx: float = DEFAULT_BX, + gamma: float = DEFAULT_GAMMA, +) -> np.ndarray: + conservative = _require_state_width(conservative_state, name="conservative_state") + + rho = conservative[..., 0] + mx = conservative[..., 1] + my = conservative[..., 2] + mz = conservative[..., 3] + energy = conservative[..., 4] + by = conservative[..., 5] + bz = conservative[..., 6] + + u = mx / rho + v = my / rho + w = mz / rho + kinetic_energy = 0.5 * rho * (u * u + v * v + w * w) + magnetic_energy = 0.5 * (bx * bx + by * by + bz * bz) + pressure = (gamma - 1.0) * (energy - kinetic_energy - magnetic_energy) + + primitive = np.empty_like(conservative, dtype=np.float64) + primitive[..., 0] = rho + primitive[..., 1] = u + primitive[..., 2] = v + primitive[..., 3] = w + primitive[..., 4] = pressure + primitive[..., 5] = by + primitive[..., 6] = bz + return primitive + + +def cell_centers( + nx: int, + x_left: float = DOMAIN_LEFT, + x_right: float = DOMAIN_RIGHT, +) -> np.ndarray: + if nx <= 0: + raise ValueError("nx must be positive") + if x_right <= x_left: + raise ValueError("x_right must be greater than x_left") + + dx = (x_right - x_left) / float(nx) + centers = x_left + (np.arange(nx, dtype=np.float64) + 0.5) * dx + return centers + + +def brio_wu_primitive_profile( + nx: int, + x_left: float = DOMAIN_LEFT, + x_right: float = DOMAIN_RIGHT, + discontinuity_x: float = DISCONTINUITY_X, +) -> np.ndarray: + centers = cell_centers(nx, x_left=x_left, x_right=x_right) + primitive_profile = np.empty((nx, STATE_WIDTH), dtype=np.float64) + left_cells = centers < discontinuity_x + primitive_profile[left_cells] = BRIO_WU_LEFT_PRIMITIVE + primitive_profile[~left_cells] = BRIO_WU_RIGHT_PRIMITIVE + return primitive_profile + + +def brio_wu_conservative_profile( + nx: int, + x_left: float = DOMAIN_LEFT, + x_right: float = DOMAIN_RIGHT, + discontinuity_x: float = DISCONTINUITY_X, + bx: float = DEFAULT_BX, + gamma: float = DEFAULT_GAMMA, +) -> np.ndarray: + primitive_profile = brio_wu_primitive_profile( + nx, + x_left=x_left, + x_right=x_right, + discontinuity_x=discontinuity_x, + ) + return primitive_to_conservative(primitive_profile, bx=bx, gamma=gamma) + + +def evolve_brio_wu_reference_profile( + nx: int = BRIO_WU_REFERENCE_NX, + t_final: float = BRIO_WU_REFERENCE_T_FINAL, + dt: float = BRIO_WU_REFERENCE_DT, + bx: float = DEFAULT_BX, + gamma: float = DEFAULT_GAMMA, +) -> np.ndarray: + conservative_profile = brio_wu_conservative_profile(nx, bx=bx, gamma=gamma) + evolved_conservative = evolve_ssp_rk3_fixed_dt( + conservative_profile, + t_final=t_final, + dt=dt, + bx=bx, + gamma=gamma, + ) + return conservative_to_primitive(evolved_conservative, bx=bx, gamma=gamma) + + +def write_brio_wu_reference_fixtures(output_directory: str | Path) -> dict[str, Path]: + output_path = Path(output_directory) + output_path.mkdir(parents=True, exist_ok=True) + + reference_profile = evolve_brio_wu_reference_profile() + center_positions = cell_centers(reference_profile.shape[0]) + + csv_path = output_path / BRIO_WU_REFERENCE_CSV_NAME + with csv_path.open("w", newline="", encoding="utf-8") as csv_file: + writer = csv.writer(csv_file) + writer.writerow(BRIO_WU_REFERENCE_HEADER) + for position, primitive_state in zip( + center_positions, reference_profile, strict=True + ): + writer.writerow( + [ + f"{float(position):.17g}", + f"{float(primitive_state[0]):.17g}", + f"{float(primitive_state[1]):.17g}", + f"{float(primitive_state[2]):.17g}", + f"{float(primitive_state[3]):.17g}", + f"{float(primitive_state[4]):.17g}", + f"{float(primitive_state[5]):.17g}", + f"{float(primitive_state[6]):.17g}", + ] + ) + + tolerance_template = {variable: 0.0 for variable in BRIO_WU_SCORING_VARIABLES} + metadata = { + "name": "brio_wu", + "domain": [DOMAIN_LEFT, DOMAIN_RIGHT], + "discontinuity_x": DISCONTINUITY_X, + "gamma": DEFAULT_GAMMA, + "bx": DEFAULT_BX, + "nx": reference_profile.shape[0], + "t_final": BRIO_WU_REFERENCE_T_FINAL, + "dt": BRIO_WU_REFERENCE_DT, + "schema": list(BRIO_WU_REFERENCE_HEADER), + "scored_variables": list(BRIO_WU_SCORING_VARIABLES), + "interior_cell_window": { + "exclude_edge_adjacents_per_side": BRIO_WU_INNER_WINDOW_EXCLUDE, + }, + "abs_l1": tolerance_template, + "abs_linf": tolerance_template.copy(), + "reference_csv": BRIO_WU_REFERENCE_CSV_NAME, + } + + json_path = output_path / BRIO_WU_FIXTURE_JSON_NAME + with json_path.open("w", encoding="utf-8") as json_file: + json.dump(metadata, json_file, indent=2, sort_keys=True) + json_file.write("\n") + + return {"csv": csv_path, "json": json_path} + + +def fill_zero_gradient_ghost_cells( + cell_state: np.ndarray, + ghost_width: int = DEFAULT_GHOST_WIDTH, +) -> np.ndarray: + if ghost_width < 0: + raise ValueError("ghost_width must be non-negative") + + interior_state = _require_state_width(cell_state, name="cell_state") + if interior_state.ndim != 2: + raise ValueError("cell_state must be a 2D array with shape (nx, 7)") + if interior_state.shape[0] == 0: + raise ValueError("cell_state must contain at least one cell") + + padded_width = interior_state.shape[0] + 2 * ghost_width + padded_state = np.empty((padded_width, STATE_WIDTH), dtype=np.float64) + padded_state[ghost_width : ghost_width + interior_state.shape[0]] = interior_state + padded_state[:ghost_width] = interior_state[0] + padded_state[ghost_width + interior_state.shape[0] :] = interior_state[-1] + return padded_state + + +def _minmod3( + first_slope: np.ndarray, second_slope: np.ndarray, third_slope: np.ndarray +) -> np.ndarray: + same_sign = (first_slope * second_slope > 0.0) & (first_slope * third_slope > 0.0) + limited = np.sign(first_slope) * np.minimum( + np.minimum(np.abs(first_slope), np.abs(second_slope)), np.abs(third_slope) + ) + return np.where(same_sign, limited, 0.0) + + +def mc2_slopes(primitive_cells: np.ndarray) -> np.ndarray: + primitive = _require_state_width(primitive_cells, name="primitive_cells") + if primitive.ndim != 2: + raise ValueError("primitive_cells must be a 2D array with shape (n, 7)") + if primitive.shape[0] < 3: + raise ValueError("primitive_cells must contain at least three cells") + + slopes = np.zeros_like(primitive, dtype=np.float64) + left_difference = primitive[1:-1] - primitive[:-2] + right_difference = primitive[2:] - primitive[1:-1] + centered_difference = 0.5 * (primitive[2:] - primitive[:-2]) + slopes[1:-1] = _minmod3( + 2.0 * left_difference, + centered_difference, + 2.0 * right_difference, + ) + return slopes + + +def reconstruct_mc2_interfaces( + primitive_cells: np.ndarray, +) -> tuple[np.ndarray, np.ndarray]: + primitive = _require_state_width(primitive_cells, name="primitive_cells") + if primitive.ndim != 2: + raise ValueError("primitive_cells must be a 2D array with shape (n, 7)") + + slopes = mc2_slopes(primitive) + left_states = primitive[:-1] + 0.5 * slopes[:-1] + right_states = primitive[1:] - 0.5 * slopes[1:] + return left_states, right_states + + +def _physical_flux_from_primitive( + primitive_state: np.ndarray, + bx: float, + gamma: float, +) -> np.ndarray: + density = float(primitive_state[0]) + velocity_x = float(primitive_state[1]) + velocity_y = float(primitive_state[2]) + velocity_z = float(primitive_state[3]) + pressure = float(primitive_state[4]) + by = float(primitive_state[5]) + bz = float(primitive_state[6]) + + magnetic_pressure = 0.5 * (bx * bx + by * by + bz * bz) + total_pressure = pressure + magnetic_pressure + + momentum_x = density * velocity_x + momentum_y = density * velocity_y + momentum_z = density * velocity_z + energy = pressure / (gamma - 1.0) + energy += 0.5 * ( + momentum_x * velocity_x + momentum_y * velocity_y + momentum_z * velocity_z + ) + energy += magnetic_pressure + + return np.array( + [ + momentum_x, + momentum_x * velocity_x + total_pressure - bx * bx, + momentum_x * velocity_y - bx * by, + momentum_x * velocity_z - bx * bz, + velocity_x * (energy + total_pressure - bx * bx) + - bx * (velocity_y * by + velocity_z * bz), + by * velocity_x - bx * velocity_y, + bz * velocity_x - bx * velocity_z, + ], + dtype=np.float64, + ) + + +def _fast_magnetosonic_speed( + density: float, + pressure: float, + by: float, + bz: float, + bx: float, + gamma: float, +) -> float: + magnetic_pressure = 0.5 * (bx * bx + by * by + bz * bz) + gamma_pressure = gamma * pressure + gamma_plus_magnetic = gamma_pressure + 2.0 * magnetic_pressure + discriminant = math.sqrt( + (gamma_pressure - 2.0 * magnetic_pressure) + * (gamma_pressure - 2.0 * magnetic_pressure) + + 4.0 * gamma_pressure * (by * by + bz * bz) + ) + return math.sqrt((gamma_plus_magnetic + discriminant) * 0.5 / density) + + +def hlld_flux_from_primitive( + left_state: np.ndarray, + right_state: np.ndarray, + bx: float = DEFAULT_BX, + gamma: float = DEFAULT_GAMMA, +) -> np.ndarray: + left = _require_state_width(left_state, name="left_state") + right = _require_state_width(right_state, name="right_state") + if left.ndim != 1 or right.ndim != 1: + raise ValueError( + "left_state and right_state must be one-dimensional state vectors" + ) + + density_left = float(left[0]) + velocity_x_left = float(left[1]) + velocity_y_left = float(left[2]) + velocity_z_left = float(left[3]) + pressure_left = float(left[4]) + by_left = float(left[5]) + bz_left = float(left[6]) + + density_right = float(right[0]) + velocity_x_right = float(right[1]) + velocity_y_right = float(right[2]) + velocity_z_right = float(right[3]) + pressure_right = float(right[4]) + by_right = float(right[5]) + bz_right = float(right[6]) + + inverse_gamma_minus_one = 1.0 / (gamma - 1.0) + bx_square = bx * bx + + magnetic_pressure_left = 0.5 * (bx_square + by_left * by_left + bz_left * bz_left) + magnetic_pressure_right = 0.5 * ( + bx_square + by_right * by_right + bz_right * bz_right + ) + total_pressure_left = pressure_left + magnetic_pressure_left + total_pressure_right = pressure_right + magnetic_pressure_right + + momentum_x_left = density_left * velocity_x_left + momentum_y_left = density_left * velocity_y_left + momentum_z_left = density_left * velocity_z_left + momentum_x_right = density_right * velocity_x_right + momentum_y_right = density_right * velocity_y_right + momentum_z_right = density_right * velocity_z_right + + energy_left = ( + pressure_left * inverse_gamma_minus_one + + 0.5 + * ( + momentum_x_left * velocity_x_left + + momentum_y_left * velocity_y_left + + momentum_z_left * velocity_z_left + ) + + magnetic_pressure_left + ) + energy_right = ( + pressure_right * inverse_gamma_minus_one + + 0.5 + * ( + momentum_x_right * velocity_x_right + + momentum_y_right * velocity_y_right + + momentum_z_right * velocity_z_right + ) + + magnetic_pressure_right + ) + + left_fast_speed = _fast_magnetosonic_speed( + density_left, + pressure_left, + by_left, + bz_left, + bx, + gamma, + ) + right_fast_speed = _fast_magnetosonic_speed( + density_right, + pressure_right, + by_right, + bz_right, + bx, + gamma, + ) + + outer_left_speed = min(velocity_x_left, velocity_x_right) - max( + left_fast_speed, right_fast_speed + ) + outer_right_speed = max(velocity_x_left, velocity_x_right) + max( + left_fast_speed, right_fast_speed + ) + + left_flux = _physical_flux_from_primitive(left, bx=bx, gamma=gamma) + right_flux = _physical_flux_from_primitive(right, bx=bx, gamma=gamma) + + left_speed_gap = outer_left_speed - velocity_x_left + right_speed_gap = outer_right_speed - velocity_x_right + left_speed_factor = density_left * left_speed_gap + right_speed_factor = density_right * right_speed_gap + denominator = right_speed_factor - left_speed_factor + contact_speed = ( + right_speed_factor * velocity_x_right + - left_speed_factor * velocity_x_left + - total_pressure_right + + total_pressure_left + ) / denominator + left_contact_gap = outer_left_speed - contact_speed + right_contact_gap = outer_right_speed - contact_speed + star_total_pressure = ( + right_speed_factor * total_pressure_left + - left_speed_factor * total_pressure_right + + left_speed_factor * right_speed_factor * (velocity_x_right - velocity_x_left) + ) / denominator + + def build_star_state( + density: float, + velocity_x: float, + velocity_y: float, + velocity_z: float, + by: float, + bz: float, + total_pressure: float, + energy: float, + speed_gap: float, + contact_gap: float, + ) -> tuple[np.ndarray, float, float, float]: + epsilon = 1.0e-40 + + gap_times_density = density * speed_gap + raw_transverse_denom = gap_times_density * contact_gap - bx_square + denominator_sign = _sign_unit(abs(raw_transverse_denom) - epsilon) + positive_branch = max(0.0, denominator_sign) + negative_branch = min(0.0, denominator_sign) + inverse_transverse_denom = 1.0 / (raw_transverse_denom + negative_branch) + inverse_contact_gap = 1.0 / contact_gap + + transverse_velocity_scale = ( + bx * (speed_gap - contact_gap) * inverse_transverse_denom + ) + density_star = ( + positive_branch * (gap_times_density * inverse_contact_gap) + - negative_branch * density + ) + velocity_x_star = positive_branch * contact_speed - negative_branch * velocity_x + momentum_x_star = density_star * velocity_x_star + velocity_y_star = ( + positive_branch * (velocity_y - by * transverse_velocity_scale) + - negative_branch * velocity_y + ) + momentum_y_star = density_star * velocity_y_star + velocity_z_star = ( + positive_branch * (velocity_z - bz * transverse_velocity_scale) + - negative_branch * velocity_z + ) + momentum_z_star = density_star * velocity_z_star + by_scale = ( + gap_times_density * speed_gap - bx_square + ) * inverse_transverse_denom + by_star = positive_branch * (by * by_scale) - negative_branch * by + bz_star = positive_branch * (bz * by_scale) - negative_branch * bz + velocity_dot_b_star = ( + velocity_x_star * bx + velocity_y_star * by_star + velocity_z_star * bz_star + ) + velocity_dot_b_original = velocity_x * bx + velocity_y * by + velocity_z * bz + starred_energy = ( + positive_branch + * ( + ( + speed_gap * energy + - total_pressure * velocity_x + + star_total_pressure * contact_speed + + bx * (velocity_dot_b_original - velocity_dot_b_star) + ) + * inverse_contact_gap + ) + - negative_branch * energy + ) + star_state = np.array( + [ + density_star, + momentum_x_star, + momentum_y_star, + momentum_z_star, + starred_energy, + by_star, + bz_star, + ], + dtype=np.float64, + ) + return star_state, density_star, by_star, bz_star + + left_star_state, left_star_density, left_star_by, left_star_bz = build_star_state( + density_left, + velocity_x_left, + velocity_y_left, + velocity_z_left, + by_left, + bz_left, + total_pressure_left, + energy_left, + left_speed_gap, + left_contact_gap, + ) + right_star_state, right_star_density, right_star_by, right_star_bz = ( + build_star_state( + density_right, + velocity_x_right, + velocity_y_right, + velocity_z_right, + by_right, + bz_right, + total_pressure_right, + energy_right, + right_speed_gap, + right_contact_gap, + ) + ) + + left_star_velocity = left_star_state[1] / left_star_density + left_star_transverse_velocity_y = left_star_state[2] / left_star_density + left_star_transverse_velocity_z = left_star_state[3] / left_star_density + right_star_velocity = right_star_state[1] / right_star_density + right_star_transverse_velocity_y = right_star_state[2] / right_star_density + right_star_transverse_velocity_z = right_star_state[3] / right_star_density + + left_star_speed = contact_speed - abs(bx) / math.sqrt(left_star_density) + right_star_speed = contact_speed + abs(bx) / math.sqrt(right_star_density) + bx_sign = _sign_unit(bx) + bx_branch = _sign_unit(abs(bx) - 1.0e-40) + use_rotational_branch = max(0.0, bx_branch) + inverse_density_sum = use_rotational_branch / ( + math.sqrt(left_star_density) + math.sqrt(right_star_density) + ) + + shared_transverse_velocity_y = inverse_density_sum * ( + math.sqrt(left_star_density) * left_star_transverse_velocity_y + + math.sqrt(right_star_density) * right_star_transverse_velocity_y + + bx_sign * (right_star_by - left_star_by) + ) + shared_transverse_velocity_z = inverse_density_sum * ( + math.sqrt(left_star_density) * left_star_transverse_velocity_z + + math.sqrt(right_star_density) * right_star_transverse_velocity_z + + bx_sign * (right_star_bz - left_star_bz) + ) + shared_by = inverse_density_sum * ( + math.sqrt(left_star_density) * right_star_by + + math.sqrt(right_star_density) * left_star_by + + bx_sign + * math.sqrt(left_star_density) + * math.sqrt(right_star_density) + * (right_star_transverse_velocity_y - left_star_transverse_velocity_y) + ) + shared_bz = inverse_density_sum * ( + math.sqrt(left_star_density) * right_star_bz + + math.sqrt(right_star_density) * left_star_bz + + bx_sign + * math.sqrt(left_star_density) + * math.sqrt(right_star_density) + * (right_star_transverse_velocity_z - left_star_transverse_velocity_z) + ) + + left_double_star_state = np.array( + [ + left_star_density, + left_star_density * contact_speed, + left_star_density * shared_transverse_velocity_y, + left_star_density * shared_transverse_velocity_z, + left_star_state[4] + - math.sqrt(left_star_density) + * bx_sign + * ( + left_star_velocity * bx + + left_star_transverse_velocity_y * left_star_by + + left_star_transverse_velocity_z * left_star_bz + - ( + contact_speed * bx + + shared_transverse_velocity_y * shared_by + + shared_transverse_velocity_z * shared_bz + ) + ) + * use_rotational_branch, + shared_by, + shared_bz, + ], + dtype=np.float64, + ) + right_double_star_state = np.array( + [ + right_star_density, + right_star_density * contact_speed, + right_star_density * shared_transverse_velocity_y, + right_star_density * shared_transverse_velocity_z, + right_star_state[4] + + math.sqrt(right_star_density) + * bx_sign + * ( + right_star_velocity * bx + + right_star_transverse_velocity_y * right_star_by + + right_star_transverse_velocity_z * right_star_bz + - ( + contact_speed * bx + + shared_transverse_velocity_y * shared_by + + shared_transverse_velocity_z * shared_bz + ) + ) + * use_rotational_branch, + shared_by, + shared_bz, + ], + dtype=np.float64, + ) + + left_state_conservative = np.array( + [ + density_left, + momentum_x_left, + momentum_y_left, + momentum_z_left, + energy_left, + by_left, + bz_left, + ], + dtype=np.float64, + ) + right_state_conservative = np.array( + [ + density_right, + momentum_x_right, + momentum_y_right, + momentum_z_right, + energy_right, + by_right, + bz_right, + ], + dtype=np.float64, + ) + left_star_flux = left_flux + outer_left_speed * ( + left_star_state - left_state_conservative + ) + right_star_flux = right_flux + outer_right_speed * ( + right_star_state - right_state_conservative + ) + left_double_star_flux = left_star_flux + left_star_speed * ( + left_double_star_state - left_star_state + ) + right_double_star_flux = right_star_flux + right_star_speed * ( + right_double_star_state - right_star_state + ) + + left_wave_branch = outer_left_speed <= 0.0 <= left_star_speed + left_double_star_branch = left_star_speed <= 0.0 <= contact_speed + right_double_star_branch = contact_speed <= 0.0 <= right_star_speed + right_wave_branch = right_star_speed <= 0.0 <= outer_right_speed + + if 0.0 <= outer_left_speed: + return left_flux + if left_wave_branch: + return left_star_flux + if left_double_star_branch: + return left_double_star_flux + if right_double_star_branch: + return right_double_star_flux + if right_wave_branch: + return right_star_flux + return right_flux + + +def hlld_flux_from_conservative( + left_state: np.ndarray, + right_state: np.ndarray, + bx: float = DEFAULT_BX, + gamma: float = DEFAULT_GAMMA, +) -> np.ndarray: + left_primitive = conservative_to_primitive(left_state, bx=bx, gamma=gamma) + right_primitive = conservative_to_primitive(right_state, bx=bx, gamma=gamma) + return hlld_flux_from_primitive(left_primitive, right_primitive, bx=bx, gamma=gamma) + + +def compute_semidiscrete_rhs( + conservative_cells: np.ndarray, + dx: float | None = None, + bx: float = DEFAULT_BX, + gamma: float = DEFAULT_GAMMA, + ghost_width: int = DEFAULT_GHOST_WIDTH, +) -> np.ndarray: + if ghost_width < 2: + raise ValueError("ghost_width must be at least 2 for MC2 reconstruction") + + interior_conservative = _require_state_width( + conservative_cells, name="conservative_cells" + ) + if interior_conservative.ndim != 2: + raise ValueError("conservative_cells must be a 2D array with shape (nx, 7)") + if interior_conservative.shape[0] == 0: + raise ValueError("conservative_cells must contain at least one cell") + + if dx is None: + dx = (DOMAIN_RIGHT - DOMAIN_LEFT) / float(interior_conservative.shape[0]) + if dx <= 0.0: + raise ValueError("dx must be positive") + + padded_conservative = fill_zero_gradient_ghost_cells( + interior_conservative, + ghost_width=ghost_width, + ) + padded_primitive = conservative_to_primitive( + padded_conservative, bx=bx, gamma=gamma + ) + left_interface_states, right_interface_states = reconstruct_mc2_interfaces( + padded_primitive + ) + + interface_fluxes = np.empty_like(left_interface_states) + for interface_index in range(interface_fluxes.shape[0]): + interface_fluxes[interface_index] = hlld_flux_from_primitive( + left_interface_states[interface_index], + right_interface_states[interface_index], + bx=bx, + gamma=gamma, + ) + + cell_count = interior_conservative.shape[0] + rhs = ( + -( + interface_fluxes[ghost_width : ghost_width + cell_count] + - interface_fluxes[ghost_width - 1 : ghost_width - 1 + cell_count] + ) + / dx + ) + return rhs + + +def brio_wu_semidiscrete_rhs( + nx: int, + bx: float = DEFAULT_BX, + gamma: float = DEFAULT_GAMMA, +) -> np.ndarray: + conservative_profile = brio_wu_conservative_profile(nx, bx=bx, gamma=gamma) + dx = (DOMAIN_RIGHT - DOMAIN_LEFT) / float(nx) + return compute_semidiscrete_rhs(conservative_profile, dx=dx, bx=bx, gamma=gamma) + + +def ssp_rk3_step( + conservative_cells: np.ndarray, + dt: float, + dx: float | None = None, + bx: float = DEFAULT_BX, + gamma: float = DEFAULT_GAMMA, + ghost_width: int = DEFAULT_GHOST_WIDTH, +) -> np.ndarray: + interior_conservative = _require_state_width( + conservative_cells, name="conservative_cells" + ) + if interior_conservative.ndim != 2: + raise ValueError("conservative_cells must be a 2D array with shape (nx, 7)") + if interior_conservative.shape[0] == 0: + raise ValueError("conservative_cells must contain at least one cell") + if dt <= 0.0: + raise ValueError("dt must be positive") + + first_rhs = compute_semidiscrete_rhs( + interior_conservative, + dx=dx, + bx=bx, + gamma=gamma, + ghost_width=ghost_width, + ) + first_stage = interior_conservative + dt * first_rhs + + second_rhs = compute_semidiscrete_rhs( + first_stage, + dx=dx, + bx=bx, + gamma=gamma, + ghost_width=ghost_width, + ) + second_stage = 0.75 * interior_conservative + 0.25 * (first_stage + dt * second_rhs) + + third_rhs = compute_semidiscrete_rhs( + second_stage, + dx=dx, + bx=bx, + gamma=gamma, + ghost_width=ghost_width, + ) + next_state = (1.0 / 3.0) * interior_conservative + (2.0 / 3.0) * ( + second_stage + dt * third_rhs + ) + return next_state + + +def evolve_ssp_rk3_fixed_dt( + conservative_cells: np.ndarray, + t_final: float, + dt: float, + dx: float | None = None, + bx: float = DEFAULT_BX, + gamma: float = DEFAULT_GAMMA, + ghost_width: int = DEFAULT_GHOST_WIDTH, +) -> np.ndarray: + interior_conservative = _require_state_width( + conservative_cells, name="conservative_cells" + ) + if interior_conservative.ndim != 2: + raise ValueError("conservative_cells must be a 2D array with shape (nx, 7)") + if interior_conservative.shape[0] == 0: + raise ValueError("conservative_cells must contain at least one cell") + if t_final < 0.0: + raise ValueError("t_final must be non-negative") + if dt <= 0.0: + raise ValueError("dt must be positive") + + evolved_state = np.array(interior_conservative, dtype=np.float64, copy=True) + elapsed_time = 0.0 + while elapsed_time < t_final: + remaining_time = t_final - elapsed_time + step_dt = min(dt, remaining_time) + evolved_state = ssp_rk3_step( + evolved_state, + step_dt, + dx=dx, + bx=bx, + gamma=gamma, + ghost_width=ghost_width, + ) + elapsed_time = t_final if step_dt < dt else elapsed_time + step_dt + return evolved_state diff --git a/benchmarks/magnetohydrodynamics/shared/eval/mhd1d_shared.py b/benchmarks/magnetohydrodynamics/shared/eval/mhd1d_shared.py new file mode 100644 index 0000000..ad1df11 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/shared/eval/mhd1d_shared.py @@ -0,0 +1,303 @@ +"""Shared hidden-eval helpers for the canonical 1D Brio-Wu benchmark.""" + +from __future__ import annotations + +import csv +import json +from dataclasses import dataclass +from pathlib import Path +from typing import Mapping, Sequence + + +CSV_HEADER = ("x", "rho", "u", "v", "w", "p", "by", "bz") +SCORING_VARIABLES = ("rho", "u", "p", "by") +DEFAULT_EXCLUDE_EDGE_ADJACENTS_PER_SIDE = 2 +DEFAULT_FIXTURE_NAME = "brio_wu_fixture.json" + + +@dataclass(frozen=True) +class MHD1DCSVProfile: + """Parsed CSV profile with schema validation already applied.""" + + csv_path: Path + header: tuple[str, ...] + rows: list[dict[str, float]] + + +@dataclass(frozen=True) +class MHD1DFixture: + """Loaded Brio-Wu fixture metadata plus the reference CSV profile.""" + + fixture_path: Path + reference_csv_path: Path + schema: tuple[str, ...] + scored_variables: tuple[str, ...] + abs_l1: dict[str, float] + abs_linf: dict[str, float] + interior_cell_window_exclude_edge_adjacents_per_side: int + metadata: dict[str, object] + reference_profile: MHD1DCSVProfile + + +@dataclass(frozen=True) +class VariableComparison: + """Per-variable error summary for a solver profile.""" + + variable: str + l1: float + linf: float + abs_l1_tolerance: float + abs_linf_tolerance: float + + @property + def passed(self) -> bool: + return self.l1 <= self.abs_l1_tolerance and self.linf <= self.abs_linf_tolerance + + +@dataclass(frozen=True) +class MHD1DComparison: + """Comparison outcome for a solver CSV against the Brio-Wu fixture.""" + + solver_csv_path: Path + fixture: MHD1DFixture + compared_row_start: int + compared_row_stop: int + compared_row_count: int + variable_comparisons: dict[str, VariableComparison] + + @property + def passed(self) -> bool: + return all(result.passed for result in self.variable_comparisons.values()) + + +def _default_fixture_path() -> Path: + return Path(__file__).resolve().parent / "fixtures" / "mhd1d" / DEFAULT_FIXTURE_NAME + + +def _require_exact_header(header: Sequence[str], *, source: Path) -> None: + actual = tuple(header) + if actual != CSV_HEADER: + raise ValueError( + f"{source} must use the exact CSV header {','.join(CSV_HEADER)}" + ) + + +def _parse_float_cell( + raw_value: str, *, source: Path, row_number: int, column_name: str +) -> float: + try: + return float(raw_value) + except ValueError as exc: + raise ValueError( + f"{source} row {row_number} column {column_name} must be a floating-point value" + ) from exc + + +def load_mhd1d_csv_profile(csv_path: str | Path) -> MHD1DCSVProfile: + """Load and validate a Brio-Wu-style CSV profile.""" + + path = Path(csv_path) + with path.open("r", encoding="utf-8", newline="") as csv_file: + reader = csv.reader(csv_file) + try: + header = next(reader) + except StopIteration as exc: + raise ValueError(f"{path} is empty") from exc + + _require_exact_header(header, source=path) + + rows: list[dict[str, float]] = [] + for row_number, raw_row in enumerate(reader, start=2): + if len(raw_row) != len(CSV_HEADER): + raise ValueError( + f"{path} row {row_number} must have exactly {len(CSV_HEADER)} columns" + ) + parsed_row: dict[str, float] = {} + for column_name, raw_value in zip(CSV_HEADER, raw_row, strict=True): + parsed_row[column_name] = _parse_float_cell( + raw_value, + source=path, + row_number=row_number, + column_name=column_name, + ) + rows.append(parsed_row) + + return MHD1DCSVProfile(csv_path=path, header=tuple(header), rows=rows) + + +def _validate_fixture_metadata( + fixture_payload: Mapping[str, object], *, source: Path +) -> None: + schema = fixture_payload.get("schema") + if tuple(schema or ()) != CSV_HEADER: + raise ValueError( + f"{source} must declare the exact schema {','.join(CSV_HEADER)}" + ) + + scored_variables = fixture_payload.get("scored_variables") + if tuple(scored_variables or ()) != SCORING_VARIABLES: + raise ValueError( + f"{source} must declare scored_variables {','.join(SCORING_VARIABLES)}" + ) + + window = fixture_payload.get("interior_cell_window") + if not isinstance(window, Mapping): + raise ValueError(f"{source} must define interior_cell_window metadata") + + exclude = window.get("exclude_edge_adjacents_per_side") + if exclude != DEFAULT_EXCLUDE_EDGE_ADJACENTS_PER_SIDE: + raise ValueError( + f"{source} must exclude {DEFAULT_EXCLUDE_EDGE_ADJACENTS_PER_SIDE} edge-adjacent cells per side" + ) + + for key_name in ("abs_l1", "abs_linf"): + tolerances = fixture_payload.get(key_name) + if not isinstance(tolerances, Mapping): + raise ValueError(f"{source} must define {key_name} tolerances") + for variable_name in SCORING_VARIABLES: + if variable_name not in tolerances: + raise ValueError(f"{source} must define {key_name}.{variable_name}") + + +def load_mhd1d_fixture(fixture_path: str | Path | None = None) -> MHD1DFixture: + """Load the canonical Brio-Wu hidden fixture and its reference CSV profile.""" + + path = Path(fixture_path) if fixture_path is not None else _default_fixture_path() + with path.open("r", encoding="utf-8") as fixture_file: + payload = json.load(fixture_file) + + if not isinstance(payload, dict): + raise ValueError(f"{path} must contain a JSON object") + + _validate_fixture_metadata(payload, source=path) + + reference_csv_name = payload.get("reference_csv") + if not isinstance(reference_csv_name, str) or not reference_csv_name: + raise ValueError(f"{path} must declare a reference_csv file name") + + reference_csv_path = (path.parent / reference_csv_name).resolve() + reference_profile = load_mhd1d_csv_profile(reference_csv_path) + + return MHD1DFixture( + fixture_path=path, + reference_csv_path=reference_csv_path, + schema=tuple(payload["schema"]), + scored_variables=tuple(payload["scored_variables"]), + abs_l1={ + variable: float(value) for variable, value in payload["abs_l1"].items() + }, + abs_linf={ + variable: float(value) for variable, value in payload["abs_linf"].items() + }, + interior_cell_window_exclude_edge_adjacents_per_side=int( + payload["interior_cell_window"]["exclude_edge_adjacents_per_side"] + ), + metadata=payload, + reference_profile=reference_profile, + ) + + +def interior_cell_window_bounds( + row_count: int, + exclude_edge_adjacents_per_side: int = DEFAULT_EXCLUDE_EDGE_ADJACENTS_PER_SIDE, +) -> tuple[int, int]: + """Return the inclusive-start/exclusive-stop comparison window for a profile.""" + + if row_count <= 0: + raise ValueError("row_count must be positive") + if exclude_edge_adjacents_per_side < 0: + raise ValueError("exclude_edge_adjacents_per_side must be non-negative") + if row_count <= 2 * exclude_edge_adjacents_per_side: + raise ValueError("row_count is too small for the requested interior window") + return exclude_edge_adjacents_per_side, row_count - exclude_edge_adjacents_per_side + + +def _compare_variable( + solver_rows: Sequence[Mapping[str, float]], + reference_rows: Sequence[Mapping[str, float]], + variable_name: str, + row_start: int, + row_stop: int, + *, + abs_l1_tolerance: float, + abs_linf_tolerance: float, +) -> VariableComparison: + l1_error = 0.0 + linf_error = 0.0 + for row_index in range(row_start, row_stop): + delta = abs( + float(solver_rows[row_index][variable_name]) + - float(reference_rows[row_index][variable_name]) + ) + l1_error += delta + if delta > linf_error: + linf_error = delta + + return VariableComparison( + variable=variable_name, + l1=l1_error, + linf=linf_error, + abs_l1_tolerance=abs_l1_tolerance, + abs_linf_tolerance=abs_linf_tolerance, + ) + + +def compare_mhd1d_csv_against_fixture( + solver_csv_path: str | Path, + fixture: MHD1DFixture | None = None, +) -> MHD1DComparison: + """Compare a solver-produced CSV profile against the canonical Brio-Wu fixture.""" + + loaded_fixture = fixture if fixture is not None else load_mhd1d_fixture() + solver_profile = load_mhd1d_csv_profile(solver_csv_path) + + if solver_profile.header != loaded_fixture.schema: + raise ValueError("solver CSV header does not match the fixture schema") + + reference_rows = loaded_fixture.reference_profile.rows + solver_rows = solver_profile.rows + if len(solver_rows) != len(reference_rows): + raise ValueError( + "solver CSV row count does not match the fixture reference profile" + ) + + row_start, row_stop = interior_cell_window_bounds( + len(reference_rows), + loaded_fixture.interior_cell_window_exclude_edge_adjacents_per_side, + ) + + variable_comparisons: dict[str, VariableComparison] = {} + for variable_name in loaded_fixture.scored_variables: + variable_comparisons[variable_name] = _compare_variable( + solver_rows, + reference_rows, + variable_name, + row_start, + row_stop, + abs_l1_tolerance=loaded_fixture.abs_l1[variable_name], + abs_linf_tolerance=loaded_fixture.abs_linf[variable_name], + ) + + return MHD1DComparison( + solver_csv_path=solver_profile.csv_path, + fixture=loaded_fixture, + compared_row_start=row_start, + compared_row_stop=row_stop, + compared_row_count=row_stop - row_start, + variable_comparisons=variable_comparisons, + ) + + +__all__ = [ + "CSV_HEADER", + "SCORING_VARIABLES", + "DEFAULT_EXCLUDE_EDGE_ADJACENTS_PER_SIDE", + "MHD1DCSVProfile", + "MHD1DFixture", + "VariableComparison", + "MHD1DComparison", + "compare_mhd1d_csv_against_fixture", + "interior_cell_window_bounds", + "load_mhd1d_csv_profile", + "load_mhd1d_fixture", +] From 777ac3031a26948e5d1271b1ada72450225fb9e0 Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Sun, 29 Mar 2026 00:15:41 +0900 Subject: [PATCH 08/39] Add golden Brio-Wu CLI regression test --- .../workspace/scripts/plot_solution.py | 23 +- .../workspace/tests/data/brio_wu_golden.csv | 401 ++++++++++++++++++ .../workspace/tests/test_public.py | 15 +- 3 files changed, 434 insertions(+), 5 deletions(-) create mode 100644 benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/data/brio_wu_golden.csv diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/scripts/plot_solution.py b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/scripts/plot_solution.py index 7cf2ca4..7ae04fc 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/scripts/plot_solution.py +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/scripts/plot_solution.py @@ -1,11 +1,11 @@ #!/usr/bin/env python3 -"""Plot a Brio-Wu solver CSV for quick inspection. +"""Plot a Brio-Wu solver CSV and save an image. Usage: - python scripts/plot_solution.py [path/to/solution.csv] + python scripts/plot_solution.py [path/to/solution.csv] [path/to/output.png] If no path is provided, the script looks for ``solution.csv`` in the current -working directory. +working directory and writes ``solution.png`` there. """ from __future__ import annotations @@ -15,11 +15,15 @@ from pathlib import Path import sys +import matplotlib + +matplotlib.use("Agg") import matplotlib.pyplot as plt EXPECTED_FIELDS = ["x", "rho", "u", "v", "w", "p", "by", "bz"] DEFAULT_CSV = Path("solution.csv") +DEFAULT_OUTPUT = Path("solution.png") def parse_args() -> argparse.Namespace: @@ -33,6 +37,13 @@ def parse_args() -> argparse.Namespace: default=DEFAULT_CSV, help="CSV file to plot (defaults to solution.csv in the current directory).", ) + parser.add_argument( + "output_path", + nargs="?", + type=Path, + default=DEFAULT_OUTPUT, + help="Output image path (defaults to solution.png in the current directory).", + ) return parser.parse_args() @@ -55,6 +66,7 @@ def load_columns(csv_path: Path) -> dict[str, list[float]]: def main() -> int: args = parse_args() csv_path = args.csv_path + output_path = args.output_path if not csv_path.is_file(): print(f"error: CSV file not found: {csv_path}", file=sys.stderr) @@ -87,7 +99,10 @@ def main() -> int: fig.suptitle(f"Brio-Wu profiles: {csv_path}") fig.tight_layout() - plt.show() + output_path.parent.mkdir(parents=True, exist_ok=True) + fig.savefig(output_path, dpi=150) + plt.close(fig) + print(output_path) return 0 diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/data/brio_wu_golden.csv b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/data/brio_wu_golden.csv new file mode 100644 index 0000000..3b96ca0 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/data/brio_wu_golden.csv @@ -0,0 +1,401 @@ +x,rho,u,v,w,p,by,bz +0.00125,1,0,0,0,1,1,0 +0.0037499999999999999,1,0,0,0,1,1,0 +0.0062500000000000003,1,0,0,0,1,1,0 +0.0087500000000000008,1,0,0,0,1,1,0 +0.01125,1,0,0,0,1,1,0 +0.01375,1,0,0,0,1,1,0 +0.016250000000000001,1,0,0,0,1,1,0 +0.018749999999999999,1,0,0,0,1,1,0 +0.021250000000000002,1,0,0,0,1,1,0 +0.02375,1,0,0,0,1,1,0 +0.026249999999999999,1,0,0,0,1,1,0 +0.028750000000000001,1,0,0,0,1,1,0 +0.03125,1,0,0,0,1,1,0 +0.033750000000000002,1,0,0,0,1,1,0 +0.036249999999999998,1,0,0,0,1,1,0 +0.03875,1,0,0,0,1,1,0 +0.041250000000000002,1,0,0,0,1,1,0 +0.043750000000000004,1,0,0,0,1,1,0 +0.046249999999999999,1,0,0,0,1,1,0 +0.048750000000000002,1,0,0,0,1,1,0 +0.051250000000000004,1,0,0,0,1,1,0 +0.053749999999999999,1,0,0,0,1,1,0 +0.056250000000000001,1,0,0,0,1,1,0 +0.058750000000000004,1,0,0,0,1,1,0 +0.061249999999999999,1,0,0,0,1,1,0 +0.063750000000000001,1,0,0,0,1,1,0 +0.066250000000000003,1,0,0,0,1,1,0 +0.068750000000000006,1,0,0,0,1,1,0 +0.071250000000000008,1,0,0,0,1,1,0 +0.073749999999999996,1,0,0,0,1,1,0 +0.076249999999999998,1,0,0,0,1,1,0 +0.078750000000000001,1,0,0,0,1,1,0 +0.081250000000000003,1,0,0,0,1,1,0 +0.083750000000000005,1,0,0,0,1,1,0 +0.086250000000000007,1,0,0,0,1,1,0 +0.088749999999999996,1,0,0,0,1,1,0 +0.091249999999999998,1,0,0,0,1,1,0 +0.09375,1,0,0,0,1,1,0 +0.096250000000000002,1,0,0,0,1,1,0 +0.098750000000000004,1,0,0,0,1,1,0 +0.10125000000000001,1,0,0,0,1,1,0 +0.10375000000000001,1,0,0,0,1,1,0 +0.10625,1,0,0,0,1,1,0 +0.10875,1,0,0,0,1,1,0 +0.11125,1,0,0,0,1,1,0 +0.11375,1,0,0,0,1,1,0 +0.11625000000000001,1,0,0,0,1,1,0 +0.11875000000000001,1,0,0,0,1,1,0 +0.12125,1,0,0,0,1,1,0 +0.12375,1,0,0,0,1,1,0 +0.12625,1,0,0,0,1,1,0 +0.12875,1,0,0,0,1,1,0 +0.13125000000000001,1,0,0,0,1,1,0 +0.13375000000000001,1,0,0,0,1,1,0 +0.13625000000000001,1,0,0,0,1,1,0 +0.13875000000000001,1,0,0,0,1,1,0 +0.14125000000000001,1,0,0,0,1,1,0 +0.14375000000000002,1,0,0,0,1,1,0 +0.14624999999999999,1,0,0,0,1,1,0 +0.14874999999999999,1,0,0,0,1,1,0 +0.15125,1,0,0,0,1,1,0 +0.15375,1,0,0,0,1,1,0 +0.15625,1,0,0,0,1,1,0 +0.15875,1,0,0,0,1,1,0 +0.16125,1,0,0,0,1,1,0 +0.16375000000000001,1,0,0,0,1,1,0 +0.16625000000000001,1,0,0,0,1,1,0 +0.16875000000000001,1,0,0,0,1,1,0 +0.17125000000000001,1,0,0,0,1,1,0 +0.17375000000000002,1,0,0,0,1,1,0 +0.17624999999999999,1,0,0,0,1,1,0 +0.17874999999999999,1,0,0,0,1,1,0 +0.18124999999999999,1,0,0,0,1,1,0 +0.18375,1,0,0,0,1,1,0 +0.18625,1,0,0,0,1,1,0 +0.18875,1,0,0,0,1,1,0 +0.19125,1,0,0,0,1,1,0 +0.19375000000000001,1,0,0,0,1,1,0 +0.19625000000000001,1,0,0,0,1,1,0 +0.19875000000000001,1,0,0,0,1,1,0 +0.20125000000000001,1,0,0,0,1,1,0 +0.20375000000000001,1,0,0,0,1,1,0 +0.20625000000000002,1,0,0,0,1,1,0 +0.20874999999999999,1,0,0,0,1,1,0 +0.21124999999999999,1,0,0,0,1,1,0 +0.21375,1,0,0,0,1,1,0 +0.21625,1,0,0,0,1,1,0 +0.21875,1,0,0,0,1,1,0 +0.22125,1,0,0,0,1,1,0 +0.22375,1,0,0,0,1,1,0 +0.22625000000000001,1,0,0,0,1,1,0 +0.22875000000000001,1,0,0,0,1,1,0 +0.23125000000000001,1,0,0,0,1,1,0 +0.23375000000000001,1,0,0,0,1,1,0 +0.23625000000000002,1,0,0,0,1,1,0 +0.23875000000000002,1,0,0,0,1,1,0 +0.24124999999999999,1,0,0,0,1,1,0 +0.24374999999999999,1,0,0,0,1,1,0 +0.24625,1,0,0,0,1,1,0 +0.24875,1,0,0,0,1,1,0 +0.25125000000000003,1,0,0,0,1,1,0 +0.25375000000000003,1,0,0,0,1,1,0 +0.25624999999999998,1,0,0,0,1,1,0 +0.25874999999999998,1,0,0,0,1,1,0 +0.26124999999999998,1,0,0,0,1,1,0 +0.26374999999999998,1,0,0,0,1,1,0 +0.26624999999999999,1,0,0,0,1,1,0 +0.26874999999999999,1,0,0,0,1,1,0 +0.27124999999999999,1,0,0,0,1,1,0 +0.27374999999999999,1,0,0,0,1,1,0 +0.27625,1,0,0,0,1,1,0 +0.27875,1,0,0,0,1,1,0 +0.28125,1,0,0,0,1,1,0 +0.28375,1,0,0,0,1,1,0 +0.28625,1,0,0,0,1,1,0 +0.28875000000000001,1,0,0,0,1,1,0 +0.29125000000000001,1,0,0,0,1,1,0 +0.29375000000000001,1,0,0,0,1,1,0 +0.29625000000000001,1,0,0,0,1,1,0 +0.29875000000000002,1,0,0,0,1,1,0 +0.30125000000000002,1,0,0,0,1,1,0 +0.30375000000000002,1,0,0,0,1,1,0 +0.30625000000000002,1,0,0,0,1,1,0 +0.30875000000000002,1,0,0,0,1,1,0 +0.31125000000000003,1,0,0,0,1,1,0 +0.31375000000000003,1,0,0,0,1,1,0 +0.31625000000000003,1,0,0,0,1,1,0 +0.31875000000000003,0.99780058962396134,0.0039418906960591756,-0.0011154453241734904,0,0.99561225261243114,0.99733567707147397,0 +0.32124999999999998,0.99173977278087055,0.014827394992909993,-0.0042179802180685351,0,0.98356266355471567,0.98997992685476155,0 +0.32374999999999998,0.98408158190126227,0.028640080174583915,-0.008186565338896416,0,0.96843552308248149,0.98067103174066461,0 +0.32624999999999998,0.97581885102428656,0.043602341839540863,-0.012527557906330034,0,0.95224184930138511,0.9706093820226751,0 +0.32874999999999999,0.9673086534619818,0.059076763367010128,-0.017064614864518685,0,0.93570643492573047,0.96022723966347923,0 +0.33124999999999999,0.95869600144853218,0.074807206835931742,-0.021727022813603607,0,0.91911880282946645,0.94969857357607346,0 +0.33374999999999999,0.95004304399744044,0.090682637384932041,-0.026484836248230038,0,0.90260259674571253,0.93909829176568671,0 +0.33624999999999999,0.9413754410079106,0.10665810127729088,-0.031327232997254678,0,0.88620791115317998,0.92845621902021158,0 +0.33875,0.93270899587811373,0.12270504519506864,-0.03624752773178725,0,0.86996537982749733,0.91779125844150933,0 +0.34125,0.92405269875686513,0.13880647959038991,-0.041242256453888439,0,0.85389282701112912,0.90711462369760387,0 +0.34375,0.9154136825409287,0.15495119344114,-0.046309690150731095,0,0.83800169918738354,0.89643357043624938,0 +0.34625,0.90679699082194087,0.1711306591640914,-0.051448892458540188,0,0.82230012152488841,0.88575334869586952,0 +0.34875,0.89820651629824644,0.18733853105308285,-0.056659474531035876,0,0.80679335763251014,0.87507771377132626,0 +0.35125000000000001,0.88964446790953033,0.20356990667607194,-0.061941601414340595,0,0.79148497989669941,0.86440935577409717,0 +0.35375000000000001,0.88111284307810034,0.21982084917897435,-0.067295796388280038,0,0.77637743892286348,0.85375027049037311,0 +0.35625000000000001,0.87261362352600136,0.23608821896065768,-0.072722798578283135,0,0.76147221221794026,0.84310187986499097,0 +0.35875000000000001,0.86414845253144101,0.25236949156988764,-0.078223462833881888,0,0.74677004107769829,0.83246518929651392,0 +0.36125000000000002,0.85571868777839477,0.26866265040738607,-0.083798844143742335,0,0.73227118643443889,0.82184083376251138,0 +0.36375000000000002,0.84732496311510741,0.28496610344607487,-0.089450235711247772,0,0.71797553105924117,0.81122913890977844,0 +0.36625000000000002,0.83896778349293599,0.30127856646716628,-0.095179100441626849,0,0.70388256773647151,0.80063021301524762,0 +0.36875000000000002,0.8306478120801315,0.31759896051856901,-0.10098705469020462,0,0.68999145285900165,0.79004396131671717,0 +0.37125000000000002,0.82236584881264441,0.33392634501819063,-0.10687586239677592,0,0.67630114289001086,0.77947010645164028,0 +0.37375000000000003,0.81412256288554841,0.35025987066405678,-0.11284737308244323,0,0.66281051894930754,0.76890827004788531,0 +0.37625000000000003,0.80591829672758197,0.36659869209219098,-0.11890344385945414,0,0.64951847025460407,0.75835806846801013,0 +0.37875000000000003,0.7977533251558977,0.38294181436792768,-0.1250459153773277,0,0.63642397465987577,0.74781916579237695,0 +0.38125000000000003,0.78962821661912974,0.39928793115627925,-0.13127661071624822,0,0.62352617265709931,0.73729131884178889,0 +0.38375000000000004,0.78154397302664014,0.4156353252154189,-0.137597311365595,0,0.61082441920290476,0.72677444954932158,0 +0.38624999999999998,0.77350187664333747,0.4319818381617635,-0.14400971569167417,0,0.59831831823337123,0.71626872248566942,0 +0.38874999999999998,0.76550325157545829,0.44832485729258581,-0.15051541230315177,0,0.58600775859846921,0.70577458163502815,0 +0.39124999999999999,0.75754943880637893,0.46466125358111438,-0.15711584492844621,0,0.57389295780390692,0.69529276621051095,0 +0.39374999999999999,0.749642062019785,0.48098718289031467,-0.16381220586479228,0,0.56197455525241757,0.68482439731157485,0 +0.39624999999999999,0.74178347298350644,0.49729755518791763,-0.17060518383658033,0,0.55025391036855997,0.67437128401935453,0 +0.39874999999999999,0.73397737021860543,0.51358474386151054,-0.17749439433254424,0,0.53873391674659166,0.66393672613728749,0 +0.40125,0.72622997539659639,0.52983568010877113,-0.18447707310794387,0,0.52742087697476669,0.65352736887877549,0 +0.40375,0.71855268032257813,0.54602571955173596,-0.19154520667480535,0,0.51632840511574407,0.64315715022632924,0 +0.40625,0.71096761592194024,0.5621064499054218,-0.19867965431348364,0,0.50548500567258359,0.6328551452014316,0 +0.40875,0.70351809004436872,0.57798308169709955,-0.20583896158449672,0,0.49494776946723229,0.62268010464122547,0 +0.41125,0.69628594147097289,0.59347633160710345,-0.21293993103100095,0,0.48482478256859951,0.61274502061463976,0 +0.41375000000000001,0.68941655050596484,0.60826664970343558,-0.2198280489776889,0,0.47530692274767161,0.60325335873851049,0 +0.41625000000000001,0.68314702755279999,0.62182858255524953,-0.22624129413552949,0,0.46670271369465616,0.59454169635904308,0 +0.41875000000000001,0.67782572058125357,0.63339457769432261,-0.23178305630796459,0,0.45946103196399823,0.58710648915432451,0 +0.42125000000000001,0.67385858441141333,0.64199490957099814,-0.23596698492475343,0,0.45409808373542004,0.58156684274258463,0 +0.42375000000000002,0.67176641453700525,0.6469162308341575,-0.238218557413787,0,0.45128138130309292,0.57843540789261583,0 +0.42625000000000002,0.67078052736841931,0.64804295449248306,-0.23931535115787175,0,0.44995578425706018,0.5776695501854906,0 +0.42875000000000002,0.67093258028176295,0.64820950444476044,-0.23909517669577307,0,0.45016128034403946,0.57748103832724251,0 +0.43125000000000002,0.67221331698599318,0.64592193639342732,-0.2376161466610561,0,0.45188502884855786,0.57898748077442441,0 +0.43375000000000002,0.67477583336680169,0.64045344684033523,-0.2349806577986025,0,0.45533846144962792,0.58257702054306215,0 +0.43625000000000003,0.67693879989409655,0.63537735860005662,-0.23276478266323203,0,0.45826311431502864,0.58589598309566848,0 +0.43875000000000003,0.67818046569816726,0.63258441699362578,-0.2316835745358842,0,0.4599465488616844,0.58788185575907725,0 +0.44125000000000003,0.67847095916753464,0.63140939827029008,-0.23102942178508992,0,0.46034108071841129,0.58814312979425298,0 +0.44375000000000003,0.67871878159900201,0.63146024939639389,-0.23068318935251569,0,0.46067790212396337,0.58810935677202825,0 +0.44625000000000004,0.67853915803526677,0.63196041084427279,-0.23090732826723964,0,0.46043473249792088,0.58787073205089513,0 +0.44874999999999998,0.67803863707314427,0.6330593415786836,-0.23162869925234153,0,0.45975750456026709,0.58736622158591256,0 +0.45124999999999998,0.6774195873474379,0.6343255739755016,-0.23239706197011983,0,0.45891948202187494,0.58672848893472662,0 +0.45374999999999999,0.67688810168571512,0.63542738781445673,-0.23285843166501846,0,0.45820017218025605,0.58601807885490564,0 +0.45624999999999999,0.67650547951151974,0.63625820689185419,-0.23305952359533008,0,0.45768328142375492,0.58533372699356645,0 +0.45874999999999999,0.67624477252807902,0.63679255704404425,-0.23324253509623569,0,0.45733207413345345,0.58480268867196805,0 +0.46124999999999999,0.67604050594546095,0.63714228317088684,-0.23351779035696307,0,0.45705721760805229,0.58451139535639995,0 +0.46375,0.67595854916299569,0.63738534647931233,-0.23385855445925771,0,0.45694869192262283,0.58435845445911683,0 +0.46625,0.68086254532175094,0.63419323611509804,-0.2627490595791831,0,0.46500839952917328,0.56267418748132525,0 +0.46875,0.75828705387253315,0.56658450267562666,-0.6403332654473326,0,0.60777176667783583,0.26462111543054406,0 +0.47125,0.81542143854087634,0.46255247850130804,-1.1427907505563049,0,0.70707779939421744,-0.17802741409121203,0 +0.47375,0.78443205530850979,0.50559776659531341,-1.332519156086944,0,0.65515890375877317,-0.354497000575831,0 +0.47625000000000001,0.76277455722849596,0.55111223050629143,-1.406110791322537,0,0.61702037783610542,-0.4194427333795091,0 +0.47875000000000001,0.74404469538178764,0.55656484646456639,-1.4611410690372477,0,0.58668848068932689,-0.45267168642034472,0 +0.48125000000000001,0.7245298456798609,0.56167647024027656,-1.5074627288434979,0,0.5571761881846935,-0.47268348346610961,0 +0.48375000000000001,0.71012228623973583,0.57027999536562946,-1.543873073536012,0,0.53528590863347425,-0.49264654415374082,0 +0.48625000000000002,0.70076710390286745,0.58241431931480048,-1.5678960177704355,0,0.52117059910324071,-0.5132537526592037,0 +0.48875000000000002,0.6958138120994154,0.59253804821509259,-1.5801243124025581,0,0.51407181012863212,-0.53018918731486608,0 +0.49125000000000002,0.69634185265480064,0.60450975725843215,-1.5824609035105774,0,0.51510350342232991,-0.54159264057279222,0 +0.49375000000000002,0.69850922424214601,0.60950400813475858,-1.585266082294966,0,0.51853234952912874,-0.54291597426192384,0 +0.49625000000000002,0.69955231023329034,0.60819583311918735,-1.5848885559239814,0,0.52027069329509679,-0.54068543052621187,0 +0.49875000000000003,0.69829488634001602,0.60250392950529474,-1.5842381917356738,0,0.51860605011188388,-0.53585805694441235,0 +0.50124999999999997,0.69473126010799702,0.59400974956106756,-1.5847165912172572,0,0.51356317210852487,-0.53134363710848087,0 +0.50375000000000003,0.69253382725834534,0.59010833084815906,-1.5851121479337069,0,0.51057824154374631,-0.53011921878496304,0 +0.50624999999999998,0.69237449532735207,0.59146895693409685,-1.5858564348296551,0,0.51054249757041459,-0.53082328680938162,0 +0.50875000000000004,0.69391541373744337,0.59634222339010579,-1.5857210122073861,0,0.51315096871714994,-0.53304618751484978,0 +0.51124999999999998,0.69634148593928047,0.60301378588754684,-1.5840840117480401,0,0.5171828111968485,-0.53600443230198036,0 +0.51375000000000004,0.69696988284642125,0.60598814490820407,-1.5822803421052867,0,0.51876741128969461,-0.53768126044759668,0 +0.51624999999999999,0.69590524459691183,0.605542191027717,-1.5815913052223451,0,0.51808417485694558,-0.53738593862540907,0 +0.51875000000000004,0.69339823569240289,0.60237234278329166,-1.5824338658055286,0,0.51564230319494531,-0.53568598390826916,0 +0.52124999999999999,0.69028268100633383,0.59775928333034656,-1.5849765752973617,0,0.51233921959100215,-0.53282107449038196,0 +0.52375000000000005,0.6885408627829227,0.59563473330607197,-1.586881633696186,0,0.51091135095358142,-0.53126090526540737,0 +0.52625,0.68845991210476676,0.59576153638350393,-1.5870959718421693,0,0.51139517765564346,-0.53172734059034754,0 +0.52875000000000005,0.68913132894514517,0.59780515337360185,-1.5859257457768372,0,0.51333149786491905,-0.53324119440484385,0 +0.53125,0.69035686600602486,0.60114183287377887,-1.583761079933232,0,0.51632762277454369,-0.53561028146436995,0 +0.53375000000000006,0.69063785151444135,0.60308915950915953,-1.5825950002547069,0,0.51816477333483568,-0.5367661728665245,0 +0.53625,0.68995642603783169,0.60271623463782054,-1.5827072676591285,0,0.51817213887569635,-0.5365529040050816,0 +0.53875000000000006,0.68912674904173354,0.60080970261747135,-1.5836585612290803,0,0.5170008482178291,-0.53535672389780986,0 +0.54125000000000001,0.68900935996710411,0.59744632555053778,-1.5849988566238742,0,0.51492442266233129,-0.53339274974699291,0 +0.54375000000000007,0.68992607319859989,0.59550495144079929,-1.5855642783840616,0,0.51380892115497334,-0.53231014634052964,0 +0.54625000000000001,0.69030209756719352,0.59574669701945138,-1.5855252584440067,0,0.51389062331612756,-0.53244809173629659,0 +0.54874999999999996,0.68902173862300931,0.59740836235396289,-1.5852477103136609,0,0.5146658368665229,-0.53339030207149196,0 +0.55125000000000002,0.68189342316100054,0.60020433676255158,-1.5844249654880713,0,0.51628053637696625,-0.53477165363768919,0 +0.55374999999999996,0.65276597713910334,0.60185672139983104,-1.5836528865010249,0,0.51743177517895211,-0.53527542396206562,0 +0.55625000000000002,0.58906478526618755,0.60185519401175147,-1.583053851614638,0,0.51755849582377766,-0.53486837400458076,0 +0.55874999999999997,0.49422558600892486,0.60118766199411133,-1.5832559126839811,0,0.5172228327206092,-0.53418658367731886,0 +0.56125000000000003,0.38247103041338487,0.59990157132174105,-1.5840925292397106,0,0.51620910738423487,-0.53342595162876671,0 +0.56374999999999997,0.28025492247104017,0.59846176638276449,-1.5851622199216584,0,0.5152364728981691,-0.53275468018860095,0 +0.56625000000000003,0.22868966508824234,0.59710231685960313,-1.5860977814707127,0,0.51481122129747781,-0.53239158687234311,0 +0.56874999999999998,0.2267856507919232,0.59640620540582956,-1.5864596507885937,0,0.51481550996877012,-0.53225943769555295,0 +0.57125000000000004,0.22713175101669475,0.59631043781086113,-1.5862941490337203,0,0.51512192557837366,-0.53221446943385053,0 +0.57374999999999998,0.22832982826697543,0.59690929717637031,-1.5856945341940099,0,0.51544195200245158,-0.53214053153219976,0 +0.57625000000000004,0.23006132532598028,0.5979765390095868,-1.5850598466399157,0,0.51604401482077034,-0.53235234485917893,0 +0.57874999999999999,0.23181956629299122,0.59934757674111083,-1.5845139129375743,0,0.51687736532492834,-0.53308886162542746,0 +0.58125000000000004,0.23316522477988719,0.60072662152561196,-1.5842849795297345,0,0.51772674090669124,-0.53394457396042982,0 +0.58374999999999999,0.23391908756041113,0.60223034496795813,-1.5839684765344821,0,0.51806461631752188,-0.53457035523447027,0 +0.58625000000000005,0.23431034941216394,0.60345350170797118,-1.5841973780115437,0,0.51789119722034871,-0.53460934483436429,0 +0.58875,0.23460990828752651,0.60387631345954085,-1.5843501276762757,0,0.51757915110632757,-0.53432910759567398,0 +0.59125000000000005,0.23506825902401635,0.60282288127804684,-1.585165115162972,0,0.51773081006565902,-0.53416645772176508,0 +0.59375,0.23554392868159077,0.60057139334604759,-1.5863553588391026,0,0.51774108981529299,-0.53376740267714529,0 +0.59625000000000006,0.23574376308649053,0.59888206501796171,-1.587249000037269,0,0.51718780070000137,-0.53273061481737882,0 +0.59875,0.2357083556292047,0.59836333208440606,-1.5873845267462028,0,0.51612520155316433,-0.53158021311167569,0 +0.60125000000000006,0.23567285891449777,0.59766263969440114,-1.5877771701611647,0,0.5153079104412206,-0.53069139651429365,0 +0.60375000000000001,0.23580149297303599,0.59664353703500261,-1.5883416830586965,0,0.51563852961964063,-0.53095430707000513,0 +0.60625000000000007,0.2361263695423006,0.59461828975577724,-1.5895049849613039,0,0.51671691867389946,-0.53190837659017298,0 +0.60875000000000001,0.23631854959443394,0.59598090215208221,-1.5892842142291126,0,0.51722476899470071,-0.53244556280972177,0 +0.61124999999999996,0.23614815457146857,0.60018906680370221,-1.5879979771038979,0,0.51632413595151727,-0.53176277681989537,0 +0.61375000000000002,0.23613289789183126,0.60417970975516422,-1.5866151046667705,0,0.51643954420713611,-0.53176024605848848,0 +0.61624999999999996,0.23636461460022473,0.60239051184144632,-1.5874214851519997,0,0.51800335570916167,-0.53290555450294708,0 +0.61875000000000002,0.23685612557714375,0.59917605052507494,-1.5887974386781778,0,0.5210289610697918,-0.53516232288950649,0 +0.62124999999999997,0.236629474827142,0.59900329149184894,-1.5883523685763601,0,0.52084906032944422,-0.53504397890458888,0 +0.62375000000000003,0.23553444051781158,0.6094416366857287,-1.5832404611606701,0,0.51646465152499421,-0.53125243577613324,0 +0.62624999999999997,0.23480711426766496,0.61276659011654855,-1.5820244559454961,0,0.51359689942899112,-0.52940636364944882,0 +0.62875000000000003,0.2356805197653731,0.59981103240692546,-1.5873723560682378,0,0.51775543844125527,-0.53341880855164581,0 +0.63124999999999998,0.23665817647544471,0.58339388331467124,-1.5915886744702512,0,0.52230143300038878,-0.53706058378831778,0 +0.63375000000000004,0.23624007285922682,0.58851017476723522,-1.59323247289284,0,0.52067660348375233,-0.5344840295515112,0 +0.63624999999999998,0.23248269439745392,0.62017067097041967,-1.5860539280724555,0,0.50441116285539445,-0.52566087023161623,0 +0.63875000000000004,0.23287406771008778,0.63021607264750734,-1.5714111287249182,0,0.50610033932647758,-0.51881227330971402,0 +0.64124999999999999,0.23535665099942626,0.54552436166512541,-1.5610957972782948,0,0.51620744848479627,-0.56037653795121478,0 +0.64375000000000004,0.20465921194562456,0.43550920292588785,-1.2461151516740705,0,0.38959320083362653,-0.65081895672509904,0 +0.64624999999999999,0.14009395039150022,-0.013620789581837623,-0.52852147362552981,0,0.14893940676494133,-0.84115443834590753,0 +0.64875000000000005,0.11751273289208522,-0.22437213354109883,-0.16226723635220483,0,0.088423364818236205,-0.90651157396572613,0 +0.65125,0.1172304349686725,-0.23055950413906093,-0.15834995998342491,0,0.087980641698620188,-0.90679519491120031,0 +0.65375000000000005,0.11725471096145602,-0.23125048663034239,-0.15988967480131078,0,0.088016824468717392,-0.90623225381858352,0 +0.65625,0.11717819471904142,-0.23427702280565715,-0.16309682007195445,0,0.087901314598951896,-0.90467584906756415,0 +0.65875000000000006,0.11701473008444113,-0.23931297733336335,-0.16679190788787737,0,0.087655777579992433,-0.90262825016899195,0 +0.66125,0.11682044790275041,-0.24514922075151147,-0.17096232324746935,0,0.087364026139568063,-0.90028034756782194,0 +0.66375000000000006,0.11664990465573849,-0.25033190821458962,-0.17474981564425235,0,0.087108330784376853,-0.89817521994953109,0 +0.66625000000000001,0.11659183681487016,-0.25210877535067339,-0.17606373800900416,0,0.087021072376205377,-0.89744964551230921,0 +0.66875000000000007,0.11659565313804586,-0.25199397498810977,-0.17597732617696363,0,0.087026305831300999,-0.89749741619551415,0 +0.67125000000000001,0.11663090160109492,-0.25091377282773697,-0.17517704012828506,0,0.087078794787367686,-0.89793883874353608,0 +0.67374999999999996,0.11672569071628684,-0.24801894198896796,-0.17304243161135532,0,0.087219942612219992,-0.89911964160362412,0 +0.67625000000000002,0.11687866962961335,-0.24335351965734039,-0.16961064512063617,0,0.087448451090979984,-0.90102219304187958,0 +0.67874999999999996,0.11706716457467407,-0.23761206836584889,-0.16539777355745228,0,0.087729984963327179,-0.903363295110168,0 +0.68125000000000002,0.11725531088500578,-0.23188499457250628,-0.16120570301525269,0,0.088011625486577039,-0.90569773785665264,0 +0.68374999999999997,0.1173869096123874,-0.22787830963670686,-0.15827892017451603,0,0.088208749864432612,-0.90733063517330292,0 +0.68625000000000003,0.11740612473963735,-0.22729629509711108,-0.15785255924099278,0,0.08823710550802899,-0.90756836804359509,0 +0.68874999999999997,0.1174043024511611,-0.22735052337058989,-0.15789017932834926,0,0.08823427512892934,-0.90754730073044609,0 +0.69125000000000003,0.117385586946818,-0.22792019819914602,-0.15830312721357306,0,0.088205717689737617,-0.90731579951421071,0 +0.69374999999999998,0.11733333794868246,-0.22950618589385671,-0.15945854815582666,0,0.088127191628521229,-0.90667017955692664,0 +0.69625000000000004,0.11723047219013001,-0.23263692843712594,-0.1617427414330794,0,0.087972319470910665,-0.90539536389292952,0 +0.69874999999999998,0.11707119965622731,-0.23748283866703485,-0.16528542583275169,0,0.087733351641583468,-0.90342149850150899,0 +0.70125000000000004,0.11687031669818926,-0.24360287346583834,-0.16977049665712179,0,0.087431835729061547,-0.90092842407432894,0 +0.70374999999999999,0.11665961352933606,-0.25002473062346064,-0.17448953235454481,0,0.087116281751007274,-0.89831176039494187,0 +0.70625000000000004,0.1165165302499433,-0.25439233792360777,-0.17770571675062352,0,0.086901806565141237,-0.89653255429149881,0 +0.70874999999999999,0.11650342706556212,-0.2547927709381313,-0.17799943043788108,0,0.086882001709442935,-0.89636978909070852,0 +0.71125000000000005,0.11651313327825538,-0.25449583971560935,-0.17777892983377314,0,0.086896257833543045,-0.8964912611982403,0 +0.71375,0.11657824875283614,-0.25250868159070106,-0.17631251476880538,0,0.086993320783096961,-0.8973018533821181,0 +0.71625000000000005,0.11670669297667058,-0.24859138314712292,-0.17342577474077817,0,0.087184751921271064,-0.89889931280557489,0 +0.71875,0.11691006489352132,-0.24238906844035901,-0.16886594442826247,0,0.087488817862619084,-0.90142781444796216,0 +0.72125000000000006,0.11715696037775949,-0.23486831445080303,-0.16335344395667553,0,0.087858057823719804,-0.90449340621863428,0 +0.72375,0.1174166577876183,-0.22696879682954138,-0.15758238759684895,0,0.08824723417305036,-0.9077124481337816,0 +0.72625000000000006,0.11761203623571825,-0.22103003047499958,-0.15325677844062333,0,0.088540228534066956,-0.9101327480055359,0 +0.72875000000000001,0.11764815223606326,-0.21993423708599183,-0.15245924851833104,0,0.08859412431248137,-0.91057953155824023,0 +0.73125000000000007,0.11764295241336808,-0.2200903293627689,-0.15257160911773979,0,0.088586337286039485,-0.91051617734452983,0 +0.73375000000000001,0.11759000660142679,-0.2217003081127347,-0.15374084437403135,0,0.088506338493284042,-0.90986082609014918,0 +0.73624999999999996,0.11746031345619404,-0.22563937809188131,-0.15660719388934993,0,0.088311340736592969,-0.90825665198961858,0 +0.73875000000000002,0.11723828372065292,-0.23239420472240171,-0.16153287456890622,0,0.087977168091466496,-0.9055058428394922,0 +0.74124999999999996,0.11695405872405729,-0.24104632732416764,-0.16786313884395296,0,0.087550606026847611,-0.90198118960069906,0 +0.74375000000000002,0.11667856642422411,-0.24944335338982396,-0.17402937906226756,0,0.087137125367697799,-0.89856002823076275,0 +0.74624999999999997,0.11652142847638322,-0.25424394334264461,-0.17756382750169244,0,0.086901454460314165,-0.89660456501140007,0 +0.74875000000000003,0.11651981293218819,-0.25428866572145908,-0.17759682581079278,0,0.086899302405564094,-0.89658628316293454,0 +0.75124999999999997,0.11654384178002924,-0.2535594566735877,-0.17705849552342462,0,0.086934742960429467,-0.89688401034771859,0 +0.75375000000000003,0.11663051640593858,-0.25091355302284074,-0.17510796984102217,0,0.08706432661997765,-0.89796267762001025,0 +0.75624999999999998,0.11678404277607407,-0.24623080770483949,-0.17166114194328411,0,0.087293311528364281,-0.89987155145629427,0 +0.75875000000000004,0.11700344302198436,-0.23954347013011862,-0.16675062625144083,0,0.087621451884493884,-0.90259743709333429,0 +0.76124999999999998,0.1172431937971754,-0.23224924863937169,-0.16141064996890825,0,0.087980008633671614,-0.90557089006933678,0 +0.76375000000000004,0.11745835723684928,-0.2257014011703927,-0.15663158785569858,0,0.088302688141607355,-0.90823890147105391,0 +0.76624999999999999,0.11754312622419839,-0.22312484757638981,-0.15475473896938308,0,0.088429763359914815,-0.90928903939657357,0 +0.76875000000000004,0.11754177990704494,-0.2231668919210899,-0.15478502917437109,0,0.08842756580276423,-0.90927164832488772,0 +0.77124999999999999,0.11752467556395679,-0.22368568226609817,-0.15516209375600826,0,0.088401836341015949,-0.90906068120615424,0 +0.77375000000000005,0.11746717207168339,-0.22543397607620042,-0.15643453805452581,0,0.088315305884747231,-0.90834911199205925,0 +0.77625,0.11736654278177328,-0.2284945234234321,-0.15866471296533163,0,0.088163952024696957,-0.90710265586110195,0 +0.77875000000000005,0.11722713361337955,-0.23273201682477188,-0.16175718703284839,0,0.087954401569682927,-0.90537555931713076,0 +0.78125,0.11707778782447791,-0.23727864076599559,-0.16508186697178692,0,0.087730265510702843,-0.90352339441354335,0 +0.78375000000000006,0.11694701926702723,-0.24126444712942194,-0.16800203883568809,0,0.087533988164180898,-0.90189987769505553,0 +0.78625,0.11687743963943051,-0.24338529654596849,-0.16955784803318272,0,0.087429820942728886,-0.90103669813034792,0 +0.78875000000000006,0.11687579781052707,-0.24343592181704782,-0.16959486107747798,0,0.08742728644424369,-0.90101601254263675,0 +0.79125000000000001,0.11687539900643468,-0.24344948224066379,-0.16960462180695862,0,0.087426474749633054,-0.90100969094006977,0 +0.79375000000000007,0.11687409481764938,-0.24348129085661555,-0.16962777224760861,0,0.087424696127569423,-0.90099540369582221,0 +0.79625000000000001,0.11687218858217306,-0.24354390911756213,-0.16967348339899166,0,0.087421752667664165,-0.90097160223299655,0 +0.79875000000000007,0.116870215752296,-0.24361058874898325,-0.1697220504681374,0,0.0874184896460376,-0.90094505886224741,0 +0.80125000000000002,0.11686946136924814,-0.2436294977483163,-0.16973560439458318,0,0.087417613977942565,-0.90093824717607751,0 +0.80374999999999996,0.11686962190859448,-0.24361757731467398,-0.16972658857626485,0,0.087417870797879327,-0.90094090262231019,0 +0.80625000000000002,0.11687356980470871,-0.24350583643941545,-0.16964422423269365,0,0.087423444046079268,-0.90098768473549895,0 +0.80874999999999997,0.11688754092326054,-0.24307479305630586,-0.16932756115966405,0,0.087444533924976753,-0.90116318958274499,0 +0.81125000000000003,0.11691972536277602,-0.24209343744922968,-0.16860707128114324,0,0.087492701479890633,-0.90156325665747283,0 +0.81374999999999997,0.11697942266283615,-0.24027908101633488,-0.16727614115169526,0,0.087581830141478023,-0.90230271944561291,0 +0.81625000000000003,0.11707126156401244,-0.23747712607290974,-0.16522305705840304,0,0.08771962969895275,-0.9034445863476972,0 +0.81874999999999998,0.11720175792642251,-0.23350615420116155,-0.16231792357714034,0,0.087915217578154237,-0.9050626671429971,0 +0.82125000000000004,0.1173736571942727,-0.22828036241638489,-0.1585025661792111,0,0.088173092622349736,-0.90719178038941839,0 +0.82374999999999998,0.11758753647266376,-0.22177196496693163,-0.15376313261251445,0,0.088495041188408119,-0.90984301103522469,0 +0.82625000000000004,0.11784277533584739,-0.21402503109325074,-0.14813976728812336,0,0.088879385731000071,-0.91299811129464448,0 +0.82874999999999999,0.11813596987373072,-0.205135924121809,-0.14171096949690176,0,0.08932189551312586,-0.91661764598071116,0 +0.83125000000000004,0.11846242009804758,-0.19523667455595015,-0.13458125038057758,0,0.089816668680236189,-0.9206475711390385,0 +0.83374999999999999,0.11881836690580111,-0.18447630678794286,-0.12686686204096317,0,0.090356823064338121,-0.92502691979325369,0 +0.83625000000000005,0.1191983441793935,-0.17300551327586872,-0.11868324695390486,0,0.090935254319816416,-0.92969427790399251,0 +0.83875,0.11959717551690868,-0.16096583965923558,-0.11013805167379476,0,0.091545418685837099,-0.93459181209615316,0 +0.84125000000000005,0.12001209755915153,-0.14848356585795672,-0.10132596582677481,0,0.092181264693114717,-0.93966810954166835,0 +0.84375,0.12043877950911509,-0.13566775697809377,-0.092327068649525487,0,0.09283750209918229,-0.94487908876250215,0 +0.84625000000000006,0.12087371396585696,-0.12260927689724001,-0.083209494160765118,0,0.093509933368980058,-0.95018748674767706,0 +0.84875,0.12131567129224743,-0.1093844697747413,-0.074028085304663455,0,0.094194471653768597,-0.95556248832995694,0 +0.85125000000000006,0.12176160189020308,-0.09605840550907592,-0.064827260654986854,0,0.094888110578776108,-0.96097800205309825,0 +0.85375000000000001,0.12220959195301018,-0.082687976622211293,-0.055648874909733553,0,0.095588128076847467,-0.96641042235416763,0 +0.85625000000000007,0.12265849289683448,-0.069328350882536471,-0.046529178998104978,0,0.096291008766648978,-0.97183799626406353,0 +0.85875000000000001,0.12310492382833711,-0.056055787146077833,-0.037517888038019767,0,0.09699339953981001,-0.97722987519548088,0 +0.86125000000000007,0.12354638322994141,-0.042956407473377395,-0.028674501720487335,0,0.09769052441735504,-0.98255051087648382,0 +0.86375000000000002,0.12397571444500097,-0.030246526919572154,-0.020138158560817101,0,0.098369693309683259,-0.9877136051082076,0 +0.86624999999999996,0.12438070565716236,-0.018268628225800106,-0.012133471567233139,0,0.099013662392659962,-0.99257887118158417,0 +0.86875000000000002,0.12473720330383267,-0.0077450726851307217,-0.0051335041220790375,0,0.099581171411821656,-0.9968532001498126,0 +0.87124999999999997,0.1249700817568199,-0.00088137321149738316,-0.00058273816183469274,0,0.099952225492064839,-0.99964210622385019,0 +0.87375000000000003,0.12500000000314493,9.2678072621328777e-11,6.1313650451563421e-11,0,0.10000000000503184,-1.0000000000376423,0 +0.87624999999999997,0.12500000000313061,9.2259592555934167e-11,6.1037663810628979e-11,0,0.10000000000500853,-1.0000000000374729,0 +0.87875000000000003,0.12500000000298683,8.8026904282191698e-11,5.823759252481918e-11,0,0.10000000000477915,-1.0000000000357536,0 +0.88124999999999998,0.12500000000268974,7.9267999569953049e-11,5.2440333555909956e-11,0,0.10000000000430354,-1.0000000000321956,0 +0.88375000000000004,0.12500000000219424,6.4666272335784794e-11,4.2780682699312474e-11,0,0.1000000000035105,-1.0000000000262652,0 +0.88624999999999998,0.1250000000015753,4.6425914963663502e-11,3.071392029557768e-11,0,0.10000000000252052,-1.0000000000188565,0 +0.88875000000000004,0.12500000000090811,2.6762103644077048e-11,1.7704741376541178e-11,0,0.10000000000145282,-1.0000000000108695,0 +0.89124999999999999,0.1250000000003243,9.5565777513424923e-12,6.3224980806181864e-12,0,0.10000000000051879,-1.0000000000038816,0 +0.89375000000000004,0.12500000000000178,5.2520950551592749e-14,3.481659405223961e-14,0,0.10000000000000264,-1.0000000000000213,0 +0.89624999999999999,0.125,0,0,0,0.099999999999999867,-1,0 +0.89875000000000005,0.125,0,0,0,0.099999999999999867,-1,0 +0.90125,0.125,0,0,0,0.099999999999999867,-1,0 +0.90375000000000005,0.125,0,0,0,0.099999999999999867,-1,0 +0.90625,0.125,0,0,0,0.099999999999999867,-1,0 +0.90875000000000006,0.125,0,0,0,0.099999999999999867,-1,0 +0.91125,0.125,0,0,0,0.099999999999999867,-1,0 +0.91375000000000006,0.125,0,0,0,0.099999999999999867,-1,0 +0.91625000000000001,0.125,0,0,0,0.099999999999999867,-1,0 +0.91875000000000007,0.125,0,0,0,0.099999999999999867,-1,0 +0.92125000000000001,0.125,0,0,0,0.099999999999999867,-1,0 +0.92375000000000007,0.125,0,0,0,0.099999999999999867,-1,0 +0.92625000000000002,0.125,0,0,0,0.099999999999999867,-1,0 +0.92874999999999996,0.125,0,0,0,0.099999999999999867,-1,0 +0.93125000000000002,0.125,0,0,0,0.099999999999999867,-1,0 +0.93374999999999997,0.125,0,0,0,0.099999999999999867,-1,0 +0.93625000000000003,0.125,0,0,0,0.099999999999999867,-1,0 +0.93874999999999997,0.125,0,0,0,0.099999999999999867,-1,0 +0.94125000000000003,0.125,0,0,0,0.099999999999999867,-1,0 +0.94374999999999998,0.125,0,0,0,0.099999999999999867,-1,0 +0.94625000000000004,0.125,0,0,0,0.099999999999999867,-1,0 +0.94874999999999998,0.125,0,0,0,0.099999999999999867,-1,0 +0.95125000000000004,0.125,0,0,0,0.099999999999999867,-1,0 +0.95374999999999999,0.125,0,0,0,0.099999999999999867,-1,0 +0.95625000000000004,0.125,0,0,0,0.099999999999999867,-1,0 +0.95874999999999999,0.125,0,0,0,0.099999999999999867,-1,0 +0.96125000000000005,0.125,0,0,0,0.099999999999999867,-1,0 +0.96375,0.125,0,0,0,0.099999999999999867,-1,0 +0.96625000000000005,0.125,0,0,0,0.099999999999999867,-1,0 +0.96875,0.125,0,0,0,0.099999999999999867,-1,0 +0.97125000000000006,0.125,0,0,0,0.099999999999999867,-1,0 +0.97375,0.125,0,0,0,0.099999999999999867,-1,0 +0.97625000000000006,0.125,0,0,0,0.099999999999999867,-1,0 +0.97875000000000001,0.125,0,0,0,0.099999999999999867,-1,0 +0.98125000000000007,0.125,0,0,0,0.099999999999999867,-1,0 +0.98375000000000001,0.125,0,0,0,0.099999999999999867,-1,0 +0.98625000000000007,0.125,0,0,0,0.099999999999999867,-1,0 +0.98875000000000002,0.125,0,0,0,0.099999999999999867,-1,0 +0.99125000000000008,0.125,0,0,0,0.099999999999999867,-1,0 +0.99375000000000002,0.125,0,0,0,0.099999999999999867,-1,0 +0.99624999999999997,0.125,0,0,0,0.099999999999999867,-1,0 +0.99875000000000003,0.125,0,0,0,0.099999999999999867,-1,0 diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/test_public.py b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/test_public.py index b15cf48..cf61218 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/test_public.py +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/test_public.py @@ -6,6 +6,8 @@ PUBLIC_TEST_TARGET = "cpp_full_solver1d_public_tests" +GOLDEN_CSV_PATH = Path("tests/data/brio_wu_golden.csv") +GOLDEN_TOLERANCE = 1.0e-12 def _build_public_tests() -> Path: @@ -40,18 +42,29 @@ def test_public_brio_wu_cli_matches_reference_grid() -> None: ) rows = list(csv.reader(completed.stdout.splitlines())) + golden_rows = list( + csv.reader(GOLDEN_CSV_PATH.read_text(encoding="utf-8").splitlines()) + ) + assert rows[0] == ["x", "rho", "u", "v", "w", "p", "by", "bz"] + assert rows[0] == golden_rows[0] assert len(rows) - 1 == 400 + assert len(rows) == len(golden_rows) dx = (1.0 - 0.0) / 400.0 - for index, row in enumerate(rows[1:]): + for index, (row, golden_row) in enumerate(zip(rows[1:], golden_rows[1:])): assert len(row) == 8 + assert len(golden_row) == 8 x_value = float(row[0]) expected_x = 0.0 + (index + 0.5) * dx assert x_value == expected_x + assert abs(x_value - float(golden_row[0])) <= GOLDEN_TOLERANCE numeric_values = [float(component) for component in row[1:]] + golden_numeric_values = [float(component) for component in golden_row[1:]] assert all(math.isfinite(component) for component in [x_value, *numeric_values]) assert numeric_values[0] > 0.0 assert numeric_values[4] > 0.0 + for component, golden_component in zip(numeric_values, golden_numeric_values): + assert abs(component - golden_component) <= GOLDEN_TOLERANCE From b3841c25a523dca1a30e79026a8f7368c7b47d4e Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Sun, 29 Mar 2026 00:32:02 +0900 Subject: [PATCH 09/39] Refactor MHD state storage to mdspan views --- .../workspace/CMakeLists.txt | 2 + .../cpp-full-solver1d/workspace/src/main.cpp | 12 +- .../cpp-full-solver1d/workspace/src/mhd1d.cpp | 316 +++++++++++------- .../cpp-full-solver1d/workspace/src/mhd1d.hpp | 80 +++-- .../workspace/tests/cpp/test_public.cpp | 79 +++-- 5 files changed, 311 insertions(+), 178 deletions(-) diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/CMakeLists.txt b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/CMakeLists.txt index 01604e3..e4889f2 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/CMakeLists.txt +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/CMakeLists.txt @@ -26,6 +26,7 @@ add_library(mhd1d_solver target_include_directories(mhd1d_solver PUBLIC src + ../../../common/include ) add_executable(cpp_full_solver1d @@ -51,6 +52,7 @@ target_link_libraries(cpp_full_solver1d_public_tests PRIVATE target_include_directories(cpp_full_solver1d_public_tests PRIVATE src + ../../../common/include ) set_target_properties(cpp_full_solver1d_public_tests PROPERTIES diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp index e94b7c3..f6cd387 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp @@ -4,8 +4,6 @@ #include #include #include -#include - int main(int argc, char** argv) { if (argc != 2) { @@ -20,15 +18,15 @@ int main(int argc, char** argv) return 1; } - const mhd1d::ProblemConfig problem = mhd1d::make_brio_wu_example(); - const std::vector final_primitive_cells = mhd1d::run_full_simulation(problem); - const std::vector centers = + const mhd1d::ProblemConfig problem = mhd1d::make_brio_wu_example(); + const mhd1d::StateArray2D final_primitive_cells = mhd1d::run_full_simulation(problem); + const std::vector centers = mhd1d::cell_centers(problem.nx, problem.x_left, problem.x_right); std::cout << "x,rho,u,v,w,p,by,bz\n"; std::cout << std::setprecision(17); - for (std::size_t index = 0; index < final_primitive_cells.size(); ++index) { - const mhd1d::StateVector& cell = final_primitive_cells[index]; + for (std::size_t index = 0; index < final_primitive_cells.rows(); ++index) { + const mhd1d::StateVector cell = final_primitive_cells.load(index); std::cout << centers[index] << ',' << cell[0] << ',' << cell[1] << ',' << cell[2] << ',' << cell[3] << ',' << cell[4] << ',' << cell[5] << ',' << cell[6] << '\n'; } diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp index 548edee..fb95b5e 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -34,24 +35,115 @@ double minmod3(double first, double second, double third) return 0.0; } +StateArray2D conservative_profile_to_primitive_profile(const StateArray2D& conservative_cells, + double bx, double gamma) +{ + StateArray2D primitive_cells(conservative_cells.rows()); + for (std::size_t index = 0; index < conservative_cells.rows(); ++index) { + primitive_cells.store(index, + conservative_to_primitive(conservative_cells.load(index), bx, gamma)); + } + + return primitive_cells; +} + } // namespace -namespace +StateArray2D::StateArray2D() : buffer(), view_() +{ +} + +StateArray2D::StateArray2D(std::size_t rows) : buffer(rows * kStateWidth, 0.0), view_() +{ + rebind_view(); +} + +StateArray2D::StateArray2D(const StateArray2D& other) : buffer(other.buffer), view_() +{ + rebind_view(); +} + +StateArray2D::StateArray2D(StateArray2D&& other) noexcept : buffer(std::move(other.buffer)), view_() { + rebind_view(); + other.rebind_view(); +} -std::vector -conservative_profile_to_primitive_profile(const std::vector& conservative_cells, - double bx, double gamma) +StateArray2D& StateArray2D::operator=(const StateArray2D& other) { - std::vector primitive_cells(conservative_cells.size()); - for (std::size_t index = 0; index < conservative_cells.size(); ++index) { - primitive_cells[index] = conservative_to_primitive(conservative_cells[index], bx, gamma); + if (this != &other) { + buffer = other.buffer; + rebind_view(); } + return *this; +} - return primitive_cells; +StateArray2D& StateArray2D::operator=(StateArray2D&& other) noexcept +{ + if (this != &other) { + buffer = std::move(other.buffer); + rebind_view(); + other.rebind_view(); + } + return *this; } -} // namespace +std::size_t StateArray2D::rows() const +{ + return buffer.size() / kStateWidth; +} + +std::size_t StateArray2D::cols() const +{ + return kStateWidth; +} + +double* StateArray2D::row_data(std::size_t row) +{ + return buffer.data() + row * kStateWidth; +} + +const double* StateArray2D::row_data(std::size_t row) const +{ + return buffer.data() + row * kStateWidth; +} + +StateVector StateArray2D::load(std::size_t row) const +{ + StateVector state{}; + std::memcpy(state.data(), row_data(row), sizeof(double) * kStateWidth); + return state; +} + +void StateArray2D::store(std::size_t row, const StateVector& state) +{ + std::memcpy(row_data(row), state.data(), sizeof(double) * kStateWidth); +} + +double& StateArray2D::operator()(std::size_t row, std::size_t col) +{ + return view_(row, col); +} + +const double& StateArray2D::operator()(std::size_t row, std::size_t col) const +{ + return view_(row, col); +} + +StateView StateArray2D::view() +{ + return view_; +} + +ConstStateView StateArray2D::view() const +{ + return ConstStateView(buffer.data(), rows(), kStateWidth); +} + +void StateArray2D::rebind_view() +{ + view_ = StateView(buffer.data(), rows(), kStateWidth); +} ProblemConfig make_brio_wu_example() { @@ -108,24 +200,22 @@ StateVector conservative_to_primitive(const StateVector& conservative, double bx return StateVector{rho, u, v, w, pressure, by, bz}; } -std::vector mc2_slopes(const std::vector& primitive_cells) +StateArray2D mc2_slopes(const StateArray2D& primitive_cells) { - if (primitive_cells.size() < 3U) { + if (primitive_cells.rows() < 3U) { throw std::runtime_error("primitive_cells must contain at least three cells"); } - std::vector slopes(primitive_cells.size()); - for (std::size_t index = 1; index + 1U < primitive_cells.size(); ++index) { - const StateVector& left_cell = primitive_cells[index - 1U]; - const StateVector& center_cell = primitive_cells[index]; - const StateVector& right_cell = primitive_cells[index + 1U]; - StateVector& limited_slope = slopes[index]; - + StateArray2D slopes(primitive_cells.rows()); + for (std::size_t index = 1; index + 1U < primitive_cells.rows(); ++index) { for (std::size_t component = 0; component < kStateWidth; ++component) { - const double left_difference = center_cell[component] - left_cell[component]; - const double right_difference = right_cell[component] - center_cell[component]; - const double centered_difference = 0.5 * (right_cell[component] - left_cell[component]); - limited_slope[component] = + const double left_difference = + primitive_cells(index, component) - primitive_cells(index - 1U, component); + const double right_difference = + primitive_cells(index + 1U, component) - primitive_cells(index, component); + const double centered_difference = + 0.5 * (primitive_cells(index + 1U, component) - primitive_cells(index - 1U, component)); + slopes(index, component) = minmod3(2.0 * left_difference, centered_difference, 2.0 * right_difference); } } @@ -133,21 +223,21 @@ std::vector mc2_slopes(const std::vector& primitive_ce return slopes; } -std::pair, std::vector> -reconstruct_mc2_interfaces(const std::vector& primitive_cells) +std::pair +reconstruct_mc2_interfaces(const StateArray2D& primitive_cells) { - const std::vector slopes = mc2_slopes(primitive_cells); - const std::size_t interface_count = primitive_cells.size() - 1U; + const StateArray2D slopes = mc2_slopes(primitive_cells); + const std::size_t interface_count = primitive_cells.rows() - 1U; - std::vector left_states(interface_count); - std::vector right_states(interface_count); + StateArray2D left_states(interface_count); + StateArray2D right_states(interface_count); for (std::size_t index = 0; index < interface_count; ++index) { for (std::size_t component = 0; component < kStateWidth; ++component) { - left_states[index][component] = - primitive_cells[index][component] + 0.5 * slopes[index][component]; - right_states[index][component] = - primitive_cells[index + 1U][component] - 0.5 * slopes[index + 1U][component]; + left_states(index, component) = + primitive_cells(index, component) + 0.5 * slopes(index, component); + right_states(index, component) = + primitive_cells(index + 1U, component) - 0.5 * slopes(index + 1U, component); } } @@ -352,17 +442,20 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& }; } -std::vector pad_zero_gradient_ghost_cells(const std::vector& cells) +StateArray2D pad_zero_gradient_ghost_cells(const StateArray2D& cells) { - if (cells.empty()) { + if (cells.rows() == 0U) { return {}; } - std::vector padded; - padded.reserve(cells.size() + 4U); - padded.insert(padded.end(), 2U, cells.front()); - padded.insert(padded.end(), cells.begin(), cells.end()); - padded.insert(padded.end(), 2U, cells.back()); + StateArray2D padded(cells.rows() + 2U * kGhostWidth); + for (std::size_t ghost = 0; ghost < kGhostWidth; ++ghost) { + padded.store(ghost, cells.load(0)); + padded.store(padded.rows() - 1U - ghost, cells.load(cells.rows() - 1U)); + } + for (std::size_t index = 0; index < cells.rows(); ++index) { + padded.store(index + kGhostWidth, cells.load(index)); + } return padded; } @@ -385,62 +478,61 @@ std::vector cell_centers(std::size_t nx, double x_left, double x_right) return centers; } -std::vector brio_wu_initial_profile(const ProblemConfig& problem) +StateArray2D brio_wu_initial_profile(const ProblemConfig& problem) { const std::vector centers = cell_centers(problem.nx, problem.x_left, problem.x_right); - std::vector profile(problem.nx); + StateArray2D profile(problem.nx); for (std::size_t index = 0; index < centers.size(); ++index) { - profile[index] = (centers[index] < problem.discontinuity_x) ? problem.left_primitive - : problem.right_primitive; + profile.store(index, (centers[index] < problem.discontinuity_x) ? problem.left_primitive + : problem.right_primitive); } return profile; } -std::vector run_full_simulation(const ProblemConfig& problem) +StateArray2D run_full_simulation(const ProblemConfig& problem) { if (problem.nx == 0U) { return {}; } - const std::vector initial_primitive_profile = brio_wu_initial_profile(problem); - std::vector conservative_cells(initial_primitive_profile.size()); - for (std::size_t index = 0; index < initial_primitive_profile.size(); ++index) { - conservative_cells[index] = - primitive_to_conservative(initial_primitive_profile[index], problem.bx, problem.gamma); + const StateArray2D initial_primitive_profile = brio_wu_initial_profile(problem); + StateArray2D conservative_cells(initial_primitive_profile.rows()); + for (std::size_t index = 0; index < initial_primitive_profile.rows(); ++index) { + conservative_cells.store(index, primitive_to_conservative(initial_primitive_profile.load(index), + problem.bx, problem.gamma)); } - const double dx = (problem.x_right - problem.x_left) / static_cast(problem.nx); - const std::vector evolved_conservative_cells = evolve_ssp_rk3_fixed_dt( + const double dx = (problem.x_right - problem.x_left) / static_cast(problem.nx); + const StateArray2D evolved_conservative_cells = evolve_ssp_rk3_fixed_dt( conservative_cells, problem.t_final, problem.dt, dx, problem.bx, problem.gamma); - std::vector final_primitive_profile(evolved_conservative_cells.size()); - for (std::size_t index = 0; index < evolved_conservative_cells.size(); ++index) { - final_primitive_profile[index] = - conservative_to_primitive(evolved_conservative_cells[index], problem.bx, problem.gamma); + StateArray2D final_primitive_profile(evolved_conservative_cells.rows()); + for (std::size_t index = 0; index < evolved_conservative_cells.rows(); ++index) { + final_primitive_profile.store(index, + conservative_to_primitive(evolved_conservative_cells.load(index), + problem.bx, problem.gamma)); } return final_primitive_profile; } -std::vector -compute_semidiscrete_rhs(const std::vector& conservative_cells, double bx, - double gamma) +StateArray2D compute_semidiscrete_rhs(const StateArray2D& conservative_cells, double bx, + double gamma) { - if (conservative_cells.empty()) { + if (conservative_cells.rows() == 0U) { throw std::runtime_error("conservative_cells must contain at least one cell"); } - const double dx = 1.0 / static_cast(conservative_cells.size()); + const double dx = 1.0 / static_cast(conservative_cells.rows()); return compute_semidiscrete_rhs(conservative_cells, dx, bx, gamma); } -std::vector -compute_semidiscrete_rhs(const std::vector& conservative_cells, double dx, double bx, - double gamma) +StateArray2D compute_semidiscrete_rhs(const StateArray2D& conservative_cells, double dx, double bx, + double gamma) { - if (conservative_cells.empty()) { + if (conservative_cells.rows() == 0U) { throw std::runtime_error("conservative_cells must contain at least one cell"); } @@ -448,49 +540,43 @@ compute_semidiscrete_rhs(const std::vector& conservative_cells, dou throw std::runtime_error("dx must be positive"); } - const std::vector padded_conservative = - pad_zero_gradient_ghost_cells(conservative_cells); - const std::vector padded_primitive = + const StateArray2D padded_conservative = pad_zero_gradient_ghost_cells(conservative_cells); + const StateArray2D padded_primitive = conservative_profile_to_primitive_profile(padded_conservative, bx, gamma); - const std::pair, std::vector> interface_states = + const auto [left_interface_states, right_interface_states] = reconstruct_mc2_interfaces(padded_primitive); - const std::vector& left_interface_states = interface_states.first; - const std::vector& right_interface_states = interface_states.second; - - std::vector interface_fluxes(left_interface_states.size()); - for (std::size_t index = 0; index < left_interface_states.size(); ++index) { - interface_fluxes[index] = hlld_flux_from_primitive(left_interface_states[index], - right_interface_states[index], bx, gamma); - } - - std::vector rhs(conservative_cells.size()); - for (std::size_t index = 0; index < conservative_cells.size(); ++index) { + StateArray2D rhs(conservative_cells.rows()); + for (std::size_t index = 0; index < conservative_cells.rows(); ++index) { + const StateVector right_flux = + hlld_flux_from_primitive(left_interface_states.load(index + kGhostWidth), + right_interface_states.load(index + kGhostWidth), bx, gamma); + const StateVector left_flux = + hlld_flux_from_primitive(left_interface_states.load(index + kGhostWidth - 1U), + right_interface_states.load(index + kGhostWidth - 1U), bx, gamma); for (std::size_t component = 0; component < kStateWidth; ++component) { - rhs[index][component] = -(interface_fluxes[index + kGhostWidth][component] - - interface_fluxes[index + kGhostWidth - 1U][component]) / - dx; + rhs(index, component) = -(right_flux[component] - left_flux[component]) / dx; } } return rhs; } -std::vector ssp_rk3_step(const std::vector& conservative_cells, double dt, - double bx, double gamma) +StateArray2D ssp_rk3_step(const StateArray2D& conservative_cells, double dt, double bx, + double gamma) { - if (conservative_cells.empty()) { + if (conservative_cells.rows() == 0U) { throw std::runtime_error("conservative_cells must contain at least one cell"); } - const double dx = 1.0 / static_cast(conservative_cells.size()); + const double dx = 1.0 / static_cast(conservative_cells.rows()); return ssp_rk3_step(conservative_cells, dt, dx, bx, gamma); } -std::vector ssp_rk3_step(const std::vector& conservative_cells, double dt, - double dx, double bx, double gamma) +StateArray2D ssp_rk3_step(const StateArray2D& conservative_cells, double dt, double dx, double bx, + double gamma) { - if (conservative_cells.empty()) { + if (conservative_cells.rows() == 0U) { throw std::runtime_error("conservative_cells must contain at least one cell"); } @@ -498,54 +584,52 @@ std::vector ssp_rk3_step(const std::vector& conservati throw std::runtime_error("dt must be positive"); } - std::vector first_stage = conservative_cells; - const std::vector first_rhs = - compute_semidiscrete_rhs(conservative_cells, dx, bx, gamma); - for (std::size_t index = 0; index < first_stage.size(); ++index) { + StateArray2D first_stage = conservative_cells; + const StateArray2D first_rhs = compute_semidiscrete_rhs(conservative_cells, dx, bx, gamma); + for (std::size_t index = 0; index < first_stage.rows(); ++index) { for (std::size_t component = 0; component < kStateWidth; ++component) { - first_stage[index][component] += dt * first_rhs[index][component]; + first_stage(index, component) += dt * first_rhs(index, component); } } - std::vector second_stage = conservative_cells; - const std::vector second_rhs = compute_semidiscrete_rhs(first_stage, dx, bx, gamma); - for (std::size_t index = 0; index < second_stage.size(); ++index) { + StateArray2D second_stage = conservative_cells; + const StateArray2D second_rhs = compute_semidiscrete_rhs(first_stage, dx, bx, gamma); + for (std::size_t index = 0; index < second_stage.rows(); ++index) { for (std::size_t component = 0; component < kStateWidth; ++component) { - second_stage[index][component] = - 0.75 * conservative_cells[index][component] + - 0.25 * (first_stage[index][component] + dt * second_rhs[index][component]); + second_stage(index, component) = + 0.75 * conservative_cells(index, component) + + 0.25 * (first_stage(index, component) + dt * second_rhs(index, component)); } } - const std::vector third_rhs = compute_semidiscrete_rhs(second_stage, dx, bx, gamma); - std::vector next_stage = conservative_cells; - for (std::size_t index = 0; index < next_stage.size(); ++index) { + const StateArray2D third_rhs = compute_semidiscrete_rhs(second_stage, dx, bx, gamma); + StateArray2D next_stage = conservative_cells; + for (std::size_t index = 0; index < next_stage.rows(); ++index) { for (std::size_t component = 0; component < kStateWidth; ++component) { - next_stage[index][component] = - (1.0 / 3.0) * conservative_cells[index][component] + - (2.0 / 3.0) * (second_stage[index][component] + dt * third_rhs[index][component]); + next_stage(index, component) = + (1.0 / 3.0) * conservative_cells(index, component) + + (2.0 / 3.0) * (second_stage(index, component) + dt * third_rhs(index, component)); } } return next_stage; } -std::vector evolve_ssp_rk3_fixed_dt(const std::vector& conservative_cells, - double t_final, double dt, double bx, double gamma) +StateArray2D evolve_ssp_rk3_fixed_dt(const StateArray2D& conservative_cells, double t_final, + double dt, double bx, double gamma) { - if (conservative_cells.empty()) { + if (conservative_cells.rows() == 0U) { throw std::runtime_error("conservative_cells must contain at least one cell"); } - const double dx = 1.0 / static_cast(conservative_cells.size()); + const double dx = 1.0 / static_cast(conservative_cells.rows()); return evolve_ssp_rk3_fixed_dt(conservative_cells, t_final, dt, dx, bx, gamma); } -std::vector evolve_ssp_rk3_fixed_dt(const std::vector& conservative_cells, - double t_final, double dt, double dx, double bx, - double gamma) +StateArray2D evolve_ssp_rk3_fixed_dt(const StateArray2D& conservative_cells, double t_final, + double dt, double dx, double bx, double gamma) { - if (conservative_cells.empty()) { + if (conservative_cells.rows() == 0U) { throw std::runtime_error("conservative_cells must contain at least one cell"); } @@ -557,8 +641,8 @@ std::vector evolve_ssp_rk3_fixed_dt(const std::vector& throw std::runtime_error("dt must be positive"); } - std::vector evolved_state = conservative_cells; - double elapsed_time = 0.0; + StateArray2D evolved_state = conservative_cells; + double elapsed_time = 0.0; while (elapsed_time < t_final) { const double remaining_time = t_final - elapsed_time; const double step_dt = std::min(dt, remaining_time); diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp index 5892aee..24aeabb 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp @@ -2,15 +2,53 @@ #include #include +#include #include #include namespace mhd1d { +namespace stdex = std::experimental; + constexpr std::size_t kStateWidth = 7; -using StateVector = std::array; +using StateVector = std::array; +using StateExtents = stdex::dextents; +using StateView = stdex::mdspan; +using ConstStateView = stdex::mdspan; + +struct StateArray2D { + StateArray2D(); + explicit StateArray2D(std::size_t rows); + + StateArray2D(const StateArray2D& other); + StateArray2D(StateArray2D&& other) noexcept; + StateArray2D& operator=(const StateArray2D& other); + StateArray2D& operator=(StateArray2D&& other) noexcept; + + [[nodiscard]] std::size_t rows() const; + [[nodiscard]] std::size_t cols() const; + + [[nodiscard]] double* row_data(std::size_t row); + [[nodiscard]] const double* row_data(std::size_t row) const; + + [[nodiscard]] StateVector load(std::size_t row) const; + void store(std::size_t row, const StateVector& state); + + double& operator()(std::size_t row, std::size_t col); + const double& operator()(std::size_t row, std::size_t col) const; + + [[nodiscard]] StateView view(); + [[nodiscard]] ConstStateView view() const; + + std::vector buffer; + +private: + void rebind_view(); + + StateView view_; +}; struct ProblemConfig { std::size_t nx = 0; @@ -31,42 +69,38 @@ StateVector primitive_to_conservative(const StateVector& primitive, double bx, d StateVector conservative_to_primitive(const StateVector& conservative, double bx, double gamma); -std::vector mc2_slopes(const std::vector& primitive_cells); +StateArray2D mc2_slopes(const StateArray2D& primitive_cells); -std::pair, std::vector> -reconstruct_mc2_interfaces(const std::vector& primitive_cells); +std::pair +reconstruct_mc2_interfaces(const StateArray2D& primitive_cells); StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, double gamma); std::vector cell_centers(std::size_t nx, double x_left, double x_right); -std::vector pad_zero_gradient_ghost_cells(const std::vector& cells); +StateArray2D pad_zero_gradient_ghost_cells(const StateArray2D& cells); -std::vector brio_wu_initial_profile(const ProblemConfig& problem); +StateArray2D brio_wu_initial_profile(const ProblemConfig& problem); -std::vector run_full_simulation(const ProblemConfig& problem); +StateArray2D run_full_simulation(const ProblemConfig& problem); -std::vector -compute_semidiscrete_rhs(const std::vector& conservative_cells, double bx = 0.75, - double gamma = 2.0); +StateArray2D compute_semidiscrete_rhs(const StateArray2D& conservative_cells, double bx = 0.75, + double gamma = 2.0); -std::vector -compute_semidiscrete_rhs(const std::vector& conservative_cells, double dx, double bx, - double gamma); +StateArray2D compute_semidiscrete_rhs(const StateArray2D& conservative_cells, double dx, double bx, + double gamma); -std::vector ssp_rk3_step(const std::vector& conservative_cells, double dt, - double bx = 0.75, double gamma = 2.0); +StateArray2D ssp_rk3_step(const StateArray2D& conservative_cells, double dt, double bx = 0.75, + double gamma = 2.0); -std::vector ssp_rk3_step(const std::vector& conservative_cells, double dt, - double dx, double bx, double gamma); +StateArray2D ssp_rk3_step(const StateArray2D& conservative_cells, double dt, double dx, double bx, + double gamma); -std::vector evolve_ssp_rk3_fixed_dt(const std::vector& conservative_cells, - double t_final, double dt, double bx = 0.75, - double gamma = 2.0); +StateArray2D evolve_ssp_rk3_fixed_dt(const StateArray2D& conservative_cells, double t_final, + double dt, double bx = 0.75, double gamma = 2.0); -std::vector evolve_ssp_rk3_fixed_dt(const std::vector& conservative_cells, - double t_final, double dt, double dx, double bx, - double gamma); +StateArray2D evolve_ssp_rk3_fixed_dt(const StateArray2D& conservative_cells, double t_final, + double dt, double dx, double bx, double gamma); } // namespace mhd1d diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp index c58c794..a5c6d9e 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp @@ -57,33 +57,37 @@ TEST_CASE("primitive and conservative states round-trip", "[mhd1d][conversion]") TEST_CASE("mc2_slopes preserve a constant primitive state", "[mhd1d][reconstruction]") { const auto constant_state = mhd1d::StateVector{1.25, -0.5, 0.25, -0.125, 2.75, 0.4, -0.3}; - const std::vector cells{constant_state, constant_state, constant_state, - constant_state}; + mhd1d::StateArray2D cells(4); + for (std::size_t index = 0; index < cells.rows(); ++index) { + cells.store(index, constant_state); + } const auto slopes = mhd1d::mc2_slopes(cells); - REQUIRE(slopes.size() == cells.size()); - for (const auto& slope : slopes) { - require_state_vector_close(slope, mhd1d::StateVector{}); + REQUIRE(slopes.rows() == cells.rows()); + for (std::size_t index = 0; index < slopes.rows(); ++index) { + require_state_vector_close(slopes.load(index), mhd1d::StateVector{}); } } TEST_CASE("reconstruct_mc2_interfaces preserves a constant primitive state exactly", "[mhd1d][reconstruction]") { - const auto constant_state = mhd1d::StateVector{0.9, 0.3, -0.2, 0.1, 1.8, -0.45, 0.6}; - const std::vector cells{constant_state, constant_state, constant_state, - constant_state}; + const auto constant_state = mhd1d::StateVector{0.9, 0.3, -0.2, 0.1, 1.8, -0.45, 0.6}; + mhd1d::StateArray2D cells(4); + for (std::size_t index = 0; index < cells.rows(); ++index) { + cells.store(index, constant_state); + } const auto [left_states, right_states] = mhd1d::reconstruct_mc2_interfaces(cells); - REQUIRE(left_states.size() == cells.size() - 1U); - REQUIRE(right_states.size() == cells.size() - 1U); - for (const auto& state : left_states) { - require_state_vector_close(state, constant_state); + REQUIRE(left_states.rows() == cells.rows() - 1U); + REQUIRE(right_states.rows() == cells.rows() - 1U); + for (std::size_t index = 0; index < left_states.rows(); ++index) { + require_state_vector_close(left_states.load(index), constant_state); } - for (const auto& state : right_states) { - require_state_vector_close(state, constant_state); + for (std::size_t index = 0; index < right_states.rows(); ++index) { + require_state_vector_close(right_states.load(index), constant_state); } } @@ -122,33 +126,44 @@ TEST_CASE("hlld_flux_from_primitive matches the physical flux for identical stat TEST_CASE("pad_zero_gradient_ghost_cells duplicates edge states on both sides", "[mhd1d][boundary]") { - const std::vector cells = { - mhd1d::StateVector{1.0, 0.5, -0.25, 0.125, 2.0, 0.1, -0.05}, - mhd1d::StateVector{1.2, 0.6, -0.2, 0.15, 2.2, 0.12, -0.02}, - mhd1d::StateVector{1.4, 0.7, -0.15, 0.175, 2.4, 0.14, 0.01}, - }; + mhd1d::StateArray2D cells(3); + cells.store(0, mhd1d::StateVector{1.0, 0.5, -0.25, 0.125, 2.0, 0.1, -0.05}); + cells.store(1, mhd1d::StateVector{1.2, 0.6, -0.2, 0.15, 2.2, 0.12, -0.02}); + cells.store(2, mhd1d::StateVector{1.4, 0.7, -0.15, 0.175, 2.4, 0.14, 0.01}); const auto padded = mhd1d::pad_zero_gradient_ghost_cells(cells); - REQUIRE(padded.size() == cells.size() + 4U); - require_state_vector_close(padded[0], cells.front()); - require_state_vector_close(padded[1], cells.front()); - require_state_vector_close(padded[2], cells[0]); - require_state_vector_close(padded[3], cells[1]); - require_state_vector_close(padded[4], cells[2]); - require_state_vector_close(padded[5], cells.back()); - require_state_vector_close(padded[6], cells.back()); + REQUIRE(padded.rows() == cells.rows() + 4U); + require_state_vector_close(padded.load(0), cells.load(0)); + require_state_vector_close(padded.load(1), cells.load(0)); + require_state_vector_close(padded.load(2), cells.load(0)); + require_state_vector_close(padded.load(3), cells.load(1)); + require_state_vector_close(padded.load(4), cells.load(2)); + require_state_vector_close(padded.load(5), cells.load(2)); + require_state_vector_close(padded.load(6), cells.load(2)); } TEST_CASE("pad_zero_gradient_ghost_cells handles a single interior cell", "[mhd1d][boundary]") { - const auto cell = mhd1d::StateVector{1.5, -0.75, 0.25, 0.0, 3.5, -0.1, 0.2}; - const std::vector cells{cell}; + const auto cell = mhd1d::StateVector{1.5, -0.75, 0.25, 0.0, 3.5, -0.1, 0.2}; + mhd1d::StateArray2D cells(1); + cells.store(0, cell); const auto padded = mhd1d::pad_zero_gradient_ghost_cells(cells); - REQUIRE(padded.size() == 5U); - for (const auto& padded_cell : padded) { - require_state_vector_close(padded_cell, cell); + REQUIRE(padded.rows() == 5U); + for (std::size_t index = 0; index < padded.rows(); ++index) { + require_state_vector_close(padded.load(index), cell); } } + +TEST_CASE("StateArray2D rows are contiguous in the right-most dimension", "[mhd1d][storage]") +{ + mhd1d::StateArray2D cells(3); + cells.store(1, mhd1d::StateVector{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}); + + const double* row_ptr = cells.row_data(1); + REQUIRE(row_ptr[0] == 1.0); + REQUIRE(row_ptr[6] == 7.0); + REQUIRE(cells.row_data(2) - cells.row_data(1) == static_cast(mhd1d::kStateWidth)); +} From 595afcfeb19ef2357cb77c1051426e849650dbfe Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Sun, 29 Mar 2026 16:38:24 +0900 Subject: [PATCH 10/39] checkpoint: spiral-unknown-1774769904852 From c8e08d6409c6e11be30be26bb725ae8aac4cdb94 Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Sun, 29 Mar 2026 17:32:17 +0900 Subject: [PATCH 11/39] checkpoint: spiral-unknown-1774773137200 From a67994d7414724a1b5c143237f9d9950b13da275 Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Sun, 29 Mar 2026 23:02:00 +0900 Subject: [PATCH 12/39] Migrate cpp-full-solver1d to mdspan views --- benchmarks/magnetohydrodynamics/README.md | 6 +- .../eval/tests/test_hidden.py | 13 +- .../cpp-full-solver1d/spec.md | 106 ++-- .../cpp-full-solver1d/workspace/README.md | 2 +- .../workspace/examples/brio_wu.toml | 28 - .../cpp-full-solver1d/workspace/src/main.cpp | 122 ++++- .../cpp-full-solver1d/workspace/src/mhd1d.cpp | 500 +++++++----------- .../cpp-full-solver1d/workspace/src/mhd1d.hpp | 153 +++--- .../workspace/tests/cpp/test_public.cpp | 196 +++++-- .../workspace/tests/test_public.py | 21 +- 10 files changed, 614 insertions(+), 533 deletions(-) delete mode 100644 benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/examples/brio_wu.toml diff --git a/benchmarks/magnetohydrodynamics/README.md b/benchmarks/magnetohydrodynamics/README.md index 4101405..ed4bcce 100644 --- a/benchmarks/magnetohydrodynamics/README.md +++ b/benchmarks/magnetohydrodynamics/README.md @@ -22,9 +22,9 @@ This suite contains benchmark tasks for ideal magnetohydrodynamics solvers. shared workspace. - `cpp-full-solver1d` scores only the interior cells, excluding two edge-adjacent cells on each side, against the variables `rho`, `u`, `p`, and - `by` using fixture-recorded `abs_l1` and `abs_linf` tolerances. CSV fixture - headers keep the magnetic fields lowercase (`by`, `bz`) even when the code - and solver notation use `By` and `Bz`. + `by` using fixture-recorded `abs_l1` and `abs_linf` tolerances. The solver + uses hardcoded Brio-Wu defaults and emits CSV with lowercase magnetic-field + headers (`by`, `bz`). ## Reference credit diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/eval/tests/test_hidden.py b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/eval/tests/test_hidden.py index 39ade8f..9f567f0 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/eval/tests/test_hidden.py +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/eval/tests/test_hidden.py @@ -1,8 +1,13 @@ import math import os import subprocess +import sys from pathlib import Path +SHARED_EVAL_ROOT = Path(__file__).resolve().parents[3] / "shared" / "eval" +if str(SHARED_EVAL_ROOT) not in sys.path: + sys.path.insert(0, str(SHARED_EVAL_ROOT)) + from mhd1d_shared import ( CSV_HEADER, compare_mhd1d_csv_against_fixture, @@ -11,13 +16,17 @@ SOLVER_TARGET = "cpp_full_solver1d" +WORKSPACE_ROOT = Path(__file__).resolve().parents[2] / "workspace" def _build_solver(build_dir: Path) -> Path: - subprocess.run(["cmake", "-S", ".", "-B", str(build_dir)], check=True) + subprocess.run( + ["cmake", "-S", ".", "-B", str(build_dir)], check=True, cwd=WORKSPACE_ROOT + ) subprocess.run( ["cmake", "--build", str(build_dir), "--target", SOLVER_TARGET], check=True, + cwd=WORKSPACE_ROOT, ) binary_name = f"{SOLVER_TARGET}.exe" if os.name == "nt" else SOLVER_TARGET @@ -31,7 +40,7 @@ def test_hidden_brio_wu_cli_matches_fixture(tmp_path: Path) -> None: output_csv_path = tmp_path / "brio_wu.csv" completed = subprocess.run( - [str(solver_path), "examples/brio_wu.toml"], + [str(solver_path)], check=True, capture_output=True, text=True, diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/spec.md b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/spec.md index 31af33a..a98becf 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/spec.md +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/spec.md @@ -13,7 +13,6 @@ The benchmark contract is fixed around these choices: - flux function: HLLD - time integration: SSP-RK3 - boundary conditions: zero-gradient -- input format: TOML - output format: CSV with columns `x,rho,u,v,w,p,by,bz` - default problem: Brio-Wu with `gamma = 2` and `Bx = 0.75` @@ -64,46 +63,15 @@ The solver executable is placed at `build/bin/cpp_full_solver1d`. ## Usage ```bash -./bin/cpp_full_solver1d +./bin/cpp_full_solver1d ``` -The solver reads a TOML configuration file and writes CSV output to stdout. - -### Example input (Brio-Wu) - -```toml -nx = 400 -x_left = 0.0 -x_right = 1.0 -discontinuity_x = 0.5 -gamma = 2.0 -bx = 0.75 -dt = 5.0e-4 -t_final = 0.1 - -[left] -rho = 1.0 -u = 0.0 -v = 0.0 -w = 0.0 -p = 1.0 -by = 1.0 -bz = 0.0 - -[right] -rho = 0.125 -u = 0.0 -v = 0.0 -w = 0.0 -p = 0.1 -by = -1.0 -bz = 0.0 -``` +The solver uses hardcoded Brio-Wu defaults and writes CSV output to stdout. ### Running and saving output ```bash -./bin/cpp_full_solver1d examples/brio_wu.toml > solution.csv +./bin/cpp_full_solver1d > solution.csv ``` ## Visualization @@ -121,9 +89,11 @@ magnetic field (`by`). ### Core functions (`mhd1d.hpp`) -#### `ProblemConfig make_brio_wu_example()` +Type aliases used by the API: -Returns a `ProblemConfig` pre-configured with the canonical Brio-Wu parameters. +- `StateVector = std::array` +- `ArrayView = std::experimental::mdspan>` +- `ConstArrayView = std::experimental::mdspan>` #### `StateVector primitive_to_conservative(const StateVector& primitive, double bx, double gamma)` @@ -147,14 +117,30 @@ Converts a conservative state vector to primitive form. **Returns:** 7-component primitive state -#### `std::pair, std::vector> reconstruct_mc2_interfaces(const std::vector& primitive_cells)` +#### `void pad_zero_gradient_ghost_cells(ConstArrayView cells, ArrayView padded)` -Performs MC2 slope-limited reconstruction at cell interfaces. +Fills the padded array with two zero-gradient ghost cells on each side. **Parameters:** -- `primitive_cells`: Cell-centered primitive states +- `cells`: interior cell-centered states with shape `(nx, 7)` +- `padded`: output with shape `(nx + 4, 7)` + +#### `void mc2_slopes(ConstArrayView primitive_cells, ArrayView slopes)` + +Computes MC2-limited slopes for primitive variables. + +**Parameters:** +- `primitive_cells`: primitive states with shape `(nx, 7)` +- `slopes`: output slopes with shape `(nx, 7)` + +#### `void reconstruct_mc2_interfaces(ConstArrayView primitive_cells, ArrayView left_states, ArrayView right_states)` + +Performs MC2 reconstruction at interfaces. -**Returns:** Pair of left and right interface states +**Parameters:** +- `primitive_cells`: primitive states with shape `(nx, 7)` +- `left_states`: left interface states with shape `(nx - 1, 7)` +- `right_states`: right interface states with shape `(nx - 1, 7)` #### `StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, double gamma)` @@ -168,27 +154,41 @@ Computes the HLLD numerical flux given left and right primitive states. **Returns:** Numerical flux vector -#### `std::vector run_full_simulation(const ProblemConfig& problem)` +#### `void compute_semidiscrete_rhs(ConstArrayView conservative_cells, ArrayView rhs, double dx, double bx = 0.75, double gamma = 2.0)` -Runs the complete simulation from initial conditions to `t_final`. +Computes the semidiscrete RHS with an explicit cell width. **Parameters:** -- `problem`: Problem configuration with initial states and parameters - -**Returns:** Final primitive state profile at `t_final` +- `conservative_cells`: conservative states with shape `(nx, 7)` +- `rhs`: output RHS with shape `(nx, 7)` +- `dx`: cell width +- `bx`: constant `Bx` +- `gamma`: adiabatic index -#### `std::vector ssp_rk3_step(const std::vector& conservative_cells, double dt, double dx, double bx, double gamma)` +#### `void ssp_rk3_step(ConstArrayView conservative_cells, ArrayView output, double dt, double dx, double bx = 0.75, double gamma = 2.0)` Performs one SSP-RK3 time step. **Parameters:** -- `conservative_cells`: Current conservative state profile -- `dt`: Time step size -- `dx`: Cell width -- `bx`: Constant x-component of magnetic field -- `gamma`: Adiabatic index +- `conservative_cells`: input conservative states with shape `(nx, 7)` +- `output`: output conservative states with shape `(nx, 7)` +- `dt`: time step +- `dx`: cell width +- `bx`: constant `Bx` +- `gamma`: adiabatic index -**Returns:** Updated conservative state profile +#### `void evolve_ssp_rk3_fixed_dt(ConstArrayView conservative_cells, ArrayView output, double t_final, double dt, double dx, double bx = 0.75, double gamma = 2.0)` + +Runs repeated SSP-RK3 updates with fixed `dt` until `t_final`. + +**Parameters:** +- `conservative_cells`: input conservative states with shape `(nx, 7)` +- `output`: output conservative states with shape `(nx, 7)` +- `t_final`: final time +- `dt`: fixed time step (final step is clipped to hit `t_final`) +- `dx`: cell width +- `bx`: constant `Bx` +- `gamma`: adiabatic index ## Evaluation diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/README.md b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/README.md index 734c8d9..38acf77 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/README.md +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/README.md @@ -1,3 +1,3 @@ -The public C++ workspace skeleton will be added next. +The public C++ workspace now contains the hardcoded Brio-Wu solver. Shared workspace docs are already mounted for this benchmark. diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/examples/brio_wu.toml b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/examples/brio_wu.toml deleted file mode 100644 index 38c3f1b..0000000 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/examples/brio_wu.toml +++ /dev/null @@ -1,28 +0,0 @@ -# Canonical Brio-Wu benchmark input for cpp-full-solver1d. - -nx = 400 -x_left = 0.0 -x_right = 1.0 -discontinuity_x = 0.5 -gamma = 2.0 -bx = 0.75 -dt = 5.0e-4 -t_final = 0.1 - -[left] -rho = 1.0 -u = 0.0 -v = 0.0 -w = 0.0 -p = 1.0 -by = 1.0 -bz = 0.0 - -[right] -rho = 0.125 -u = 0.0 -v = 0.0 -w = 0.0 -p = 0.1 -by = -1.0 -bz = 0.0 diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp index f6cd387..a23bbd2 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp @@ -1,34 +1,118 @@ #include "mhd1d.hpp" -#include #include #include -#include -int main(int argc, char** argv) +#include + +namespace +{ + +constexpr std::size_t kBrioWuNx = 400; +constexpr double kBrioWuXLeft = 0.0; +constexpr double kBrioWuXRight = 1.0; +constexpr double kBrioWuDiscontinuityX = 0.5; +constexpr double kBrioWuDt = 5.0e-4; +constexpr double kBrioWuTFinal = 0.1; +constexpr double kBrioWuGamma = 2.0; +constexpr double kBrioWuBx = 0.75; +constexpr mhd1d::StateVector kBrioWuLeftPrimitive{ + 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, +}; +constexpr mhd1d::StateVector kBrioWuRightPrimitive{ + 0.125, 0.0, 0.0, 0.0, 0.1, -1.0, 0.0, +}; + +void fill_brio_wu_initial_profile(mhd1d::ArrayView profile) { - if (argc != 2) { - std::cerr << "usage: cpp_full_solver1d \n"; - return 2; + const std::vector centers = mhd1d::cell_centers(kBrioWuNx, kBrioWuXLeft, kBrioWuXRight); + + for (std::size_t index = 0; index < centers.size(); ++index) { + const mhd1d::StateVector& state = + (centers[index] < kBrioWuDiscontinuityX) ? kBrioWuLeftPrimitive : kBrioWuRightPrimitive; + for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + profile(index, component) = state[component]; + } } +} - const std::string input_path = argv[1]; - std::ifstream input_stream(input_path); - if (!input_stream) { - std::cerr << "cpp-full-solver1d: unable to read TOML input '" << input_path << "'\n"; - return 1; +void primitive_to_conservative_profile(mhd1d::ConstArrayView primitive_cells, + mhd1d::ArrayView conservative_cells) +{ + const int nx = static_cast(primitive_cells.extent(0)); + for (int ix = 0; ix < nx; ++ix) { + const std::size_t x = static_cast(ix); + mhd1d::StateVector primitive{}; + for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + primitive[component] = primitive_cells(x, component); + } + const mhd1d::StateVector conservative = + mhd1d::primitive_to_conservative(primitive, kBrioWuBx, kBrioWuGamma); + for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + conservative_cells(x, component) = conservative[component]; + } + } +} + +void conservative_to_primitive_profile(mhd1d::ConstArrayView conservative_cells, + mhd1d::ArrayView primitive_cells) +{ + const int nx = static_cast(conservative_cells.extent(0)); + for (int ix = 0; ix < nx; ++ix) { + const std::size_t x = static_cast(ix); + mhd1d::StateVector conservative{}; + for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + conservative[component] = conservative_cells(x, component); + } + const mhd1d::StateVector primitive = + mhd1d::conservative_to_primitive(conservative, kBrioWuBx, kBrioWuGamma); + for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + primitive_cells(x, component) = primitive[component]; + } } +} + +std::vector run_brio_wu_simulation() +{ + std::vector primitive_buffer(kBrioWuNx * mhd1d::kStateWidth); + std::vector conservative_buffer(kBrioWuNx * mhd1d::kStateWidth); + std::vector final_primitive_buffer(kBrioWuNx * mhd1d::kStateWidth); + + fill_brio_wu_initial_profile( + mhd1d::ArrayView(primitive_buffer.data(), kBrioWuNx, mhd1d::kStateWidth)); + + primitive_to_conservative_profile( + mhd1d::ConstArrayView(primitive_buffer.data(), kBrioWuNx, mhd1d::kStateWidth), + mhd1d::ArrayView(conservative_buffer.data(), kBrioWuNx, mhd1d::kStateWidth)); + + const double dx = (kBrioWuXRight - kBrioWuXLeft) / static_cast(kBrioWuNx); + mhd1d::evolve_ssp_rk3_fixed_dt( + mhd1d::ConstArrayView(conservative_buffer.data(), kBrioWuNx, mhd1d::kStateWidth), + mhd1d::ArrayView(conservative_buffer.data(), kBrioWuNx, mhd1d::kStateWidth), kBrioWuTFinal, + kBrioWuDt, dx, kBrioWuBx, kBrioWuGamma); - const mhd1d::ProblemConfig problem = mhd1d::make_brio_wu_example(); - const mhd1d::StateArray2D final_primitive_cells = mhd1d::run_full_simulation(problem); - const std::vector centers = - mhd1d::cell_centers(problem.nx, problem.x_left, problem.x_right); + conservative_to_primitive_profile( + mhd1d::ConstArrayView(conservative_buffer.data(), kBrioWuNx, mhd1d::kStateWidth), + mhd1d::ArrayView(final_primitive_buffer.data(), kBrioWuNx, mhd1d::kStateWidth)); + + return final_primitive_buffer; +} + +} // namespace + +int main() +{ + const std::vector final_primitive_buffer = run_brio_wu_simulation(); + const mhd1d::ConstArrayView final_primitive_cells(final_primitive_buffer.data(), kBrioWuNx, + mhd1d::kStateWidth); + const std::vector centers = mhd1d::cell_centers(kBrioWuNx, kBrioWuXLeft, kBrioWuXRight); std::cout << "x,rho,u,v,w,p,by,bz\n"; std::cout << std::setprecision(17); - for (std::size_t index = 0; index < final_primitive_cells.rows(); ++index) { - const mhd1d::StateVector cell = final_primitive_cells.load(index); - std::cout << centers[index] << ',' << cell[0] << ',' << cell[1] << ',' << cell[2] << ',' - << cell[3] << ',' << cell[4] << ',' << cell[5] << ',' << cell[6] << '\n'; + for (std::size_t index = 0; index < kBrioWuNx; ++index) { + std::cout << centers[index] << ',' << final_primitive_cells(index, 0) << ',' + << final_primitive_cells(index, 1) << ',' << final_primitive_cells(index, 2) << ',' + << final_primitive_cells(index, 3) << ',' << final_primitive_cells(index, 4) << ',' + << final_primitive_cells(index, 5) << ',' << final_primitive_cells(index, 6) << '\n'; } return 0; diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp index fb95b5e..bf385f0 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -12,18 +11,11 @@ namespace mhd1d namespace { -constexpr double kDefaultGamma = 2.0; -constexpr double kDefaultBx = 0.75; -constexpr double kDefaultDt = 5.0e-4; -constexpr double kDefaultTFinal = 0.1; -constexpr std::size_t kDefaultNx = 400; -constexpr std::size_t kGhostWidth = 2U; -constexpr double kHlldEps = 1.0e-40; +constexpr double kHlldEps = 1.0e-40; +constexpr int kGhost = static_cast(kGhostWidth); -double sign_unit(double x) -{ - return (x >= 0.0) ? 1.0 : -1.0; -} +using ArrayView = stdex::mdspan>; +using ConstArrayView = stdex::mdspan>; double minmod3(double first, double second, double third) { @@ -35,132 +27,185 @@ double minmod3(double first, double second, double third) return 0.0; } -StateArray2D conservative_profile_to_primitive_profile(const StateArray2D& conservative_cells, - double bx, double gamma) +StateVector row_to_state(ConstArrayView cells, std::size_t row) { - StateArray2D primitive_cells(conservative_cells.rows()); - for (std::size_t index = 0; index < conservative_cells.rows(); ++index) { - primitive_cells.store(index, - conservative_to_primitive(conservative_cells.load(index), bx, gamma)); + StateVector state{}; + for (std::size_t component = 0; component < kStateWidth; ++component) { + state[component] = cells(row, component); } - - return primitive_cells; + return state; } -} // namespace - -StateArray2D::StateArray2D() : buffer(), view_() +void state_to_row(const StateVector& state, ArrayView cells, std::size_t row) { + for (std::size_t component = 0; component < kStateWidth; ++component) { + cells(row, component) = state[component]; + } } -StateArray2D::StateArray2D(std::size_t rows) : buffer(rows * kStateWidth, 0.0), view_() +void conservative_profile_to_primitive_profile_inplace(ConstArrayView conservative_cells, + ArrayView primitive_cells, double bx, + double gamma) { - rebind_view(); + const int nx = static_cast(conservative_cells.extent(0)); + for (int ix = 0; ix < nx; ++ix) { + const std::size_t x = static_cast(ix); + const StateVector primitive = + conservative_to_primitive(row_to_state(conservative_cells, x), bx, gamma); + state_to_row(primitive, primitive_cells, x); + } } -StateArray2D::StateArray2D(const StateArray2D& other) : buffer(other.buffer), view_() +void pad_zero_gradient_ghost_cells_inplace(ConstArrayView cells, ArrayView padded) { - rebind_view(); -} + const int nx = static_cast(cells.extent(0)); + const int padded_nx = static_cast(padded.extent(0)); -StateArray2D::StateArray2D(StateArray2D&& other) noexcept : buffer(std::move(other.buffer)), view_() -{ - rebind_view(); - other.rebind_view(); -} + for (int ghost = 0; ghost < kGhost; ++ghost) { + const std::size_t g = static_cast(ghost); + for (std::size_t component = 0; component < kStateWidth; ++component) { + padded(g, component) = cells(0U, component); + padded(static_cast(padded_nx - 1 - ghost), component) = + cells(static_cast(nx - 1), component); + } + } -StateArray2D& StateArray2D::operator=(const StateArray2D& other) -{ - if (this != &other) { - buffer = other.buffer; - rebind_view(); + for (int ix = 0; ix < nx; ++ix) { + const std::size_t src = static_cast(ix); + const std::size_t dst = static_cast(kGhost + ix); + for (std::size_t component = 0; component < kStateWidth; ++component) { + padded(dst, component) = cells(src, component); + } } - return *this; } -StateArray2D& StateArray2D::operator=(StateArray2D&& other) noexcept +void mc2_slopes_inplace(ConstArrayView primitive_cells, ArrayView slopes) { - if (this != &other) { - buffer = std::move(other.buffer); - rebind_view(); - other.rebind_view(); + const int nx = static_cast(primitive_cells.extent(0)); + + for (int ix = 0; ix < nx; ++ix) { + const std::size_t x = static_cast(ix); + for (std::size_t component = 0; component < kStateWidth; ++component) { + slopes(x, component) = 0.0; + } } - return *this; -} -std::size_t StateArray2D::rows() const -{ - return buffer.size() / kStateWidth; + for (int ix = 1; ix <= nx - 2; ++ix) { + const std::size_t x = static_cast(ix); + for (std::size_t component = 0; component < kStateWidth; ++component) { + const double left_difference = primitive_cells(x, component) - + primitive_cells(static_cast(ix - 1), component); + const double right_difference = primitive_cells(static_cast(ix + 1), component) - + primitive_cells(x, component); + const double centered_difference = + 0.5 * (primitive_cells(static_cast(ix + 1), component) - + primitive_cells(static_cast(ix - 1), component)); + slopes(x, component) = + minmod3(2.0 * left_difference, centered_difference, 2.0 * right_difference); + } + } } -std::size_t StateArray2D::cols() const +void reconstruct_mc2_interfaces_inplace(ConstArrayView primitive_cells, ConstArrayView slopes, + ArrayView left_states, ArrayView right_states) { - return kStateWidth; + const int interface_count = static_cast(primitive_cells.extent(0) - 1U); + for (int ix = 0; ix < interface_count; ++ix) { + const std::size_t x = static_cast(ix); + for (std::size_t component = 0; component < kStateWidth; ++component) { + left_states(x, component) = primitive_cells(x, component) + 0.5 * slopes(x, component); + right_states(x, component) = primitive_cells(static_cast(ix + 1), component) - + 0.5 * slopes(static_cast(ix + 1), component); + } + } } -double* StateArray2D::row_data(std::size_t row) +void copy_cells(ConstArrayView source, ArrayView destination) { - return buffer.data() + row * kStateWidth; + const int nx = static_cast(source.extent(0)); + for (int ix = 0; ix < nx; ++ix) { + const std::size_t x = static_cast(ix); + for (std::size_t component = 0; component < kStateWidth; ++component) { + destination(x, component) = source(x, component); + } + } } -const double* StateArray2D::row_data(std::size_t row) const +void compute_semidiscrete_rhs_inplace(ConstArrayView conservative_cells, double dx, double bx, + double gamma, SolverWorkspace& workspace, ArrayView rhs) { - return buffer.data() + row * kStateWidth; -} + const ArrayView padded_conservative = workspace.conservative; + const ArrayView padded_primitive = workspace.primitive; + const ArrayView slopes = workspace.slopes; + const ArrayView left_interface = workspace.primitive_left; + const ArrayView right_interface = workspace.primitive_right; -StateVector StateArray2D::load(std::size_t row) const -{ - StateVector state{}; - std::memcpy(state.data(), row_data(row), sizeof(double) * kStateWidth); - return state; -} + pad_zero_gradient_ghost_cells_inplace(conservative_cells, padded_conservative); + conservative_profile_to_primitive_profile_inplace(padded_conservative, padded_primitive, bx, + gamma); + mc2_slopes_inplace(padded_primitive, slopes); + reconstruct_mc2_interfaces_inplace(padded_primitive, slopes, left_interface, right_interface); -void StateArray2D::store(std::size_t row, const StateVector& state) -{ - std::memcpy(row_data(row), state.data(), sizeof(double) * kStateWidth); -} + const int lbx = static_cast(workspace.Lbx); + const int ubx = static_cast(workspace.Ubx); + for (int ix = lbx; ix <= ubx; ++ix) { + const std::size_t i = static_cast(ix - lbx); + const std::size_t x = static_cast(ix); -double& StateArray2D::operator()(std::size_t row, std::size_t col) -{ - return view_(row, col); + const StateVector right_flux = hlld_flux_from_primitive( + row_to_state(left_interface, x), row_to_state(right_interface, x), bx, gamma); + const StateVector left_flux = hlld_flux_from_primitive( + row_to_state(left_interface, x - 1U), row_to_state(right_interface, x - 1U), bx, gamma); + for (std::size_t component = 0; component < kStateWidth; ++component) { + rhs(i, component) = -(right_flux[component] - left_flux[component]) / dx; + } + } } -const double& StateArray2D::operator()(std::size_t row, std::size_t col) const +void ssp_rk3_step_inplace(ConstArrayView conservative_cells, double dt, double dx, double bx, + double gamma, SolverWorkspace& workspace, ArrayView output) { - return view_(row, col); -} + const ArrayView first_stage = workspace.stage1; + const ArrayView second_stage = workspace.stage2; + const ArrayView first_rhs = workspace.rhs1; + const ArrayView second_rhs = workspace.rhs2; + const ArrayView third_rhs = workspace.rhs3; -StateView StateArray2D::view() -{ - return view_; -} + copy_cells(conservative_cells, first_stage); + compute_semidiscrete_rhs_inplace(conservative_cells, dx, bx, gamma, workspace, first_rhs); + const int lbx = static_cast(workspace.Lbx); + const int ubx = static_cast(workspace.Ubx); -ConstStateView StateArray2D::view() const -{ - return ConstStateView(buffer.data(), rows(), kStateWidth); -} + for (int ix = lbx; ix <= ubx; ++ix) { + const std::size_t i = static_cast(ix - lbx); + for (std::size_t component = 0; component < kStateWidth; ++component) { + first_stage(i, component) += dt * first_rhs(i, component); + } + } -void StateArray2D::rebind_view() -{ - view_ = StateView(buffer.data(), rows(), kStateWidth); -} + compute_semidiscrete_rhs_inplace(first_stage, dx, bx, gamma, workspace, second_rhs); + for (int ix = lbx; ix <= ubx; ++ix) { + const std::size_t i = static_cast(ix - lbx); + for (std::size_t component = 0; component < kStateWidth; ++component) { + second_stage(i, component) = + 0.75 * conservative_cells(i, component) + + 0.25 * (first_stage(i, component) + dt * second_rhs(i, component)); + } + } -ProblemConfig make_brio_wu_example() -{ - return ProblemConfig{ - kDefaultNx, - 0.0, - 1.0, - 0.5, - kDefaultDt, - kDefaultTFinal, - kDefaultGamma, - kDefaultBx, - StateVector{1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0}, - StateVector{0.125, 0.0, 0.0, 0.0, 0.1, -1.0, 0.0}, - }; + compute_semidiscrete_rhs_inplace(second_stage, dx, bx, gamma, workspace, third_rhs); + for (int ix = lbx; ix <= ubx; ++ix) { + const std::size_t i = static_cast(ix - lbx); + for (std::size_t component = 0; component < kStateWidth; ++component) { + output(i, component) = + (1.0 / 3.0) * conservative_cells(i, component) + + (2.0 / 3.0) * (second_stage(i, component) + dt * third_rhs(i, component)); + } + } } +} // namespace + StateVector primitive_to_conservative(const StateVector& primitive, double bx, double gamma) { const double rho = primitive[0]; @@ -200,48 +245,27 @@ StateVector conservative_to_primitive(const StateVector& conservative, double bx return StateVector{rho, u, v, w, pressure, by, bz}; } -StateArray2D mc2_slopes(const StateArray2D& primitive_cells) +void mc2_slopes(ConstArrayView primitive_cells, ArrayView slopes) { - if (primitive_cells.rows() < 3U) { + if (primitive_cells.extent(0) < 3U) { throw std::runtime_error("primitive_cells must contain at least three cells"); } - StateArray2D slopes(primitive_cells.rows()); - for (std::size_t index = 1; index + 1U < primitive_cells.rows(); ++index) { - for (std::size_t component = 0; component < kStateWidth; ++component) { - const double left_difference = - primitive_cells(index, component) - primitive_cells(index - 1U, component); - const double right_difference = - primitive_cells(index + 1U, component) - primitive_cells(index, component); - const double centered_difference = - 0.5 * (primitive_cells(index + 1U, component) - primitive_cells(index - 1U, component)); - slopes(index, component) = - minmod3(2.0 * left_difference, centered_difference, 2.0 * right_difference); - } - } - - return slopes; + mc2_slopes_inplace(primitive_cells, slopes); } -std::pair -reconstruct_mc2_interfaces(const StateArray2D& primitive_cells) +void reconstruct_mc2_interfaces(ConstArrayView primitive_cells, ArrayView left_states, + ArrayView right_states) { - const StateArray2D slopes = mc2_slopes(primitive_cells); - const std::size_t interface_count = primitive_cells.rows() - 1U; - - StateArray2D left_states(interface_count); - StateArray2D right_states(interface_count); - - for (std::size_t index = 0; index < interface_count; ++index) { - for (std::size_t component = 0; component < kStateWidth; ++component) { - left_states(index, component) = - primitive_cells(index, component) + 0.5 * slopes(index, component); - right_states(index, component) = - primitive_cells(index + 1U, component) - 0.5 * slopes(index + 1U, component); - } + if (primitive_cells.extent(0) < 2U) { + throw std::runtime_error("primitive_cells must contain at least two cells"); } - return {left_states, right_states}; + const std::size_t interface_count = primitive_cells.extent(0) - 1U; + std::vector slopes_buffer(primitive_cells.extent(0) * kStateWidth, 0.0); + ArrayView slopes(slopes_buffer.data(), primitive_cells.extent(0), kStateWidth); + mc2_slopes_inplace(primitive_cells, slopes); + reconstruct_mc2_interfaces_inplace(primitive_cells, slopes, left_states, right_states); } StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, @@ -323,7 +347,7 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& const double ptst = (rosdr * ptl - rosdl * ptr + rosdl * rosdr * (vxr - vxl)) * temp; const double temp_fst_l = rosdl * sdml - bxsq; - const double sign1_l = sign_unit(std::abs(temp_fst_l) - kHlldEps); + const double sign1_l = std::copysign(1.0, std::abs(temp_fst_l) - kHlldEps); const double maxs1_l = std::max(0.0, sign1_l); const double mins1_l = std::min(0.0, sign1_l); const double itf_l = 1.0 / (temp_fst_l + mins1_l); @@ -347,7 +371,7 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& mins1_l * eel; const double temp_fst_r = rosdr * sdmr - bxsq; - const double sign1_r = sign_unit(std::abs(temp_fst_r) - kHlldEps); + const double sign1_r = std::copysign(1.0, std::abs(temp_fst_r) - kHlldEps); const double maxs1_r = std::max(0.0, sign1_r); const double mins1_r = std::min(0.0, sign1_r); const double itf_r = 1.0 / (temp_fst_r + mins1_r); @@ -375,8 +399,8 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& const double abbx = std::abs(bxs); const double slst = sm - abbx / sqrtrol; const double srst = sm + abbx / sqrtror; - const double signbx = sign_unit(bxs); - const double sign1_b = sign_unit(abbx - kHlldEps); + const double signbx = std::copysign(1.0, bxs); + const double sign1_b = std::copysign(1.0, abbx - kHlldEps); const double maxs1_b = std::max(0.0, sign1_b); const double mins1_b = -std::min(0.0, sign1_b); const double invsumro = maxs1_b / (sqrtrol + sqrtror); @@ -414,7 +438,7 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& const double eeldst = eelst - sqrtrol * signbx * (vdbstl - temp_dst) * maxs1_b; const double eerdst = eerst + sqrtror * signbx * (vdbstr - temp_dst) * maxs1_b; - const double sign1 = sign_unit(sm); + const double sign1 = std::copysign(1.0, sm); const double maxs1 = std::max(0.0, sign1); const double mins1 = -std::min(0.0, sign1); const double msl = std::min(sl, 0.0); @@ -442,21 +466,24 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& }; } -StateArray2D pad_zero_gradient_ghost_cells(const StateArray2D& cells) +void pad_zero_gradient_ghost_cells(ConstArrayView cells, ArrayView padded) { - if (cells.rows() == 0U) { - return {}; + if (cells.extent(0) == 0U) { + return; } - StateArray2D padded(cells.rows() + 2U * kGhostWidth); for (std::size_t ghost = 0; ghost < kGhostWidth; ++ghost) { - padded.store(ghost, cells.load(0)); - padded.store(padded.rows() - 1U - ghost, cells.load(cells.rows() - 1U)); + for (std::size_t component = 0; component < kStateWidth; ++component) { + padded(ghost, component) = cells(0, component); + padded(padded.extent(0) - 1U - ghost, component) = cells(cells.extent(0) - 1U, component); + } } - for (std::size_t index = 0; index < cells.rows(); ++index) { - padded.store(index + kGhostWidth, cells.load(index)); + + for (std::size_t index = 0; index < cells.extent(0); ++index) { + for (std::size_t component = 0; component < kStateWidth; ++component) { + padded(index + kGhostWidth, component) = cells(index, component); + } } - return padded; } std::vector cell_centers(std::size_t nx, double x_left, double x_right) @@ -478,179 +505,50 @@ std::vector cell_centers(std::size_t nx, double x_left, double x_right) return centers; } -StateArray2D brio_wu_initial_profile(const ProblemConfig& problem) +void compute_semidiscrete_rhs(ConstArrayView conservative_cells, ArrayView rhs, double dx, + double bx, double gamma) { - const std::vector centers = cell_centers(problem.nx, problem.x_left, problem.x_right); - StateArray2D profile(problem.nx); - - for (std::size_t index = 0; index < centers.size(); ++index) { - profile.store(index, (centers[index] < problem.discontinuity_x) ? problem.left_primitive - : problem.right_primitive); - } - - return profile; + SolverWorkspace workspace(conservative_cells.extent(0)); + compute_semidiscrete_rhs_inplace(conservative_cells, dx, bx, gamma, workspace, rhs); } -StateArray2D run_full_simulation(const ProblemConfig& problem) +void ssp_rk3_step(ConstArrayView conservative_cells, ArrayView output, double dt, double dx, + double bx, double gamma) { - if (problem.nx == 0U) { - return {}; - } - - const StateArray2D initial_primitive_profile = brio_wu_initial_profile(problem); - StateArray2D conservative_cells(initial_primitive_profile.rows()); - for (std::size_t index = 0; index < initial_primitive_profile.rows(); ++index) { - conservative_cells.store(index, primitive_to_conservative(initial_primitive_profile.load(index), - problem.bx, problem.gamma)); - } - - const double dx = (problem.x_right - problem.x_left) / static_cast(problem.nx); - const StateArray2D evolved_conservative_cells = evolve_ssp_rk3_fixed_dt( - conservative_cells, problem.t_final, problem.dt, dx, problem.bx, problem.gamma); - - StateArray2D final_primitive_profile(evolved_conservative_cells.rows()); - for (std::size_t index = 0; index < evolved_conservative_cells.rows(); ++index) { - final_primitive_profile.store(index, - conservative_to_primitive(evolved_conservative_cells.load(index), - problem.bx, problem.gamma)); - } - - return final_primitive_profile; + SolverWorkspace workspace(conservative_cells.extent(0)); + ssp_rk3_step_inplace(conservative_cells, dt, dx, bx, gamma, workspace, output); } -StateArray2D compute_semidiscrete_rhs(const StateArray2D& conservative_cells, double bx, - double gamma) +void evolve_ssp_rk3_fixed_dt(ConstArrayView conservative_cells, ArrayView output, double t_final, + double dt, double dx, double bx, double gamma) { - if (conservative_cells.rows() == 0U) { - throw std::runtime_error("conservative_cells must contain at least one cell"); + if (conservative_cells.extent(0) == 0U || t_final < 0.0 || dt <= 0.0) { + copy_cells(conservative_cells, output); + return; } - const double dx = 1.0 / static_cast(conservative_cells.rows()); - return compute_semidiscrete_rhs(conservative_cells, dx, bx, gamma); -} + const std::size_t state_size = conservative_cells.extent(0) * kStateWidth; + std::vector evolved_buffer(state_size); + std::vector stage_buffer(state_size); -StateArray2D compute_semidiscrete_rhs(const StateArray2D& conservative_cells, double dx, double bx, - double gamma) -{ - if (conservative_cells.rows() == 0U) { - throw std::runtime_error("conservative_cells must contain at least one cell"); - } + ArrayView evolved_state(evolved_buffer.data(), conservative_cells.extent(0), kStateWidth); + ArrayView stage_state(stage_buffer.data(), conservative_cells.extent(0), kStateWidth); - if (dx <= 0.0) { - throw std::runtime_error("dx must be positive"); - } - - const StateArray2D padded_conservative = pad_zero_gradient_ghost_cells(conservative_cells); - const StateArray2D padded_primitive = - conservative_profile_to_primitive_profile(padded_conservative, bx, gamma); - const auto [left_interface_states, right_interface_states] = - reconstruct_mc2_interfaces(padded_primitive); - - StateArray2D rhs(conservative_cells.rows()); - for (std::size_t index = 0; index < conservative_cells.rows(); ++index) { - const StateVector right_flux = - hlld_flux_from_primitive(left_interface_states.load(index + kGhostWidth), - right_interface_states.load(index + kGhostWidth), bx, gamma); - const StateVector left_flux = - hlld_flux_from_primitive(left_interface_states.load(index + kGhostWidth - 1U), - right_interface_states.load(index + kGhostWidth - 1U), bx, gamma); - for (std::size_t component = 0; component < kStateWidth; ++component) { - rhs(index, component) = -(right_flux[component] - left_flux[component]) / dx; - } - } - - return rhs; -} - -StateArray2D ssp_rk3_step(const StateArray2D& conservative_cells, double dt, double bx, - double gamma) -{ - if (conservative_cells.rows() == 0U) { - throw std::runtime_error("conservative_cells must contain at least one cell"); - } - - const double dx = 1.0 / static_cast(conservative_cells.rows()); - return ssp_rk3_step(conservative_cells, dt, dx, bx, gamma); -} - -StateArray2D ssp_rk3_step(const StateArray2D& conservative_cells, double dt, double dx, double bx, - double gamma) -{ - if (conservative_cells.rows() == 0U) { - throw std::runtime_error("conservative_cells must contain at least one cell"); - } - - if (dt <= 0.0) { - throw std::runtime_error("dt must be positive"); - } - - StateArray2D first_stage = conservative_cells; - const StateArray2D first_rhs = compute_semidiscrete_rhs(conservative_cells, dx, bx, gamma); - for (std::size_t index = 0; index < first_stage.rows(); ++index) { - for (std::size_t component = 0; component < kStateWidth; ++component) { - first_stage(index, component) += dt * first_rhs(index, component); - } - } - - StateArray2D second_stage = conservative_cells; - const StateArray2D second_rhs = compute_semidiscrete_rhs(first_stage, dx, bx, gamma); - for (std::size_t index = 0; index < second_stage.rows(); ++index) { - for (std::size_t component = 0; component < kStateWidth; ++component) { - second_stage(index, component) = - 0.75 * conservative_cells(index, component) + - 0.25 * (first_stage(index, component) + dt * second_rhs(index, component)); - } - } - - const StateArray2D third_rhs = compute_semidiscrete_rhs(second_stage, dx, bx, gamma); - StateArray2D next_stage = conservative_cells; - for (std::size_t index = 0; index < next_stage.rows(); ++index) { - for (std::size_t component = 0; component < kStateWidth; ++component) { - next_stage(index, component) = - (1.0 / 3.0) * conservative_cells(index, component) + - (2.0 / 3.0) * (second_stage(index, component) + dt * third_rhs(index, component)); - } - } - - return next_stage; -} - -StateArray2D evolve_ssp_rk3_fixed_dt(const StateArray2D& conservative_cells, double t_final, - double dt, double bx, double gamma) -{ - if (conservative_cells.rows() == 0U) { - throw std::runtime_error("conservative_cells must contain at least one cell"); - } - - const double dx = 1.0 / static_cast(conservative_cells.rows()); - return evolve_ssp_rk3_fixed_dt(conservative_cells, t_final, dt, dx, bx, gamma); -} - -StateArray2D evolve_ssp_rk3_fixed_dt(const StateArray2D& conservative_cells, double t_final, - double dt, double dx, double bx, double gamma) -{ - if (conservative_cells.rows() == 0U) { - throw std::runtime_error("conservative_cells must contain at least one cell"); - } - - if (t_final < 0.0) { - throw std::runtime_error("t_final must be non-negative"); - } - - if (dt <= 0.0) { - throw std::runtime_error("dt must be positive"); - } + copy_cells(conservative_cells, evolved_state); - StateArray2D evolved_state = conservative_cells; - double elapsed_time = 0.0; + SolverWorkspace workspace(conservative_cells.extent(0)); + double elapsed_time = 0.0; while (elapsed_time < t_final) { const double remaining_time = t_final - elapsed_time; const double step_dt = std::min(dt, remaining_time); - evolved_state = ssp_rk3_step(evolved_state, step_dt, dx, bx, gamma); - elapsed_time = (step_dt < dt) ? t_final : (elapsed_time + step_dt); + ssp_rk3_step_inplace(evolved_state, step_dt, dx, bx, gamma, workspace, stage_state); + std::swap(evolved_buffer, stage_buffer); + evolved_state = ArrayView(evolved_buffer.data(), conservative_cells.extent(0), kStateWidth); + stage_state = ArrayView(stage_buffer.data(), conservative_cells.extent(0), kStateWidth); + elapsed_time = (step_dt < dt) ? t_final : (elapsed_time + step_dt); } - return evolved_state; + copy_cells(evolved_state, output); } } // namespace mhd1d diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp index 24aeabb..e9dd2b9 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp @@ -2,105 +2,112 @@ #include #include -#include #include #include +#include + namespace mhd1d { namespace stdex = std::experimental; constexpr std::size_t kStateWidth = 7; +constexpr std::size_t kGhostWidth = 2; using StateVector = std::array; -using StateExtents = stdex::dextents; -using StateView = stdex::mdspan; -using ConstStateView = stdex::mdspan; - -struct StateArray2D { - StateArray2D(); - explicit StateArray2D(std::size_t rows); - - StateArray2D(const StateArray2D& other); - StateArray2D(StateArray2D&& other) noexcept; - StateArray2D& operator=(const StateArray2D& other); - StateArray2D& operator=(StateArray2D&& other) noexcept; - - [[nodiscard]] std::size_t rows() const; - [[nodiscard]] std::size_t cols() const; - - [[nodiscard]] double* row_data(std::size_t row); - [[nodiscard]] const double* row_data(std::size_t row) const; - - [[nodiscard]] StateVector load(std::size_t row) const; - void store(std::size_t row, const StateVector& state); - - double& operator()(std::size_t row, std::size_t col); - const double& operator()(std::size_t row, std::size_t col) const; - - [[nodiscard]] StateView view(); - [[nodiscard]] ConstStateView view() const; - - std::vector buffer; - -private: - void rebind_view(); - - StateView view_; +using ArrayView = stdex::mdspan>; +using ConstArrayView = stdex::mdspan>; + +struct SolverWorkspace { + explicit SolverWorkspace(std::size_t nx) : Nx(nx), Lbx(kGhostWidth), Ubx(kGhostWidth + nx - 1U) + { + const std::size_t Nx_total = Nx + 2U * kGhostWidth; + const std::size_t interface_n = Nx_total - 1U; + const std::size_t padded_size = Nx_total * kStateWidth; + const std::size_t state_size = Nx * kStateWidth; + + buf_conservative.resize(padded_size); + buf_primitive.resize(padded_size); + buf_slopes.resize(padded_size); + buf_primitive_left.resize(interface_n * kStateWidth); + buf_primitive_right.resize(interface_n * kStateWidth); + buf_rhs1.resize(state_size); + buf_rhs2.resize(state_size); + buf_rhs3.resize(state_size); + buf_stage1.resize(state_size); + buf_stage2.resize(state_size); + buf_stage3.resize(state_size); + + conservative = ArrayView(buf_conservative.data(), Nx_total, kStateWidth); + primitive = ArrayView(buf_primitive.data(), Nx_total, kStateWidth); + slopes = ArrayView(buf_slopes.data(), Nx_total, kStateWidth); + primitive_left = ArrayView(buf_primitive_left.data(), interface_n, kStateWidth); + primitive_right = ArrayView(buf_primitive_right.data(), interface_n, kStateWidth); + rhs1 = ArrayView(buf_rhs1.data(), Nx, kStateWidth); + rhs2 = ArrayView(buf_rhs2.data(), Nx, kStateWidth); + rhs3 = ArrayView(buf_rhs3.data(), Nx, kStateWidth); + stage1 = ArrayView(buf_stage1.data(), Nx, kStateWidth); + stage2 = ArrayView(buf_stage2.data(), Nx, kStateWidth); + stage3 = ArrayView(buf_stage3.data(), Nx, kStateWidth); + } + + using ArrayView = stdex::mdspan>; + + std::size_t Nx; // number of grids for the physical domain (excluding the ghost cells) + std::size_t Lbx; // lower bound of the physical domain in padded indexing + std::size_t Ubx; // upper bound of the physical domain in padded indexing + + // buffer + std::vector buf_conservative; + std::vector buf_primitive; + std::vector buf_slopes; + std::vector buf_primitive_left; + std::vector buf_primitive_right; + std::vector buf_rhs1; + std::vector buf_rhs2; + std::vector buf_rhs3; + std::vector buf_stage1; + std::vector buf_stage2; + std::vector buf_stage3; + + // view + ArrayView conservative; + ArrayView primitive; + ArrayView slopes; + ArrayView primitive_left; + ArrayView primitive_right; + ArrayView rhs1; + ArrayView rhs2; + ArrayView rhs3; + ArrayView stage1; + ArrayView stage2; + ArrayView stage3; }; -struct ProblemConfig { - std::size_t nx = 0; - double x_left = 0.0; - double x_right = 1.0; - double discontinuity_x = 0.5; - double dt = 0.0; - double t_final = 0.0; - double gamma = 0.0; - double bx = 0.0; - StateVector left_primitive{}; - StateVector right_primitive{}; -}; - -ProblemConfig make_brio_wu_example(); - StateVector primitive_to_conservative(const StateVector& primitive, double bx, double gamma); StateVector conservative_to_primitive(const StateVector& conservative, double bx, double gamma); -StateArray2D mc2_slopes(const StateArray2D& primitive_cells); - -std::pair -reconstruct_mc2_interfaces(const StateArray2D& primitive_cells); - StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, double gamma); std::vector cell_centers(std::size_t nx, double x_left, double x_right); -StateArray2D pad_zero_gradient_ghost_cells(const StateArray2D& cells); - -StateArray2D brio_wu_initial_profile(const ProblemConfig& problem); - -StateArray2D run_full_simulation(const ProblemConfig& problem); - -StateArray2D compute_semidiscrete_rhs(const StateArray2D& conservative_cells, double bx = 0.75, - double gamma = 2.0); +void pad_zero_gradient_ghost_cells(ConstArrayView cells, ArrayView padded); -StateArray2D compute_semidiscrete_rhs(const StateArray2D& conservative_cells, double dx, double bx, - double gamma); +void mc2_slopes(ConstArrayView primitive_cells, ArrayView slopes); -StateArray2D ssp_rk3_step(const StateArray2D& conservative_cells, double dt, double bx = 0.75, - double gamma = 2.0); +void reconstruct_mc2_interfaces(ConstArrayView primitive_cells, ArrayView left_states, + ArrayView right_states); -StateArray2D ssp_rk3_step(const StateArray2D& conservative_cells, double dt, double dx, double bx, - double gamma); +void compute_semidiscrete_rhs(ConstArrayView conservative_cells, ArrayView rhs, double dx, + double bx = 0.75, double gamma = 2.0); -StateArray2D evolve_ssp_rk3_fixed_dt(const StateArray2D& conservative_cells, double t_final, - double dt, double bx = 0.75, double gamma = 2.0); +void ssp_rk3_step(ConstArrayView conservative_cells, ArrayView output, double dt, double dx, + double bx = 0.75, double gamma = 2.0); -StateArray2D evolve_ssp_rk3_fixed_dt(const StateArray2D& conservative_cells, double t_final, - double dt, double dx, double bx, double gamma); +void evolve_ssp_rk3_fixed_dt(ConstArrayView conservative_cells, ArrayView output, double t_final, + double dt, double dx, double bx = 0.75, double gamma = 2.0); } // namespace mhd1d diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp index a5c6d9e..cf4177b 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp @@ -10,6 +10,22 @@ namespace constexpr double kTolerance = 1.0e-12; +mhd1d::StateVector row_to_state(mhd1d::ConstArrayView cells, std::size_t row) +{ + mhd1d::StateVector state{}; + for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + state[component] = cells(row, component); + } + return state; +} + +void state_to_row(mhd1d::ArrayView cells, std::size_t row, const mhd1d::StateVector& state) +{ + for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + cells(row, component) = state[component]; + } +} + void require_state_vector_close(const mhd1d::StateVector& actual, const mhd1d::StateVector& expected) { @@ -57,37 +73,43 @@ TEST_CASE("primitive and conservative states round-trip", "[mhd1d][conversion]") TEST_CASE("mc2_slopes preserve a constant primitive state", "[mhd1d][reconstruction]") { const auto constant_state = mhd1d::StateVector{1.25, -0.5, 0.25, -0.125, 2.75, 0.4, -0.3}; - mhd1d::StateArray2D cells(4); - for (std::size_t index = 0; index < cells.rows(); ++index) { - cells.store(index, constant_state); + std::vector cells_buffer(4 * mhd1d::kStateWidth, 0.0); + const mhd1d::ArrayView cells(cells_buffer.data(), 4, mhd1d::kStateWidth); + for (std::size_t index = 0; index < 4; ++index) { + state_to_row(cells, index, constant_state); } - const auto slopes = mhd1d::mc2_slopes(cells); + std::vector slopes_buffer(4 * mhd1d::kStateWidth, 0.0); + const mhd1d::ArrayView slopes(slopes_buffer.data(), 4, mhd1d::kStateWidth); + mhd1d::mc2_slopes(mhd1d::ConstArrayView(cells_buffer.data(), 4, mhd1d::kStateWidth), slopes); - REQUIRE(slopes.rows() == cells.rows()); - for (std::size_t index = 0; index < slopes.rows(); ++index) { - require_state_vector_close(slopes.load(index), mhd1d::StateVector{}); + for (std::size_t index = 0; index < 4; ++index) { + require_state_vector_close(row_to_state(slopes, index), mhd1d::StateVector{}); } } TEST_CASE("reconstruct_mc2_interfaces preserves a constant primitive state exactly", "[mhd1d][reconstruction]") { - const auto constant_state = mhd1d::StateVector{0.9, 0.3, -0.2, 0.1, 1.8, -0.45, 0.6}; - mhd1d::StateArray2D cells(4); - for (std::size_t index = 0; index < cells.rows(); ++index) { - cells.store(index, constant_state); + const auto constant_state = mhd1d::StateVector{0.9, 0.3, -0.2, 0.1, 1.8, -0.45, 0.6}; + std::vector cells_buffer(4 * mhd1d::kStateWidth, 0.0); + const mhd1d::ArrayView cells(cells_buffer.data(), 4, mhd1d::kStateWidth); + for (std::size_t index = 0; index < 4; ++index) { + state_to_row(cells, index, constant_state); } - const auto [left_states, right_states] = mhd1d::reconstruct_mc2_interfaces(cells); + std::vector left_buffer(3 * mhd1d::kStateWidth, 0.0); + std::vector right_buffer(3 * mhd1d::kStateWidth, 0.0); + const mhd1d::ArrayView left_states(left_buffer.data(), 3, mhd1d::kStateWidth); + const mhd1d::ArrayView right_states(right_buffer.data(), 3, mhd1d::kStateWidth); + mhd1d::reconstruct_mc2_interfaces( + mhd1d::ConstArrayView(cells_buffer.data(), 4, mhd1d::kStateWidth), left_states, right_states); - REQUIRE(left_states.rows() == cells.rows() - 1U); - REQUIRE(right_states.rows() == cells.rows() - 1U); - for (std::size_t index = 0; index < left_states.rows(); ++index) { - require_state_vector_close(left_states.load(index), constant_state); + for (std::size_t index = 0; index < 3; ++index) { + require_state_vector_close(row_to_state(left_states, index), constant_state); } - for (std::size_t index = 0; index < right_states.rows(); ++index) { - require_state_vector_close(right_states.load(index), constant_state); + for (std::size_t index = 0; index < 3; ++index) { + require_state_vector_close(row_to_state(right_states, index), constant_state); } } @@ -126,44 +148,124 @@ TEST_CASE("hlld_flux_from_primitive matches the physical flux for identical stat TEST_CASE("pad_zero_gradient_ghost_cells duplicates edge states on both sides", "[mhd1d][boundary]") { - mhd1d::StateArray2D cells(3); - cells.store(0, mhd1d::StateVector{1.0, 0.5, -0.25, 0.125, 2.0, 0.1, -0.05}); - cells.store(1, mhd1d::StateVector{1.2, 0.6, -0.2, 0.15, 2.2, 0.12, -0.02}); - cells.store(2, mhd1d::StateVector{1.4, 0.7, -0.15, 0.175, 2.4, 0.14, 0.01}); - - const auto padded = mhd1d::pad_zero_gradient_ghost_cells(cells); - - REQUIRE(padded.rows() == cells.rows() + 4U); - require_state_vector_close(padded.load(0), cells.load(0)); - require_state_vector_close(padded.load(1), cells.load(0)); - require_state_vector_close(padded.load(2), cells.load(0)); - require_state_vector_close(padded.load(3), cells.load(1)); - require_state_vector_close(padded.load(4), cells.load(2)); - require_state_vector_close(padded.load(5), cells.load(2)); - require_state_vector_close(padded.load(6), cells.load(2)); + std::vector cells_buffer(3 * mhd1d::kStateWidth, 0.0); + const mhd1d::ArrayView cells(cells_buffer.data(), 3, mhd1d::kStateWidth); + state_to_row(cells, 0, mhd1d::StateVector{1.0, 0.5, -0.25, 0.125, 2.0, 0.1, -0.05}); + state_to_row(cells, 1, mhd1d::StateVector{1.2, 0.6, -0.2, 0.15, 2.2, 0.12, -0.02}); + state_to_row(cells, 2, mhd1d::StateVector{1.4, 0.7, -0.15, 0.175, 2.4, 0.14, 0.01}); + + std::vector padded_buffer(7 * mhd1d::kStateWidth, 0.0); + const mhd1d::ArrayView padded(padded_buffer.data(), 7, mhd1d::kStateWidth); + mhd1d::pad_zero_gradient_ghost_cells( + mhd1d::ConstArrayView(cells_buffer.data(), 3, mhd1d::kStateWidth), padded); + + require_state_vector_close(row_to_state(padded, 0), row_to_state(cells, 0)); + require_state_vector_close(row_to_state(padded, 1), row_to_state(cells, 0)); + require_state_vector_close(row_to_state(padded, 2), row_to_state(cells, 0)); + require_state_vector_close(row_to_state(padded, 3), row_to_state(cells, 1)); + require_state_vector_close(row_to_state(padded, 4), row_to_state(cells, 2)); + require_state_vector_close(row_to_state(padded, 5), row_to_state(cells, 2)); + require_state_vector_close(row_to_state(padded, 6), row_to_state(cells, 2)); } TEST_CASE("pad_zero_gradient_ghost_cells handles a single interior cell", "[mhd1d][boundary]") { - const auto cell = mhd1d::StateVector{1.5, -0.75, 0.25, 0.0, 3.5, -0.1, 0.2}; - mhd1d::StateArray2D cells(1); - cells.store(0, cell); + const auto cell = mhd1d::StateVector{1.5, -0.75, 0.25, 0.0, 3.5, -0.1, 0.2}; + std::vector cells_buffer(1 * mhd1d::kStateWidth, 0.0); + const mhd1d::ArrayView cells(cells_buffer.data(), 1, mhd1d::kStateWidth); + state_to_row(cells, 0, cell); + + std::vector padded_buffer(5 * mhd1d::kStateWidth, 0.0); + const mhd1d::ArrayView padded(padded_buffer.data(), 5, mhd1d::kStateWidth); + mhd1d::pad_zero_gradient_ghost_cells( + mhd1d::ConstArrayView(cells_buffer.data(), 1, mhd1d::kStateWidth), padded); + + for (std::size_t index = 0; index < 5; ++index) { + require_state_vector_close(row_to_state(padded, index), cell); + } +} + +std::vector make_sample_conservative_cells() +{ + std::vector conservative_cells(4 * mhd1d::kStateWidth, 0.0); + const mhd1d::ArrayView view(conservative_cells.data(), 4, mhd1d::kStateWidth); + state_to_row(view, 0, mhd1d::StateVector{1.0, 0.1, 0.0, 0.0, 1.6, 0.20, 0.00}); + state_to_row(view, 1, mhd1d::StateVector{0.9, 0.0, 0.1, 0.0, 1.3, 0.15, 0.05}); + state_to_row(view, 2, mhd1d::StateVector{0.8, -0.1, 0.0, 0.1, 1.1, 0.10, 0.10}); + state_to_row(view, 3, mhd1d::StateVector{0.7, -0.2, -0.1, 0.0, 0.9, 0.05, 0.15}); + return conservative_cells; +} + +TEST_CASE("arrayview compute_semidiscrete_rhs returns finite values", "[mhd1d][arrayview]") +{ + const std::vector conservative_cells = make_sample_conservative_cells(); + const std::size_t nx = 4; + + const double dx = 1.0 / static_cast(nx); - const auto padded = mhd1d::pad_zero_gradient_ghost_cells(cells); + std::vector rhs_buffer(nx * mhd1d::kStateWidth, 0.0); + mhd1d::compute_semidiscrete_rhs( + mhd1d::ConstArrayView(conservative_cells.data(), nx, mhd1d::kStateWidth), + mhd1d::ArrayView(rhs_buffer.data(), nx, mhd1d::kStateWidth), dx, 0.75, 2.0); - REQUIRE(padded.rows() == 5U); - for (std::size_t index = 0; index < padded.rows(); ++index) { - require_state_vector_close(padded.load(index), cell); + for (std::size_t row = 0; row < nx; ++row) { + for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + REQUIRE(std::isfinite(rhs_buffer[row * mhd1d::kStateWidth + component])); + } } } -TEST_CASE("StateArray2D rows are contiguous in the right-most dimension", "[mhd1d][storage]") +TEST_CASE("arrayview ssp_rk3_step evolves state with finite conservative values", + "[mhd1d][arrayview]") { - mhd1d::StateArray2D cells(3); - cells.store(1, mhd1d::StateVector{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}); + const std::vector conservative_cells = make_sample_conservative_cells(); + const std::size_t nx = 4; - const double* row_ptr = cells.row_data(1); - REQUIRE(row_ptr[0] == 1.0); - REQUIRE(row_ptr[6] == 7.0); - REQUIRE(cells.row_data(2) - cells.row_data(1) == static_cast(mhd1d::kStateWidth)); + const double dx = 1.0 / static_cast(nx); + const double dt = 1.0e-4; + std::vector next_buffer(nx * mhd1d::kStateWidth, 0.0); + + mhd1d::ssp_rk3_step(mhd1d::ConstArrayView(conservative_cells.data(), nx, mhd1d::kStateWidth), + mhd1d::ArrayView(next_buffer.data(), nx, mhd1d::kStateWidth), dt, dx, 0.75, + 2.0); + + for (std::size_t row = 0; row < nx; ++row) { + const double rho = next_buffer[row * mhd1d::kStateWidth + 0U]; + for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + REQUIRE(std::isfinite(next_buffer[row * mhd1d::kStateWidth + component])); + } + REQUIRE(rho > 0.0); + } +} + +TEST_CASE("arrayview evolve_ssp_rk3_fixed_dt matches repeated arrayview steps", + "[mhd1d][arrayview]") +{ + const std::vector conservative_cells = make_sample_conservative_cells(); + const std::size_t nx = 4; + const double dx = 1.0 / static_cast(nx); + const double dt = 1.0e-4; + const double t_final = 2.0e-4; + + std::vector evolved_buffer(nx * mhd1d::kStateWidth, 0.0); + std::vector step_buffer(nx * mhd1d::kStateWidth, 0.0); + std::vector manual_buffer = conservative_cells; + + mhd1d::evolve_ssp_rk3_fixed_dt( + mhd1d::ConstArrayView(conservative_cells.data(), nx, mhd1d::kStateWidth), + mhd1d::ArrayView(evolved_buffer.data(), nx, mhd1d::kStateWidth), t_final, dt, dx, 0.75, 2.0); + + for (int step = 0; step < 2; ++step) { + mhd1d::ssp_rk3_step(mhd1d::ConstArrayView(manual_buffer.data(), nx, mhd1d::kStateWidth), + mhd1d::ArrayView(step_buffer.data(), nx, mhd1d::kStateWidth), dt, dx, 0.75, + 2.0); + manual_buffer.swap(step_buffer); + } + + for (std::size_t row = 0; row < nx; ++row) { + for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + REQUIRE(std::fabs(manual_buffer[row * mhd1d::kStateWidth + component] - + evolved_buffer[row * mhd1d::kStateWidth + component]) <= kTolerance); + } + } } diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/test_public.py b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/test_public.py index cf61218..79cd798 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/test_public.py +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/test_public.py @@ -6,19 +6,28 @@ PUBLIC_TEST_TARGET = "cpp_full_solver1d_public_tests" -GOLDEN_CSV_PATH = Path("tests/data/brio_wu_golden.csv") +GOLDEN_CSV_PATH = Path(__file__).resolve().parents[1] / "tests/data/brio_wu_golden.csv" GOLDEN_TOLERANCE = 1.0e-12 +WORKSPACE_ROOT = Path(__file__).resolve().parents[1] def _build_public_tests() -> Path: - subprocess.run(["cmake", "-S", ".", "-B", "build"], check=True) + subprocess.run(["cmake", "-S", ".", "-B", "build"], check=True, cwd=WORKSPACE_ROOT) subprocess.run( - ["cmake", "--build", "build", "--target", PUBLIC_TEST_TARGET], + [ + "cmake", + "--build", + "build", + "--target", + "cpp_full_solver1d", + PUBLIC_TEST_TARGET, + ], check=True, + cwd=WORKSPACE_ROOT, ) binary_name = f"{PUBLIC_TEST_TARGET}.exe" if os.name == "nt" else PUBLIC_TEST_TARGET - executable_path = Path("build/tests") / binary_name + executable_path = WORKSPACE_ROOT / "build/tests" / binary_name assert executable_path.exists() return executable_path @@ -31,11 +40,11 @@ def test_public_brio_wu_cli_matches_reference_grid() -> None: _build_public_tests() solver_name = "cpp_full_solver1d.exe" if os.name == "nt" else "cpp_full_solver1d" - solver_path = Path("build/bin") / solver_name + solver_path = WORKSPACE_ROOT / "build/bin" / solver_name assert solver_path.exists() completed = subprocess.run( - [str(solver_path), "examples/brio_wu.toml"], + [str(solver_path)], check=True, capture_output=True, text=True, From 5290c7c7c7cf618c38fbacef67be5cfaf0798d80 Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Sun, 29 Mar 2026 23:16:07 +0900 Subject: [PATCH 13/39] Refactor Brio-Wu CLI around SolverWorkspace --- .../cpp-full-solver1d/workspace/src/main.cpp | 102 ++++-------------- .../cpp-full-solver1d/workspace/src/mhd1d.cpp | 24 +++++ .../cpp-full-solver1d/workspace/src/mhd1d.hpp | 20 +++- 3 files changed, 66 insertions(+), 80 deletions(-) diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp index a23bbd2..27d9af4 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp @@ -22,97 +22,41 @@ constexpr mhd1d::StateVector kBrioWuRightPrimitive{ 0.125, 0.0, 0.0, 0.0, 0.1, -1.0, 0.0, }; -void fill_brio_wu_initial_profile(mhd1d::ArrayView profile) -{ - const std::vector centers = mhd1d::cell_centers(kBrioWuNx, kBrioWuXLeft, kBrioWuXRight); +} // namespace - for (std::size_t index = 0; index < centers.size(); ++index) { +int main() +{ + mhd1d::SolverWorkspace workspace(kBrioWuNx, kBrioWuXLeft, kBrioWuXRight, kBrioWuDt, kBrioWuTFinal, + kBrioWuGamma, kBrioWuBx); + const mhd1d::ArrayView primitive_cells(workspace.buf_primitive.data(), workspace.Nx, + mhd1d::kStateWidth); + const std::vector centers = + mhd1d::cell_centers(workspace.Nx, workspace.x_left, workspace.x_right); + + for (std::size_t index = 0; index < workspace.Nx; ++index) { const mhd1d::StateVector& state = (centers[index] < kBrioWuDiscontinuityX) ? kBrioWuLeftPrimitive : kBrioWuRightPrimitive; for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { - profile(index, component) = state[component]; + primitive_cells(index, component) = state[component]; } } -} -void primitive_to_conservative_profile(mhd1d::ConstArrayView primitive_cells, - mhd1d::ArrayView conservative_cells) -{ - const int nx = static_cast(primitive_cells.extent(0)); - for (int ix = 0; ix < nx; ++ix) { - const std::size_t x = static_cast(ix); - mhd1d::StateVector primitive{}; - for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { - primitive[component] = primitive_cells(x, component); - } - const mhd1d::StateVector conservative = - mhd1d::primitive_to_conservative(primitive, kBrioWuBx, kBrioWuGamma); - for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { - conservative_cells(x, component) = conservative[component]; - } - } -} + mhd1d::primitive_profile_to_conservative(primitive_cells, workspace.stage1, workspace.bx, + workspace.gamma); -void conservative_to_primitive_profile(mhd1d::ConstArrayView conservative_cells, - mhd1d::ArrayView primitive_cells) -{ - const int nx = static_cast(conservative_cells.extent(0)); - for (int ix = 0; ix < nx; ++ix) { - const std::size_t x = static_cast(ix); - mhd1d::StateVector conservative{}; - for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { - conservative[component] = conservative_cells(x, component); - } - const mhd1d::StateVector primitive = - mhd1d::conservative_to_primitive(conservative, kBrioWuBx, kBrioWuGamma); - for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { - primitive_cells(x, component) = primitive[component]; - } - } -} - -std::vector run_brio_wu_simulation() -{ - std::vector primitive_buffer(kBrioWuNx * mhd1d::kStateWidth); - std::vector conservative_buffer(kBrioWuNx * mhd1d::kStateWidth); - std::vector final_primitive_buffer(kBrioWuNx * mhd1d::kStateWidth); - - fill_brio_wu_initial_profile( - mhd1d::ArrayView(primitive_buffer.data(), kBrioWuNx, mhd1d::kStateWidth)); - - primitive_to_conservative_profile( - mhd1d::ConstArrayView(primitive_buffer.data(), kBrioWuNx, mhd1d::kStateWidth), - mhd1d::ArrayView(conservative_buffer.data(), kBrioWuNx, mhd1d::kStateWidth)); - - const double dx = (kBrioWuXRight - kBrioWuXLeft) / static_cast(kBrioWuNx); - mhd1d::evolve_ssp_rk3_fixed_dt( - mhd1d::ConstArrayView(conservative_buffer.data(), kBrioWuNx, mhd1d::kStateWidth), - mhd1d::ArrayView(conservative_buffer.data(), kBrioWuNx, mhd1d::kStateWidth), kBrioWuTFinal, - kBrioWuDt, dx, kBrioWuBx, kBrioWuGamma); + mhd1d::evolve_ssp_rk3_fixed_dt(workspace.stage1, workspace.stage1, workspace.t_final, + workspace.dt, workspace.dx, workspace.bx, workspace.gamma); - conservative_to_primitive_profile( - mhd1d::ConstArrayView(conservative_buffer.data(), kBrioWuNx, mhd1d::kStateWidth), - mhd1d::ArrayView(final_primitive_buffer.data(), kBrioWuNx, mhd1d::kStateWidth)); - - return final_primitive_buffer; -} - -} // namespace - -int main() -{ - const std::vector final_primitive_buffer = run_brio_wu_simulation(); - const mhd1d::ConstArrayView final_primitive_cells(final_primitive_buffer.data(), kBrioWuNx, - mhd1d::kStateWidth); - const std::vector centers = mhd1d::cell_centers(kBrioWuNx, kBrioWuXLeft, kBrioWuXRight); + mhd1d::conservative_profile_to_primitive(workspace.stage1, primitive_cells, workspace.bx, + workspace.gamma); std::cout << "x,rho,u,v,w,p,by,bz\n"; std::cout << std::setprecision(17); - for (std::size_t index = 0; index < kBrioWuNx; ++index) { - std::cout << centers[index] << ',' << final_primitive_cells(index, 0) << ',' - << final_primitive_cells(index, 1) << ',' << final_primitive_cells(index, 2) << ',' - << final_primitive_cells(index, 3) << ',' << final_primitive_cells(index, 4) << ',' - << final_primitive_cells(index, 5) << ',' << final_primitive_cells(index, 6) << '\n'; + for (std::size_t index = 0; index < workspace.Nx; ++index) { + std::cout << centers[index] << ',' << primitive_cells(index, 0) << ',' + << primitive_cells(index, 1) << ',' << primitive_cells(index, 2) << ',' + << primitive_cells(index, 3) << ',' << primitive_cells(index, 4) << ',' + << primitive_cells(index, 5) << ',' << primitive_cells(index, 6) << '\n'; } return 0; diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp index bf385f0..40b18c9 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp @@ -245,6 +245,30 @@ StateVector conservative_to_primitive(const StateVector& conservative, double bx return StateVector{rho, u, v, w, pressure, by, bz}; } +void primitive_profile_to_conservative(ConstArrayView primitive_cells, ArrayView conservative_cells, + double bx, double gamma) +{ + const int nx = static_cast(primitive_cells.extent(0)); + for (int ix = 0; ix < nx; ++ix) { + const std::size_t x = static_cast(ix); + const StateVector conservative = + primitive_to_conservative(row_to_state(primitive_cells, x), bx, gamma); + state_to_row(conservative, conservative_cells, x); + } +} + +void conservative_profile_to_primitive(ConstArrayView conservative_cells, ArrayView primitive_cells, + double bx, double gamma) +{ + const int nx = static_cast(conservative_cells.extent(0)); + for (int ix = 0; ix < nx; ++ix) { + const std::size_t x = static_cast(ix); + const StateVector primitive = + conservative_to_primitive(row_to_state(conservative_cells, x), bx, gamma); + state_to_row(primitive, primitive_cells, x); + } +} + void mc2_slopes(ConstArrayView primitive_cells, ArrayView slopes) { if (primitive_cells.extent(0) < 3U) { diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp index e9dd2b9..2338a64 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp @@ -20,7 +20,12 @@ using ArrayView = stdex::mdspan>; using ConstArrayView = stdex::mdspan>; struct SolverWorkspace { - explicit SolverWorkspace(std::size_t nx) : Nx(nx), Lbx(kGhostWidth), Ubx(kGhostWidth + nx - 1U) + explicit SolverWorkspace(std::size_t nx, double x_left = 0.0, double x_right = 1.0, + double dt = 5.0e-4, double t_final = 0.1, double gamma = 2.0, + double bx = 0.75) + : Nx(nx), Lbx(kGhostWidth), Ubx(kGhostWidth + nx - 1U), x_left(x_left), x_right(x_right), + dx(nx == 0U ? 0.0 : (x_right - x_left) / static_cast(nx)), dt(dt), t_final(t_final), + gamma(gamma), bx(bx) { const std::size_t Nx_total = Nx + 2U * kGhostWidth; const std::size_t interface_n = Nx_total - 1U; @@ -57,6 +62,13 @@ struct SolverWorkspace { std::size_t Nx; // number of grids for the physical domain (excluding the ghost cells) std::size_t Lbx; // lower bound of the physical domain in padded indexing std::size_t Ubx; // upper bound of the physical domain in padded indexing + double x_left; + double x_right; + double dx; + double dt; + double t_final; + double gamma; + double bx; // buffer std::vector buf_conservative; @@ -89,6 +101,12 @@ StateVector primitive_to_conservative(const StateVector& primitive, double bx, d StateVector conservative_to_primitive(const StateVector& conservative, double bx, double gamma); +void primitive_profile_to_conservative(ConstArrayView primitive_cells, ArrayView conservative_cells, + double bx = 0.75, double gamma = 2.0); + +void conservative_profile_to_primitive(ConstArrayView conservative_cells, ArrayView primitive_cells, + double bx = 0.75, double gamma = 2.0); + StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, double gamma); From 37eb42e1976cd5c21181d7ecc309d8a9dbb5aaf2 Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Mon, 30 Mar 2026 00:07:48 +0900 Subject: [PATCH 14/39] WIP: normalize solver workspace shapes --- .../cpp-full-solver1d/workspace/src/main.cpp | 13 ++++--- .../cpp-full-solver1d/workspace/src/mhd1d.cpp | 23 ++++++++++--- .../cpp-full-solver1d/workspace/src/mhd1d.hpp | 34 +++++++++---------- 3 files changed, 42 insertions(+), 28 deletions(-) diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp index 27d9af4..8e1d085 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp @@ -28,8 +28,11 @@ int main() { mhd1d::SolverWorkspace workspace(kBrioWuNx, kBrioWuXLeft, kBrioWuXRight, kBrioWuDt, kBrioWuTFinal, kBrioWuGamma, kBrioWuBx); - const mhd1d::ArrayView primitive_cells(workspace.buf_primitive.data(), workspace.Nx, - mhd1d::kStateWidth); + const std::size_t physical_offset = mhd1d::kGhostWidth * mhd1d::kStateWidth; + const mhd1d::ArrayView primitive_cells(workspace.buf_primitive.data() + physical_offset, + workspace.Nx, mhd1d::kStateWidth); + const mhd1d::ArrayView conservative_cells(workspace.buf_stage1.data() + physical_offset, + workspace.Nx, mhd1d::kStateWidth); const std::vector centers = mhd1d::cell_centers(workspace.Nx, workspace.x_left, workspace.x_right); @@ -41,13 +44,13 @@ int main() } } - mhd1d::primitive_profile_to_conservative(primitive_cells, workspace.stage1, workspace.bx, + mhd1d::primitive_profile_to_conservative(primitive_cells, conservative_cells, workspace.bx, workspace.gamma); - mhd1d::evolve_ssp_rk3_fixed_dt(workspace.stage1, workspace.stage1, workspace.t_final, + mhd1d::evolve_ssp_rk3_fixed_dt(conservative_cells, conservative_cells, workspace.t_final, workspace.dt, workspace.dx, workspace.bx, workspace.gamma); - mhd1d::conservative_profile_to_primitive(workspace.stage1, primitive_cells, workspace.bx, + mhd1d::conservative_profile_to_primitive(conservative_cells, primitive_cells, workspace.bx, workspace.gamma); std::cout << "x,rho,u,v,w,p,by,bz\n"; diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp index 40b18c9..aedce7d 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp @@ -17,6 +17,23 @@ constexpr int kGhost = static_cast(kGhostWidth); using ArrayView = stdex::mdspan>; using ConstArrayView = stdex::mdspan>; +double sign(double value) +{ + if (value > 0.0) { + return 1.0; + } + if (value < 0.0) { + return -1.0; + } + return 0.0; +} + +double mc2(double a, double b) +{ + return 0.5 * (sign(a) + sign(b)) * + std::min({2.0 * std::abs(a), 2.0 * std::abs(b), 0.5 * std::abs(a + b)}); +} + double minmod3(double first, double second, double third) { if (first * second > 0.0 && first * third > 0.0) { @@ -97,11 +114,7 @@ void mc2_slopes_inplace(ConstArrayView primitive_cells, ArrayView slopes) primitive_cells(static_cast(ix - 1), component); const double right_difference = primitive_cells(static_cast(ix + 1), component) - primitive_cells(x, component); - const double centered_difference = - 0.5 * (primitive_cells(static_cast(ix + 1), component) - - primitive_cells(static_cast(ix - 1), component)); - slopes(x, component) = - minmod3(2.0 * left_difference, centered_difference, 2.0 * right_difference); + slopes(x, component) = mc2(left_difference, right_difference); } } } diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp index 2338a64..a0db338 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp @@ -28,33 +28,31 @@ struct SolverWorkspace { gamma(gamma), bx(bx) { const std::size_t Nx_total = Nx + 2U * kGhostWidth; - const std::size_t interface_n = Nx_total - 1U; const std::size_t padded_size = Nx_total * kStateWidth; - const std::size_t state_size = Nx * kStateWidth; buf_conservative.resize(padded_size); buf_primitive.resize(padded_size); buf_slopes.resize(padded_size); - buf_primitive_left.resize(interface_n * kStateWidth); - buf_primitive_right.resize(interface_n * kStateWidth); - buf_rhs1.resize(state_size); - buf_rhs2.resize(state_size); - buf_rhs3.resize(state_size); - buf_stage1.resize(state_size); - buf_stage2.resize(state_size); - buf_stage3.resize(state_size); + buf_primitive_left.resize(padded_size); + buf_primitive_right.resize(padded_size); + buf_rhs1.resize(padded_size); + buf_rhs2.resize(padded_size); + buf_rhs3.resize(padded_size); + buf_stage1.resize(padded_size); + buf_stage2.resize(padded_size); + buf_stage3.resize(padded_size); conservative = ArrayView(buf_conservative.data(), Nx_total, kStateWidth); primitive = ArrayView(buf_primitive.data(), Nx_total, kStateWidth); slopes = ArrayView(buf_slopes.data(), Nx_total, kStateWidth); - primitive_left = ArrayView(buf_primitive_left.data(), interface_n, kStateWidth); - primitive_right = ArrayView(buf_primitive_right.data(), interface_n, kStateWidth); - rhs1 = ArrayView(buf_rhs1.data(), Nx, kStateWidth); - rhs2 = ArrayView(buf_rhs2.data(), Nx, kStateWidth); - rhs3 = ArrayView(buf_rhs3.data(), Nx, kStateWidth); - stage1 = ArrayView(buf_stage1.data(), Nx, kStateWidth); - stage2 = ArrayView(buf_stage2.data(), Nx, kStateWidth); - stage3 = ArrayView(buf_stage3.data(), Nx, kStateWidth); + primitive_left = ArrayView(buf_primitive_left.data(), Nx_total, kStateWidth); + primitive_right = ArrayView(buf_primitive_right.data(), Nx_total, kStateWidth); + rhs1 = ArrayView(buf_rhs1.data(), Nx_total, kStateWidth); + rhs2 = ArrayView(buf_rhs2.data(), Nx_total, kStateWidth); + rhs3 = ArrayView(buf_rhs3.data(), Nx_total, kStateWidth); + stage1 = ArrayView(buf_stage1.data(), Nx_total, kStateWidth); + stage2 = ArrayView(buf_stage2.data(), Nx_total, kStateWidth); + stage3 = ArrayView(buf_stage3.data(), Nx_total, kStateWidth); } using ArrayView = stdex::mdspan>; From a719ec4a290e877aba359a391424b99dff24788c Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Mon, 30 Mar 2026 00:17:57 +0900 Subject: [PATCH 15/39] WIP: add primitive reconstruction helper --- .../cpp-full-solver1d/workspace/src/mhd1d.cpp | 22 +++++++++++++++++++ .../cpp-full-solver1d/workspace/src/mhd1d.hpp | 2 ++ 2 files changed, 24 insertions(+) diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp index aedce7d..3ed67f1 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp @@ -291,6 +291,28 @@ void mc2_slopes(ConstArrayView primitive_cells, ArrayView slopes) mc2_slopes_inplace(primitive_cells, slopes); } +void reconstruct_mc2_primitive_states(SolverWorkspace& workspace) +{ + const ArrayView primitive_cells = workspace.primitive; + const ArrayView left_states = workspace.primitive_left; + const ArrayView right_states = workspace.primitive_right; + + const int lbx = static_cast(workspace.Lbx); + const int ubx = static_cast(workspace.Ubx); + for (int ix = lbx; ix <= ubx; ++ix) { + const std::size_t i = static_cast(ix); + for (std::size_t component = 0; component < kStateWidth; ++component) { + const double left_slope = primitive_cells(i, component) - + primitive_cells(static_cast(ix - 1), component); + const double right_slope = primitive_cells(static_cast(ix + 1), component) - + primitive_cells(i, component); + const double slope = mc2(left_slope, right_slope); + left_states(i, component) = primitive_cells(i, component) - 0.5 * slope; + right_states(i, component) = primitive_cells(i, component) + 0.5 * slope; + } + } +} + void reconstruct_mc2_interfaces(ConstArrayView primitive_cells, ArrayView left_states, ArrayView right_states) { diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp index a0db338..116819f 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp @@ -114,6 +114,8 @@ void pad_zero_gradient_ghost_cells(ConstArrayView cells, ArrayView padded); void mc2_slopes(ConstArrayView primitive_cells, ArrayView slopes); +void reconstruct_mc2_primitive_states(SolverWorkspace& workspace); + void reconstruct_mc2_interfaces(ConstArrayView primitive_cells, ArrayView left_states, ArrayView right_states); From 3f6d4a9d83aba859b80f3dfe5480c269c2619de0 Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Tue, 31 Mar 2026 23:31:19 +0900 Subject: [PATCH 16/39] WIP: add workspace-patterned RK3 path --- .../cpp-full-solver1d/workspace/src/mhd1d.cpp | 181 +++++++++++++++++- .../cpp-full-solver1d/workspace/src/mhd1d.hpp | 32 ++++ .../workspace/tests/cpp/test_public.cpp | 28 +++ 3 files changed, 239 insertions(+), 2 deletions(-) diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp index 3ed67f1..4cde430 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp @@ -217,6 +217,66 @@ void ssp_rk3_step_inplace(ConstArrayView conservative_cells, double dt, double d } } +void compute_semidiscrete_rhs_patterned_inplace(SolverWorkspace& workspace, ArrayView rhs) +{ + const ArrayView conservative = workspace.conservative; + const ArrayView primitive = workspace.primitive; + const ArrayView fluxes = workspace.flux; + + apply_zero_gradient_boundary(conservative, workspace.Lbx, workspace.Ubx); + conservative_profile_to_primitive_profile_inplace(conservative, primitive, workspace.bx, + workspace.gamma); + apply_zero_gradient_boundary(primitive, workspace.Lbx, workspace.Ubx); + reconstruct_mc2_primitive_states(workspace); + compute_hlld_fluxes_from_reconstructed(workspace, workspace.bx, workspace.gamma); + + const int lbx = static_cast(workspace.Lbx); + const int ubx = static_cast(workspace.Ubx); + for (int ix = lbx; ix <= ubx; ++ix) { + const std::size_t x = static_cast(ix); + for (std::size_t component = 0; component < kStateWidth; ++component) { + rhs(x, component) = + -(fluxes(x, component) - fluxes(static_cast(ix - 1), component)) / + workspace.dx; + } + } +} + +void ssp_rk3_substep_patterned(ConstArrayView u0, ArrayView rhs, double dt, double a, double b, + double c, SolverWorkspace& workspace) +{ + compute_semidiscrete_rhs_patterned_inplace(workspace, rhs); + + const int lbx = static_cast(workspace.Lbx); + const int ubx = static_cast(workspace.Ubx); + for (int ix = lbx; ix <= ubx; ++ix) { + const std::size_t x = static_cast(ix); + for (std::size_t component = 0; component < kStateWidth; ++component) { + workspace.conservative(x, component) = a * u0(x, component) + + b * workspace.conservative(x, component) + + c * dt * rhs(x, component); + } + } + + conservative_profile_to_primitive_profile_inplace(workspace.conservative, workspace.primitive, + workspace.bx, workspace.gamma); + apply_zero_gradient_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); +} + +void ssp_rk3_step_patterned_inplace(SolverWorkspace& workspace, double dt) +{ + const ArrayView u0 = workspace.stage1; + const ArrayView rhs = workspace.rhs1; + + copy_cells(workspace.conservative, u0); + + ssp_rk3_substep_patterned(u0, rhs, dt, 1.0, 0.0, 1.0, workspace); + ssp_rk3_substep_patterned(u0, rhs, dt, 3.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0, workspace); + ssp_rk3_substep_patterned(u0, rhs, dt, 1.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0, workspace); + + apply_zero_gradient_boundary(workspace.conservative, workspace.Lbx, workspace.Ubx); +} + } // namespace StateVector primitive_to_conservative(const StateVector& primitive, double bx, double gamma) @@ -307,12 +367,29 @@ void reconstruct_mc2_primitive_states(SolverWorkspace& workspace) const double right_slope = primitive_cells(static_cast(ix + 1), component) - primitive_cells(i, component); const double slope = mc2(left_slope, right_slope); - left_states(i, component) = primitive_cells(i, component) - 0.5 * slope; - right_states(i, component) = primitive_cells(i, component) + 0.5 * slope; + left_states(i, component) = primitive_cells(i, component) + 0.5 * slope; + right_states(i, component) = primitive_cells(i, component) - 0.5 * slope; } } } +void compute_hlld_fluxes_from_reconstructed(SolverWorkspace& workspace, double bx, double gamma) +{ + const ArrayView left_states = workspace.primitive_left; + const ArrayView right_states = workspace.primitive_right; + const ArrayView fluxes = workspace.flux; + + const int lbx = static_cast(workspace.Lbx); + const int ubx = static_cast(workspace.Ubx); + for (int ix = lbx - 1; ix <= ubx; ++ix) { + const std::size_t i = static_cast(ix); + const StateVector flux = hlld_flux_from_primitive( + row_to_state(left_states, i), row_to_state(right_states, static_cast(ix + 1)), + bx, gamma); + state_to_row(flux, fluxes, i); + } +} + void reconstruct_mc2_interfaces(ConstArrayView primitive_cells, ArrayView left_states, ArrayView right_states) { @@ -564,6 +641,23 @@ std::vector cell_centers(std::size_t nx, double x_left, double x_right) return centers; } +void apply_zero_gradient_boundary(ArrayView u, std::size_t lbx, std::size_t ubx) +{ + const std::size_t nx_total = u.extent(0); + + for (std::size_t ix = 0; ix < lbx; ++ix) { + for (std::size_t component = 0; component < kStateWidth; ++component) { + u(ix, component) = u(lbx, component); + } + } + + for (std::size_t ix = ubx + 1U; ix < nx_total; ++ix) { + for (std::size_t component = 0; component < kStateWidth; ++component) { + u(ix, component) = u(ubx, component); + } + } +} + void compute_semidiscrete_rhs(ConstArrayView conservative_cells, ArrayView rhs, double dx, double bx, double gamma) { @@ -571,6 +665,24 @@ void compute_semidiscrete_rhs(ConstArrayView conservative_cells, ArrayView rhs, compute_semidiscrete_rhs_inplace(conservative_cells, dx, bx, gamma, workspace, rhs); } +void compute_semidiscrete_rhs_patterned(ConstArrayView conservative_cells, ArrayView rhs, double dx, + double bx, double gamma) +{ + const std::size_t nx = conservative_cells.extent(0) - 2U * kGhostWidth; + SolverWorkspace workspace(nx); + workspace.dx = dx; + workspace.bx = bx; + workspace.gamma = gamma; + copy_cells(conservative_cells, workspace.conservative); + compute_semidiscrete_rhs_patterned_inplace(workspace, workspace.rhs1); + copy_cells(workspace.rhs1, rhs); +} + +void compute_semidiscrete_rhs_patterned(SolverWorkspace& workspace) +{ + compute_semidiscrete_rhs_patterned_inplace(workspace, workspace.rhs1); +} + void ssp_rk3_step(ConstArrayView conservative_cells, ArrayView output, double dt, double dx, double bx, double gamma) { @@ -578,6 +690,27 @@ void ssp_rk3_step(ConstArrayView conservative_cells, ArrayView output, double dt ssp_rk3_step_inplace(conservative_cells, dt, dx, bx, gamma, workspace, output); } +void ssp_rk3_step_patterned(ConstArrayView conservative_cells, ArrayView output, double dt, + double dx, double bx, double gamma) +{ + const std::size_t nx = conservative_cells.extent(0) - 2U * kGhostWidth; + SolverWorkspace workspace(nx); + workspace.dx = dx; + workspace.bx = bx; + workspace.gamma = gamma; + copy_cells(conservative_cells, workspace.conservative); + conservative_profile_to_primitive_profile_inplace(workspace.conservative, workspace.primitive, + workspace.bx, workspace.gamma); + apply_zero_gradient_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); + ssp_rk3_step_patterned_inplace(workspace, dt); + copy_cells(workspace.conservative, output); +} + +void ssp_rk3_step_patterned(SolverWorkspace& workspace, double dt) +{ + ssp_rk3_step_patterned_inplace(workspace, dt); +} + void evolve_ssp_rk3_fixed_dt(ConstArrayView conservative_cells, ArrayView output, double t_final, double dt, double dx, double bx, double gamma) { @@ -610,4 +743,48 @@ void evolve_ssp_rk3_fixed_dt(ConstArrayView conservative_cells, ArrayView output copy_cells(evolved_state, output); } +void evolve_ssp_rk3_fixed_dt_patterned(ConstArrayView conservative_cells, ArrayView output, + double t_final, double dt, double dx, double bx, + double gamma) +{ + if (conservative_cells.extent(0) == 0U || t_final < 0.0 || dt <= 0.0) { + copy_cells(conservative_cells, output); + return; + } + + const std::size_t nx = conservative_cells.extent(0) - 2U * kGhostWidth; + SolverWorkspace workspace(nx); + workspace.dx = dx; + workspace.bx = bx; + workspace.gamma = gamma; + workspace.t_final = t_final; + workspace.dt = dt; + + copy_cells(conservative_cells, workspace.conservative); + evolve_ssp_rk3_fixed_dt_patterned(workspace); + copy_cells(workspace.conservative, output); +} + +void evolve_ssp_rk3_fixed_dt_patterned(SolverWorkspace& workspace) +{ + if (workspace.t_final < 0.0 || workspace.dt <= 0.0) { + conservative_profile_to_primitive_profile_inplace(workspace.conservative, workspace.primitive, + workspace.bx, workspace.gamma); + apply_zero_gradient_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); + return; + } + + conservative_profile_to_primitive_profile_inplace(workspace.conservative, workspace.primitive, + workspace.bx, workspace.gamma); + apply_zero_gradient_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); + + double elapsed_time = 0.0; + while (elapsed_time < workspace.t_final) { + const double remaining_time = workspace.t_final - elapsed_time; + const double step_dt = std::min(workspace.dt, remaining_time); + ssp_rk3_step_patterned_inplace(workspace, step_dt); + elapsed_time = (step_dt < workspace.dt) ? workspace.t_final : (elapsed_time + step_dt); + } +} + } // namespace mhd1d diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp index 116819f..15f03aa 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp @@ -41,6 +41,7 @@ struct SolverWorkspace { buf_stage1.resize(padded_size); buf_stage2.resize(padded_size); buf_stage3.resize(padded_size); + buf_flux.resize(padded_size); conservative = ArrayView(buf_conservative.data(), Nx_total, kStateWidth); primitive = ArrayView(buf_primitive.data(), Nx_total, kStateWidth); @@ -53,6 +54,7 @@ struct SolverWorkspace { stage1 = ArrayView(buf_stage1.data(), Nx_total, kStateWidth); stage2 = ArrayView(buf_stage2.data(), Nx_total, kStateWidth); stage3 = ArrayView(buf_stage3.data(), Nx_total, kStateWidth); + flux = ArrayView(buf_flux.data(), Nx_total, kStateWidth); } using ArrayView = stdex::mdspan>; @@ -80,6 +82,7 @@ struct SolverWorkspace { std::vector buf_stage1; std::vector buf_stage2; std::vector buf_stage3; + std::vector buf_flux; // view ArrayView conservative; @@ -93,6 +96,7 @@ struct SolverWorkspace { ArrayView stage1; ArrayView stage2; ArrayView stage3; + ArrayView flux; }; StateVector primitive_to_conservative(const StateVector& primitive, double bx, double gamma); @@ -110,22 +114,50 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& std::vector cell_centers(std::size_t nx, double x_left, double x_right); +void apply_zero_gradient_boundary(ArrayView u, std::size_t lbx, std::size_t ubx); + void pad_zero_gradient_ghost_cells(ConstArrayView cells, ArrayView padded); void mc2_slopes(ConstArrayView primitive_cells, ArrayView slopes); +// Interface semantics: +// - primitive_left(ix, :) is the left state at interface ix + 1/2. +// - primitive_right(ix, :) is the right state at interface ix - 1/2. void reconstruct_mc2_primitive_states(SolverWorkspace& workspace); +// flux(ix, :) stores the HLLD flux at interface ix + 1/2. +// The interface state pair is: +// - left = primitive_left(ix, :) +// - right = primitive_right(ix + 1, :) +void compute_hlld_fluxes_from_reconstructed(SolverWorkspace& workspace, double bx = 0.75, + double gamma = 2.0); + void reconstruct_mc2_interfaces(ConstArrayView primitive_cells, ArrayView left_states, ArrayView right_states); void compute_semidiscrete_rhs(ConstArrayView conservative_cells, ArrayView rhs, double dx, double bx = 0.75, double gamma = 2.0); +void compute_semidiscrete_rhs_patterned(ConstArrayView conservative_cells, ArrayView rhs, double dx, + double bx = 0.75, double gamma = 2.0); + +void compute_semidiscrete_rhs_patterned(SolverWorkspace& workspace); + void ssp_rk3_step(ConstArrayView conservative_cells, ArrayView output, double dt, double dx, double bx = 0.75, double gamma = 2.0); +void ssp_rk3_step_patterned(ConstArrayView conservative_cells, ArrayView output, double dt, + double dx, double bx = 0.75, double gamma = 2.0); + +void ssp_rk3_step_patterned(SolverWorkspace& workspace, double dt); + void evolve_ssp_rk3_fixed_dt(ConstArrayView conservative_cells, ArrayView output, double t_final, double dt, double dx, double bx = 0.75, double gamma = 2.0); +void evolve_ssp_rk3_fixed_dt_patterned(ConstArrayView conservative_cells, ArrayView output, + double t_final, double dt, double dx, double bx = 0.75, + double gamma = 2.0); + +void evolve_ssp_rk3_fixed_dt_patterned(SolverWorkspace& workspace); + } // namespace mhd1d diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp index cf4177b..cc7a045 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp @@ -185,6 +185,34 @@ TEST_CASE("pad_zero_gradient_ghost_cells handles a single interior cell", "[mhd1 } } +TEST_CASE("apply_zero_gradient_boundary overwrites ghost cells from interior boundary", + "[mhd1d][boundary]") +{ + std::vector cells_buffer(6 * mhd1d::kStateWidth, 0.0); + const mhd1d::ArrayView cells(cells_buffer.data(), 6, mhd1d::kStateWidth); + + state_to_row(cells, 0, mhd1d::StateVector{-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0}); + state_to_row(cells, 1, mhd1d::StateVector{1.0, 0.1, 0.2, 0.3, 2.0, 0.4, 0.5}); + state_to_row(cells, 2, mhd1d::StateVector{2.0, 0.2, 0.3, 0.4, 2.1, 0.5, 0.6}); + state_to_row(cells, 3, mhd1d::StateVector{3.0, 0.3, 0.4, 0.5, 2.2, 0.6, 0.7}); + state_to_row(cells, 4, mhd1d::StateVector{4.0, 0.4, 0.5, 0.6, 2.3, 0.7, 0.8}); + state_to_row(cells, 5, mhd1d::StateVector{-2.0, -2.0, -2.0, -2.0, -2.0, -2.0, -2.0}); + + const mhd1d::StateVector interior_left = row_to_state(cells, 1); + const mhd1d::StateVector interior_right = row_to_state(cells, 4); + const mhd1d::StateVector interior_mid_2 = row_to_state(cells, 2); + const mhd1d::StateVector interior_mid_3 = row_to_state(cells, 3); + + mhd1d::apply_zero_gradient_boundary(cells, 1, 4); + + require_state_vector_close(row_to_state(cells, 0), interior_left); + require_state_vector_close(row_to_state(cells, 5), interior_right); + require_state_vector_close(row_to_state(cells, 1), interior_left); + require_state_vector_close(row_to_state(cells, 2), interior_mid_2); + require_state_vector_close(row_to_state(cells, 3), interior_mid_3); + require_state_vector_close(row_to_state(cells, 4), interior_right); +} + std::vector make_sample_conservative_cells() { std::vector conservative_cells(4 * mhd1d::kStateWidth, 0.0); From 80acf9646e4cf05024e0233ad2b663da93aa633e Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Tue, 31 Mar 2026 23:35:36 +0900 Subject: [PATCH 17/39] WIP: run full solver via workspace-patterned RK3 --- .../cpp-full-solver1d/workspace/src/main.cpp | 38 ++++++++----------- .../cpp-full-solver1d/workspace/src/mhd1d.cpp | 4 +- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp index 8e1d085..6d22d19 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp @@ -28,38 +28,32 @@ int main() { mhd1d::SolverWorkspace workspace(kBrioWuNx, kBrioWuXLeft, kBrioWuXRight, kBrioWuDt, kBrioWuTFinal, kBrioWuGamma, kBrioWuBx); - const std::size_t physical_offset = mhd1d::kGhostWidth * mhd1d::kStateWidth; - const mhd1d::ArrayView primitive_cells(workspace.buf_primitive.data() + physical_offset, - workspace.Nx, mhd1d::kStateWidth); - const mhd1d::ArrayView conservative_cells(workspace.buf_stage1.data() + physical_offset, - workspace.Nx, mhd1d::kStateWidth); const std::vector centers = mhd1d::cell_centers(workspace.Nx, workspace.x_left, workspace.x_right); - for (std::size_t index = 0; index < workspace.Nx; ++index) { - const mhd1d::StateVector& state = - (centers[index] < kBrioWuDiscontinuityX) ? kBrioWuLeftPrimitive : kBrioWuRightPrimitive; + for (std::size_t index = workspace.Lbx; index <= workspace.Ubx; ++index) { + const std::size_t center_index = index - workspace.Lbx; + const mhd1d::StateVector& state = (centers[center_index] < kBrioWuDiscontinuityX) + ? kBrioWuLeftPrimitive + : kBrioWuRightPrimitive; for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { - primitive_cells(index, component) = state[component]; + workspace.primitive(index, component) = state[component]; } } - mhd1d::primitive_profile_to_conservative(primitive_cells, conservative_cells, workspace.bx, - workspace.gamma); - - mhd1d::evolve_ssp_rk3_fixed_dt(conservative_cells, conservative_cells, workspace.t_final, - workspace.dt, workspace.dx, workspace.bx, workspace.gamma); - - mhd1d::conservative_profile_to_primitive(conservative_cells, primitive_cells, workspace.bx, - workspace.gamma); + mhd1d::apply_zero_gradient_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); + mhd1d::primitive_profile_to_conservative(workspace.primitive, workspace.conservative, + workspace.bx, workspace.gamma); + mhd1d::evolve_ssp_rk3_fixed_dt_patterned(workspace); std::cout << "x,rho,u,v,w,p,by,bz\n"; std::cout << std::setprecision(17); - for (std::size_t index = 0; index < workspace.Nx; ++index) { - std::cout << centers[index] << ',' << primitive_cells(index, 0) << ',' - << primitive_cells(index, 1) << ',' << primitive_cells(index, 2) << ',' - << primitive_cells(index, 3) << ',' << primitive_cells(index, 4) << ',' - << primitive_cells(index, 5) << ',' << primitive_cells(index, 6) << '\n'; + for (std::size_t index = workspace.Lbx; index <= workspace.Ubx; ++index) { + const std::size_t center_index = index - workspace.Lbx; + std::cout << centers[center_index] << ',' << workspace.primitive(index, 0) << ',' + << workspace.primitive(index, 1) << ',' << workspace.primitive(index, 2) << ',' + << workspace.primitive(index, 3) << ',' << workspace.primitive(index, 4) << ',' + << workspace.primitive(index, 5) << ',' << workspace.primitive(index, 6) << '\n'; } return 0; diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp index 4cde430..2cd9b62 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp @@ -357,8 +357,8 @@ void reconstruct_mc2_primitive_states(SolverWorkspace& workspace) const ArrayView left_states = workspace.primitive_left; const ArrayView right_states = workspace.primitive_right; - const int lbx = static_cast(workspace.Lbx); - const int ubx = static_cast(workspace.Ubx); + const int lbx = static_cast(workspace.Lbx) - 1; + const int ubx = static_cast(workspace.Ubx) + 1; for (int ix = lbx; ix <= ubx; ++ix) { const std::size_t i = static_cast(ix); for (std::size_t component = 0; component < kStateWidth; ++component) { From c2eddde0327a7790711c9dce371b15041404112b Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Wed, 1 Apr 2026 00:04:41 +0900 Subject: [PATCH 18/39] Migrate fully to workspace-patterned RK3 solver --- .../cpp-full-solver1d/workspace/src/mhd1d.cpp | 212 +----------------- .../cpp-full-solver1d/workspace/src/mhd1d.hpp | 32 --- .../workspace/tests/cpp/test_public.cpp | 183 +++++++-------- 3 files changed, 88 insertions(+), 339 deletions(-) diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp index 2cd9b62..66bc469 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp @@ -12,7 +12,6 @@ namespace { constexpr double kHlldEps = 1.0e-40; -constexpr int kGhost = static_cast(kGhostWidth); using ArrayView = stdex::mdspan>; using ConstArrayView = stdex::mdspan>; @@ -34,16 +33,6 @@ double mc2(double a, double b) std::min({2.0 * std::abs(a), 2.0 * std::abs(b), 0.5 * std::abs(a + b)}); } -double minmod3(double first, double second, double third) -{ - if (first * second > 0.0 && first * third > 0.0) { - const double limited = std::min({std::abs(first), std::abs(second), std::abs(third)}); - return std::copysign(limited, first); - } - - return 0.0; -} - StateVector row_to_state(ConstArrayView cells, std::size_t row) { StateVector state{}; @@ -73,29 +62,6 @@ void conservative_profile_to_primitive_profile_inplace(ConstArrayView conservati } } -void pad_zero_gradient_ghost_cells_inplace(ConstArrayView cells, ArrayView padded) -{ - const int nx = static_cast(cells.extent(0)); - const int padded_nx = static_cast(padded.extent(0)); - - for (int ghost = 0; ghost < kGhost; ++ghost) { - const std::size_t g = static_cast(ghost); - for (std::size_t component = 0; component < kStateWidth; ++component) { - padded(g, component) = cells(0U, component); - padded(static_cast(padded_nx - 1 - ghost), component) = - cells(static_cast(nx - 1), component); - } - } - - for (int ix = 0; ix < nx; ++ix) { - const std::size_t src = static_cast(ix); - const std::size_t dst = static_cast(kGhost + ix); - for (std::size_t component = 0; component < kStateWidth; ++component) { - padded(dst, component) = cells(src, component); - } - } -} - void mc2_slopes_inplace(ConstArrayView primitive_cells, ArrayView slopes) { const int nx = static_cast(primitive_cells.extent(0)); @@ -119,20 +85,6 @@ void mc2_slopes_inplace(ConstArrayView primitive_cells, ArrayView slopes) } } -void reconstruct_mc2_interfaces_inplace(ConstArrayView primitive_cells, ConstArrayView slopes, - ArrayView left_states, ArrayView right_states) -{ - const int interface_count = static_cast(primitive_cells.extent(0) - 1U); - for (int ix = 0; ix < interface_count; ++ix) { - const std::size_t x = static_cast(ix); - for (std::size_t component = 0; component < kStateWidth; ++component) { - left_states(x, component) = primitive_cells(x, component) + 0.5 * slopes(x, component); - right_states(x, component) = primitive_cells(static_cast(ix + 1), component) - - 0.5 * slopes(static_cast(ix + 1), component); - } - } -} - void copy_cells(ConstArrayView source, ArrayView destination) { const int nx = static_cast(source.extent(0)); @@ -144,79 +96,6 @@ void copy_cells(ConstArrayView source, ArrayView destination) } } -void compute_semidiscrete_rhs_inplace(ConstArrayView conservative_cells, double dx, double bx, - double gamma, SolverWorkspace& workspace, ArrayView rhs) -{ - const ArrayView padded_conservative = workspace.conservative; - const ArrayView padded_primitive = workspace.primitive; - const ArrayView slopes = workspace.slopes; - const ArrayView left_interface = workspace.primitive_left; - const ArrayView right_interface = workspace.primitive_right; - - pad_zero_gradient_ghost_cells_inplace(conservative_cells, padded_conservative); - conservative_profile_to_primitive_profile_inplace(padded_conservative, padded_primitive, bx, - gamma); - mc2_slopes_inplace(padded_primitive, slopes); - reconstruct_mc2_interfaces_inplace(padded_primitive, slopes, left_interface, right_interface); - - const int lbx = static_cast(workspace.Lbx); - const int ubx = static_cast(workspace.Ubx); - for (int ix = lbx; ix <= ubx; ++ix) { - const std::size_t i = static_cast(ix - lbx); - const std::size_t x = static_cast(ix); - - const StateVector right_flux = hlld_flux_from_primitive( - row_to_state(left_interface, x), row_to_state(right_interface, x), bx, gamma); - const StateVector left_flux = hlld_flux_from_primitive( - row_to_state(left_interface, x - 1U), row_to_state(right_interface, x - 1U), bx, gamma); - for (std::size_t component = 0; component < kStateWidth; ++component) { - rhs(i, component) = -(right_flux[component] - left_flux[component]) / dx; - } - } -} - -void ssp_rk3_step_inplace(ConstArrayView conservative_cells, double dt, double dx, double bx, - double gamma, SolverWorkspace& workspace, ArrayView output) -{ - const ArrayView first_stage = workspace.stage1; - const ArrayView second_stage = workspace.stage2; - const ArrayView first_rhs = workspace.rhs1; - const ArrayView second_rhs = workspace.rhs2; - const ArrayView third_rhs = workspace.rhs3; - - copy_cells(conservative_cells, first_stage); - compute_semidiscrete_rhs_inplace(conservative_cells, dx, bx, gamma, workspace, first_rhs); - const int lbx = static_cast(workspace.Lbx); - const int ubx = static_cast(workspace.Ubx); - - for (int ix = lbx; ix <= ubx; ++ix) { - const std::size_t i = static_cast(ix - lbx); - for (std::size_t component = 0; component < kStateWidth; ++component) { - first_stage(i, component) += dt * first_rhs(i, component); - } - } - - compute_semidiscrete_rhs_inplace(first_stage, dx, bx, gamma, workspace, second_rhs); - for (int ix = lbx; ix <= ubx; ++ix) { - const std::size_t i = static_cast(ix - lbx); - for (std::size_t component = 0; component < kStateWidth; ++component) { - second_stage(i, component) = - 0.75 * conservative_cells(i, component) + - 0.25 * (first_stage(i, component) + dt * second_rhs(i, component)); - } - } - - compute_semidiscrete_rhs_inplace(second_stage, dx, bx, gamma, workspace, third_rhs); - for (int ix = lbx; ix <= ubx; ++ix) { - const std::size_t i = static_cast(ix - lbx); - for (std::size_t component = 0; component < kStateWidth; ++component) { - output(i, component) = - (1.0 / 3.0) * conservative_cells(i, component) + - (2.0 / 3.0) * (second_stage(i, component) + dt * third_rhs(i, component)); - } - } -} - void compute_semidiscrete_rhs_patterned_inplace(SolverWorkspace& workspace, ArrayView rhs) { const ArrayView conservative = workspace.conservative; @@ -342,15 +221,6 @@ void conservative_profile_to_primitive(ConstArrayView conservative_cells, ArrayV } } -void mc2_slopes(ConstArrayView primitive_cells, ArrayView slopes) -{ - if (primitive_cells.extent(0) < 3U) { - throw std::runtime_error("primitive_cells must contain at least three cells"); - } - - mc2_slopes_inplace(primitive_cells, slopes); -} - void reconstruct_mc2_primitive_states(SolverWorkspace& workspace) { const ArrayView primitive_cells = workspace.primitive; @@ -390,20 +260,6 @@ void compute_hlld_fluxes_from_reconstructed(SolverWorkspace& workspace, double b } } -void reconstruct_mc2_interfaces(ConstArrayView primitive_cells, ArrayView left_states, - ArrayView right_states) -{ - if (primitive_cells.extent(0) < 2U) { - throw std::runtime_error("primitive_cells must contain at least two cells"); - } - - const std::size_t interface_count = primitive_cells.extent(0) - 1U; - std::vector slopes_buffer(primitive_cells.extent(0) * kStateWidth, 0.0); - ArrayView slopes(slopes_buffer.data(), primitive_cells.extent(0), kStateWidth); - mc2_slopes_inplace(primitive_cells, slopes); - reconstruct_mc2_interfaces_inplace(primitive_cells, slopes, left_states, right_states); -} - StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, double gamma) { @@ -602,26 +458,6 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& }; } -void pad_zero_gradient_ghost_cells(ConstArrayView cells, ArrayView padded) -{ - if (cells.extent(0) == 0U) { - return; - } - - for (std::size_t ghost = 0; ghost < kGhostWidth; ++ghost) { - for (std::size_t component = 0; component < kStateWidth; ++component) { - padded(ghost, component) = cells(0, component); - padded(padded.extent(0) - 1U - ghost, component) = cells(cells.extent(0) - 1U, component); - } - } - - for (std::size_t index = 0; index < cells.extent(0); ++index) { - for (std::size_t component = 0; component < kStateWidth; ++component) { - padded(index + kGhostWidth, component) = cells(index, component); - } - } -} - std::vector cell_centers(std::size_t nx, double x_left, double x_right) { if (nx == 0U) { @@ -658,13 +494,6 @@ void apply_zero_gradient_boundary(ArrayView u, std::size_t lbx, std::size_t ubx) } } -void compute_semidiscrete_rhs(ConstArrayView conservative_cells, ArrayView rhs, double dx, - double bx, double gamma) -{ - SolverWorkspace workspace(conservative_cells.extent(0)); - compute_semidiscrete_rhs_inplace(conservative_cells, dx, bx, gamma, workspace, rhs); -} - void compute_semidiscrete_rhs_patterned(ConstArrayView conservative_cells, ArrayView rhs, double dx, double bx, double gamma) { @@ -683,13 +512,6 @@ void compute_semidiscrete_rhs_patterned(SolverWorkspace& workspace) compute_semidiscrete_rhs_patterned_inplace(workspace, workspace.rhs1); } -void ssp_rk3_step(ConstArrayView conservative_cells, ArrayView output, double dt, double dx, - double bx, double gamma) -{ - SolverWorkspace workspace(conservative_cells.extent(0)); - ssp_rk3_step_inplace(conservative_cells, dt, dx, bx, gamma, workspace, output); -} - void ssp_rk3_step_patterned(ConstArrayView conservative_cells, ArrayView output, double dt, double dx, double bx, double gamma) { @@ -711,38 +533,6 @@ void ssp_rk3_step_patterned(SolverWorkspace& workspace, double dt) ssp_rk3_step_patterned_inplace(workspace, dt); } -void evolve_ssp_rk3_fixed_dt(ConstArrayView conservative_cells, ArrayView output, double t_final, - double dt, double dx, double bx, double gamma) -{ - if (conservative_cells.extent(0) == 0U || t_final < 0.0 || dt <= 0.0) { - copy_cells(conservative_cells, output); - return; - } - - const std::size_t state_size = conservative_cells.extent(0) * kStateWidth; - std::vector evolved_buffer(state_size); - std::vector stage_buffer(state_size); - - ArrayView evolved_state(evolved_buffer.data(), conservative_cells.extent(0), kStateWidth); - ArrayView stage_state(stage_buffer.data(), conservative_cells.extent(0), kStateWidth); - - copy_cells(conservative_cells, evolved_state); - - SolverWorkspace workspace(conservative_cells.extent(0)); - double elapsed_time = 0.0; - while (elapsed_time < t_final) { - const double remaining_time = t_final - elapsed_time; - const double step_dt = std::min(dt, remaining_time); - ssp_rk3_step_inplace(evolved_state, step_dt, dx, bx, gamma, workspace, stage_state); - std::swap(evolved_buffer, stage_buffer); - evolved_state = ArrayView(evolved_buffer.data(), conservative_cells.extent(0), kStateWidth); - stage_state = ArrayView(stage_buffer.data(), conservative_cells.extent(0), kStateWidth); - elapsed_time = (step_dt < dt) ? t_final : (elapsed_time + step_dt); - } - - copy_cells(evolved_state, output); -} - void evolve_ssp_rk3_fixed_dt_patterned(ConstArrayView conservative_cells, ArrayView output, double t_final, double dt, double dx, double bx, double gamma) @@ -768,12 +558,14 @@ void evolve_ssp_rk3_fixed_dt_patterned(ConstArrayView conservative_cells, ArrayV void evolve_ssp_rk3_fixed_dt_patterned(SolverWorkspace& workspace) { if (workspace.t_final < 0.0 || workspace.dt <= 0.0) { + apply_zero_gradient_boundary(workspace.conservative, workspace.Lbx, workspace.Ubx); conservative_profile_to_primitive_profile_inplace(workspace.conservative, workspace.primitive, workspace.bx, workspace.gamma); apply_zero_gradient_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); return; } + apply_zero_gradient_boundary(workspace.conservative, workspace.Lbx, workspace.Ubx); conservative_profile_to_primitive_profile_inplace(workspace.conservative, workspace.primitive, workspace.bx, workspace.gamma); apply_zero_gradient_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp index 15f03aa..ddd7f62 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp @@ -36,11 +36,7 @@ struct SolverWorkspace { buf_primitive_left.resize(padded_size); buf_primitive_right.resize(padded_size); buf_rhs1.resize(padded_size); - buf_rhs2.resize(padded_size); - buf_rhs3.resize(padded_size); buf_stage1.resize(padded_size); - buf_stage2.resize(padded_size); - buf_stage3.resize(padded_size); buf_flux.resize(padded_size); conservative = ArrayView(buf_conservative.data(), Nx_total, kStateWidth); @@ -49,11 +45,7 @@ struct SolverWorkspace { primitive_left = ArrayView(buf_primitive_left.data(), Nx_total, kStateWidth); primitive_right = ArrayView(buf_primitive_right.data(), Nx_total, kStateWidth); rhs1 = ArrayView(buf_rhs1.data(), Nx_total, kStateWidth); - rhs2 = ArrayView(buf_rhs2.data(), Nx_total, kStateWidth); - rhs3 = ArrayView(buf_rhs3.data(), Nx_total, kStateWidth); stage1 = ArrayView(buf_stage1.data(), Nx_total, kStateWidth); - stage2 = ArrayView(buf_stage2.data(), Nx_total, kStateWidth); - stage3 = ArrayView(buf_stage3.data(), Nx_total, kStateWidth); flux = ArrayView(buf_flux.data(), Nx_total, kStateWidth); } @@ -77,11 +69,7 @@ struct SolverWorkspace { std::vector buf_primitive_left; std::vector buf_primitive_right; std::vector buf_rhs1; - std::vector buf_rhs2; - std::vector buf_rhs3; std::vector buf_stage1; - std::vector buf_stage2; - std::vector buf_stage3; std::vector buf_flux; // view @@ -91,11 +79,7 @@ struct SolverWorkspace { ArrayView primitive_left; ArrayView primitive_right; ArrayView rhs1; - ArrayView rhs2; - ArrayView rhs3; ArrayView stage1; - ArrayView stage2; - ArrayView stage3; ArrayView flux; }; @@ -116,10 +100,6 @@ std::vector cell_centers(std::size_t nx, double x_left, double x_right); void apply_zero_gradient_boundary(ArrayView u, std::size_t lbx, std::size_t ubx); -void pad_zero_gradient_ghost_cells(ConstArrayView cells, ArrayView padded); - -void mc2_slopes(ConstArrayView primitive_cells, ArrayView slopes); - // Interface semantics: // - primitive_left(ix, :) is the left state at interface ix + 1/2. // - primitive_right(ix, :) is the right state at interface ix - 1/2. @@ -132,28 +112,16 @@ void reconstruct_mc2_primitive_states(SolverWorkspace& workspace); void compute_hlld_fluxes_from_reconstructed(SolverWorkspace& workspace, double bx = 0.75, double gamma = 2.0); -void reconstruct_mc2_interfaces(ConstArrayView primitive_cells, ArrayView left_states, - ArrayView right_states); - -void compute_semidiscrete_rhs(ConstArrayView conservative_cells, ArrayView rhs, double dx, - double bx = 0.75, double gamma = 2.0); - void compute_semidiscrete_rhs_patterned(ConstArrayView conservative_cells, ArrayView rhs, double dx, double bx = 0.75, double gamma = 2.0); void compute_semidiscrete_rhs_patterned(SolverWorkspace& workspace); -void ssp_rk3_step(ConstArrayView conservative_cells, ArrayView output, double dt, double dx, - double bx = 0.75, double gamma = 2.0); - void ssp_rk3_step_patterned(ConstArrayView conservative_cells, ArrayView output, double dt, double dx, double bx = 0.75, double gamma = 2.0); void ssp_rk3_step_patterned(SolverWorkspace& workspace, double dt); -void evolve_ssp_rk3_fixed_dt(ConstArrayView conservative_cells, ArrayView output, double t_final, - double dt, double dx, double bx = 0.75, double gamma = 2.0); - void evolve_ssp_rk3_fixed_dt_patterned(ConstArrayView conservative_cells, ArrayView output, double t_final, double dt, double dx, double bx = 0.75, double gamma = 2.0); diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp index cc7a045..e739dcc 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp @@ -70,46 +70,21 @@ TEST_CASE("primitive and conservative states round-trip", "[mhd1d][conversion]") require_state_vector_close(output, input); } -TEST_CASE("mc2_slopes preserve a constant primitive state", "[mhd1d][reconstruction]") -{ - const auto constant_state = mhd1d::StateVector{1.25, -0.5, 0.25, -0.125, 2.75, 0.4, -0.3}; - std::vector cells_buffer(4 * mhd1d::kStateWidth, 0.0); - const mhd1d::ArrayView cells(cells_buffer.data(), 4, mhd1d::kStateWidth); - for (std::size_t index = 0; index < 4; ++index) { - state_to_row(cells, index, constant_state); - } - - std::vector slopes_buffer(4 * mhd1d::kStateWidth, 0.0); - const mhd1d::ArrayView slopes(slopes_buffer.data(), 4, mhd1d::kStateWidth); - mhd1d::mc2_slopes(mhd1d::ConstArrayView(cells_buffer.data(), 4, mhd1d::kStateWidth), slopes); - - for (std::size_t index = 0; index < 4; ++index) { - require_state_vector_close(row_to_state(slopes, index), mhd1d::StateVector{}); - } -} - -TEST_CASE("reconstruct_mc2_interfaces preserves a constant primitive state exactly", +TEST_CASE("reconstruct_mc2_primitive_states preserves a constant primitive state exactly", "[mhd1d][reconstruction]") { + mhd1d::SolverWorkspace workspace(4); const auto constant_state = mhd1d::StateVector{0.9, 0.3, -0.2, 0.1, 1.8, -0.45, 0.6}; - std::vector cells_buffer(4 * mhd1d::kStateWidth, 0.0); - const mhd1d::ArrayView cells(cells_buffer.data(), 4, mhd1d::kStateWidth); - for (std::size_t index = 0; index < 4; ++index) { - state_to_row(cells, index, constant_state); + + for (std::size_t index = 0; index < workspace.conservative.extent(0); ++index) { + state_to_row(workspace.primitive, index, constant_state); } - std::vector left_buffer(3 * mhd1d::kStateWidth, 0.0); - std::vector right_buffer(3 * mhd1d::kStateWidth, 0.0); - const mhd1d::ArrayView left_states(left_buffer.data(), 3, mhd1d::kStateWidth); - const mhd1d::ArrayView right_states(right_buffer.data(), 3, mhd1d::kStateWidth); - mhd1d::reconstruct_mc2_interfaces( - mhd1d::ConstArrayView(cells_buffer.data(), 4, mhd1d::kStateWidth), left_states, right_states); + mhd1d::reconstruct_mc2_primitive_states(workspace); - for (std::size_t index = 0; index < 3; ++index) { - require_state_vector_close(row_to_state(left_states, index), constant_state); - } - for (std::size_t index = 0; index < 3; ++index) { - require_state_vector_close(row_to_state(right_states, index), constant_state); + for (std::size_t index = workspace.Lbx; index <= workspace.Ubx; ++index) { + require_state_vector_close(row_to_state(workspace.primitive_left, index), constant_state); + require_state_vector_close(row_to_state(workspace.primitive_right, index), constant_state); } } @@ -146,39 +121,32 @@ TEST_CASE("hlld_flux_from_primitive matches the physical flux for identical stat require_state_vector_close(actual, expected); } -TEST_CASE("pad_zero_gradient_ghost_cells duplicates edge states on both sides", "[mhd1d][boundary]") +TEST_CASE("apply_zero_gradient_boundary duplicates edge states on both sides", "[mhd1d][boundary]") { - std::vector cells_buffer(3 * mhd1d::kStateWidth, 0.0); - const mhd1d::ArrayView cells(cells_buffer.data(), 3, mhd1d::kStateWidth); - state_to_row(cells, 0, mhd1d::StateVector{1.0, 0.5, -0.25, 0.125, 2.0, 0.1, -0.05}); - state_to_row(cells, 1, mhd1d::StateVector{1.2, 0.6, -0.2, 0.15, 2.2, 0.12, -0.02}); - state_to_row(cells, 2, mhd1d::StateVector{1.4, 0.7, -0.15, 0.175, 2.4, 0.14, 0.01}); - std::vector padded_buffer(7 * mhd1d::kStateWidth, 0.0); const mhd1d::ArrayView padded(padded_buffer.data(), 7, mhd1d::kStateWidth); - mhd1d::pad_zero_gradient_ghost_cells( - mhd1d::ConstArrayView(cells_buffer.data(), 3, mhd1d::kStateWidth), padded); - - require_state_vector_close(row_to_state(padded, 0), row_to_state(cells, 0)); - require_state_vector_close(row_to_state(padded, 1), row_to_state(cells, 0)); - require_state_vector_close(row_to_state(padded, 2), row_to_state(cells, 0)); - require_state_vector_close(row_to_state(padded, 3), row_to_state(cells, 1)); - require_state_vector_close(row_to_state(padded, 4), row_to_state(cells, 2)); - require_state_vector_close(row_to_state(padded, 5), row_to_state(cells, 2)); - require_state_vector_close(row_to_state(padded, 6), row_to_state(cells, 2)); + state_to_row(padded, 2, mhd1d::StateVector{1.0, 0.5, -0.25, 0.125, 2.0, 0.1, -0.05}); + state_to_row(padded, 3, mhd1d::StateVector{1.2, 0.6, -0.2, 0.15, 2.2, 0.12, -0.02}); + state_to_row(padded, 4, mhd1d::StateVector{1.4, 0.7, -0.15, 0.175, 2.4, 0.14, 0.01}); + + mhd1d::apply_zero_gradient_boundary(padded, 2, 4); + + require_state_vector_close(row_to_state(padded, 0), row_to_state(padded, 2)); + require_state_vector_close(row_to_state(padded, 1), row_to_state(padded, 2)); + require_state_vector_close(row_to_state(padded, 2), row_to_state(padded, 2)); + require_state_vector_close(row_to_state(padded, 3), row_to_state(padded, 3)); + require_state_vector_close(row_to_state(padded, 4), row_to_state(padded, 4)); + require_state_vector_close(row_to_state(padded, 5), row_to_state(padded, 4)); + require_state_vector_close(row_to_state(padded, 6), row_to_state(padded, 4)); } -TEST_CASE("pad_zero_gradient_ghost_cells handles a single interior cell", "[mhd1d][boundary]") +TEST_CASE("apply_zero_gradient_boundary handles a single interior cell", "[mhd1d][boundary]") { - const auto cell = mhd1d::StateVector{1.5, -0.75, 0.25, 0.0, 3.5, -0.1, 0.2}; - std::vector cells_buffer(1 * mhd1d::kStateWidth, 0.0); - const mhd1d::ArrayView cells(cells_buffer.data(), 1, mhd1d::kStateWidth); - state_to_row(cells, 0, cell); - std::vector padded_buffer(5 * mhd1d::kStateWidth, 0.0); const mhd1d::ArrayView padded(padded_buffer.data(), 5, mhd1d::kStateWidth); - mhd1d::pad_zero_gradient_ghost_cells( - mhd1d::ConstArrayView(cells_buffer.data(), 1, mhd1d::kStateWidth), padded); + const auto cell = mhd1d::StateVector{1.5, -0.75, 0.25, 0.0, 3.5, -0.1, 0.2}; + state_to_row(padded, 2, cell); + mhd1d::apply_zero_gradient_boundary(padded, 2, 2); for (std::size_t index = 0; index < 5; ++index) { require_state_vector_close(row_to_state(padded, index), cell); @@ -226,19 +194,24 @@ std::vector make_sample_conservative_cells() TEST_CASE("arrayview compute_semidiscrete_rhs returns finite values", "[mhd1d][arrayview]") { - const std::vector conservative_cells = make_sample_conservative_cells(); - const std::size_t nx = 4; - - const double dx = 1.0 / static_cast(nx); - - std::vector rhs_buffer(nx * mhd1d::kStateWidth, 0.0); - mhd1d::compute_semidiscrete_rhs( - mhd1d::ConstArrayView(conservative_cells.data(), nx, mhd1d::kStateWidth), - mhd1d::ArrayView(rhs_buffer.data(), nx, mhd1d::kStateWidth), dx, 0.75, 2.0); + const std::size_t nx = 4; + mhd1d::SolverWorkspace workspace(nx); + workspace.dx = 1.0 / static_cast(nx); + workspace.bx = 0.75; + workspace.gamma = 2.0; + const std::vector conservative_cells = make_sample_conservative_cells(); for (std::size_t row = 0; row < nx; ++row) { for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { - REQUIRE(std::isfinite(rhs_buffer[row * mhd1d::kStateWidth + component])); + workspace.conservative(workspace.Lbx + row, component) = + conservative_cells[row * mhd1d::kStateWidth + component]; + } + } + + mhd1d::compute_semidiscrete_rhs_patterned(workspace); + for (std::size_t row = workspace.Lbx; row <= workspace.Ubx; ++row) { + for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + REQUIRE(std::isfinite(workspace.rhs1(row, component))); } } } @@ -246,21 +219,26 @@ TEST_CASE("arrayview compute_semidiscrete_rhs returns finite values", "[mhd1d][a TEST_CASE("arrayview ssp_rk3_step evolves state with finite conservative values", "[mhd1d][arrayview]") { - const std::vector conservative_cells = make_sample_conservative_cells(); - const std::size_t nx = 4; + const std::size_t nx = 4; + mhd1d::SolverWorkspace workspace(nx); + workspace.dx = 1.0 / static_cast(nx); + workspace.bx = 0.75; + workspace.gamma = 2.0; - const double dx = 1.0 / static_cast(nx); - const double dt = 1.0e-4; - std::vector next_buffer(nx * mhd1d::kStateWidth, 0.0); + const std::vector conservative_cells = make_sample_conservative_cells(); + for (std::size_t row = 0; row < nx; ++row) { + for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + workspace.conservative(workspace.Lbx + row, component) = + conservative_cells[row * mhd1d::kStateWidth + component]; + } + } - mhd1d::ssp_rk3_step(mhd1d::ConstArrayView(conservative_cells.data(), nx, mhd1d::kStateWidth), - mhd1d::ArrayView(next_buffer.data(), nx, mhd1d::kStateWidth), dt, dx, 0.75, - 2.0); + mhd1d::ssp_rk3_step_patterned(workspace, 1.0e-4); - for (std::size_t row = 0; row < nx; ++row) { - const double rho = next_buffer[row * mhd1d::kStateWidth + 0U]; + for (std::size_t row = workspace.Lbx; row <= workspace.Ubx; ++row) { + const double rho = workspace.conservative(row, 0U); for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { - REQUIRE(std::isfinite(next_buffer[row * mhd1d::kStateWidth + component])); + REQUIRE(std::isfinite(workspace.conservative(row, component))); } REQUIRE(rho > 0.0); } @@ -269,31 +247,42 @@ TEST_CASE("arrayview ssp_rk3_step evolves state with finite conservative values" TEST_CASE("arrayview evolve_ssp_rk3_fixed_dt matches repeated arrayview steps", "[mhd1d][arrayview]") { - const std::vector conservative_cells = make_sample_conservative_cells(); - const std::size_t nx = 4; - const double dx = 1.0 / static_cast(nx); - const double dt = 1.0e-4; - const double t_final = 2.0e-4; + const std::size_t nx = 4; + const double dt = 1.0e-4; + const double t_final = 2.0e-4; + + mhd1d::SolverWorkspace evolved_workspace(nx); + evolved_workspace.dx = 1.0 / static_cast(nx); + evolved_workspace.bx = 0.75; + evolved_workspace.gamma = 2.0; + evolved_workspace.dt = dt; + evolved_workspace.t_final = t_final; + + mhd1d::SolverWorkspace manual_workspace(nx); + manual_workspace.dx = evolved_workspace.dx; + manual_workspace.bx = evolved_workspace.bx; + manual_workspace.gamma = evolved_workspace.gamma; - std::vector evolved_buffer(nx * mhd1d::kStateWidth, 0.0); - std::vector step_buffer(nx * mhd1d::kStateWidth, 0.0); - std::vector manual_buffer = conservative_cells; + const std::vector conservative_cells = make_sample_conservative_cells(); + for (std::size_t row = 0; row < nx; ++row) { + for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + const double value = conservative_cells[row * mhd1d::kStateWidth + component]; + evolved_workspace.conservative(evolved_workspace.Lbx + row, component) = value; + manual_workspace.conservative(manual_workspace.Lbx + row, component) = value; + } + } - mhd1d::evolve_ssp_rk3_fixed_dt( - mhd1d::ConstArrayView(conservative_cells.data(), nx, mhd1d::kStateWidth), - mhd1d::ArrayView(evolved_buffer.data(), nx, mhd1d::kStateWidth), t_final, dt, dx, 0.75, 2.0); + mhd1d::evolve_ssp_rk3_fixed_dt_patterned(evolved_workspace); for (int step = 0; step < 2; ++step) { - mhd1d::ssp_rk3_step(mhd1d::ConstArrayView(manual_buffer.data(), nx, mhd1d::kStateWidth), - mhd1d::ArrayView(step_buffer.data(), nx, mhd1d::kStateWidth), dt, dx, 0.75, - 2.0); - manual_buffer.swap(step_buffer); + mhd1d::ssp_rk3_step_patterned(manual_workspace, dt); } for (std::size_t row = 0; row < nx; ++row) { + const std::size_t i = evolved_workspace.Lbx + row; for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { - REQUIRE(std::fabs(manual_buffer[row * mhd1d::kStateWidth + component] - - evolved_buffer[row * mhd1d::kStateWidth + component]) <= kTolerance); + REQUIRE(std::fabs(manual_workspace.conservative(i, component) - + evolved_workspace.conservative(i, component)) <= kTolerance); } } } From a88dc8d4d914d6cdf61583db7174e9a331c2094b Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Wed, 1 Apr 2026 13:13:56 +0900 Subject: [PATCH 19/39] checkpoint: spiral-unknown-1775016836330 From 98e4bf27333106d4eec88caf43633dadbc3291d8 Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Wed, 1 Apr 2026 13:14:03 +0900 Subject: [PATCH 20/39] checkpoint: spiral-unknown-1775016843861 From fa65f36340a955b0e9d96fc1b3dee3f7a0f54cae Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Wed, 1 Apr 2026 13:14:09 +0900 Subject: [PATCH 21/39] checkpoint: spiral-unknown-1775016849781 From b70f67ba3b10e98bebf8ebb35ea377aa410bdde6 Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Wed, 1 Apr 2026 13:53:38 +0900 Subject: [PATCH 22/39] refactor(cpp-full-solver1d): simplify API and remove dead code - Rename ArrayView/XView to ArrayView2D/ArrayView1D, drop ConstArrayView - Remove all _inplace wrappers and ConstArrayView overloads - Drop default constructor parameters (domain fixed to [0,1]) - Use constexpr coefficient table for SSP-RK3 substeps - Extract init_brio_wu_primitive() in main.cpp - Add cell center view (x) to SolverWorkspace, remove cell_centers() - Update tests to match new type names and required constructor args --- .../cpp-full-solver1d/workspace/src/main.cpp | 20 +- .../cpp-full-solver1d/workspace/src/mhd1d.cpp | 259 +++++------------- .../cpp-full-solver1d/workspace/src/mhd1d.hpp | 84 +++--- .../workspace/tests/cpp/test_public.cpp | 46 +--- 4 files changed, 133 insertions(+), 276 deletions(-) diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp index 6d22d19..1b60dec 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp @@ -8,8 +8,6 @@ namespace { constexpr std::size_t kBrioWuNx = 400; -constexpr double kBrioWuXLeft = 0.0; -constexpr double kBrioWuXRight = 1.0; constexpr double kBrioWuDiscontinuityX = 0.5; constexpr double kBrioWuDt = 5.0e-4; constexpr double kBrioWuTFinal = 0.1; @@ -24,22 +22,24 @@ constexpr mhd1d::StateVector kBrioWuRightPrimitive{ } // namespace -int main() +void init_brio_wu_primitive(mhd1d::SolverWorkspace& workspace) { - mhd1d::SolverWorkspace workspace(kBrioWuNx, kBrioWuXLeft, kBrioWuXRight, kBrioWuDt, kBrioWuTFinal, - kBrioWuGamma, kBrioWuBx); - const std::vector centers = - mhd1d::cell_centers(workspace.Nx, workspace.x_left, workspace.x_right); - for (std::size_t index = workspace.Lbx; index <= workspace.Ubx; ++index) { const std::size_t center_index = index - workspace.Lbx; - const mhd1d::StateVector& state = (centers[center_index] < kBrioWuDiscontinuityX) + const mhd1d::StateVector& state = (workspace.x(center_index) < kBrioWuDiscontinuityX) ? kBrioWuLeftPrimitive : kBrioWuRightPrimitive; for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { workspace.primitive(index, component) = state[component]; } } +} + +int main() +{ + mhd1d::SolverWorkspace workspace(kBrioWuNx, kBrioWuDt, kBrioWuTFinal, kBrioWuGamma, kBrioWuBx); + + init_brio_wu_primitive(workspace); mhd1d::apply_zero_gradient_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); mhd1d::primitive_profile_to_conservative(workspace.primitive, workspace.conservative, @@ -50,7 +50,7 @@ int main() std::cout << std::setprecision(17); for (std::size_t index = workspace.Lbx; index <= workspace.Ubx; ++index) { const std::size_t center_index = index - workspace.Lbx; - std::cout << centers[center_index] << ',' << workspace.primitive(index, 0) << ',' + std::cout << workspace.x(center_index) << ',' << workspace.primitive(index, 0) << ',' << workspace.primitive(index, 1) << ',' << workspace.primitive(index, 2) << ',' << workspace.primitive(index, 3) << ',' << workspace.primitive(index, 4) << ',' << workspace.primitive(index, 5) << ',' << workspace.primitive(index, 6) << '\n'; diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp index 66bc469..d330188 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp @@ -13,9 +13,6 @@ namespace constexpr double kHlldEps = 1.0e-40; -using ArrayView = stdex::mdspan>; -using ConstArrayView = stdex::mdspan>; - double sign(double value) { if (value > 0.0) { @@ -33,7 +30,7 @@ double mc2(double a, double b) std::min({2.0 * std::abs(a), 2.0 * std::abs(b), 0.5 * std::abs(a + b)}); } -StateVector row_to_state(ConstArrayView cells, std::size_t row) +StateVector row_to_state(ArrayView2D cells, std::size_t row) { StateVector state{}; for (std::size_t component = 0; component < kStateWidth; ++component) { @@ -42,50 +39,14 @@ StateVector row_to_state(ConstArrayView cells, std::size_t row) return state; } -void state_to_row(const StateVector& state, ArrayView cells, std::size_t row) +void state_to_row(const StateVector& state, ArrayView2D cells, std::size_t row) { for (std::size_t component = 0; component < kStateWidth; ++component) { cells(row, component) = state[component]; } } -void conservative_profile_to_primitive_profile_inplace(ConstArrayView conservative_cells, - ArrayView primitive_cells, double bx, - double gamma) -{ - const int nx = static_cast(conservative_cells.extent(0)); - for (int ix = 0; ix < nx; ++ix) { - const std::size_t x = static_cast(ix); - const StateVector primitive = - conservative_to_primitive(row_to_state(conservative_cells, x), bx, gamma); - state_to_row(primitive, primitive_cells, x); - } -} - -void mc2_slopes_inplace(ConstArrayView primitive_cells, ArrayView slopes) -{ - const int nx = static_cast(primitive_cells.extent(0)); - - for (int ix = 0; ix < nx; ++ix) { - const std::size_t x = static_cast(ix); - for (std::size_t component = 0; component < kStateWidth; ++component) { - slopes(x, component) = 0.0; - } - } - - for (int ix = 1; ix <= nx - 2; ++ix) { - const std::size_t x = static_cast(ix); - for (std::size_t component = 0; component < kStateWidth; ++component) { - const double left_difference = primitive_cells(x, component) - - primitive_cells(static_cast(ix - 1), component); - const double right_difference = primitive_cells(static_cast(ix + 1), component) - - primitive_cells(x, component); - slopes(x, component) = mc2(left_difference, right_difference); - } - } -} - -void copy_cells(ConstArrayView source, ArrayView destination) +void copy_cells(ArrayView2D source, ArrayView2D destination) { const int nx = static_cast(source.extent(0)); for (int ix = 0; ix < nx; ++ix) { @@ -96,64 +57,17 @@ void copy_cells(ConstArrayView source, ArrayView destination) } } -void compute_semidiscrete_rhs_patterned_inplace(SolverWorkspace& workspace, ArrayView rhs) -{ - const ArrayView conservative = workspace.conservative; - const ArrayView primitive = workspace.primitive; - const ArrayView fluxes = workspace.flux; - - apply_zero_gradient_boundary(conservative, workspace.Lbx, workspace.Ubx); - conservative_profile_to_primitive_profile_inplace(conservative, primitive, workspace.bx, - workspace.gamma); - apply_zero_gradient_boundary(primitive, workspace.Lbx, workspace.Ubx); - reconstruct_mc2_primitive_states(workspace); - compute_hlld_fluxes_from_reconstructed(workspace, workspace.bx, workspace.gamma); - - const int lbx = static_cast(workspace.Lbx); - const int ubx = static_cast(workspace.Ubx); - for (int ix = lbx; ix <= ubx; ++ix) { - const std::size_t x = static_cast(ix); - for (std::size_t component = 0; component < kStateWidth; ++component) { - rhs(x, component) = - -(fluxes(x, component) - fluxes(static_cast(ix - 1), component)) / - workspace.dx; - } - } -} - -void ssp_rk3_substep_patterned(ConstArrayView u0, ArrayView rhs, double dt, double a, double b, - double c, SolverWorkspace& workspace) +void conservative_profile_to_primitive_profile_inplace(ArrayView2D conservative_cells, + ArrayView2D primitive_cells, double bx, + double gamma) { - compute_semidiscrete_rhs_patterned_inplace(workspace, rhs); - - const int lbx = static_cast(workspace.Lbx); - const int ubx = static_cast(workspace.Ubx); - for (int ix = lbx; ix <= ubx; ++ix) { + const int nx = static_cast(conservative_cells.extent(0)); + for (int ix = 0; ix < nx; ++ix) { const std::size_t x = static_cast(ix); - for (std::size_t component = 0; component < kStateWidth; ++component) { - workspace.conservative(x, component) = a * u0(x, component) + - b * workspace.conservative(x, component) + - c * dt * rhs(x, component); - } + const StateVector primitive = + conservative_to_primitive(row_to_state(conservative_cells, x), bx, gamma); + state_to_row(primitive, primitive_cells, x); } - - conservative_profile_to_primitive_profile_inplace(workspace.conservative, workspace.primitive, - workspace.bx, workspace.gamma); - apply_zero_gradient_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); -} - -void ssp_rk3_step_patterned_inplace(SolverWorkspace& workspace, double dt) -{ - const ArrayView u0 = workspace.stage1; - const ArrayView rhs = workspace.rhs1; - - copy_cells(workspace.conservative, u0); - - ssp_rk3_substep_patterned(u0, rhs, dt, 1.0, 0.0, 1.0, workspace); - ssp_rk3_substep_patterned(u0, rhs, dt, 3.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0, workspace); - ssp_rk3_substep_patterned(u0, rhs, dt, 1.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0, workspace); - - apply_zero_gradient_boundary(workspace.conservative, workspace.Lbx, workspace.Ubx); } } // namespace @@ -197,7 +111,7 @@ StateVector conservative_to_primitive(const StateVector& conservative, double bx return StateVector{rho, u, v, w, pressure, by, bz}; } -void primitive_profile_to_conservative(ConstArrayView primitive_cells, ArrayView conservative_cells, +void primitive_profile_to_conservative(ArrayView2D primitive_cells, ArrayView2D conservative_cells, double bx, double gamma) { const int nx = static_cast(primitive_cells.extent(0)); @@ -209,23 +123,11 @@ void primitive_profile_to_conservative(ConstArrayView primitive_cells, ArrayView } } -void conservative_profile_to_primitive(ConstArrayView conservative_cells, ArrayView primitive_cells, - double bx, double gamma) -{ - const int nx = static_cast(conservative_cells.extent(0)); - for (int ix = 0; ix < nx; ++ix) { - const std::size_t x = static_cast(ix); - const StateVector primitive = - conservative_to_primitive(row_to_state(conservative_cells, x), bx, gamma); - state_to_row(primitive, primitive_cells, x); - } -} - void reconstruct_mc2_primitive_states(SolverWorkspace& workspace) { - const ArrayView primitive_cells = workspace.primitive; - const ArrayView left_states = workspace.primitive_left; - const ArrayView right_states = workspace.primitive_right; + const ArrayView2D primitive_cells = workspace.primitive; + const ArrayView2D left_states = workspace.primitive_left; + const ArrayView2D right_states = workspace.primitive_right; const int lbx = static_cast(workspace.Lbx) - 1; const int ubx = static_cast(workspace.Ubx) + 1; @@ -245,9 +147,9 @@ void reconstruct_mc2_primitive_states(SolverWorkspace& workspace) void compute_hlld_fluxes_from_reconstructed(SolverWorkspace& workspace, double bx, double gamma) { - const ArrayView left_states = workspace.primitive_left; - const ArrayView right_states = workspace.primitive_right; - const ArrayView fluxes = workspace.flux; + const ArrayView2D left_states = workspace.primitive_left; + const ArrayView2D right_states = workspace.primitive_right; + const ArrayView2D fluxes = workspace.flux; const int lbx = static_cast(workspace.Lbx); const int ubx = static_cast(workspace.Ubx); @@ -458,26 +360,7 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& }; } -std::vector cell_centers(std::size_t nx, double x_left, double x_right) -{ - if (nx == 0U) { - return {}; - } - - if (!(x_right > x_left)) { - throw std::runtime_error("x_right must be greater than x_left"); - } - - const double dx = (x_right - x_left) / static_cast(nx); - std::vector centers(nx); - for (std::size_t index = 0; index < nx; ++index) { - centers[index] = x_left + (static_cast(index) + 0.5) * dx; - } - - return centers; -} - -void apply_zero_gradient_boundary(ArrayView u, std::size_t lbx, std::size_t ubx) +void apply_zero_gradient_boundary(ArrayView2D u, std::size_t lbx, std::size_t ubx) { const std::size_t nx_total = u.extent(0); @@ -494,65 +377,69 @@ void apply_zero_gradient_boundary(ArrayView u, std::size_t lbx, std::size_t ubx) } } -void compute_semidiscrete_rhs_patterned(ConstArrayView conservative_cells, ArrayView rhs, double dx, - double bx, double gamma) -{ - const std::size_t nx = conservative_cells.extent(0) - 2U * kGhostWidth; - SolverWorkspace workspace(nx); - workspace.dx = dx; - workspace.bx = bx; - workspace.gamma = gamma; - copy_cells(conservative_cells, workspace.conservative); - compute_semidiscrete_rhs_patterned_inplace(workspace, workspace.rhs1); - copy_cells(workspace.rhs1, rhs); -} - void compute_semidiscrete_rhs_patterned(SolverWorkspace& workspace) { - compute_semidiscrete_rhs_patterned_inplace(workspace, workspace.rhs1); -} + const ArrayView2D conservative = workspace.conservative; + const ArrayView2D primitive = workspace.primitive; + const ArrayView2D fluxes = workspace.flux; + const ArrayView2D rhs = workspace.rhs1; -void ssp_rk3_step_patterned(ConstArrayView conservative_cells, ArrayView output, double dt, - double dx, double bx, double gamma) -{ - const std::size_t nx = conservative_cells.extent(0) - 2U * kGhostWidth; - SolverWorkspace workspace(nx); - workspace.dx = dx; - workspace.bx = bx; - workspace.gamma = gamma; - copy_cells(conservative_cells, workspace.conservative); - conservative_profile_to_primitive_profile_inplace(workspace.conservative, workspace.primitive, - workspace.bx, workspace.gamma); - apply_zero_gradient_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); - ssp_rk3_step_patterned_inplace(workspace, dt); - copy_cells(workspace.conservative, output); + apply_zero_gradient_boundary(conservative, workspace.Lbx, workspace.Ubx); + conservative_profile_to_primitive_profile_inplace(conservative, primitive, workspace.bx, + workspace.gamma); + apply_zero_gradient_boundary(primitive, workspace.Lbx, workspace.Ubx); + reconstruct_mc2_primitive_states(workspace); + compute_hlld_fluxes_from_reconstructed(workspace, workspace.bx, workspace.gamma); + + const int lbx = static_cast(workspace.Lbx); + const int ubx = static_cast(workspace.Ubx); + for (int ix = lbx; ix <= ubx; ++ix) { + const std::size_t x = static_cast(ix); + for (std::size_t component = 0; component < kStateWidth; ++component) { + rhs(x, component) = + -(fluxes(x, component) - fluxes(static_cast(ix - 1), component)) / + workspace.dx; + } + } } void ssp_rk3_step_patterned(SolverWorkspace& workspace, double dt) { - ssp_rk3_step_patterned_inplace(workspace, dt); -} + constexpr double kCoeffs[3][3] = { + {1.0, 0.0, 1.0}, + {3.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0}, + {1.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0}, + }; -void evolve_ssp_rk3_fixed_dt_patterned(ConstArrayView conservative_cells, ArrayView output, - double t_final, double dt, double dx, double bx, - double gamma) -{ - if (conservative_cells.extent(0) == 0U || t_final < 0.0 || dt <= 0.0) { - copy_cells(conservative_cells, output); - return; + const ArrayView2D u0 = workspace.stage1; + const ArrayView2D rhs = workspace.rhs1; + + copy_cells(workspace.conservative, u0); + + for (int substep = 0; substep < 3; ++substep) { + compute_semidiscrete_rhs_patterned(workspace); + + const double a = kCoeffs[substep][0]; + const double b = kCoeffs[substep][1]; + const double c = kCoeffs[substep][2]; + + const int lbx = static_cast(workspace.Lbx); + const int ubx = static_cast(workspace.Ubx); + for (int ix = lbx; ix <= ubx; ++ix) { + const std::size_t x = static_cast(ix); + for (std::size_t component = 0; component < kStateWidth; ++component) { + workspace.conservative(x, component) = a * u0(x, component) + + b * workspace.conservative(x, component) + + c * dt * rhs(x, component); + } + } + + conservative_profile_to_primitive_profile_inplace(workspace.conservative, workspace.primitive, + workspace.bx, workspace.gamma); + apply_zero_gradient_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); } - const std::size_t nx = conservative_cells.extent(0) - 2U * kGhostWidth; - SolverWorkspace workspace(nx); - workspace.dx = dx; - workspace.bx = bx; - workspace.gamma = gamma; - workspace.t_final = t_final; - workspace.dt = dt; - - copy_cells(conservative_cells, workspace.conservative); - evolve_ssp_rk3_fixed_dt_patterned(workspace); - copy_cells(workspace.conservative, output); + apply_zero_gradient_boundary(workspace.conservative, workspace.Lbx, workspace.Ubx); } void evolve_ssp_rk3_fixed_dt_patterned(SolverWorkspace& workspace) @@ -574,7 +461,7 @@ void evolve_ssp_rk3_fixed_dt_patterned(SolverWorkspace& workspace) while (elapsed_time < workspace.t_final) { const double remaining_time = workspace.t_final - elapsed_time; const double step_dt = std::min(workspace.dt, remaining_time); - ssp_rk3_step_patterned_inplace(workspace, step_dt); + ssp_rk3_step_patterned(workspace, step_dt); elapsed_time = (step_dt < workspace.dt) ? workspace.t_final : (elapsed_time + step_dt); } } diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp index ddd7f62..05d2529 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp @@ -15,16 +15,14 @@ namespace stdex = std::experimental; constexpr std::size_t kStateWidth = 7; constexpr std::size_t kGhostWidth = 2; -using StateVector = std::array; -using ArrayView = stdex::mdspan>; -using ConstArrayView = stdex::mdspan>; +using StateVector = std::array; +using ArrayView2D = stdex::mdspan>; +using ArrayView1D = stdex::mdspan>; struct SolverWorkspace { - explicit SolverWorkspace(std::size_t nx, double x_left = 0.0, double x_right = 1.0, - double dt = 5.0e-4, double t_final = 0.1, double gamma = 2.0, - double bx = 0.75) - : Nx(nx), Lbx(kGhostWidth), Ubx(kGhostWidth + nx - 1U), x_left(x_left), x_right(x_right), - dx(nx == 0U ? 0.0 : (x_right - x_left) / static_cast(nx)), dt(dt), t_final(t_final), + explicit SolverWorkspace(std::size_t nx, double dt, double t_final, double gamma, double bx) + : Nx(nx), Lbx(kGhostWidth), Ubx(kGhostWidth + nx - 1U), + dx(nx == 0U ? 0.0 : 1.0 / static_cast(nx)), dt(dt), t_final(t_final), gamma(gamma), bx(bx) { const std::size_t Nx_total = Nx + 2U * kGhostWidth; @@ -38,24 +36,26 @@ struct SolverWorkspace { buf_rhs1.resize(padded_size); buf_stage1.resize(padded_size); buf_flux.resize(padded_size); - - conservative = ArrayView(buf_conservative.data(), Nx_total, kStateWidth); - primitive = ArrayView(buf_primitive.data(), Nx_total, kStateWidth); - slopes = ArrayView(buf_slopes.data(), Nx_total, kStateWidth); - primitive_left = ArrayView(buf_primitive_left.data(), Nx_total, kStateWidth); - primitive_right = ArrayView(buf_primitive_right.data(), Nx_total, kStateWidth); - rhs1 = ArrayView(buf_rhs1.data(), Nx_total, kStateWidth); - stage1 = ArrayView(buf_stage1.data(), Nx_total, kStateWidth); - flux = ArrayView(buf_flux.data(), Nx_total, kStateWidth); + buf_x.resize(Nx_total); + + conservative = ArrayView2D(buf_conservative.data(), Nx_total, kStateWidth); + primitive = ArrayView2D(buf_primitive.data(), Nx_total, kStateWidth); + slopes = ArrayView2D(buf_slopes.data(), Nx_total, kStateWidth); + primitive_left = ArrayView2D(buf_primitive_left.data(), Nx_total, kStateWidth); + primitive_right = ArrayView2D(buf_primitive_right.data(), Nx_total, kStateWidth); + rhs1 = ArrayView2D(buf_rhs1.data(), Nx_total, kStateWidth); + stage1 = ArrayView2D(buf_stage1.data(), Nx_total, kStateWidth); + flux = ArrayView2D(buf_flux.data(), Nx_total, kStateWidth); + x = ArrayView1D(buf_x.data(), Nx_total); + + for (std::size_t i = 0; i < Nx_total; ++i) { + x(i) = (static_cast(i) + 0.5) * dx; + } } - using ArrayView = stdex::mdspan>; - std::size_t Nx; // number of grids for the physical domain (excluding the ghost cells) std::size_t Lbx; // lower bound of the physical domain in padded indexing std::size_t Ubx; // upper bound of the physical domain in padded indexing - double x_left; - double x_right; double dx; double dt; double t_final; @@ -71,34 +71,31 @@ struct SolverWorkspace { std::vector buf_rhs1; std::vector buf_stage1; std::vector buf_flux; + std::vector buf_x; // view - ArrayView conservative; - ArrayView primitive; - ArrayView slopes; - ArrayView primitive_left; - ArrayView primitive_right; - ArrayView rhs1; - ArrayView stage1; - ArrayView flux; + ArrayView2D conservative; + ArrayView2D primitive; + ArrayView2D slopes; + ArrayView2D primitive_left; + ArrayView2D primitive_right; + ArrayView2D rhs1; + ArrayView2D stage1; + ArrayView2D flux; + ArrayView1D x; }; StateVector primitive_to_conservative(const StateVector& primitive, double bx, double gamma); StateVector conservative_to_primitive(const StateVector& conservative, double bx, double gamma); -void primitive_profile_to_conservative(ConstArrayView primitive_cells, ArrayView conservative_cells, - double bx = 0.75, double gamma = 2.0); - -void conservative_profile_to_primitive(ConstArrayView conservative_cells, ArrayView primitive_cells, - double bx = 0.75, double gamma = 2.0); +void primitive_profile_to_conservative(ArrayView2D primitive_cells, ArrayView2D conservative_cells, + double bx, double gamma); StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, double gamma); -std::vector cell_centers(std::size_t nx, double x_left, double x_right); - -void apply_zero_gradient_boundary(ArrayView u, std::size_t lbx, std::size_t ubx); +void apply_zero_gradient_boundary(ArrayView2D u, std::size_t lbx, std::size_t ubx); // Interface semantics: // - primitive_left(ix, :) is the left state at interface ix + 1/2. @@ -109,23 +106,12 @@ void reconstruct_mc2_primitive_states(SolverWorkspace& workspace); // The interface state pair is: // - left = primitive_left(ix, :) // - right = primitive_right(ix + 1, :) -void compute_hlld_fluxes_from_reconstructed(SolverWorkspace& workspace, double bx = 0.75, - double gamma = 2.0); - -void compute_semidiscrete_rhs_patterned(ConstArrayView conservative_cells, ArrayView rhs, double dx, - double bx = 0.75, double gamma = 2.0); +void compute_hlld_fluxes_from_reconstructed(SolverWorkspace& workspace, double bx, double gamma); void compute_semidiscrete_rhs_patterned(SolverWorkspace& workspace); -void ssp_rk3_step_patterned(ConstArrayView conservative_cells, ArrayView output, double dt, - double dx, double bx = 0.75, double gamma = 2.0); - void ssp_rk3_step_patterned(SolverWorkspace& workspace, double dt); -void evolve_ssp_rk3_fixed_dt_patterned(ConstArrayView conservative_cells, ArrayView output, - double t_final, double dt, double dx, double bx = 0.75, - double gamma = 2.0); - void evolve_ssp_rk3_fixed_dt_patterned(SolverWorkspace& workspace); } // namespace mhd1d diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp index e739dcc..c7cdd45 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp @@ -10,7 +10,7 @@ namespace constexpr double kTolerance = 1.0e-12; -mhd1d::StateVector row_to_state(mhd1d::ConstArrayView cells, std::size_t row) +mhd1d::StateVector row_to_state(mhd1d::ArrayView2D cells, std::size_t row) { mhd1d::StateVector state{}; for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { @@ -19,7 +19,7 @@ mhd1d::StateVector row_to_state(mhd1d::ConstArrayView cells, std::size_t row) return state; } -void state_to_row(mhd1d::ArrayView cells, std::size_t row, const mhd1d::StateVector& state) +void state_to_row(mhd1d::ArrayView2D cells, std::size_t row, const mhd1d::StateVector& state) { for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { cells(row, component) = state[component]; @@ -73,7 +73,7 @@ TEST_CASE("primitive and conservative states round-trip", "[mhd1d][conversion]") TEST_CASE("reconstruct_mc2_primitive_states preserves a constant primitive state exactly", "[mhd1d][reconstruction]") { - mhd1d::SolverWorkspace workspace(4); + mhd1d::SolverWorkspace workspace(4, 5.0e-4, 0.1, 2.0, 0.75); const auto constant_state = mhd1d::StateVector{0.9, 0.3, -0.2, 0.1, 1.8, -0.45, 0.6}; for (std::size_t index = 0; index < workspace.conservative.extent(0); ++index) { @@ -124,7 +124,7 @@ TEST_CASE("hlld_flux_from_primitive matches the physical flux for identical stat TEST_CASE("apply_zero_gradient_boundary duplicates edge states on both sides", "[mhd1d][boundary]") { std::vector padded_buffer(7 * mhd1d::kStateWidth, 0.0); - const mhd1d::ArrayView padded(padded_buffer.data(), 7, mhd1d::kStateWidth); + const mhd1d::ArrayView2D padded(padded_buffer.data(), 7, mhd1d::kStateWidth); state_to_row(padded, 2, mhd1d::StateVector{1.0, 0.5, -0.25, 0.125, 2.0, 0.1, -0.05}); state_to_row(padded, 3, mhd1d::StateVector{1.2, 0.6, -0.2, 0.15, 2.2, 0.12, -0.02}); state_to_row(padded, 4, mhd1d::StateVector{1.4, 0.7, -0.15, 0.175, 2.4, 0.14, 0.01}); @@ -143,7 +143,7 @@ TEST_CASE("apply_zero_gradient_boundary duplicates edge states on both sides", " TEST_CASE("apply_zero_gradient_boundary handles a single interior cell", "[mhd1d][boundary]") { std::vector padded_buffer(5 * mhd1d::kStateWidth, 0.0); - const mhd1d::ArrayView padded(padded_buffer.data(), 5, mhd1d::kStateWidth); + const mhd1d::ArrayView2D padded(padded_buffer.data(), 5, mhd1d::kStateWidth); const auto cell = mhd1d::StateVector{1.5, -0.75, 0.25, 0.0, 3.5, -0.1, 0.2}; state_to_row(padded, 2, cell); mhd1d::apply_zero_gradient_boundary(padded, 2, 2); @@ -157,7 +157,7 @@ TEST_CASE("apply_zero_gradient_boundary overwrites ghost cells from interior bou "[mhd1d][boundary]") { std::vector cells_buffer(6 * mhd1d::kStateWidth, 0.0); - const mhd1d::ArrayView cells(cells_buffer.data(), 6, mhd1d::kStateWidth); + const mhd1d::ArrayView2D cells(cells_buffer.data(), 6, mhd1d::kStateWidth); state_to_row(cells, 0, mhd1d::StateVector{-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0}); state_to_row(cells, 1, mhd1d::StateVector{1.0, 0.1, 0.2, 0.3, 2.0, 0.4, 0.5}); @@ -184,7 +184,7 @@ TEST_CASE("apply_zero_gradient_boundary overwrites ghost cells from interior bou std::vector make_sample_conservative_cells() { std::vector conservative_cells(4 * mhd1d::kStateWidth, 0.0); - const mhd1d::ArrayView view(conservative_cells.data(), 4, mhd1d::kStateWidth); + const mhd1d::ArrayView2D view(conservative_cells.data(), 4, mhd1d::kStateWidth); state_to_row(view, 0, mhd1d::StateVector{1.0, 0.1, 0.0, 0.0, 1.6, 0.20, 0.00}); state_to_row(view, 1, mhd1d::StateVector{0.9, 0.0, 0.1, 0.0, 1.3, 0.15, 0.05}); state_to_row(view, 2, mhd1d::StateVector{0.8, -0.1, 0.0, 0.1, 1.1, 0.10, 0.10}); @@ -192,13 +192,10 @@ std::vector make_sample_conservative_cells() return conservative_cells; } -TEST_CASE("arrayview compute_semidiscrete_rhs returns finite values", "[mhd1d][arrayview]") +TEST_CASE("compute_semidiscrete_rhs returns finite values", "[mhd1d][evolution]") { const std::size_t nx = 4; - mhd1d::SolverWorkspace workspace(nx); - workspace.dx = 1.0 / static_cast(nx); - workspace.bx = 0.75; - workspace.gamma = 2.0; + mhd1d::SolverWorkspace workspace(nx, 5.0e-4, 0.1, 2.0, 0.75); const std::vector conservative_cells = make_sample_conservative_cells(); for (std::size_t row = 0; row < nx; ++row) { @@ -216,14 +213,10 @@ TEST_CASE("arrayview compute_semidiscrete_rhs returns finite values", "[mhd1d][a } } -TEST_CASE("arrayview ssp_rk3_step evolves state with finite conservative values", - "[mhd1d][arrayview]") +TEST_CASE("ssp_rk3_step evolves state with finite conservative values", "[mhd1d][evolution]") { const std::size_t nx = 4; - mhd1d::SolverWorkspace workspace(nx); - workspace.dx = 1.0 / static_cast(nx); - workspace.bx = 0.75; - workspace.gamma = 2.0; + mhd1d::SolverWorkspace workspace(nx, 5.0e-4, 0.1, 2.0, 0.75); const std::vector conservative_cells = make_sample_conservative_cells(); for (std::size_t row = 0; row < nx; ++row) { @@ -244,24 +237,15 @@ TEST_CASE("arrayview ssp_rk3_step evolves state with finite conservative values" } } -TEST_CASE("arrayview evolve_ssp_rk3_fixed_dt matches repeated arrayview steps", - "[mhd1d][arrayview]") +TEST_CASE("evolve_ssp_rk3_fixed_dt matches repeated ssp_rk3_step calls", "[mhd1d][evolution]") { const std::size_t nx = 4; const double dt = 1.0e-4; const double t_final = 2.0e-4; - mhd1d::SolverWorkspace evolved_workspace(nx); - evolved_workspace.dx = 1.0 / static_cast(nx); - evolved_workspace.bx = 0.75; - evolved_workspace.gamma = 2.0; - evolved_workspace.dt = dt; - evolved_workspace.t_final = t_final; - - mhd1d::SolverWorkspace manual_workspace(nx); - manual_workspace.dx = evolved_workspace.dx; - manual_workspace.bx = evolved_workspace.bx; - manual_workspace.gamma = evolved_workspace.gamma; + mhd1d::SolverWorkspace evolved_workspace(nx, dt, t_final, 2.0, 0.75); + + mhd1d::SolverWorkspace manual_workspace(nx, dt, t_final, 2.0, 0.75); const std::vector conservative_cells = make_sample_conservative_cells(); for (std::size_t row = 0; row < nx; ++row) { From a6e4cb821c4743e433915bc500b243e149885c2e Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Wed, 1 Apr 2026 14:10:09 +0900 Subject: [PATCH 23/39] refactor(cpp-full-solver1d): drop dt/t_final from SolverWorkspace Remove dt and t_final from SolverWorkspace constructor and members. Pass them directly to evolve_ssp_rk3(workspace, dt, t_final) instead. Constructor now takes (nx, gamma, bx) only. --- .../cpp-full-solver1d/workspace/src/main.cpp | 10 +-- .../cpp-full-solver1d/workspace/src/mhd1d.cpp | 76 +++++++++---------- .../cpp-full-solver1d/workspace/src/mhd1d.hpp | 28 +++---- .../workspace/tests/cpp/test_public.cpp | 41 +++++----- 4 files changed, 68 insertions(+), 87 deletions(-) diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp index 1b60dec..50dbc5e 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp @@ -22,7 +22,7 @@ constexpr mhd1d::StateVector kBrioWuRightPrimitive{ } // namespace -void init_brio_wu_primitive(mhd1d::SolverWorkspace& workspace) +void initialize(mhd1d::SolverWorkspace& workspace) { for (std::size_t index = workspace.Lbx; index <= workspace.Ubx; ++index) { const std::size_t center_index = index - workspace.Lbx; @@ -37,14 +37,14 @@ void init_brio_wu_primitive(mhd1d::SolverWorkspace& workspace) int main() { - mhd1d::SolverWorkspace workspace(kBrioWuNx, kBrioWuDt, kBrioWuTFinal, kBrioWuGamma, kBrioWuBx); + mhd1d::SolverWorkspace workspace(kBrioWuNx, kBrioWuGamma, kBrioWuBx); - init_brio_wu_primitive(workspace); + initialize(workspace); - mhd1d::apply_zero_gradient_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); + mhd1d::set_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); mhd1d::primitive_profile_to_conservative(workspace.primitive, workspace.conservative, workspace.bx, workspace.gamma); - mhd1d::evolve_ssp_rk3_fixed_dt_patterned(workspace); + mhd1d::evolve_ssp_rk3(workspace, kBrioWuDt, kBrioWuTFinal); std::cout << "x,rho,u,v,w,p,by,bz\n"; std::cout << std::setprecision(17); diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp index d330188..163e9a2 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp @@ -13,15 +13,9 @@ namespace constexpr double kHlldEps = 1.0e-40; -double sign(double value) +double sign(const double x) { - if (value > 0.0) { - return 1.0; - } - if (value < 0.0) { - return -1.0; - } - return 0.0; + return copysign(1.0, x); } double mc2(double a, double b) @@ -57,9 +51,8 @@ void copy_cells(ArrayView2D source, ArrayView2D destination) } } -void conservative_profile_to_primitive_profile_inplace(ArrayView2D conservative_cells, - ArrayView2D primitive_cells, double bx, - double gamma) +void convert_conservative_to_primitive(ArrayView2D conservative_cells, ArrayView2D primitive_cells, + double bx, double gamma) { const int nx = static_cast(conservative_cells.extent(0)); for (int ix = 0; ix < nx; ++ix) { @@ -123,7 +116,7 @@ void primitive_profile_to_conservative(ArrayView2D primitive_cells, ArrayView2D } } -void reconstruct_mc2_primitive_states(SolverWorkspace& workspace) +void reconstruct_mc2(SolverWorkspace& workspace) { const ArrayView2D primitive_cells = workspace.primitive; const ArrayView2D left_states = workspace.primitive_left; @@ -145,7 +138,7 @@ void reconstruct_mc2_primitive_states(SolverWorkspace& workspace) } } -void compute_hlld_fluxes_from_reconstructed(SolverWorkspace& workspace, double bx, double gamma) +void compute_flux_hlld(SolverWorkspace& workspace, double bx, double gamma) { const ArrayView2D left_states = workspace.primitive_left; const ArrayView2D right_states = workspace.primitive_right; @@ -360,7 +353,7 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& }; } -void apply_zero_gradient_boundary(ArrayView2D u, std::size_t lbx, std::size_t ubx) +void set_boundary(ArrayView2D u, std::size_t lbx, std::size_t ubx) { const std::size_t nx_total = u.extent(0); @@ -377,19 +370,18 @@ void apply_zero_gradient_boundary(ArrayView2D u, std::size_t lbx, std::size_t ub } } -void compute_semidiscrete_rhs_patterned(SolverWorkspace& workspace) +void compute_rhs(SolverWorkspace& workspace) { const ArrayView2D conservative = workspace.conservative; const ArrayView2D primitive = workspace.primitive; const ArrayView2D fluxes = workspace.flux; const ArrayView2D rhs = workspace.rhs1; - apply_zero_gradient_boundary(conservative, workspace.Lbx, workspace.Ubx); - conservative_profile_to_primitive_profile_inplace(conservative, primitive, workspace.bx, - workspace.gamma); - apply_zero_gradient_boundary(primitive, workspace.Lbx, workspace.Ubx); - reconstruct_mc2_primitive_states(workspace); - compute_hlld_fluxes_from_reconstructed(workspace, workspace.bx, workspace.gamma); + set_boundary(conservative, workspace.Lbx, workspace.Ubx); + convert_conservative_to_primitive(conservative, primitive, workspace.bx, workspace.gamma); + set_boundary(primitive, workspace.Lbx, workspace.Ubx); + reconstruct_mc2(workspace); + compute_flux_hlld(workspace, workspace.bx, workspace.gamma); const int lbx = static_cast(workspace.Lbx); const int ubx = static_cast(workspace.Ubx); @@ -403,7 +395,7 @@ void compute_semidiscrete_rhs_patterned(SolverWorkspace& workspace) } } -void ssp_rk3_step_patterned(SolverWorkspace& workspace, double dt) +void push_ssp_rk3(SolverWorkspace& workspace, double dt) { constexpr double kCoeffs[3][3] = { {1.0, 0.0, 1.0}, @@ -417,7 +409,7 @@ void ssp_rk3_step_patterned(SolverWorkspace& workspace, double dt) copy_cells(workspace.conservative, u0); for (int substep = 0; substep < 3; ++substep) { - compute_semidiscrete_rhs_patterned(workspace); + compute_rhs(workspace); const double a = kCoeffs[substep][0]; const double b = kCoeffs[substep][1]; @@ -434,35 +426,35 @@ void ssp_rk3_step_patterned(SolverWorkspace& workspace, double dt) } } - conservative_profile_to_primitive_profile_inplace(workspace.conservative, workspace.primitive, - workspace.bx, workspace.gamma); - apply_zero_gradient_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); + convert_conservative_to_primitive(workspace.conservative, workspace.primitive, workspace.bx, + workspace.gamma); + set_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); } - apply_zero_gradient_boundary(workspace.conservative, workspace.Lbx, workspace.Ubx); + set_boundary(workspace.conservative, workspace.Lbx, workspace.Ubx); } -void evolve_ssp_rk3_fixed_dt_patterned(SolverWorkspace& workspace) +void evolve_ssp_rk3(SolverWorkspace& workspace, double dt, double t_final) { - if (workspace.t_final < 0.0 || workspace.dt <= 0.0) { - apply_zero_gradient_boundary(workspace.conservative, workspace.Lbx, workspace.Ubx); - conservative_profile_to_primitive_profile_inplace(workspace.conservative, workspace.primitive, - workspace.bx, workspace.gamma); - apply_zero_gradient_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); + if (t_final < 0.0 || dt <= 0.0) { + set_boundary(workspace.conservative, workspace.Lbx, workspace.Ubx); + convert_conservative_to_primitive(workspace.conservative, workspace.primitive, workspace.bx, + workspace.gamma); + set_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); return; } - apply_zero_gradient_boundary(workspace.conservative, workspace.Lbx, workspace.Ubx); - conservative_profile_to_primitive_profile_inplace(workspace.conservative, workspace.primitive, - workspace.bx, workspace.gamma); - apply_zero_gradient_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); + set_boundary(workspace.conservative, workspace.Lbx, workspace.Ubx); + convert_conservative_to_primitive(workspace.conservative, workspace.primitive, workspace.bx, + workspace.gamma); + set_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); double elapsed_time = 0.0; - while (elapsed_time < workspace.t_final) { - const double remaining_time = workspace.t_final - elapsed_time; - const double step_dt = std::min(workspace.dt, remaining_time); - ssp_rk3_step_patterned(workspace, step_dt); - elapsed_time = (step_dt < workspace.dt) ? workspace.t_final : (elapsed_time + step_dt); + while (elapsed_time < t_final) { + const double remaining_time = t_final - elapsed_time; + const double step_dt = std::min(dt, remaining_time); + push_ssp_rk3(workspace, step_dt); + elapsed_time = (step_dt < dt) ? t_final : (elapsed_time + step_dt); } } diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp index 05d2529..0b694b9 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp @@ -16,14 +16,13 @@ constexpr std::size_t kStateWidth = 7; constexpr std::size_t kGhostWidth = 2; using StateVector = std::array; -using ArrayView2D = stdex::mdspan>; using ArrayView1D = stdex::mdspan>; +using ArrayView2D = stdex::mdspan>; struct SolverWorkspace { - explicit SolverWorkspace(std::size_t nx, double dt, double t_final, double gamma, double bx) + explicit SolverWorkspace(std::size_t nx, double gamma, double bx) : Nx(nx), Lbx(kGhostWidth), Ubx(kGhostWidth + nx - 1U), - dx(nx == 0U ? 0.0 : 1.0 / static_cast(nx)), dt(dt), t_final(t_final), - gamma(gamma), bx(bx) + dx(nx == 0U ? 0.0 : 1.0 / static_cast(nx)), gamma(gamma), bx(bx) { const std::size_t Nx_total = Nx + 2U * kGhostWidth; const std::size_t padded_size = Nx_total * kStateWidth; @@ -57,8 +56,6 @@ struct SolverWorkspace { std::size_t Lbx; // lower bound of the physical domain in padded indexing std::size_t Ubx; // upper bound of the physical domain in padded indexing double dx; - double dt; - double t_final; double gamma; double bx; @@ -95,23 +92,16 @@ void primitive_profile_to_conservative(ArrayView2D primitive_cells, ArrayView2D StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, double gamma); -void apply_zero_gradient_boundary(ArrayView2D u, std::size_t lbx, std::size_t ubx); +void set_boundary(ArrayView2D u, std::size_t lbx, std::size_t ubx); -// Interface semantics: -// - primitive_left(ix, :) is the left state at interface ix + 1/2. -// - primitive_right(ix, :) is the right state at interface ix - 1/2. -void reconstruct_mc2_primitive_states(SolverWorkspace& workspace); +void reconstruct_mc2(SolverWorkspace& workspace); -// flux(ix, :) stores the HLLD flux at interface ix + 1/2. -// The interface state pair is: -// - left = primitive_left(ix, :) -// - right = primitive_right(ix + 1, :) -void compute_hlld_fluxes_from_reconstructed(SolverWorkspace& workspace, double bx, double gamma); +void compute_flux_hlld(SolverWorkspace& workspace, double bx, double gamma); -void compute_semidiscrete_rhs_patterned(SolverWorkspace& workspace); +void compute_rhs(SolverWorkspace& workspace); -void ssp_rk3_step_patterned(SolverWorkspace& workspace, double dt); +void push_ssp_rk3(SolverWorkspace& workspace, double dt); -void evolve_ssp_rk3_fixed_dt_patterned(SolverWorkspace& workspace); +void evolve_ssp_rk3(SolverWorkspace& workspace, double dt, double t_final); } // namespace mhd1d diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp index c7cdd45..df02eca 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp @@ -70,17 +70,17 @@ TEST_CASE("primitive and conservative states round-trip", "[mhd1d][conversion]") require_state_vector_close(output, input); } -TEST_CASE("reconstruct_mc2_primitive_states preserves a constant primitive state exactly", +TEST_CASE("reconstruct_mc2 preserves a constant primitive state exactly", "[mhd1d][reconstruction]") { - mhd1d::SolverWorkspace workspace(4, 5.0e-4, 0.1, 2.0, 0.75); + mhd1d::SolverWorkspace workspace(4, 2.0, 0.75); const auto constant_state = mhd1d::StateVector{0.9, 0.3, -0.2, 0.1, 1.8, -0.45, 0.6}; for (std::size_t index = 0; index < workspace.conservative.extent(0); ++index) { state_to_row(workspace.primitive, index, constant_state); } - mhd1d::reconstruct_mc2_primitive_states(workspace); + mhd1d::reconstruct_mc2(workspace); for (std::size_t index = workspace.Lbx; index <= workspace.Ubx; ++index) { require_state_vector_close(row_to_state(workspace.primitive_left, index), constant_state); @@ -121,7 +121,7 @@ TEST_CASE("hlld_flux_from_primitive matches the physical flux for identical stat require_state_vector_close(actual, expected); } -TEST_CASE("apply_zero_gradient_boundary duplicates edge states on both sides", "[mhd1d][boundary]") +TEST_CASE("set_boundary duplicates edge states on both sides", "[mhd1d][boundary]") { std::vector padded_buffer(7 * mhd1d::kStateWidth, 0.0); const mhd1d::ArrayView2D padded(padded_buffer.data(), 7, mhd1d::kStateWidth); @@ -129,7 +129,7 @@ TEST_CASE("apply_zero_gradient_boundary duplicates edge states on both sides", " state_to_row(padded, 3, mhd1d::StateVector{1.2, 0.6, -0.2, 0.15, 2.2, 0.12, -0.02}); state_to_row(padded, 4, mhd1d::StateVector{1.4, 0.7, -0.15, 0.175, 2.4, 0.14, 0.01}); - mhd1d::apply_zero_gradient_boundary(padded, 2, 4); + mhd1d::set_boundary(padded, 2, 4); require_state_vector_close(row_to_state(padded, 0), row_to_state(padded, 2)); require_state_vector_close(row_to_state(padded, 1), row_to_state(padded, 2)); @@ -140,20 +140,20 @@ TEST_CASE("apply_zero_gradient_boundary duplicates edge states on both sides", " require_state_vector_close(row_to_state(padded, 6), row_to_state(padded, 4)); } -TEST_CASE("apply_zero_gradient_boundary handles a single interior cell", "[mhd1d][boundary]") +TEST_CASE("set_boundary handles a single interior cell", "[mhd1d][boundary]") { std::vector padded_buffer(5 * mhd1d::kStateWidth, 0.0); const mhd1d::ArrayView2D padded(padded_buffer.data(), 5, mhd1d::kStateWidth); const auto cell = mhd1d::StateVector{1.5, -0.75, 0.25, 0.0, 3.5, -0.1, 0.2}; state_to_row(padded, 2, cell); - mhd1d::apply_zero_gradient_boundary(padded, 2, 2); + mhd1d::set_boundary(padded, 2, 2); for (std::size_t index = 0; index < 5; ++index) { require_state_vector_close(row_to_state(padded, index), cell); } } -TEST_CASE("apply_zero_gradient_boundary overwrites ghost cells from interior boundary", +TEST_CASE("set_boundary overwrites ghost cells from interior boundary", "[mhd1d][boundary]") { std::vector cells_buffer(6 * mhd1d::kStateWidth, 0.0); @@ -171,7 +171,7 @@ TEST_CASE("apply_zero_gradient_boundary overwrites ghost cells from interior bou const mhd1d::StateVector interior_mid_2 = row_to_state(cells, 2); const mhd1d::StateVector interior_mid_3 = row_to_state(cells, 3); - mhd1d::apply_zero_gradient_boundary(cells, 1, 4); + mhd1d::set_boundary(cells, 1, 4); require_state_vector_close(row_to_state(cells, 0), interior_left); require_state_vector_close(row_to_state(cells, 5), interior_right); @@ -192,10 +192,10 @@ std::vector make_sample_conservative_cells() return conservative_cells; } -TEST_CASE("compute_semidiscrete_rhs returns finite values", "[mhd1d][evolution]") +TEST_CASE("compute_rhs returns finite values", "[mhd1d][evolution]") { const std::size_t nx = 4; - mhd1d::SolverWorkspace workspace(nx, 5.0e-4, 0.1, 2.0, 0.75); + mhd1d::SolverWorkspace workspace(nx, 2.0, 0.75); const std::vector conservative_cells = make_sample_conservative_cells(); for (std::size_t row = 0; row < nx; ++row) { @@ -205,7 +205,7 @@ TEST_CASE("compute_semidiscrete_rhs returns finite values", "[mhd1d][evolution]" } } - mhd1d::compute_semidiscrete_rhs_patterned(workspace); + mhd1d::compute_rhs(workspace); for (std::size_t row = workspace.Lbx; row <= workspace.Ubx; ++row) { for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { REQUIRE(std::isfinite(workspace.rhs1(row, component))); @@ -213,10 +213,10 @@ TEST_CASE("compute_semidiscrete_rhs returns finite values", "[mhd1d][evolution]" } } -TEST_CASE("ssp_rk3_step evolves state with finite conservative values", "[mhd1d][evolution]") +TEST_CASE("push_ssp_rk3 evolves state with finite conservative values", "[mhd1d][evolution]") { const std::size_t nx = 4; - mhd1d::SolverWorkspace workspace(nx, 5.0e-4, 0.1, 2.0, 0.75); + mhd1d::SolverWorkspace workspace(nx, 2.0, 0.75); const std::vector conservative_cells = make_sample_conservative_cells(); for (std::size_t row = 0; row < nx; ++row) { @@ -226,7 +226,7 @@ TEST_CASE("ssp_rk3_step evolves state with finite conservative values", "[mhd1d] } } - mhd1d::ssp_rk3_step_patterned(workspace, 1.0e-4); + mhd1d::push_ssp_rk3(workspace, 1.0e-4); for (std::size_t row = workspace.Lbx; row <= workspace.Ubx; ++row) { const double rho = workspace.conservative(row, 0U); @@ -237,15 +237,14 @@ TEST_CASE("ssp_rk3_step evolves state with finite conservative values", "[mhd1d] } } -TEST_CASE("evolve_ssp_rk3_fixed_dt matches repeated ssp_rk3_step calls", "[mhd1d][evolution]") +TEST_CASE("evolve_ssp_rk3 matches repeated push_ssp_rk3 calls", "[mhd1d][evolution]") { const std::size_t nx = 4; const double dt = 1.0e-4; const double t_final = 2.0e-4; - mhd1d::SolverWorkspace evolved_workspace(nx, dt, t_final, 2.0, 0.75); - - mhd1d::SolverWorkspace manual_workspace(nx, dt, t_final, 2.0, 0.75); + mhd1d::SolverWorkspace evolved_workspace(nx, 2.0, 0.75); + mhd1d::SolverWorkspace manual_workspace(nx, 2.0, 0.75); const std::vector conservative_cells = make_sample_conservative_cells(); for (std::size_t row = 0; row < nx; ++row) { @@ -256,10 +255,10 @@ TEST_CASE("evolve_ssp_rk3_fixed_dt matches repeated ssp_rk3_step calls", "[mhd1d } } - mhd1d::evolve_ssp_rk3_fixed_dt_patterned(evolved_workspace); + mhd1d::evolve_ssp_rk3(evolved_workspace, dt, t_final); for (int step = 0; step < 2; ++step) { - mhd1d::ssp_rk3_step_patterned(manual_workspace, dt); + mhd1d::push_ssp_rk3(manual_workspace, dt); } for (std::size_t row = 0; row < nx; ++row) { From 32138c33e5d2c23dad1e051ebd8eb50108d9c2a3 Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Wed, 1 Apr 2026 14:30:14 +0900 Subject: [PATCH 24/39] refactor(cpp-full-solver1d): clean up initialize and cell center indexing - Simplify initialize() signature: remove discontinuity_x parameter, hardcode 0.5 inside; remove unused constants from main.cpp - Fix cell center initialization to only fill interior cells (Lbx..Ubx) instead of all padded cells, matching the physical domain convention - Rename local dt/t_final to delt/tmax in main() --- .../cpp-full-solver1d/workspace/src/main.cpp | 35 ++++++++++--------- .../cpp-full-solver1d/workspace/src/mhd1d.hpp | 4 +-- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp index 50dbc5e..a0118aa 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp @@ -7,12 +7,9 @@ namespace { -constexpr std::size_t kBrioWuNx = 400; -constexpr double kBrioWuDiscontinuityX = 0.5; -constexpr double kBrioWuDt = 5.0e-4; -constexpr double kBrioWuTFinal = 0.1; -constexpr double kBrioWuGamma = 2.0; -constexpr double kBrioWuBx = 0.75; +constexpr std::size_t kBrioWuNx = 400; +constexpr double kBrioWuGamma = 2.0; +constexpr double kBrioWuBx = 0.75; constexpr mhd1d::StateVector kBrioWuLeftPrimitive{ 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, }; @@ -22,29 +19,35 @@ constexpr mhd1d::StateVector kBrioWuRightPrimitive{ } // namespace -void initialize(mhd1d::SolverWorkspace& workspace) +mhd1d::SolverWorkspace initialize(std::size_t nx, double gamma, double bx, + const mhd1d::StateVector& left_state, + const mhd1d::StateVector& right_state) { + mhd1d::SolverWorkspace workspace(nx, gamma, bx); + for (std::size_t index = workspace.Lbx; index <= workspace.Ubx; ++index) { const std::size_t center_index = index - workspace.Lbx; - const mhd1d::StateVector& state = (workspace.x(center_index) < kBrioWuDiscontinuityX) - ? kBrioWuLeftPrimitive - : kBrioWuRightPrimitive; + const mhd1d::StateVector& state = (workspace.x(center_index) < 0.5) ? left_state : right_state; for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { workspace.primitive(index, component) = state[component]; } } + + mhd1d::set_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); + mhd1d::primitive_profile_to_conservative(workspace.primitive, workspace.conservative, bx, gamma); + + return workspace; } int main() { - mhd1d::SolverWorkspace workspace(kBrioWuNx, kBrioWuGamma, kBrioWuBx); + const double delt = 5.0e-4; + const double tmax = 0.1; - initialize(workspace); + auto workspace = + initialize(kBrioWuNx, kBrioWuGamma, kBrioWuBx, kBrioWuLeftPrimitive, kBrioWuRightPrimitive); - mhd1d::set_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); - mhd1d::primitive_profile_to_conservative(workspace.primitive, workspace.conservative, - workspace.bx, workspace.gamma); - mhd1d::evolve_ssp_rk3(workspace, kBrioWuDt, kBrioWuTFinal); + mhd1d::evolve_ssp_rk3(workspace, delt, tmax); std::cout << "x,rho,u,v,w,p,by,bz\n"; std::cout << std::setprecision(17); diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp index 0b694b9..5a60e4b 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp @@ -47,8 +47,8 @@ struct SolverWorkspace { flux = ArrayView2D(buf_flux.data(), Nx_total, kStateWidth); x = ArrayView1D(buf_x.data(), Nx_total); - for (std::size_t i = 0; i < Nx_total; ++i) { - x(i) = (static_cast(i) + 0.5) * dx; + for (std::size_t ix = Lbx; ix <= Ubx; ++ix) { + x(ix) = (static_cast(ix - Lbx) + 0.5) * dx; } } From 98f26bebbe9830150e33f27d23c19c1fc3220e8a Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Wed, 1 Apr 2026 17:47:34 +0900 Subject: [PATCH 25/39] refactor(cpp-full-solver1d): simplify storage and boundary handling --- .../cpp-full-solver1d/workspace/src/main.cpp | 54 ++++--- .../cpp-full-solver1d/workspace/src/mhd1d.cpp | 143 ++++++++---------- .../cpp-full-solver1d/workspace/src/mhd1d.hpp | 111 +++++++------- .../workspace/tests/cpp/test_public.cpp | 129 ++++++++-------- 4 files changed, 209 insertions(+), 228 deletions(-) diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp index a0118aa..e7e29be 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp @@ -4,60 +4,58 @@ #include #include -namespace -{ - -constexpr std::size_t kBrioWuNx = 400; -constexpr double kBrioWuGamma = 2.0; -constexpr double kBrioWuBx = 0.75; -constexpr mhd1d::StateVector kBrioWuLeftPrimitive{ +constexpr int Nx = 400; +constexpr double Gamma = 2.0; +constexpr double Bx = 0.75; +constexpr mhd1d::StateVector LeftPrimitive{ 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, }; -constexpr mhd1d::StateVector kBrioWuRightPrimitive{ +constexpr mhd1d::StateVector RightPrimitive{ 0.125, 0.0, 0.0, 0.0, 0.1, -1.0, 0.0, }; -} // namespace - -mhd1d::SolverWorkspace initialize(std::size_t nx, double gamma, double bx, +mhd1d::SolverWorkspace initialize(int nx, double gamma, double bx, const mhd1d::StateVector& left_state, const mhd1d::StateVector& right_state) { mhd1d::SolverWorkspace workspace(nx, gamma, bx); - for (std::size_t index = workspace.Lbx; index <= workspace.Ubx; ++index) { - const std::size_t center_index = index - workspace.Lbx; - const mhd1d::StateVector& state = (workspace.x(center_index) < 0.5) ? left_state : right_state; - for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { - workspace.primitive(index, component) = state[component]; + for (int ix = workspace.Lbx; ix <= workspace.Ubx; ++ix) { + const mhd1d::StateVector& state = (workspace.x(ix) < 0.5) ? left_state : right_state; + for (int component = 0; component < mhd1d::kStateWidth; ++component) { + workspace.primitive(ix, component) = state[component]; } } - mhd1d::set_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); + mhd1d::set_left_boundary(workspace.primitive, workspace.primitive, workspace.Lbx); + mhd1d::set_right_boundary(workspace.primitive, workspace.primitive, workspace.Ubx); mhd1d::primitive_profile_to_conservative(workspace.primitive, workspace.conservative, bx, gamma); return workspace; } +void write_csv(const mhd1d::SolverWorkspace& workspace, std::ostream& os) +{ + os << "x,rho,u,v,w,p,by,bz\n"; + os << std::setprecision(17); + for (int ix = workspace.Lbx; ix <= workspace.Ubx; ++ix) { + os << workspace.x(ix) << ',' << workspace.primitive(ix, 0) << ',' << workspace.primitive(ix, 1) + << ',' << workspace.primitive(ix, 2) << ',' << workspace.primitive(ix, 3) << ',' + << workspace.primitive(ix, 4) << ',' << workspace.primitive(ix, 5) << ',' + << workspace.primitive(ix, 6) << '\n'; + } +} + int main() { const double delt = 5.0e-4; const double tmax = 0.1; - auto workspace = - initialize(kBrioWuNx, kBrioWuGamma, kBrioWuBx, kBrioWuLeftPrimitive, kBrioWuRightPrimitive); + auto workspace = initialize(Nx, Gamma, Bx, LeftPrimitive, RightPrimitive); mhd1d::evolve_ssp_rk3(workspace, delt, tmax); - std::cout << "x,rho,u,v,w,p,by,bz\n"; - std::cout << std::setprecision(17); - for (std::size_t index = workspace.Lbx; index <= workspace.Ubx; ++index) { - const std::size_t center_index = index - workspace.Lbx; - std::cout << workspace.x(center_index) << ',' << workspace.primitive(index, 0) << ',' - << workspace.primitive(index, 1) << ',' << workspace.primitive(index, 2) << ',' - << workspace.primitive(index, 3) << ',' << workspace.primitive(index, 4) << ',' - << workspace.primitive(index, 5) << ',' << workspace.primitive(index, 6) << '\n'; - } + write_csv(workspace, std::cout); return 0; } diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp index 163e9a2..94856eb 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp @@ -24,29 +24,28 @@ double mc2(double a, double b) std::min({2.0 * std::abs(a), 2.0 * std::abs(b), 0.5 * std::abs(a + b)}); } -StateVector row_to_state(ArrayView2D cells, std::size_t row) +StateVector row_to_state(ArrayView2D cells, int row) { StateVector state{}; - for (std::size_t component = 0; component < kStateWidth; ++component) { + for (int component = 0; component < kStateWidth; ++component) { state[component] = cells(row, component); } return state; } -void state_to_row(const StateVector& state, ArrayView2D cells, std::size_t row) +void state_to_row(const StateVector& state, ArrayView2D cells, int row) { - for (std::size_t component = 0; component < kStateWidth; ++component) { + for (int component = 0; component < kStateWidth; ++component) { cells(row, component) = state[component]; } } void copy_cells(ArrayView2D source, ArrayView2D destination) { - const int nx = static_cast(source.extent(0)); + const int nx = source.extent(0); for (int ix = 0; ix < nx; ++ix) { - const std::size_t x = static_cast(ix); - for (std::size_t component = 0; component < kStateWidth; ++component) { - destination(x, component) = source(x, component); + for (int component = 0; component < kStateWidth; ++component) { + destination(ix, component) = source(ix, component); } } } @@ -54,12 +53,11 @@ void copy_cells(ArrayView2D source, ArrayView2D destination) void convert_conservative_to_primitive(ArrayView2D conservative_cells, ArrayView2D primitive_cells, double bx, double gamma) { - const int nx = static_cast(conservative_cells.extent(0)); + const int nx = conservative_cells.extent(0); for (int ix = 0; ix < nx; ++ix) { - const std::size_t x = static_cast(ix); const StateVector primitive = - conservative_to_primitive(row_to_state(conservative_cells, x), bx, gamma); - state_to_row(primitive, primitive_cells, x); + conservative_to_primitive(row_to_state(conservative_cells, ix), bx, gamma); + state_to_row(primitive, primitive_cells, ix); } } @@ -107,12 +105,11 @@ StateVector conservative_to_primitive(const StateVector& conservative, double bx void primitive_profile_to_conservative(ArrayView2D primitive_cells, ArrayView2D conservative_cells, double bx, double gamma) { - const int nx = static_cast(primitive_cells.extent(0)); + const int nx = primitive_cells.extent(0); for (int ix = 0; ix < nx; ++ix) { - const std::size_t x = static_cast(ix); const StateVector conservative = - primitive_to_conservative(row_to_state(primitive_cells, x), bx, gamma); - state_to_row(conservative, conservative_cells, x); + primitive_to_conservative(row_to_state(primitive_cells, ix), bx, gamma); + state_to_row(conservative, conservative_cells, ix); } } @@ -122,20 +119,21 @@ void reconstruct_mc2(SolverWorkspace& workspace) const ArrayView2D left_states = workspace.primitive_left; const ArrayView2D right_states = workspace.primitive_right; - const int lbx = static_cast(workspace.Lbx) - 1; - const int ubx = static_cast(workspace.Ubx) + 1; + const int lbx = workspace.Lbx; + const int ubx = workspace.Ubx; for (int ix = lbx; ix <= ubx; ++ix) { - const std::size_t i = static_cast(ix); - for (std::size_t component = 0; component < kStateWidth; ++component) { - const double left_slope = primitive_cells(i, component) - - primitive_cells(static_cast(ix - 1), component); - const double right_slope = primitive_cells(static_cast(ix + 1), component) - - primitive_cells(i, component); - const double slope = mc2(left_slope, right_slope); - left_states(i, component) = primitive_cells(i, component) + 0.5 * slope; - right_states(i, component) = primitive_cells(i, component) - 0.5 * slope; + for (int component = 0; component < kStateWidth; ++component) { + const double left_slope = primitive_cells(ix, component) - primitive_cells(ix - 1, component); + const double right_slope = + primitive_cells(ix + 1, component) - primitive_cells(ix, component); + const double slope = mc2(left_slope, right_slope); + left_states(ix, component) = primitive_cells(ix, component) + 0.5 * slope; + right_states(ix, component) = primitive_cells(ix, component) - 0.5 * slope; } } + + set_left_boundary(left_states, right_states, lbx); + set_right_boundary(right_states, left_states, ubx); } void compute_flux_hlld(SolverWorkspace& workspace, double bx, double gamma) @@ -144,14 +142,12 @@ void compute_flux_hlld(SolverWorkspace& workspace, double bx, double gamma) const ArrayView2D right_states = workspace.primitive_right; const ArrayView2D fluxes = workspace.flux; - const int lbx = static_cast(workspace.Lbx); - const int ubx = static_cast(workspace.Ubx); - for (int ix = lbx - 1; ix <= ubx; ++ix) { - const std::size_t i = static_cast(ix); + const int lbx = workspace.Lbx; + const int ubx = workspace.Ubx; + for (int ix = lbx - 1; ix <= ubx + 1; ++ix) { const StateVector flux = hlld_flux_from_primitive( - row_to_state(left_states, i), row_to_state(right_states, static_cast(ix + 1)), - bx, gamma); - state_to_row(flux, fluxes, i); + row_to_state(left_states, ix), row_to_state(right_states, ix + 1), bx, gamma); + state_to_row(flux, fluxes, ix); } } @@ -353,19 +349,22 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& }; } -void set_boundary(ArrayView2D u, std::size_t lbx, std::size_t ubx) +void set_left_boundary(ArrayView2D dst, ArrayView2D src, int lbx) { - const std::size_t nx_total = u.extent(0); - - for (std::size_t ix = 0; ix < lbx; ++ix) { - for (std::size_t component = 0; component < kStateWidth; ++component) { - u(ix, component) = u(lbx, component); + for (int ix = 0; ix < lbx; ++ix) { + for (int component = 0; component < kStateWidth; ++component) { + dst(ix, component) = src(lbx, component); } } +} - for (std::size_t ix = ubx + 1U; ix < nx_total; ++ix) { - for (std::size_t component = 0; component < kStateWidth; ++component) { - u(ix, component) = u(ubx, component); +void set_right_boundary(ArrayView2D dst, ArrayView2D src, int ubx) +{ + const int ix_max = dst.extent(0) - 1; + + for (int ix = ubx + 1; ix <= ix_max; ++ix) { + for (int component = 0; component < kStateWidth; ++component) { + dst(ix, component) = src(ubx, component); } } } @@ -375,22 +374,21 @@ void compute_rhs(SolverWorkspace& workspace) const ArrayView2D conservative = workspace.conservative; const ArrayView2D primitive = workspace.primitive; const ArrayView2D fluxes = workspace.flux; - const ArrayView2D rhs = workspace.rhs1; + const ArrayView2D rhs = workspace.rhs; - set_boundary(conservative, workspace.Lbx, workspace.Ubx); + set_left_boundary(conservative, conservative, workspace.Lbx); + set_right_boundary(conservative, conservative, workspace.Ubx); convert_conservative_to_primitive(conservative, primitive, workspace.bx, workspace.gamma); - set_boundary(primitive, workspace.Lbx, workspace.Ubx); + set_left_boundary(primitive, primitive, workspace.Lbx); + set_right_boundary(primitive, primitive, workspace.Ubx); reconstruct_mc2(workspace); compute_flux_hlld(workspace, workspace.bx, workspace.gamma); - const int lbx = static_cast(workspace.Lbx); - const int ubx = static_cast(workspace.Ubx); + const int lbx = workspace.Lbx; + const int ubx = workspace.Ubx; for (int ix = lbx; ix <= ubx; ++ix) { - const std::size_t x = static_cast(ix); - for (std::size_t component = 0; component < kStateWidth; ++component) { - rhs(x, component) = - -(fluxes(x, component) - fluxes(static_cast(ix - 1), component)) / - workspace.dx; + for (int component = 0; component < kStateWidth; ++component) { + rhs(ix, component) = -(fluxes(ix, component) - fluxes(ix - 1, component)) / workspace.dx; } } } @@ -403,10 +401,10 @@ void push_ssp_rk3(SolverWorkspace& workspace, double dt) {1.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0}, }; - const ArrayView2D u0 = workspace.stage1; - const ArrayView2D rhs = workspace.rhs1; + const ArrayView2D prev = workspace.prev; + const ArrayView2D rhs = workspace.rhs; - copy_cells(workspace.conservative, u0); + copy_cells(workspace.conservative, prev); for (int substep = 0; substep < 3; ++substep) { compute_rhs(workspace); @@ -415,40 +413,27 @@ void push_ssp_rk3(SolverWorkspace& workspace, double dt) const double b = kCoeffs[substep][1]; const double c = kCoeffs[substep][2]; - const int lbx = static_cast(workspace.Lbx); - const int ubx = static_cast(workspace.Ubx); + const int lbx = workspace.Lbx; + const int ubx = workspace.Ubx; for (int ix = lbx; ix <= ubx; ++ix) { - const std::size_t x = static_cast(ix); - for (std::size_t component = 0; component < kStateWidth; ++component) { - workspace.conservative(x, component) = a * u0(x, component) + - b * workspace.conservative(x, component) + - c * dt * rhs(x, component); + for (int component = 0; component < kStateWidth; ++component) { + workspace.conservative(ix, component) = a * prev(ix, component) + + b * workspace.conservative(ix, component) + + c * dt * rhs(ix, component); } } + set_left_boundary(workspace.conservative, workspace.conservative, workspace.Lbx); + set_right_boundary(workspace.conservative, workspace.conservative, workspace.Ubx); convert_conservative_to_primitive(workspace.conservative, workspace.primitive, workspace.bx, workspace.gamma); - set_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); + set_left_boundary(workspace.primitive, workspace.primitive, workspace.Lbx); + set_right_boundary(workspace.primitive, workspace.primitive, workspace.Ubx); } - - set_boundary(workspace.conservative, workspace.Lbx, workspace.Ubx); } void evolve_ssp_rk3(SolverWorkspace& workspace, double dt, double t_final) { - if (t_final < 0.0 || dt <= 0.0) { - set_boundary(workspace.conservative, workspace.Lbx, workspace.Ubx); - convert_conservative_to_primitive(workspace.conservative, workspace.primitive, workspace.bx, - workspace.gamma); - set_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); - return; - } - - set_boundary(workspace.conservative, workspace.Lbx, workspace.Ubx); - convert_conservative_to_primitive(workspace.conservative, workspace.primitive, workspace.bx, - workspace.gamma); - set_boundary(workspace.primitive, workspace.Lbx, workspace.Ubx); - double elapsed_time = 0.0; while (elapsed_time < t_final) { const double remaining_time = t_final - elapsed_time; diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp index 5a60e4b..a82bb4e 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include @@ -12,74 +11,74 @@ namespace mhd1d namespace stdex = std::experimental; -constexpr std::size_t kStateWidth = 7; -constexpr std::size_t kGhostWidth = 2; +constexpr int kStateWidth = 7; +constexpr int kGhostWidth = 1; using StateVector = std::array; -using ArrayView1D = stdex::mdspan>; -using ArrayView2D = stdex::mdspan>; +using ArrayView1D = stdex::mdspan>; +using ArrayView2D = stdex::mdspan>; struct SolverWorkspace { - explicit SolverWorkspace(std::size_t nx, double gamma, double bx) - : Nx(nx), Lbx(kGhostWidth), Ubx(kGhostWidth + nx - 1U), - dx(nx == 0U ? 0.0 : 1.0 / static_cast(nx)), gamma(gamma), bx(bx) + struct Storage { + explicit Storage(int nx_total) + : conservative(nx_total * kStateWidth), primitive(nx_total * kStateWidth), + primitive_left(nx_total * kStateWidth), primitive_right(nx_total * kStateWidth), + rhs(nx_total * kStateWidth), prev(nx_total * kStateWidth), flux(nx_total * kStateWidth), + x(nx_total) + { + } + + std::vector conservative; + std::vector primitive; + std::vector primitive_left; + std::vector primitive_right; + std::vector rhs; + std::vector prev; + std::vector flux; + std::vector x; + }; + + explicit SolverWorkspace(int nx, double gamma, double bx) + : Nx(nx), Lbx(kGhostWidth), Ubx(kGhostWidth + nx - 1), + dx(nx == 0 ? 0.0 : 1.0 / static_cast(nx)), gamma(gamma), bx(bx), + storage(Nx + 2 * kGhostWidth) { - const std::size_t Nx_total = Nx + 2U * kGhostWidth; - const std::size_t padded_size = Nx_total * kStateWidth; - - buf_conservative.resize(padded_size); - buf_primitive.resize(padded_size); - buf_slopes.resize(padded_size); - buf_primitive_left.resize(padded_size); - buf_primitive_right.resize(padded_size); - buf_rhs1.resize(padded_size); - buf_stage1.resize(padded_size); - buf_flux.resize(padded_size); - buf_x.resize(Nx_total); - - conservative = ArrayView2D(buf_conservative.data(), Nx_total, kStateWidth); - primitive = ArrayView2D(buf_primitive.data(), Nx_total, kStateWidth); - slopes = ArrayView2D(buf_slopes.data(), Nx_total, kStateWidth); - primitive_left = ArrayView2D(buf_primitive_left.data(), Nx_total, kStateWidth); - primitive_right = ArrayView2D(buf_primitive_right.data(), Nx_total, kStateWidth); - rhs1 = ArrayView2D(buf_rhs1.data(), Nx_total, kStateWidth); - stage1 = ArrayView2D(buf_stage1.data(), Nx_total, kStateWidth); - flux = ArrayView2D(buf_flux.data(), Nx_total, kStateWidth); - x = ArrayView1D(buf_x.data(), Nx_total); - - for (std::size_t ix = Lbx; ix <= Ubx; ++ix) { + init_views(Nx + 2 * kGhostWidth); + + for (int ix = Lbx; ix <= Ubx; ++ix) { x(ix) = (static_cast(ix - Lbx) + 0.5) * dx; } } - std::size_t Nx; // number of grids for the physical domain (excluding the ghost cells) - std::size_t Lbx; // lower bound of the physical domain in padded indexing - std::size_t Ubx; // upper bound of the physical domain in padded indexing - double dx; - double gamma; - double bx; - - // buffer - std::vector buf_conservative; - std::vector buf_primitive; - std::vector buf_slopes; - std::vector buf_primitive_left; - std::vector buf_primitive_right; - std::vector buf_rhs1; - std::vector buf_stage1; - std::vector buf_flux; - std::vector buf_x; - - // view + int Nx; + int Lbx; + int Ubx; + double dx; + double gamma; + double bx; + + Storage storage; + ArrayView2D conservative; ArrayView2D primitive; - ArrayView2D slopes; ArrayView2D primitive_left; ArrayView2D primitive_right; - ArrayView2D rhs1; - ArrayView2D stage1; + ArrayView2D rhs; + ArrayView2D prev; ArrayView2D flux; ArrayView1D x; + + void init_views(int nx_total) + { + conservative = ArrayView2D(storage.conservative.data(), nx_total, kStateWidth); + primitive = ArrayView2D(storage.primitive.data(), nx_total, kStateWidth); + primitive_left = ArrayView2D(storage.primitive_left.data(), nx_total, kStateWidth); + primitive_right = ArrayView2D(storage.primitive_right.data(), nx_total, kStateWidth); + rhs = ArrayView2D(storage.rhs.data(), nx_total, kStateWidth); + prev = ArrayView2D(storage.prev.data(), nx_total, kStateWidth); + flux = ArrayView2D(storage.flux.data(), nx_total, kStateWidth); + x = ArrayView1D(storage.x.data(), nx_total); + } }; StateVector primitive_to_conservative(const StateVector& primitive, double bx, double gamma); @@ -92,7 +91,9 @@ void primitive_profile_to_conservative(ArrayView2D primitive_cells, ArrayView2D StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, double gamma); -void set_boundary(ArrayView2D u, std::size_t lbx, std::size_t ubx); +void set_left_boundary(ArrayView2D dst, ArrayView2D src, int lbx); + +void set_right_boundary(ArrayView2D dst, ArrayView2D src, int ubx); void reconstruct_mc2(SolverWorkspace& workspace); diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp index df02eca..76f0bbc 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp @@ -10,18 +10,18 @@ namespace constexpr double kTolerance = 1.0e-12; -mhd1d::StateVector row_to_state(mhd1d::ArrayView2D cells, std::size_t row) +mhd1d::StateVector row_to_state(mhd1d::ArrayView2D cells, int row) { mhd1d::StateVector state{}; - for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + for (int component = 0; component < mhd1d::kStateWidth; ++component) { state[component] = cells(row, component); } return state; } -void state_to_row(mhd1d::ArrayView2D cells, std::size_t row, const mhd1d::StateVector& state) +void state_to_row(mhd1d::ArrayView2D cells, int row, const mhd1d::StateVector& state) { - for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + for (int component = 0; component < mhd1d::kStateWidth; ++component) { cells(row, component) = state[component]; } } @@ -29,7 +29,7 @@ void state_to_row(mhd1d::ArrayView2D cells, std::size_t row, const mhd1d::StateV void require_state_vector_close(const mhd1d::StateVector& actual, const mhd1d::StateVector& expected) { - for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + for (int component = 0; component < mhd1d::kStateWidth; ++component) { REQUIRE(std::fabs(actual[component] - expected[component]) <= kTolerance); } } @@ -70,22 +70,26 @@ TEST_CASE("primitive and conservative states round-trip", "[mhd1d][conversion]") require_state_vector_close(output, input); } -TEST_CASE("reconstruct_mc2 preserves a constant primitive state exactly", - "[mhd1d][reconstruction]") +TEST_CASE("reconstruct_mc2 preserves a constant primitive state exactly", "[mhd1d][reconstruction]") { mhd1d::SolverWorkspace workspace(4, 2.0, 0.75); const auto constant_state = mhd1d::StateVector{0.9, 0.3, -0.2, 0.1, 1.8, -0.45, 0.6}; - for (std::size_t index = 0; index < workspace.conservative.extent(0); ++index) { + for (int index = 0; index < static_cast(workspace.conservative.extent(0)); ++index) { state_to_row(workspace.primitive, index, constant_state); } mhd1d::reconstruct_mc2(workspace); - for (std::size_t index = workspace.Lbx; index <= workspace.Ubx; ++index) { + for (int index = workspace.Lbx; index <= workspace.Ubx; ++index) { require_state_vector_close(row_to_state(workspace.primitive_left, index), constant_state); require_state_vector_close(row_to_state(workspace.primitive_right, index), constant_state); } + + require_state_vector_close(row_to_state(workspace.primitive_left, workspace.Lbx - 1), + row_to_state(workspace.primitive_right, workspace.Lbx)); + require_state_vector_close(row_to_state(workspace.primitive_right, workspace.Ubx + 1), + row_to_state(workspace.primitive_left, workspace.Ubx)); } TEST_CASE("hlld_flux_from_primitive matches the physical flux for identical states", @@ -123,67 +127,59 @@ TEST_CASE("hlld_flux_from_primitive matches the physical flux for identical stat TEST_CASE("set_boundary duplicates edge states on both sides", "[mhd1d][boundary]") { - std::vector padded_buffer(7 * mhd1d::kStateWidth, 0.0); - const mhd1d::ArrayView2D padded(padded_buffer.data(), 7, mhd1d::kStateWidth); + std::vector padded_buffer(4 * mhd1d::kStateWidth, 0.0); + const mhd1d::ArrayView2D padded(padded_buffer.data(), 4, mhd1d::kStateWidth); state_to_row(padded, 2, mhd1d::StateVector{1.0, 0.5, -0.25, 0.125, 2.0, 0.1, -0.05}); - state_to_row(padded, 3, mhd1d::StateVector{1.2, 0.6, -0.2, 0.15, 2.2, 0.12, -0.02}); - state_to_row(padded, 4, mhd1d::StateVector{1.4, 0.7, -0.15, 0.175, 2.4, 0.14, 0.01}); + state_to_row(padded, 1, mhd1d::StateVector{1.2, 0.6, -0.2, 0.15, 2.2, 0.12, -0.02}); + state_to_row(padded, 2, mhd1d::StateVector{1.4, 0.7, -0.15, 0.175, 2.4, 0.14, 0.01}); - mhd1d::set_boundary(padded, 2, 4); + mhd1d::set_left_boundary(padded, padded, 1); + mhd1d::set_right_boundary(padded, padded, 2); - require_state_vector_close(row_to_state(padded, 0), row_to_state(padded, 2)); - require_state_vector_close(row_to_state(padded, 1), row_to_state(padded, 2)); + require_state_vector_close(row_to_state(padded, 0), row_to_state(padded, 1)); + require_state_vector_close(row_to_state(padded, 1), row_to_state(padded, 1)); require_state_vector_close(row_to_state(padded, 2), row_to_state(padded, 2)); - require_state_vector_close(row_to_state(padded, 3), row_to_state(padded, 3)); - require_state_vector_close(row_to_state(padded, 4), row_to_state(padded, 4)); - require_state_vector_close(row_to_state(padded, 5), row_to_state(padded, 4)); - require_state_vector_close(row_to_state(padded, 6), row_to_state(padded, 4)); + require_state_vector_close(row_to_state(padded, 3), row_to_state(padded, 2)); } TEST_CASE("set_boundary handles a single interior cell", "[mhd1d][boundary]") { - std::vector padded_buffer(5 * mhd1d::kStateWidth, 0.0); - const mhd1d::ArrayView2D padded(padded_buffer.data(), 5, mhd1d::kStateWidth); - const auto cell = mhd1d::StateVector{1.5, -0.75, 0.25, 0.0, 3.5, -0.1, 0.2}; - state_to_row(padded, 2, cell); - mhd1d::set_boundary(padded, 2, 2); - - for (std::size_t index = 0; index < 5; ++index) { + std::vector padded_buffer(3 * mhd1d::kStateWidth, 0.0); + const mhd1d::ArrayView2D padded(padded_buffer.data(), 3, mhd1d::kStateWidth); + const auto cell = mhd1d::StateVector{1.5, -0.75, 0.25, 0.0, 3.5, -0.1, 0.2}; + state_to_row(padded, 1, cell); + mhd1d::set_left_boundary(padded, padded, 1); + mhd1d::set_right_boundary(padded, padded, 1); + + for (int index = 0; index < 3; ++index) { require_state_vector_close(row_to_state(padded, index), cell); } } -TEST_CASE("set_boundary overwrites ghost cells from interior boundary", - "[mhd1d][boundary]") +TEST_CASE("set_boundary overwrites ghost cells from interior boundary", "[mhd1d][boundary]") { - std::vector cells_buffer(6 * mhd1d::kStateWidth, 0.0); - const mhd1d::ArrayView2D cells(cells_buffer.data(), 6, mhd1d::kStateWidth); + std::vector cells_buffer(4 * mhd1d::kStateWidth, 0.0); + const mhd1d::ArrayView2D cells(cells_buffer.data(), 4, mhd1d::kStateWidth); state_to_row(cells, 0, mhd1d::StateVector{-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0}); state_to_row(cells, 1, mhd1d::StateVector{1.0, 0.1, 0.2, 0.3, 2.0, 0.4, 0.5}); state_to_row(cells, 2, mhd1d::StateVector{2.0, 0.2, 0.3, 0.4, 2.1, 0.5, 0.6}); - state_to_row(cells, 3, mhd1d::StateVector{3.0, 0.3, 0.4, 0.5, 2.2, 0.6, 0.7}); - state_to_row(cells, 4, mhd1d::StateVector{4.0, 0.4, 0.5, 0.6, 2.3, 0.7, 0.8}); - state_to_row(cells, 5, mhd1d::StateVector{-2.0, -2.0, -2.0, -2.0, -2.0, -2.0, -2.0}); + state_to_row(cells, 3, mhd1d::StateVector{-2.0, -2.0, -2.0, -2.0, -2.0, -2.0, -2.0}); const mhd1d::StateVector interior_left = row_to_state(cells, 1); - const mhd1d::StateVector interior_right = row_to_state(cells, 4); - const mhd1d::StateVector interior_mid_2 = row_to_state(cells, 2); - const mhd1d::StateVector interior_mid_3 = row_to_state(cells, 3); + const mhd1d::StateVector interior_right = row_to_state(cells, 2); - mhd1d::set_boundary(cells, 1, 4); + mhd1d::set_left_boundary(cells, cells, 1); + mhd1d::set_right_boundary(cells, cells, 2); require_state_vector_close(row_to_state(cells, 0), interior_left); - require_state_vector_close(row_to_state(cells, 5), interior_right); + require_state_vector_close(row_to_state(cells, 3), interior_right); require_state_vector_close(row_to_state(cells, 1), interior_left); - require_state_vector_close(row_to_state(cells, 2), interior_mid_2); - require_state_vector_close(row_to_state(cells, 3), interior_mid_3); - require_state_vector_close(row_to_state(cells, 4), interior_right); } std::vector make_sample_conservative_cells() { - std::vector conservative_cells(4 * mhd1d::kStateWidth, 0.0); + std::vector conservative_cells(4 * mhd1d::kStateWidth, 0.0); const mhd1d::ArrayView2D view(conservative_cells.data(), 4, mhd1d::kStateWidth); state_to_row(view, 0, mhd1d::StateVector{1.0, 0.1, 0.0, 0.0, 1.6, 0.20, 0.00}); state_to_row(view, 1, mhd1d::StateVector{0.9, 0.0, 0.1, 0.0, 1.3, 0.15, 0.05}); @@ -194,43 +190,43 @@ std::vector make_sample_conservative_cells() TEST_CASE("compute_rhs returns finite values", "[mhd1d][evolution]") { - const std::size_t nx = 4; + const int nx = 4; mhd1d::SolverWorkspace workspace(nx, 2.0, 0.75); const std::vector conservative_cells = make_sample_conservative_cells(); - for (std::size_t row = 0; row < nx; ++row) { - for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + for (int row = 0; row < nx; ++row) { + for (int component = 0; component < mhd1d::kStateWidth; ++component) { workspace.conservative(workspace.Lbx + row, component) = - conservative_cells[row * mhd1d::kStateWidth + component]; + conservative_cells[static_cast(row * mhd1d::kStateWidth + component)]; } } mhd1d::compute_rhs(workspace); - for (std::size_t row = workspace.Lbx; row <= workspace.Ubx; ++row) { - for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { - REQUIRE(std::isfinite(workspace.rhs1(row, component))); + for (int row = workspace.Lbx; row <= workspace.Ubx; ++row) { + for (int component = 0; component < mhd1d::kStateWidth; ++component) { + REQUIRE(std::isfinite(workspace.rhs(row, component))); } } } TEST_CASE("push_ssp_rk3 evolves state with finite conservative values", "[mhd1d][evolution]") { - const std::size_t nx = 4; + const int nx = 4; mhd1d::SolverWorkspace workspace(nx, 2.0, 0.75); const std::vector conservative_cells = make_sample_conservative_cells(); - for (std::size_t row = 0; row < nx; ++row) { - for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + for (int row = 0; row < nx; ++row) { + for (int component = 0; component < mhd1d::kStateWidth; ++component) { workspace.conservative(workspace.Lbx + row, component) = - conservative_cells[row * mhd1d::kStateWidth + component]; + conservative_cells[static_cast(row * mhd1d::kStateWidth + component)]; } } mhd1d::push_ssp_rk3(workspace, 1.0e-4); - for (std::size_t row = workspace.Lbx; row <= workspace.Ubx; ++row) { - const double rho = workspace.conservative(row, 0U); - for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + for (int row = workspace.Lbx; row <= workspace.Ubx; ++row) { + const double rho = workspace.conservative(row, 0); + for (int component = 0; component < mhd1d::kStateWidth; ++component) { REQUIRE(std::isfinite(workspace.conservative(row, component))); } REQUIRE(rho > 0.0); @@ -239,17 +235,18 @@ TEST_CASE("push_ssp_rk3 evolves state with finite conservative values", "[mhd1d] TEST_CASE("evolve_ssp_rk3 matches repeated push_ssp_rk3 calls", "[mhd1d][evolution]") { - const std::size_t nx = 4; - const double dt = 1.0e-4; - const double t_final = 2.0e-4; + const int nx = 4; + const double dt = 1.0e-4; + const double t_final = 2.0e-4; mhd1d::SolverWorkspace evolved_workspace(nx, 2.0, 0.75); mhd1d::SolverWorkspace manual_workspace(nx, 2.0, 0.75); const std::vector conservative_cells = make_sample_conservative_cells(); - for (std::size_t row = 0; row < nx; ++row) { - for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { - const double value = conservative_cells[row * mhd1d::kStateWidth + component]; + for (int row = 0; row < nx; ++row) { + for (int component = 0; component < mhd1d::kStateWidth; ++component) { + const double value = + conservative_cells[static_cast(row * mhd1d::kStateWidth + component)]; evolved_workspace.conservative(evolved_workspace.Lbx + row, component) = value; manual_workspace.conservative(manual_workspace.Lbx + row, component) = value; } @@ -261,9 +258,9 @@ TEST_CASE("evolve_ssp_rk3 matches repeated push_ssp_rk3 calls", "[mhd1d][evoluti mhd1d::push_ssp_rk3(manual_workspace, dt); } - for (std::size_t row = 0; row < nx; ++row) { - const std::size_t i = evolved_workspace.Lbx + row; - for (std::size_t component = 0; component < mhd1d::kStateWidth; ++component) { + for (int row = 0; row < nx; ++row) { + const int i = evolved_workspace.Lbx + row; + for (int component = 0; component < mhd1d::kStateWidth; ++component) { REQUIRE(std::fabs(manual_workspace.conservative(i, component) - evolved_workspace.conservative(i, component)) <= kTolerance); } From 1d410df9881d1a71a23b2b9ee89d94dbf7a4b823 Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Wed, 1 Apr 2026 19:07:53 +0900 Subject: [PATCH 26/39] refactor(cpp-full-solver1d): tighten workspace layout and boundaries --- .../cpp-full-solver1d/workspace/src/main.cpp | 16 +- .../cpp-full-solver1d/workspace/src/mhd1d.cpp | 148 +++++++++--------- .../cpp-full-solver1d/workspace/src/mhd1d.hpp | 93 +++++------ .../workspace/tests/cpp/test_public.cpp | 84 +++++----- 4 files changed, 173 insertions(+), 168 deletions(-) diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp index e7e29be..e84c51b 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp @@ -22,14 +22,13 @@ mhd1d::SolverWorkspace initialize(int nx, double gamma, double bx, for (int ix = workspace.Lbx; ix <= workspace.Ubx; ++ix) { const mhd1d::StateVector& state = (workspace.x(ix) < 0.5) ? left_state : right_state; - for (int component = 0; component < mhd1d::kStateWidth; ++component) { - workspace.primitive(ix, component) = state[component]; + for (int component = 0; component < mhd1d::N_Component; ++component) { + workspace.up(ix, component) = state[component]; } } - mhd1d::set_left_boundary(workspace.primitive, workspace.primitive, workspace.Lbx); - mhd1d::set_right_boundary(workspace.primitive, workspace.primitive, workspace.Ubx); - mhd1d::primitive_profile_to_conservative(workspace.primitive, workspace.conservative, bx, gamma); + mhd1d::set_boundary(workspace.up, workspace.up, workspace.Lbx, workspace.Ubx); + mhd1d::primitive_profile_to_conservative(workspace.up, workspace.uc, bx, gamma); return workspace; } @@ -39,10 +38,9 @@ void write_csv(const mhd1d::SolverWorkspace& workspace, std::ostream& os) os << "x,rho,u,v,w,p,by,bz\n"; os << std::setprecision(17); for (int ix = workspace.Lbx; ix <= workspace.Ubx; ++ix) { - os << workspace.x(ix) << ',' << workspace.primitive(ix, 0) << ',' << workspace.primitive(ix, 1) - << ',' << workspace.primitive(ix, 2) << ',' << workspace.primitive(ix, 3) << ',' - << workspace.primitive(ix, 4) << ',' << workspace.primitive(ix, 5) << ',' - << workspace.primitive(ix, 6) << '\n'; + os << workspace.x(ix) << ',' << workspace.up(ix, 0) << ',' << workspace.up(ix, 1) << ',' + << workspace.up(ix, 2) << ',' << workspace.up(ix, 3) << ',' << workspace.up(ix, 4) << ',' + << workspace.up(ix, 5) << ',' << workspace.up(ix, 6) << '\n'; } } diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp index 94856eb..c2622ef 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp @@ -11,7 +11,7 @@ namespace mhd1d namespace { -constexpr double kHlldEps = 1.0e-40; +constexpr double HLLD_EPS = 1.0e-40; double sign(const double x) { @@ -27,7 +27,7 @@ double mc2(double a, double b) StateVector row_to_state(ArrayView2D cells, int row) { StateVector state{}; - for (int component = 0; component < kStateWidth; ++component) { + for (int component = 0; component < N_Component; ++component) { state[component] = cells(row, component); } return state; @@ -35,7 +35,7 @@ StateVector row_to_state(ArrayView2D cells, int row) void state_to_row(const StateVector& state, ArrayView2D cells, int row) { - for (int component = 0; component < kStateWidth; ++component) { + for (int component = 0; component < N_Component; ++component) { cells(row, component) = state[component]; } } @@ -44,20 +44,21 @@ void copy_cells(ArrayView2D source, ArrayView2D destination) { const int nx = source.extent(0); for (int ix = 0; ix < nx; ++ix) { - for (int component = 0; component < kStateWidth; ++component) { + for (int component = 0; component < N_Component; ++component) { destination(ix, component) = source(ix, component); } } } -void convert_conservative_to_primitive(ArrayView2D conservative_cells, ArrayView2D primitive_cells, - double bx, double gamma) +void convert_conservative_to_primitive(ArrayView2D conservative, ArrayView2D primitive, double bx, + double gamma) { - const int nx = conservative_cells.extent(0); - for (int ix = 0; ix < nx; ++ix) { - const StateVector primitive = - conservative_to_primitive(row_to_state(conservative_cells, ix), bx, gamma); - state_to_row(primitive, primitive_cells, ix); + const int ix_min = 0; + const int ix_max = conservative.extent(0) - 1; + + for (int ix = ix_min; ix <= ix_max; ++ix) { + const StateVector up = conservative_to_primitive(row_to_state(conservative, ix), bx, gamma); + state_to_row(up, primitive, ix); } } @@ -102,52 +103,55 @@ StateVector conservative_to_primitive(const StateVector& conservative, double bx return StateVector{rho, u, v, w, pressure, by, bz}; } -void primitive_profile_to_conservative(ArrayView2D primitive_cells, ArrayView2D conservative_cells, - double bx, double gamma) +void primitive_profile_to_conservative(ArrayView2D primitive, ArrayView2D conservative, double bx, + double gamma) { - const int nx = primitive_cells.extent(0); - for (int ix = 0; ix < nx; ++ix) { - const StateVector conservative = - primitive_to_conservative(row_to_state(primitive_cells, ix), bx, gamma); - state_to_row(conservative, conservative_cells, ix); + const int ix_min = 0; + const int ix_max = primitive.extent(0) - 1; + + for (int ix = ix_min; ix <= ix_max; ++ix) { + const StateVector uc = primitive_to_conservative(row_to_state(primitive, ix), bx, gamma); + state_to_row(uc, conservative, ix); } } +StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, + double gamma); + void reconstruct_mc2(SolverWorkspace& workspace) { - const ArrayView2D primitive_cells = workspace.primitive; - const ArrayView2D left_states = workspace.primitive_left; - const ArrayView2D right_states = workspace.primitive_right; + const ArrayView2D up = workspace.up; + const ArrayView2D up_l = workspace.up_l; + const ArrayView2D up_r = workspace.up_r; const int lbx = workspace.Lbx; const int ubx = workspace.Ubx; for (int ix = lbx; ix <= ubx; ++ix) { - for (int component = 0; component < kStateWidth; ++component) { - const double left_slope = primitive_cells(ix, component) - primitive_cells(ix - 1, component); - const double right_slope = - primitive_cells(ix + 1, component) - primitive_cells(ix, component); - const double slope = mc2(left_slope, right_slope); - left_states(ix, component) = primitive_cells(ix, component) + 0.5 * slope; - right_states(ix, component) = primitive_cells(ix, component) - 0.5 * slope; + for (int component = 0; component < N_Component; ++component) { + const double slope_l = up(ix, component) - up(ix - 1, component); + const double slope_r = up(ix + 1, component) - up(ix, component); + const double slope = mc2(slope_l, slope_r); + up_l(ix, component) = up(ix, component) + 0.5 * slope; + up_r(ix, component) = up(ix, component) - 0.5 * slope; } } - set_left_boundary(left_states, right_states, lbx); - set_right_boundary(right_states, left_states, ubx); + set_boundary_lb(up_l, up_r, lbx); + set_boundary_ub(up_r, up_l, ubx); } void compute_flux_hlld(SolverWorkspace& workspace, double bx, double gamma) { - const ArrayView2D left_states = workspace.primitive_left; - const ArrayView2D right_states = workspace.primitive_right; - const ArrayView2D fluxes = workspace.flux; + const ArrayView2D up_l = workspace.up_l; + const ArrayView2D up_r = workspace.up_r; + const ArrayView2D flux = workspace.flux; const int lbx = workspace.Lbx; const int ubx = workspace.Ubx; for (int ix = lbx - 1; ix <= ubx + 1; ++ix) { - const StateVector flux = hlld_flux_from_primitive( - row_to_state(left_states, ix), row_to_state(right_states, ix + 1), bx, gamma); - state_to_row(flux, fluxes, ix); + const StateVector flux_hlld = + hlld_flux_from_primitive(row_to_state(up_l, ix), row_to_state(up_r, ix + 1), bx, gamma); + state_to_row(flux_hlld, flux, ix); } } @@ -230,7 +234,7 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& const double ptst = (rosdr * ptl - rosdl * ptr + rosdl * rosdr * (vxr - vxl)) * temp; const double temp_fst_l = rosdl * sdml - bxsq; - const double sign1_l = std::copysign(1.0, std::abs(temp_fst_l) - kHlldEps); + const double sign1_l = std::copysign(1.0, std::abs(temp_fst_l) - HLLD_EPS); const double maxs1_l = std::max(0.0, sign1_l); const double mins1_l = std::min(0.0, sign1_l); const double itf_l = 1.0 / (temp_fst_l + mins1_l); @@ -254,7 +258,7 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& mins1_l * eel; const double temp_fst_r = rosdr * sdmr - bxsq; - const double sign1_r = std::copysign(1.0, std::abs(temp_fst_r) - kHlldEps); + const double sign1_r = std::copysign(1.0, std::abs(temp_fst_r) - HLLD_EPS); const double maxs1_r = std::max(0.0, sign1_r); const double mins1_r = std::min(0.0, sign1_r); const double itf_r = 1.0 / (temp_fst_r + mins1_r); @@ -283,7 +287,7 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& const double slst = sm - abbx / sqrtrol; const double srst = sm + abbx / sqrtror; const double signbx = std::copysign(1.0, bxs); - const double sign1_b = std::copysign(1.0, abbx - kHlldEps); + const double sign1_b = std::copysign(1.0, abbx - HLLD_EPS); const double maxs1_b = std::max(0.0, sign1_b); const double mins1_b = -std::min(0.0, sign1_b); const double invsumro = maxs1_b / (sqrtrol + sqrtror); @@ -349,53 +353,59 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& }; } -void set_left_boundary(ArrayView2D dst, ArrayView2D src, int lbx) +void set_boundary_lb(ArrayView2D dst, ArrayView2D src, int lbx) { - for (int ix = 0; ix < lbx; ++ix) { - for (int component = 0; component < kStateWidth; ++component) { + const int ix_min = 0; + + for (int ix = ix_min; ix < lbx; ++ix) { + for (int component = 0; component < N_Component; ++component) { dst(ix, component) = src(lbx, component); } } } -void set_right_boundary(ArrayView2D dst, ArrayView2D src, int ubx) +void set_boundary_ub(ArrayView2D dst, ArrayView2D src, int ubx) { const int ix_max = dst.extent(0) - 1; for (int ix = ubx + 1; ix <= ix_max; ++ix) { - for (int component = 0; component < kStateWidth; ++component) { + for (int component = 0; component < N_Component; ++component) { dst(ix, component) = src(ubx, component); } } } +void set_boundary(ArrayView2D dst, ArrayView2D src, int lbx, int ubx) +{ + set_boundary_lb(dst, src, lbx); + set_boundary_ub(dst, src, ubx); +} + void compute_rhs(SolverWorkspace& workspace) { - const ArrayView2D conservative = workspace.conservative; - const ArrayView2D primitive = workspace.primitive; - const ArrayView2D fluxes = workspace.flux; - const ArrayView2D rhs = workspace.rhs; - - set_left_boundary(conservative, conservative, workspace.Lbx); - set_right_boundary(conservative, conservative, workspace.Ubx); - convert_conservative_to_primitive(conservative, primitive, workspace.bx, workspace.gamma); - set_left_boundary(primitive, primitive, workspace.Lbx); - set_right_boundary(primitive, primitive, workspace.Ubx); + const ArrayView2D uc = workspace.uc; + const ArrayView2D up = workspace.up; + const ArrayView2D flux = workspace.flux; + const ArrayView2D rhs = workspace.rhs; + + set_boundary(uc, uc, workspace.Lbx, workspace.Ubx); + convert_conservative_to_primitive(uc, up, workspace.bx, workspace.gamma); + set_boundary(up, up, workspace.Lbx, workspace.Ubx); reconstruct_mc2(workspace); compute_flux_hlld(workspace, workspace.bx, workspace.gamma); const int lbx = workspace.Lbx; const int ubx = workspace.Ubx; for (int ix = lbx; ix <= ubx; ++ix) { - for (int component = 0; component < kStateWidth; ++component) { - rhs(ix, component) = -(fluxes(ix, component) - fluxes(ix - 1, component)) / workspace.dx; + for (int component = 0; component < N_Component; ++component) { + rhs(ix, component) = -(flux(ix, component) - flux(ix - 1, component)) / workspace.dx; } } } void push_ssp_rk3(SolverWorkspace& workspace, double dt) { - constexpr double kCoeffs[3][3] = { + constexpr double coeffs[3][3] = { {1.0, 0.0, 1.0}, {3.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0}, {1.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0}, @@ -404,31 +414,27 @@ void push_ssp_rk3(SolverWorkspace& workspace, double dt) const ArrayView2D prev = workspace.prev; const ArrayView2D rhs = workspace.rhs; - copy_cells(workspace.conservative, prev); + copy_cells(workspace.uc, prev); for (int substep = 0; substep < 3; ++substep) { compute_rhs(workspace); - const double a = kCoeffs[substep][0]; - const double b = kCoeffs[substep][1]; - const double c = kCoeffs[substep][2]; + const double a = coeffs[substep][0]; + const double b = coeffs[substep][1]; + const double c = coeffs[substep][2]; const int lbx = workspace.Lbx; const int ubx = workspace.Ubx; for (int ix = lbx; ix <= ubx; ++ix) { - for (int component = 0; component < kStateWidth; ++component) { - workspace.conservative(ix, component) = a * prev(ix, component) + - b * workspace.conservative(ix, component) + - c * dt * rhs(ix, component); + for (int component = 0; component < N_Component; ++component) { + workspace.uc(ix, component) = + a * prev(ix, component) + b * workspace.uc(ix, component) + c * dt * rhs(ix, component); } } - set_left_boundary(workspace.conservative, workspace.conservative, workspace.Lbx); - set_right_boundary(workspace.conservative, workspace.conservative, workspace.Ubx); - convert_conservative_to_primitive(workspace.conservative, workspace.primitive, workspace.bx, - workspace.gamma); - set_left_boundary(workspace.primitive, workspace.primitive, workspace.Lbx); - set_right_boundary(workspace.primitive, workspace.primitive, workspace.Ubx); + set_boundary(workspace.uc, workspace.uc, workspace.Lbx, workspace.Ubx); + convert_conservative_to_primitive(workspace.uc, workspace.up, workspace.bx, workspace.gamma); + set_boundary(workspace.up, workspace.up, workspace.Lbx, workspace.Ubx); } } diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp index a82bb4e..8e56eca 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp @@ -11,39 +11,19 @@ namespace mhd1d namespace stdex = std::experimental; -constexpr int kStateWidth = 7; -constexpr int kGhostWidth = 1; +constexpr int N_Component = 7; +constexpr int N_margin = 1; -using StateVector = std::array; +using StateVector = std::array; using ArrayView1D = stdex::mdspan>; using ArrayView2D = stdex::mdspan>; struct SolverWorkspace { - struct Storage { - explicit Storage(int nx_total) - : conservative(nx_total * kStateWidth), primitive(nx_total * kStateWidth), - primitive_left(nx_total * kStateWidth), primitive_right(nx_total * kStateWidth), - rhs(nx_total * kStateWidth), prev(nx_total * kStateWidth), flux(nx_total * kStateWidth), - x(nx_total) - { - } - - std::vector conservative; - std::vector primitive; - std::vector primitive_left; - std::vector primitive_right; - std::vector rhs; - std::vector prev; - std::vector flux; - std::vector x; - }; - explicit SolverWorkspace(int nx, double gamma, double bx) - : Nx(nx), Lbx(kGhostWidth), Ubx(kGhostWidth + nx - 1), - dx(nx == 0 ? 0.0 : 1.0 / static_cast(nx)), gamma(gamma), bx(bx), - storage(Nx + 2 * kGhostWidth) + : Nx(nx), Lbx(N_margin), Ubx(N_margin + nx - 1), dx(1.0 / static_cast(nx)), + gamma(gamma), bx(bx), storage(Nx + 2 * N_margin, N_Component) { - init_views(Nx + 2 * kGhostWidth); + init_views(Nx + 2 * N_margin, N_Component); for (int ix = Lbx; ix <= Ubx; ++ix) { x(ix) = (static_cast(ix - Lbx) + 0.5) * dx; @@ -57,28 +37,47 @@ struct SolverWorkspace { double gamma; double bx; - Storage storage; - - ArrayView2D conservative; - ArrayView2D primitive; - ArrayView2D primitive_left; - ArrayView2D primitive_right; + ArrayView1D x; + ArrayView2D uc; + ArrayView2D up; + ArrayView2D up_l; + ArrayView2D up_r; ArrayView2D rhs; ArrayView2D prev; ArrayView2D flux; - ArrayView1D x; - void init_views(int nx_total) +private: + void init_views(int n_grid, int n_component) { - conservative = ArrayView2D(storage.conservative.data(), nx_total, kStateWidth); - primitive = ArrayView2D(storage.primitive.data(), nx_total, kStateWidth); - primitive_left = ArrayView2D(storage.primitive_left.data(), nx_total, kStateWidth); - primitive_right = ArrayView2D(storage.primitive_right.data(), nx_total, kStateWidth); - rhs = ArrayView2D(storage.rhs.data(), nx_total, kStateWidth); - prev = ArrayView2D(storage.prev.data(), nx_total, kStateWidth); - flux = ArrayView2D(storage.flux.data(), nx_total, kStateWidth); - x = ArrayView1D(storage.x.data(), nx_total); + x = ArrayView1D(storage.x.data(), n_grid); + uc = ArrayView2D(storage.uc.data(), n_grid, n_component); + up = ArrayView2D(storage.up.data(), n_grid, n_component); + up_l = ArrayView2D(storage.up_l.data(), n_grid, n_component); + up_r = ArrayView2D(storage.up_r.data(), n_grid, n_component); + rhs = ArrayView2D(storage.rhs.data(), n_grid, n_component); + prev = ArrayView2D(storage.prev.data(), n_grid, n_component); + flux = ArrayView2D(storage.flux.data(), n_grid, n_component); } + + struct Storage { + explicit Storage(int n_grid, int n_component) + : x(n_grid), uc(n_grid * n_component), up(n_grid * n_component), up_l(n_grid * n_component), + up_r(n_grid * n_component), rhs(n_grid * n_component), prev(n_grid * n_component), + flux(n_grid * n_component) + { + } + + std::vector x; + std::vector uc; + std::vector up; + std::vector up_l; + std::vector up_r; + std::vector rhs; + std::vector prev; + std::vector flux; + }; + + Storage storage; }; StateVector primitive_to_conservative(const StateVector& primitive, double bx, double gamma); @@ -88,12 +87,14 @@ StateVector conservative_to_primitive(const StateVector& conservative, double bx void primitive_profile_to_conservative(ArrayView2D primitive_cells, ArrayView2D conservative_cells, double bx, double gamma); -StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, - double gamma); +void set_boundary_lb(ArrayView2D dst, ArrayView2D src, int lbx); -void set_left_boundary(ArrayView2D dst, ArrayView2D src, int lbx); +void set_boundary_ub(ArrayView2D dst, ArrayView2D src, int ubx); -void set_right_boundary(ArrayView2D dst, ArrayView2D src, int ubx); +void set_boundary(ArrayView2D dst, ArrayView2D src, int lbx, int ubx); + +StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, + double gamma); void reconstruct_mc2(SolverWorkspace& workspace); diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp index 76f0bbc..82a442f 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp @@ -13,7 +13,7 @@ constexpr double kTolerance = 1.0e-12; mhd1d::StateVector row_to_state(mhd1d::ArrayView2D cells, int row) { mhd1d::StateVector state{}; - for (int component = 0; component < mhd1d::kStateWidth; ++component) { + for (int component = 0; component < mhd1d::N_Component; ++component) { state[component] = cells(row, component); } return state; @@ -21,7 +21,7 @@ mhd1d::StateVector row_to_state(mhd1d::ArrayView2D cells, int row) void state_to_row(mhd1d::ArrayView2D cells, int row, const mhd1d::StateVector& state) { - for (int component = 0; component < mhd1d::kStateWidth; ++component) { + for (int component = 0; component < mhd1d::N_Component; ++component) { cells(row, component) = state[component]; } } @@ -29,7 +29,7 @@ void state_to_row(mhd1d::ArrayView2D cells, int row, const mhd1d::StateVector& s void require_state_vector_close(const mhd1d::StateVector& actual, const mhd1d::StateVector& expected) { - for (int component = 0; component < mhd1d::kStateWidth; ++component) { + for (int component = 0; component < mhd1d::N_Component; ++component) { REQUIRE(std::fabs(actual[component] - expected[component]) <= kTolerance); } } @@ -75,21 +75,21 @@ TEST_CASE("reconstruct_mc2 preserves a constant primitive state exactly", "[mhd1 mhd1d::SolverWorkspace workspace(4, 2.0, 0.75); const auto constant_state = mhd1d::StateVector{0.9, 0.3, -0.2, 0.1, 1.8, -0.45, 0.6}; - for (int index = 0; index < static_cast(workspace.conservative.extent(0)); ++index) { - state_to_row(workspace.primitive, index, constant_state); + for (int index = 0; index < static_cast(workspace.uc.extent(0)); ++index) { + state_to_row(workspace.up, index, constant_state); } mhd1d::reconstruct_mc2(workspace); for (int index = workspace.Lbx; index <= workspace.Ubx; ++index) { - require_state_vector_close(row_to_state(workspace.primitive_left, index), constant_state); - require_state_vector_close(row_to_state(workspace.primitive_right, index), constant_state); + require_state_vector_close(row_to_state(workspace.up_l, index), constant_state); + require_state_vector_close(row_to_state(workspace.up_r, index), constant_state); } - require_state_vector_close(row_to_state(workspace.primitive_left, workspace.Lbx - 1), - row_to_state(workspace.primitive_right, workspace.Lbx)); - require_state_vector_close(row_to_state(workspace.primitive_right, workspace.Ubx + 1), - row_to_state(workspace.primitive_left, workspace.Ubx)); + require_state_vector_close(row_to_state(workspace.up_l, workspace.Lbx - 1), + row_to_state(workspace.up_r, workspace.Lbx)); + require_state_vector_close(row_to_state(workspace.up_r, workspace.Ubx + 1), + row_to_state(workspace.up_l, workspace.Ubx)); } TEST_CASE("hlld_flux_from_primitive matches the physical flux for identical states", @@ -127,14 +127,14 @@ TEST_CASE("hlld_flux_from_primitive matches the physical flux for identical stat TEST_CASE("set_boundary duplicates edge states on both sides", "[mhd1d][boundary]") { - std::vector padded_buffer(4 * mhd1d::kStateWidth, 0.0); - const mhd1d::ArrayView2D padded(padded_buffer.data(), 4, mhd1d::kStateWidth); + std::vector padded_buffer(4 * mhd1d::N_Component, 0.0); + const mhd1d::ArrayView2D padded(padded_buffer.data(), 4, mhd1d::N_Component); state_to_row(padded, 2, mhd1d::StateVector{1.0, 0.5, -0.25, 0.125, 2.0, 0.1, -0.05}); state_to_row(padded, 1, mhd1d::StateVector{1.2, 0.6, -0.2, 0.15, 2.2, 0.12, -0.02}); state_to_row(padded, 2, mhd1d::StateVector{1.4, 0.7, -0.15, 0.175, 2.4, 0.14, 0.01}); - mhd1d::set_left_boundary(padded, padded, 1); - mhd1d::set_right_boundary(padded, padded, 2); + mhd1d::set_boundary_lb(padded, padded, 1); + mhd1d::set_boundary_ub(padded, padded, 2); require_state_vector_close(row_to_state(padded, 0), row_to_state(padded, 1)); require_state_vector_close(row_to_state(padded, 1), row_to_state(padded, 1)); @@ -144,12 +144,12 @@ TEST_CASE("set_boundary duplicates edge states on both sides", "[mhd1d][boundary TEST_CASE("set_boundary handles a single interior cell", "[mhd1d][boundary]") { - std::vector padded_buffer(3 * mhd1d::kStateWidth, 0.0); - const mhd1d::ArrayView2D padded(padded_buffer.data(), 3, mhd1d::kStateWidth); + std::vector padded_buffer(3 * mhd1d::N_Component, 0.0); + const mhd1d::ArrayView2D padded(padded_buffer.data(), 3, mhd1d::N_Component); const auto cell = mhd1d::StateVector{1.5, -0.75, 0.25, 0.0, 3.5, -0.1, 0.2}; state_to_row(padded, 1, cell); - mhd1d::set_left_boundary(padded, padded, 1); - mhd1d::set_right_boundary(padded, padded, 1); + mhd1d::set_boundary_lb(padded, padded, 1); + mhd1d::set_boundary_ub(padded, padded, 1); for (int index = 0; index < 3; ++index) { require_state_vector_close(row_to_state(padded, index), cell); @@ -158,8 +158,8 @@ TEST_CASE("set_boundary handles a single interior cell", "[mhd1d][boundary]") TEST_CASE("set_boundary overwrites ghost cells from interior boundary", "[mhd1d][boundary]") { - std::vector cells_buffer(4 * mhd1d::kStateWidth, 0.0); - const mhd1d::ArrayView2D cells(cells_buffer.data(), 4, mhd1d::kStateWidth); + std::vector cells_buffer(4 * mhd1d::N_Component, 0.0); + const mhd1d::ArrayView2D cells(cells_buffer.data(), 4, mhd1d::N_Component); state_to_row(cells, 0, mhd1d::StateVector{-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0}); state_to_row(cells, 1, mhd1d::StateVector{1.0, 0.1, 0.2, 0.3, 2.0, 0.4, 0.5}); @@ -169,8 +169,8 @@ TEST_CASE("set_boundary overwrites ghost cells from interior boundary", "[mhd1d] const mhd1d::StateVector interior_left = row_to_state(cells, 1); const mhd1d::StateVector interior_right = row_to_state(cells, 2); - mhd1d::set_left_boundary(cells, cells, 1); - mhd1d::set_right_boundary(cells, cells, 2); + mhd1d::set_boundary_lb(cells, cells, 1); + mhd1d::set_boundary_ub(cells, cells, 2); require_state_vector_close(row_to_state(cells, 0), interior_left); require_state_vector_close(row_to_state(cells, 3), interior_right); @@ -179,8 +179,8 @@ TEST_CASE("set_boundary overwrites ghost cells from interior boundary", "[mhd1d] std::vector make_sample_conservative_cells() { - std::vector conservative_cells(4 * mhd1d::kStateWidth, 0.0); - const mhd1d::ArrayView2D view(conservative_cells.data(), 4, mhd1d::kStateWidth); + std::vector conservative_cells(4 * mhd1d::N_Component, 0.0); + const mhd1d::ArrayView2D view(conservative_cells.data(), 4, mhd1d::N_Component); state_to_row(view, 0, mhd1d::StateVector{1.0, 0.1, 0.0, 0.0, 1.6, 0.20, 0.00}); state_to_row(view, 1, mhd1d::StateVector{0.9, 0.0, 0.1, 0.0, 1.3, 0.15, 0.05}); state_to_row(view, 2, mhd1d::StateVector{0.8, -0.1, 0.0, 0.1, 1.1, 0.10, 0.10}); @@ -195,15 +195,15 @@ TEST_CASE("compute_rhs returns finite values", "[mhd1d][evolution]") const std::vector conservative_cells = make_sample_conservative_cells(); for (int row = 0; row < nx; ++row) { - for (int component = 0; component < mhd1d::kStateWidth; ++component) { - workspace.conservative(workspace.Lbx + row, component) = - conservative_cells[static_cast(row * mhd1d::kStateWidth + component)]; + for (int component = 0; component < mhd1d::N_Component; ++component) { + workspace.uc(workspace.Lbx + row, component) = + conservative_cells[static_cast(row * mhd1d::N_Component + component)]; } } mhd1d::compute_rhs(workspace); for (int row = workspace.Lbx; row <= workspace.Ubx; ++row) { - for (int component = 0; component < mhd1d::kStateWidth; ++component) { + for (int component = 0; component < mhd1d::N_Component; ++component) { REQUIRE(std::isfinite(workspace.rhs(row, component))); } } @@ -216,18 +216,18 @@ TEST_CASE("push_ssp_rk3 evolves state with finite conservative values", "[mhd1d] const std::vector conservative_cells = make_sample_conservative_cells(); for (int row = 0; row < nx; ++row) { - for (int component = 0; component < mhd1d::kStateWidth; ++component) { - workspace.conservative(workspace.Lbx + row, component) = - conservative_cells[static_cast(row * mhd1d::kStateWidth + component)]; + for (int component = 0; component < mhd1d::N_Component; ++component) { + workspace.uc(workspace.Lbx + row, component) = + conservative_cells[static_cast(row * mhd1d::N_Component + component)]; } } mhd1d::push_ssp_rk3(workspace, 1.0e-4); for (int row = workspace.Lbx; row <= workspace.Ubx; ++row) { - const double rho = workspace.conservative(row, 0); - for (int component = 0; component < mhd1d::kStateWidth; ++component) { - REQUIRE(std::isfinite(workspace.conservative(row, component))); + const double rho = workspace.uc(row, 0); + for (int component = 0; component < mhd1d::N_Component; ++component) { + REQUIRE(std::isfinite(workspace.uc(row, component))); } REQUIRE(rho > 0.0); } @@ -244,11 +244,11 @@ TEST_CASE("evolve_ssp_rk3 matches repeated push_ssp_rk3 calls", "[mhd1d][evoluti const std::vector conservative_cells = make_sample_conservative_cells(); for (int row = 0; row < nx; ++row) { - for (int component = 0; component < mhd1d::kStateWidth; ++component) { + for (int component = 0; component < mhd1d::N_Component; ++component) { const double value = - conservative_cells[static_cast(row * mhd1d::kStateWidth + component)]; - evolved_workspace.conservative(evolved_workspace.Lbx + row, component) = value; - manual_workspace.conservative(manual_workspace.Lbx + row, component) = value; + conservative_cells[static_cast(row * mhd1d::N_Component + component)]; + evolved_workspace.uc(evolved_workspace.Lbx + row, component) = value; + manual_workspace.uc(manual_workspace.Lbx + row, component) = value; } } @@ -260,9 +260,9 @@ TEST_CASE("evolve_ssp_rk3 matches repeated push_ssp_rk3 calls", "[mhd1d][evoluti for (int row = 0; row < nx; ++row) { const int i = evolved_workspace.Lbx + row; - for (int component = 0; component < mhd1d::kStateWidth; ++component) { - REQUIRE(std::fabs(manual_workspace.conservative(i, component) - - evolved_workspace.conservative(i, component)) <= kTolerance); + for (int component = 0; component < mhd1d::N_Component; ++component) { + REQUIRE(std::fabs(manual_workspace.uc(i, component) - evolved_workspace.uc(i, component)) <= + kTolerance); } } } From 2f5e503573b5639b48b3e4ab0ce6930368f9d69a Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Wed, 1 Apr 2026 23:42:39 +0900 Subject: [PATCH 27/39] refactor(magnetohydrodynamics): reduce grid resolution from 400 to 100 cells Update default Nx constant and regenerate golden/reference CSV files. Improve plot styling with math mode labels and remove subplot titles. --- .../cpp-full-solver1d/spec.md | 2 +- .../workspace/scripts/plot_solution.py | 17 +- .../cpp-full-solver1d/workspace/src/main.cpp | 2 +- .../workspace/tests/data/brio_wu_golden.csv | 500 ++++-------------- .../workspace/tests/test_public.py | 4 +- .../eval/fixtures/mhd1d/brio_wu_fixture.json | 2 +- .../eval/fixtures/mhd1d/brio_wu_reference.csv | 500 ++++-------------- 7 files changed, 213 insertions(+), 814 deletions(-) diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/spec.md b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/spec.md index a98becf..5796019 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/spec.md +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/spec.md @@ -48,7 +48,7 @@ where `mx = rho * u`, `my = rho * v`, `mz = rho * w`, and total energy | `Bx` | 0.75 | | `dt` | 5.0e-4 | | `t_final` | 0.1 | -| `nx` | 400 | +| `nx` | 100 | ## Building diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/scripts/plot_solution.py b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/scripts/plot_solution.py index 7ae04fc..507bc68 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/scripts/plot_solution.py +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/scripts/plot_solution.py @@ -82,22 +82,21 @@ def main() -> int: fig, axes = plt.subplots(2, 2, figsize=(10, 7), sharex=True) plots = [ - (axes[0, 0], "rho", "Density"), - (axes[0, 1], "u", "Velocity u"), - (axes[1, 0], "p", "Pressure"), - (axes[1, 1], "by", "Magnetic field by"), + (axes[0, 0], "rho", r"$\rho$"), + (axes[0, 1], "u", r"$u$"), + (axes[1, 0], "p", r"$p$"), + (axes[1, 1], "by", r"$B_y$"), ] - for axis, field, title in plots: + for axis, field, ylabel in plots: axis.plot(x_values, columns[field], linewidth=1.5) - axis.set_title(title) - axis.set_ylabel(field) + axis.set_ylabel(ylabel) axis.grid(True, alpha=0.3) for axis in axes[1, :]: - axis.set_xlabel("x") + axis.set_xlabel(r"$x$") - fig.suptitle(f"Brio-Wu profiles: {csv_path}") + fig.suptitle(r"Brio-Wu Problem at $t = 0.1$") fig.tight_layout() output_path.parent.mkdir(parents=True, exist_ok=True) fig.savefig(output_path, dpi=150) diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp index e84c51b..228c330 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp @@ -4,7 +4,7 @@ #include #include -constexpr int Nx = 400; +constexpr int Nx = 100; constexpr double Gamma = 2.0; constexpr double Bx = 0.75; constexpr mhd1d::StateVector LeftPrimitive{ diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/data/brio_wu_golden.csv b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/data/brio_wu_golden.csv index 3b96ca0..e72dfa5 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/data/brio_wu_golden.csv +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/data/brio_wu_golden.csv @@ -1,401 +1,101 @@ x,rho,u,v,w,p,by,bz -0.00125,1,0,0,0,1,1,0 -0.0037499999999999999,1,0,0,0,1,1,0 -0.0062500000000000003,1,0,0,0,1,1,0 -0.0087500000000000008,1,0,0,0,1,1,0 -0.01125,1,0,0,0,1,1,0 -0.01375,1,0,0,0,1,1,0 -0.016250000000000001,1,0,0,0,1,1,0 -0.018749999999999999,1,0,0,0,1,1,0 -0.021250000000000002,1,0,0,0,1,1,0 -0.02375,1,0,0,0,1,1,0 -0.026249999999999999,1,0,0,0,1,1,0 -0.028750000000000001,1,0,0,0,1,1,0 -0.03125,1,0,0,0,1,1,0 -0.033750000000000002,1,0,0,0,1,1,0 -0.036249999999999998,1,0,0,0,1,1,0 -0.03875,1,0,0,0,1,1,0 -0.041250000000000002,1,0,0,0,1,1,0 -0.043750000000000004,1,0,0,0,1,1,0 -0.046249999999999999,1,0,0,0,1,1,0 -0.048750000000000002,1,0,0,0,1,1,0 -0.051250000000000004,1,0,0,0,1,1,0 -0.053749999999999999,1,0,0,0,1,1,0 -0.056250000000000001,1,0,0,0,1,1,0 -0.058750000000000004,1,0,0,0,1,1,0 -0.061249999999999999,1,0,0,0,1,1,0 -0.063750000000000001,1,0,0,0,1,1,0 -0.066250000000000003,1,0,0,0,1,1,0 -0.068750000000000006,1,0,0,0,1,1,0 -0.071250000000000008,1,0,0,0,1,1,0 -0.073749999999999996,1,0,0,0,1,1,0 -0.076249999999999998,1,0,0,0,1,1,0 -0.078750000000000001,1,0,0,0,1,1,0 -0.081250000000000003,1,0,0,0,1,1,0 -0.083750000000000005,1,0,0,0,1,1,0 -0.086250000000000007,1,0,0,0,1,1,0 -0.088749999999999996,1,0,0,0,1,1,0 -0.091249999999999998,1,0,0,0,1,1,0 -0.09375,1,0,0,0,1,1,0 -0.096250000000000002,1,0,0,0,1,1,0 -0.098750000000000004,1,0,0,0,1,1,0 -0.10125000000000001,1,0,0,0,1,1,0 -0.10375000000000001,1,0,0,0,1,1,0 -0.10625,1,0,0,0,1,1,0 -0.10875,1,0,0,0,1,1,0 -0.11125,1,0,0,0,1,1,0 -0.11375,1,0,0,0,1,1,0 -0.11625000000000001,1,0,0,0,1,1,0 -0.11875000000000001,1,0,0,0,1,1,0 -0.12125,1,0,0,0,1,1,0 -0.12375,1,0,0,0,1,1,0 -0.12625,1,0,0,0,1,1,0 -0.12875,1,0,0,0,1,1,0 -0.13125000000000001,1,0,0,0,1,1,0 -0.13375000000000001,1,0,0,0,1,1,0 -0.13625000000000001,1,0,0,0,1,1,0 -0.13875000000000001,1,0,0,0,1,1,0 -0.14125000000000001,1,0,0,0,1,1,0 -0.14375000000000002,1,0,0,0,1,1,0 -0.14624999999999999,1,0,0,0,1,1,0 -0.14874999999999999,1,0,0,0,1,1,0 -0.15125,1,0,0,0,1,1,0 -0.15375,1,0,0,0,1,1,0 -0.15625,1,0,0,0,1,1,0 -0.15875,1,0,0,0,1,1,0 -0.16125,1,0,0,0,1,1,0 -0.16375000000000001,1,0,0,0,1,1,0 -0.16625000000000001,1,0,0,0,1,1,0 -0.16875000000000001,1,0,0,0,1,1,0 -0.17125000000000001,1,0,0,0,1,1,0 -0.17375000000000002,1,0,0,0,1,1,0 -0.17624999999999999,1,0,0,0,1,1,0 -0.17874999999999999,1,0,0,0,1,1,0 -0.18124999999999999,1,0,0,0,1,1,0 -0.18375,1,0,0,0,1,1,0 -0.18625,1,0,0,0,1,1,0 -0.18875,1,0,0,0,1,1,0 -0.19125,1,0,0,0,1,1,0 -0.19375000000000001,1,0,0,0,1,1,0 -0.19625000000000001,1,0,0,0,1,1,0 -0.19875000000000001,1,0,0,0,1,1,0 -0.20125000000000001,1,0,0,0,1,1,0 -0.20375000000000001,1,0,0,0,1,1,0 -0.20625000000000002,1,0,0,0,1,1,0 -0.20874999999999999,1,0,0,0,1,1,0 -0.21124999999999999,1,0,0,0,1,1,0 -0.21375,1,0,0,0,1,1,0 -0.21625,1,0,0,0,1,1,0 -0.21875,1,0,0,0,1,1,0 -0.22125,1,0,0,0,1,1,0 -0.22375,1,0,0,0,1,1,0 -0.22625000000000001,1,0,0,0,1,1,0 -0.22875000000000001,1,0,0,0,1,1,0 -0.23125000000000001,1,0,0,0,1,1,0 -0.23375000000000001,1,0,0,0,1,1,0 -0.23625000000000002,1,0,0,0,1,1,0 -0.23875000000000002,1,0,0,0,1,1,0 -0.24124999999999999,1,0,0,0,1,1,0 -0.24374999999999999,1,0,0,0,1,1,0 -0.24625,1,0,0,0,1,1,0 -0.24875,1,0,0,0,1,1,0 -0.25125000000000003,1,0,0,0,1,1,0 -0.25375000000000003,1,0,0,0,1,1,0 -0.25624999999999998,1,0,0,0,1,1,0 -0.25874999999999998,1,0,0,0,1,1,0 -0.26124999999999998,1,0,0,0,1,1,0 -0.26374999999999998,1,0,0,0,1,1,0 -0.26624999999999999,1,0,0,0,1,1,0 -0.26874999999999999,1,0,0,0,1,1,0 -0.27124999999999999,1,0,0,0,1,1,0 -0.27374999999999999,1,0,0,0,1,1,0 -0.27625,1,0,0,0,1,1,0 -0.27875,1,0,0,0,1,1,0 -0.28125,1,0,0,0,1,1,0 -0.28375,1,0,0,0,1,1,0 -0.28625,1,0,0,0,1,1,0 -0.28875000000000001,1,0,0,0,1,1,0 -0.29125000000000001,1,0,0,0,1,1,0 -0.29375000000000001,1,0,0,0,1,1,0 -0.29625000000000001,1,0,0,0,1,1,0 -0.29875000000000002,1,0,0,0,1,1,0 -0.30125000000000002,1,0,0,0,1,1,0 -0.30375000000000002,1,0,0,0,1,1,0 -0.30625000000000002,1,0,0,0,1,1,0 -0.30875000000000002,1,0,0,0,1,1,0 -0.31125000000000003,1,0,0,0,1,1,0 -0.31375000000000003,1,0,0,0,1,1,0 -0.31625000000000003,1,0,0,0,1,1,0 -0.31875000000000003,0.99780058962396134,0.0039418906960591756,-0.0011154453241734904,0,0.99561225261243114,0.99733567707147397,0 -0.32124999999999998,0.99173977278087055,0.014827394992909993,-0.0042179802180685351,0,0.98356266355471567,0.98997992685476155,0 -0.32374999999999998,0.98408158190126227,0.028640080174583915,-0.008186565338896416,0,0.96843552308248149,0.98067103174066461,0 -0.32624999999999998,0.97581885102428656,0.043602341839540863,-0.012527557906330034,0,0.95224184930138511,0.9706093820226751,0 -0.32874999999999999,0.9673086534619818,0.059076763367010128,-0.017064614864518685,0,0.93570643492573047,0.96022723966347923,0 -0.33124999999999999,0.95869600144853218,0.074807206835931742,-0.021727022813603607,0,0.91911880282946645,0.94969857357607346,0 -0.33374999999999999,0.95004304399744044,0.090682637384932041,-0.026484836248230038,0,0.90260259674571253,0.93909829176568671,0 -0.33624999999999999,0.9413754410079106,0.10665810127729088,-0.031327232997254678,0,0.88620791115317998,0.92845621902021158,0 -0.33875,0.93270899587811373,0.12270504519506864,-0.03624752773178725,0,0.86996537982749733,0.91779125844150933,0 -0.34125,0.92405269875686513,0.13880647959038991,-0.041242256453888439,0,0.85389282701112912,0.90711462369760387,0 -0.34375,0.9154136825409287,0.15495119344114,-0.046309690150731095,0,0.83800169918738354,0.89643357043624938,0 -0.34625,0.90679699082194087,0.1711306591640914,-0.051448892458540188,0,0.82230012152488841,0.88575334869586952,0 -0.34875,0.89820651629824644,0.18733853105308285,-0.056659474531035876,0,0.80679335763251014,0.87507771377132626,0 -0.35125000000000001,0.88964446790953033,0.20356990667607194,-0.061941601414340595,0,0.79148497989669941,0.86440935577409717,0 -0.35375000000000001,0.88111284307810034,0.21982084917897435,-0.067295796388280038,0,0.77637743892286348,0.85375027049037311,0 -0.35625000000000001,0.87261362352600136,0.23608821896065768,-0.072722798578283135,0,0.76147221221794026,0.84310187986499097,0 -0.35875000000000001,0.86414845253144101,0.25236949156988764,-0.078223462833881888,0,0.74677004107769829,0.83246518929651392,0 -0.36125000000000002,0.85571868777839477,0.26866265040738607,-0.083798844143742335,0,0.73227118643443889,0.82184083376251138,0 -0.36375000000000002,0.84732496311510741,0.28496610344607487,-0.089450235711247772,0,0.71797553105924117,0.81122913890977844,0 -0.36625000000000002,0.83896778349293599,0.30127856646716628,-0.095179100441626849,0,0.70388256773647151,0.80063021301524762,0 -0.36875000000000002,0.8306478120801315,0.31759896051856901,-0.10098705469020462,0,0.68999145285900165,0.79004396131671717,0 -0.37125000000000002,0.82236584881264441,0.33392634501819063,-0.10687586239677592,0,0.67630114289001086,0.77947010645164028,0 -0.37375000000000003,0.81412256288554841,0.35025987066405678,-0.11284737308244323,0,0.66281051894930754,0.76890827004788531,0 -0.37625000000000003,0.80591829672758197,0.36659869209219098,-0.11890344385945414,0,0.64951847025460407,0.75835806846801013,0 -0.37875000000000003,0.7977533251558977,0.38294181436792768,-0.1250459153773277,0,0.63642397465987577,0.74781916579237695,0 -0.38125000000000003,0.78962821661912974,0.39928793115627925,-0.13127661071624822,0,0.62352617265709931,0.73729131884178889,0 -0.38375000000000004,0.78154397302664014,0.4156353252154189,-0.137597311365595,0,0.61082441920290476,0.72677444954932158,0 -0.38624999999999998,0.77350187664333747,0.4319818381617635,-0.14400971569167417,0,0.59831831823337123,0.71626872248566942,0 -0.38874999999999998,0.76550325157545829,0.44832485729258581,-0.15051541230315177,0,0.58600775859846921,0.70577458163502815,0 -0.39124999999999999,0.75754943880637893,0.46466125358111438,-0.15711584492844621,0,0.57389295780390692,0.69529276621051095,0 -0.39374999999999999,0.749642062019785,0.48098718289031467,-0.16381220586479228,0,0.56197455525241757,0.68482439731157485,0 -0.39624999999999999,0.74178347298350644,0.49729755518791763,-0.17060518383658033,0,0.55025391036855997,0.67437128401935453,0 -0.39874999999999999,0.73397737021860543,0.51358474386151054,-0.17749439433254424,0,0.53873391674659166,0.66393672613728749,0 -0.40125,0.72622997539659639,0.52983568010877113,-0.18447707310794387,0,0.52742087697476669,0.65352736887877549,0 -0.40375,0.71855268032257813,0.54602571955173596,-0.19154520667480535,0,0.51632840511574407,0.64315715022632924,0 -0.40625,0.71096761592194024,0.5621064499054218,-0.19867965431348364,0,0.50548500567258359,0.6328551452014316,0 -0.40875,0.70351809004436872,0.57798308169709955,-0.20583896158449672,0,0.49494776946723229,0.62268010464122547,0 -0.41125,0.69628594147097289,0.59347633160710345,-0.21293993103100095,0,0.48482478256859951,0.61274502061463976,0 -0.41375000000000001,0.68941655050596484,0.60826664970343558,-0.2198280489776889,0,0.47530692274767161,0.60325335873851049,0 -0.41625000000000001,0.68314702755279999,0.62182858255524953,-0.22624129413552949,0,0.46670271369465616,0.59454169635904308,0 -0.41875000000000001,0.67782572058125357,0.63339457769432261,-0.23178305630796459,0,0.45946103196399823,0.58710648915432451,0 -0.42125000000000001,0.67385858441141333,0.64199490957099814,-0.23596698492475343,0,0.45409808373542004,0.58156684274258463,0 -0.42375000000000002,0.67176641453700525,0.6469162308341575,-0.238218557413787,0,0.45128138130309292,0.57843540789261583,0 -0.42625000000000002,0.67078052736841931,0.64804295449248306,-0.23931535115787175,0,0.44995578425706018,0.5776695501854906,0 -0.42875000000000002,0.67093258028176295,0.64820950444476044,-0.23909517669577307,0,0.45016128034403946,0.57748103832724251,0 -0.43125000000000002,0.67221331698599318,0.64592193639342732,-0.2376161466610561,0,0.45188502884855786,0.57898748077442441,0 -0.43375000000000002,0.67477583336680169,0.64045344684033523,-0.2349806577986025,0,0.45533846144962792,0.58257702054306215,0 -0.43625000000000003,0.67693879989409655,0.63537735860005662,-0.23276478266323203,0,0.45826311431502864,0.58589598309566848,0 -0.43875000000000003,0.67818046569816726,0.63258441699362578,-0.2316835745358842,0,0.4599465488616844,0.58788185575907725,0 -0.44125000000000003,0.67847095916753464,0.63140939827029008,-0.23102942178508992,0,0.46034108071841129,0.58814312979425298,0 -0.44375000000000003,0.67871878159900201,0.63146024939639389,-0.23068318935251569,0,0.46067790212396337,0.58810935677202825,0 -0.44625000000000004,0.67853915803526677,0.63196041084427279,-0.23090732826723964,0,0.46043473249792088,0.58787073205089513,0 -0.44874999999999998,0.67803863707314427,0.6330593415786836,-0.23162869925234153,0,0.45975750456026709,0.58736622158591256,0 -0.45124999999999998,0.6774195873474379,0.6343255739755016,-0.23239706197011983,0,0.45891948202187494,0.58672848893472662,0 -0.45374999999999999,0.67688810168571512,0.63542738781445673,-0.23285843166501846,0,0.45820017218025605,0.58601807885490564,0 -0.45624999999999999,0.67650547951151974,0.63625820689185419,-0.23305952359533008,0,0.45768328142375492,0.58533372699356645,0 -0.45874999999999999,0.67624477252807902,0.63679255704404425,-0.23324253509623569,0,0.45733207413345345,0.58480268867196805,0 -0.46124999999999999,0.67604050594546095,0.63714228317088684,-0.23351779035696307,0,0.45705721760805229,0.58451139535639995,0 -0.46375,0.67595854916299569,0.63738534647931233,-0.23385855445925771,0,0.45694869192262283,0.58435845445911683,0 -0.46625,0.68086254532175094,0.63419323611509804,-0.2627490595791831,0,0.46500839952917328,0.56267418748132525,0 -0.46875,0.75828705387253315,0.56658450267562666,-0.6403332654473326,0,0.60777176667783583,0.26462111543054406,0 -0.47125,0.81542143854087634,0.46255247850130804,-1.1427907505563049,0,0.70707779939421744,-0.17802741409121203,0 -0.47375,0.78443205530850979,0.50559776659531341,-1.332519156086944,0,0.65515890375877317,-0.354497000575831,0 -0.47625000000000001,0.76277455722849596,0.55111223050629143,-1.406110791322537,0,0.61702037783610542,-0.4194427333795091,0 -0.47875000000000001,0.74404469538178764,0.55656484646456639,-1.4611410690372477,0,0.58668848068932689,-0.45267168642034472,0 -0.48125000000000001,0.7245298456798609,0.56167647024027656,-1.5074627288434979,0,0.5571761881846935,-0.47268348346610961,0 -0.48375000000000001,0.71012228623973583,0.57027999536562946,-1.543873073536012,0,0.53528590863347425,-0.49264654415374082,0 -0.48625000000000002,0.70076710390286745,0.58241431931480048,-1.5678960177704355,0,0.52117059910324071,-0.5132537526592037,0 -0.48875000000000002,0.6958138120994154,0.59253804821509259,-1.5801243124025581,0,0.51407181012863212,-0.53018918731486608,0 -0.49125000000000002,0.69634185265480064,0.60450975725843215,-1.5824609035105774,0,0.51510350342232991,-0.54159264057279222,0 -0.49375000000000002,0.69850922424214601,0.60950400813475858,-1.585266082294966,0,0.51853234952912874,-0.54291597426192384,0 -0.49625000000000002,0.69955231023329034,0.60819583311918735,-1.5848885559239814,0,0.52027069329509679,-0.54068543052621187,0 -0.49875000000000003,0.69829488634001602,0.60250392950529474,-1.5842381917356738,0,0.51860605011188388,-0.53585805694441235,0 -0.50124999999999997,0.69473126010799702,0.59400974956106756,-1.5847165912172572,0,0.51356317210852487,-0.53134363710848087,0 -0.50375000000000003,0.69253382725834534,0.59010833084815906,-1.5851121479337069,0,0.51057824154374631,-0.53011921878496304,0 -0.50624999999999998,0.69237449532735207,0.59146895693409685,-1.5858564348296551,0,0.51054249757041459,-0.53082328680938162,0 -0.50875000000000004,0.69391541373744337,0.59634222339010579,-1.5857210122073861,0,0.51315096871714994,-0.53304618751484978,0 -0.51124999999999998,0.69634148593928047,0.60301378588754684,-1.5840840117480401,0,0.5171828111968485,-0.53600443230198036,0 -0.51375000000000004,0.69696988284642125,0.60598814490820407,-1.5822803421052867,0,0.51876741128969461,-0.53768126044759668,0 -0.51624999999999999,0.69590524459691183,0.605542191027717,-1.5815913052223451,0,0.51808417485694558,-0.53738593862540907,0 -0.51875000000000004,0.69339823569240289,0.60237234278329166,-1.5824338658055286,0,0.51564230319494531,-0.53568598390826916,0 -0.52124999999999999,0.69028268100633383,0.59775928333034656,-1.5849765752973617,0,0.51233921959100215,-0.53282107449038196,0 -0.52375000000000005,0.6885408627829227,0.59563473330607197,-1.586881633696186,0,0.51091135095358142,-0.53126090526540737,0 -0.52625,0.68845991210476676,0.59576153638350393,-1.5870959718421693,0,0.51139517765564346,-0.53172734059034754,0 -0.52875000000000005,0.68913132894514517,0.59780515337360185,-1.5859257457768372,0,0.51333149786491905,-0.53324119440484385,0 -0.53125,0.69035686600602486,0.60114183287377887,-1.583761079933232,0,0.51632762277454369,-0.53561028146436995,0 -0.53375000000000006,0.69063785151444135,0.60308915950915953,-1.5825950002547069,0,0.51816477333483568,-0.5367661728665245,0 -0.53625,0.68995642603783169,0.60271623463782054,-1.5827072676591285,0,0.51817213887569635,-0.5365529040050816,0 -0.53875000000000006,0.68912674904173354,0.60080970261747135,-1.5836585612290803,0,0.5170008482178291,-0.53535672389780986,0 -0.54125000000000001,0.68900935996710411,0.59744632555053778,-1.5849988566238742,0,0.51492442266233129,-0.53339274974699291,0 -0.54375000000000007,0.68992607319859989,0.59550495144079929,-1.5855642783840616,0,0.51380892115497334,-0.53231014634052964,0 -0.54625000000000001,0.69030209756719352,0.59574669701945138,-1.5855252584440067,0,0.51389062331612756,-0.53244809173629659,0 -0.54874999999999996,0.68902173862300931,0.59740836235396289,-1.5852477103136609,0,0.5146658368665229,-0.53339030207149196,0 -0.55125000000000002,0.68189342316100054,0.60020433676255158,-1.5844249654880713,0,0.51628053637696625,-0.53477165363768919,0 -0.55374999999999996,0.65276597713910334,0.60185672139983104,-1.5836528865010249,0,0.51743177517895211,-0.53527542396206562,0 -0.55625000000000002,0.58906478526618755,0.60185519401175147,-1.583053851614638,0,0.51755849582377766,-0.53486837400458076,0 -0.55874999999999997,0.49422558600892486,0.60118766199411133,-1.5832559126839811,0,0.5172228327206092,-0.53418658367731886,0 -0.56125000000000003,0.38247103041338487,0.59990157132174105,-1.5840925292397106,0,0.51620910738423487,-0.53342595162876671,0 -0.56374999999999997,0.28025492247104017,0.59846176638276449,-1.5851622199216584,0,0.5152364728981691,-0.53275468018860095,0 -0.56625000000000003,0.22868966508824234,0.59710231685960313,-1.5860977814707127,0,0.51481122129747781,-0.53239158687234311,0 -0.56874999999999998,0.2267856507919232,0.59640620540582956,-1.5864596507885937,0,0.51481550996877012,-0.53225943769555295,0 -0.57125000000000004,0.22713175101669475,0.59631043781086113,-1.5862941490337203,0,0.51512192557837366,-0.53221446943385053,0 -0.57374999999999998,0.22832982826697543,0.59690929717637031,-1.5856945341940099,0,0.51544195200245158,-0.53214053153219976,0 -0.57625000000000004,0.23006132532598028,0.5979765390095868,-1.5850598466399157,0,0.51604401482077034,-0.53235234485917893,0 -0.57874999999999999,0.23181956629299122,0.59934757674111083,-1.5845139129375743,0,0.51687736532492834,-0.53308886162542746,0 -0.58125000000000004,0.23316522477988719,0.60072662152561196,-1.5842849795297345,0,0.51772674090669124,-0.53394457396042982,0 -0.58374999999999999,0.23391908756041113,0.60223034496795813,-1.5839684765344821,0,0.51806461631752188,-0.53457035523447027,0 -0.58625000000000005,0.23431034941216394,0.60345350170797118,-1.5841973780115437,0,0.51789119722034871,-0.53460934483436429,0 -0.58875,0.23460990828752651,0.60387631345954085,-1.5843501276762757,0,0.51757915110632757,-0.53432910759567398,0 -0.59125000000000005,0.23506825902401635,0.60282288127804684,-1.585165115162972,0,0.51773081006565902,-0.53416645772176508,0 -0.59375,0.23554392868159077,0.60057139334604759,-1.5863553588391026,0,0.51774108981529299,-0.53376740267714529,0 -0.59625000000000006,0.23574376308649053,0.59888206501796171,-1.587249000037269,0,0.51718780070000137,-0.53273061481737882,0 -0.59875,0.2357083556292047,0.59836333208440606,-1.5873845267462028,0,0.51612520155316433,-0.53158021311167569,0 -0.60125000000000006,0.23567285891449777,0.59766263969440114,-1.5877771701611647,0,0.5153079104412206,-0.53069139651429365,0 -0.60375000000000001,0.23580149297303599,0.59664353703500261,-1.5883416830586965,0,0.51563852961964063,-0.53095430707000513,0 -0.60625000000000007,0.2361263695423006,0.59461828975577724,-1.5895049849613039,0,0.51671691867389946,-0.53190837659017298,0 -0.60875000000000001,0.23631854959443394,0.59598090215208221,-1.5892842142291126,0,0.51722476899470071,-0.53244556280972177,0 -0.61124999999999996,0.23614815457146857,0.60018906680370221,-1.5879979771038979,0,0.51632413595151727,-0.53176277681989537,0 -0.61375000000000002,0.23613289789183126,0.60417970975516422,-1.5866151046667705,0,0.51643954420713611,-0.53176024605848848,0 -0.61624999999999996,0.23636461460022473,0.60239051184144632,-1.5874214851519997,0,0.51800335570916167,-0.53290555450294708,0 -0.61875000000000002,0.23685612557714375,0.59917605052507494,-1.5887974386781778,0,0.5210289610697918,-0.53516232288950649,0 -0.62124999999999997,0.236629474827142,0.59900329149184894,-1.5883523685763601,0,0.52084906032944422,-0.53504397890458888,0 -0.62375000000000003,0.23553444051781158,0.6094416366857287,-1.5832404611606701,0,0.51646465152499421,-0.53125243577613324,0 -0.62624999999999997,0.23480711426766496,0.61276659011654855,-1.5820244559454961,0,0.51359689942899112,-0.52940636364944882,0 -0.62875000000000003,0.2356805197653731,0.59981103240692546,-1.5873723560682378,0,0.51775543844125527,-0.53341880855164581,0 -0.63124999999999998,0.23665817647544471,0.58339388331467124,-1.5915886744702512,0,0.52230143300038878,-0.53706058378831778,0 -0.63375000000000004,0.23624007285922682,0.58851017476723522,-1.59323247289284,0,0.52067660348375233,-0.5344840295515112,0 -0.63624999999999998,0.23248269439745392,0.62017067097041967,-1.5860539280724555,0,0.50441116285539445,-0.52566087023161623,0 -0.63875000000000004,0.23287406771008778,0.63021607264750734,-1.5714111287249182,0,0.50610033932647758,-0.51881227330971402,0 -0.64124999999999999,0.23535665099942626,0.54552436166512541,-1.5610957972782948,0,0.51620744848479627,-0.56037653795121478,0 -0.64375000000000004,0.20465921194562456,0.43550920292588785,-1.2461151516740705,0,0.38959320083362653,-0.65081895672509904,0 -0.64624999999999999,0.14009395039150022,-0.013620789581837623,-0.52852147362552981,0,0.14893940676494133,-0.84115443834590753,0 -0.64875000000000005,0.11751273289208522,-0.22437213354109883,-0.16226723635220483,0,0.088423364818236205,-0.90651157396572613,0 -0.65125,0.1172304349686725,-0.23055950413906093,-0.15834995998342491,0,0.087980641698620188,-0.90679519491120031,0 -0.65375000000000005,0.11725471096145602,-0.23125048663034239,-0.15988967480131078,0,0.088016824468717392,-0.90623225381858352,0 -0.65625,0.11717819471904142,-0.23427702280565715,-0.16309682007195445,0,0.087901314598951896,-0.90467584906756415,0 -0.65875000000000006,0.11701473008444113,-0.23931297733336335,-0.16679190788787737,0,0.087655777579992433,-0.90262825016899195,0 -0.66125,0.11682044790275041,-0.24514922075151147,-0.17096232324746935,0,0.087364026139568063,-0.90028034756782194,0 -0.66375000000000006,0.11664990465573849,-0.25033190821458962,-0.17474981564425235,0,0.087108330784376853,-0.89817521994953109,0 -0.66625000000000001,0.11659183681487016,-0.25210877535067339,-0.17606373800900416,0,0.087021072376205377,-0.89744964551230921,0 -0.66875000000000007,0.11659565313804586,-0.25199397498810977,-0.17597732617696363,0,0.087026305831300999,-0.89749741619551415,0 -0.67125000000000001,0.11663090160109492,-0.25091377282773697,-0.17517704012828506,0,0.087078794787367686,-0.89793883874353608,0 -0.67374999999999996,0.11672569071628684,-0.24801894198896796,-0.17304243161135532,0,0.087219942612219992,-0.89911964160362412,0 -0.67625000000000002,0.11687866962961335,-0.24335351965734039,-0.16961064512063617,0,0.087448451090979984,-0.90102219304187958,0 -0.67874999999999996,0.11706716457467407,-0.23761206836584889,-0.16539777355745228,0,0.087729984963327179,-0.903363295110168,0 -0.68125000000000002,0.11725531088500578,-0.23188499457250628,-0.16120570301525269,0,0.088011625486577039,-0.90569773785665264,0 -0.68374999999999997,0.1173869096123874,-0.22787830963670686,-0.15827892017451603,0,0.088208749864432612,-0.90733063517330292,0 -0.68625000000000003,0.11740612473963735,-0.22729629509711108,-0.15785255924099278,0,0.08823710550802899,-0.90756836804359509,0 -0.68874999999999997,0.1174043024511611,-0.22735052337058989,-0.15789017932834926,0,0.08823427512892934,-0.90754730073044609,0 -0.69125000000000003,0.117385586946818,-0.22792019819914602,-0.15830312721357306,0,0.088205717689737617,-0.90731579951421071,0 -0.69374999999999998,0.11733333794868246,-0.22950618589385671,-0.15945854815582666,0,0.088127191628521229,-0.90667017955692664,0 -0.69625000000000004,0.11723047219013001,-0.23263692843712594,-0.1617427414330794,0,0.087972319470910665,-0.90539536389292952,0 -0.69874999999999998,0.11707119965622731,-0.23748283866703485,-0.16528542583275169,0,0.087733351641583468,-0.90342149850150899,0 -0.70125000000000004,0.11687031669818926,-0.24360287346583834,-0.16977049665712179,0,0.087431835729061547,-0.90092842407432894,0 -0.70374999999999999,0.11665961352933606,-0.25002473062346064,-0.17448953235454481,0,0.087116281751007274,-0.89831176039494187,0 -0.70625000000000004,0.1165165302499433,-0.25439233792360777,-0.17770571675062352,0,0.086901806565141237,-0.89653255429149881,0 -0.70874999999999999,0.11650342706556212,-0.2547927709381313,-0.17799943043788108,0,0.086882001709442935,-0.89636978909070852,0 -0.71125000000000005,0.11651313327825538,-0.25449583971560935,-0.17777892983377314,0,0.086896257833543045,-0.8964912611982403,0 -0.71375,0.11657824875283614,-0.25250868159070106,-0.17631251476880538,0,0.086993320783096961,-0.8973018533821181,0 -0.71625000000000005,0.11670669297667058,-0.24859138314712292,-0.17342577474077817,0,0.087184751921271064,-0.89889931280557489,0 -0.71875,0.11691006489352132,-0.24238906844035901,-0.16886594442826247,0,0.087488817862619084,-0.90142781444796216,0 -0.72125000000000006,0.11715696037775949,-0.23486831445080303,-0.16335344395667553,0,0.087858057823719804,-0.90449340621863428,0 -0.72375,0.1174166577876183,-0.22696879682954138,-0.15758238759684895,0,0.08824723417305036,-0.9077124481337816,0 -0.72625000000000006,0.11761203623571825,-0.22103003047499958,-0.15325677844062333,0,0.088540228534066956,-0.9101327480055359,0 -0.72875000000000001,0.11764815223606326,-0.21993423708599183,-0.15245924851833104,0,0.08859412431248137,-0.91057953155824023,0 -0.73125000000000007,0.11764295241336808,-0.2200903293627689,-0.15257160911773979,0,0.088586337286039485,-0.91051617734452983,0 -0.73375000000000001,0.11759000660142679,-0.2217003081127347,-0.15374084437403135,0,0.088506338493284042,-0.90986082609014918,0 -0.73624999999999996,0.11746031345619404,-0.22563937809188131,-0.15660719388934993,0,0.088311340736592969,-0.90825665198961858,0 -0.73875000000000002,0.11723828372065292,-0.23239420472240171,-0.16153287456890622,0,0.087977168091466496,-0.9055058428394922,0 -0.74124999999999996,0.11695405872405729,-0.24104632732416764,-0.16786313884395296,0,0.087550606026847611,-0.90198118960069906,0 -0.74375000000000002,0.11667856642422411,-0.24944335338982396,-0.17402937906226756,0,0.087137125367697799,-0.89856002823076275,0 -0.74624999999999997,0.11652142847638322,-0.25424394334264461,-0.17756382750169244,0,0.086901454460314165,-0.89660456501140007,0 -0.74875000000000003,0.11651981293218819,-0.25428866572145908,-0.17759682581079278,0,0.086899302405564094,-0.89658628316293454,0 -0.75124999999999997,0.11654384178002924,-0.2535594566735877,-0.17705849552342462,0,0.086934742960429467,-0.89688401034771859,0 -0.75375000000000003,0.11663051640593858,-0.25091355302284074,-0.17510796984102217,0,0.08706432661997765,-0.89796267762001025,0 -0.75624999999999998,0.11678404277607407,-0.24623080770483949,-0.17166114194328411,0,0.087293311528364281,-0.89987155145629427,0 -0.75875000000000004,0.11700344302198436,-0.23954347013011862,-0.16675062625144083,0,0.087621451884493884,-0.90259743709333429,0 -0.76124999999999998,0.1172431937971754,-0.23224924863937169,-0.16141064996890825,0,0.087980008633671614,-0.90557089006933678,0 -0.76375000000000004,0.11745835723684928,-0.2257014011703927,-0.15663158785569858,0,0.088302688141607355,-0.90823890147105391,0 -0.76624999999999999,0.11754312622419839,-0.22312484757638981,-0.15475473896938308,0,0.088429763359914815,-0.90928903939657357,0 -0.76875000000000004,0.11754177990704494,-0.2231668919210899,-0.15478502917437109,0,0.08842756580276423,-0.90927164832488772,0 -0.77124999999999999,0.11752467556395679,-0.22368568226609817,-0.15516209375600826,0,0.088401836341015949,-0.90906068120615424,0 -0.77375000000000005,0.11746717207168339,-0.22543397607620042,-0.15643453805452581,0,0.088315305884747231,-0.90834911199205925,0 -0.77625,0.11736654278177328,-0.2284945234234321,-0.15866471296533163,0,0.088163952024696957,-0.90710265586110195,0 -0.77875000000000005,0.11722713361337955,-0.23273201682477188,-0.16175718703284839,0,0.087954401569682927,-0.90537555931713076,0 -0.78125,0.11707778782447791,-0.23727864076599559,-0.16508186697178692,0,0.087730265510702843,-0.90352339441354335,0 -0.78375000000000006,0.11694701926702723,-0.24126444712942194,-0.16800203883568809,0,0.087533988164180898,-0.90189987769505553,0 -0.78625,0.11687743963943051,-0.24338529654596849,-0.16955784803318272,0,0.087429820942728886,-0.90103669813034792,0 -0.78875000000000006,0.11687579781052707,-0.24343592181704782,-0.16959486107747798,0,0.08742728644424369,-0.90101601254263675,0 -0.79125000000000001,0.11687539900643468,-0.24344948224066379,-0.16960462180695862,0,0.087426474749633054,-0.90100969094006977,0 -0.79375000000000007,0.11687409481764938,-0.24348129085661555,-0.16962777224760861,0,0.087424696127569423,-0.90099540369582221,0 -0.79625000000000001,0.11687218858217306,-0.24354390911756213,-0.16967348339899166,0,0.087421752667664165,-0.90097160223299655,0 -0.79875000000000007,0.116870215752296,-0.24361058874898325,-0.1697220504681374,0,0.0874184896460376,-0.90094505886224741,0 -0.80125000000000002,0.11686946136924814,-0.2436294977483163,-0.16973560439458318,0,0.087417613977942565,-0.90093824717607751,0 -0.80374999999999996,0.11686962190859448,-0.24361757731467398,-0.16972658857626485,0,0.087417870797879327,-0.90094090262231019,0 -0.80625000000000002,0.11687356980470871,-0.24350583643941545,-0.16964422423269365,0,0.087423444046079268,-0.90098768473549895,0 -0.80874999999999997,0.11688754092326054,-0.24307479305630586,-0.16932756115966405,0,0.087444533924976753,-0.90116318958274499,0 -0.81125000000000003,0.11691972536277602,-0.24209343744922968,-0.16860707128114324,0,0.087492701479890633,-0.90156325665747283,0 -0.81374999999999997,0.11697942266283615,-0.24027908101633488,-0.16727614115169526,0,0.087581830141478023,-0.90230271944561291,0 -0.81625000000000003,0.11707126156401244,-0.23747712607290974,-0.16522305705840304,0,0.08771962969895275,-0.9034445863476972,0 -0.81874999999999998,0.11720175792642251,-0.23350615420116155,-0.16231792357714034,0,0.087915217578154237,-0.9050626671429971,0 -0.82125000000000004,0.1173736571942727,-0.22828036241638489,-0.1585025661792111,0,0.088173092622349736,-0.90719178038941839,0 -0.82374999999999998,0.11758753647266376,-0.22177196496693163,-0.15376313261251445,0,0.088495041188408119,-0.90984301103522469,0 -0.82625000000000004,0.11784277533584739,-0.21402503109325074,-0.14813976728812336,0,0.088879385731000071,-0.91299811129464448,0 -0.82874999999999999,0.11813596987373072,-0.205135924121809,-0.14171096949690176,0,0.08932189551312586,-0.91661764598071116,0 -0.83125000000000004,0.11846242009804758,-0.19523667455595015,-0.13458125038057758,0,0.089816668680236189,-0.9206475711390385,0 -0.83374999999999999,0.11881836690580111,-0.18447630678794286,-0.12686686204096317,0,0.090356823064338121,-0.92502691979325369,0 -0.83625000000000005,0.1191983441793935,-0.17300551327586872,-0.11868324695390486,0,0.090935254319816416,-0.92969427790399251,0 -0.83875,0.11959717551690868,-0.16096583965923558,-0.11013805167379476,0,0.091545418685837099,-0.93459181209615316,0 -0.84125000000000005,0.12001209755915153,-0.14848356585795672,-0.10132596582677481,0,0.092181264693114717,-0.93966810954166835,0 -0.84375,0.12043877950911509,-0.13566775697809377,-0.092327068649525487,0,0.09283750209918229,-0.94487908876250215,0 -0.84625000000000006,0.12087371396585696,-0.12260927689724001,-0.083209494160765118,0,0.093509933368980058,-0.95018748674767706,0 -0.84875,0.12131567129224743,-0.1093844697747413,-0.074028085304663455,0,0.094194471653768597,-0.95556248832995694,0 -0.85125000000000006,0.12176160189020308,-0.09605840550907592,-0.064827260654986854,0,0.094888110578776108,-0.96097800205309825,0 -0.85375000000000001,0.12220959195301018,-0.082687976622211293,-0.055648874909733553,0,0.095588128076847467,-0.96641042235416763,0 -0.85625000000000007,0.12265849289683448,-0.069328350882536471,-0.046529178998104978,0,0.096291008766648978,-0.97183799626406353,0 -0.85875000000000001,0.12310492382833711,-0.056055787146077833,-0.037517888038019767,0,0.09699339953981001,-0.97722987519548088,0 -0.86125000000000007,0.12354638322994141,-0.042956407473377395,-0.028674501720487335,0,0.09769052441735504,-0.98255051087648382,0 -0.86375000000000002,0.12397571444500097,-0.030246526919572154,-0.020138158560817101,0,0.098369693309683259,-0.9877136051082076,0 -0.86624999999999996,0.12438070565716236,-0.018268628225800106,-0.012133471567233139,0,0.099013662392659962,-0.99257887118158417,0 -0.86875000000000002,0.12473720330383267,-0.0077450726851307217,-0.0051335041220790375,0,0.099581171411821656,-0.9968532001498126,0 -0.87124999999999997,0.1249700817568199,-0.00088137321149738316,-0.00058273816183469274,0,0.099952225492064839,-0.99964210622385019,0 -0.87375000000000003,0.12500000000314493,9.2678072621328777e-11,6.1313650451563421e-11,0,0.10000000000503184,-1.0000000000376423,0 -0.87624999999999997,0.12500000000313061,9.2259592555934167e-11,6.1037663810628979e-11,0,0.10000000000500853,-1.0000000000374729,0 -0.87875000000000003,0.12500000000298683,8.8026904282191698e-11,5.823759252481918e-11,0,0.10000000000477915,-1.0000000000357536,0 -0.88124999999999998,0.12500000000268974,7.9267999569953049e-11,5.2440333555909956e-11,0,0.10000000000430354,-1.0000000000321956,0 -0.88375000000000004,0.12500000000219424,6.4666272335784794e-11,4.2780682699312474e-11,0,0.1000000000035105,-1.0000000000262652,0 -0.88624999999999998,0.1250000000015753,4.6425914963663502e-11,3.071392029557768e-11,0,0.10000000000252052,-1.0000000000188565,0 -0.88875000000000004,0.12500000000090811,2.6762103644077048e-11,1.7704741376541178e-11,0,0.10000000000145282,-1.0000000000108695,0 -0.89124999999999999,0.1250000000003243,9.5565777513424923e-12,6.3224980806181864e-12,0,0.10000000000051879,-1.0000000000038816,0 -0.89375000000000004,0.12500000000000178,5.2520950551592749e-14,3.481659405223961e-14,0,0.10000000000000264,-1.0000000000000213,0 -0.89624999999999999,0.125,0,0,0,0.099999999999999867,-1,0 -0.89875000000000005,0.125,0,0,0,0.099999999999999867,-1,0 -0.90125,0.125,0,0,0,0.099999999999999867,-1,0 -0.90375000000000005,0.125,0,0,0,0.099999999999999867,-1,0 -0.90625,0.125,0,0,0,0.099999999999999867,-1,0 -0.90875000000000006,0.125,0,0,0,0.099999999999999867,-1,0 -0.91125,0.125,0,0,0,0.099999999999999867,-1,0 -0.91375000000000006,0.125,0,0,0,0.099999999999999867,-1,0 -0.91625000000000001,0.125,0,0,0,0.099999999999999867,-1,0 -0.91875000000000007,0.125,0,0,0,0.099999999999999867,-1,0 -0.92125000000000001,0.125,0,0,0,0.099999999999999867,-1,0 -0.92375000000000007,0.125,0,0,0,0.099999999999999867,-1,0 -0.92625000000000002,0.125,0,0,0,0.099999999999999867,-1,0 -0.92874999999999996,0.125,0,0,0,0.099999999999999867,-1,0 -0.93125000000000002,0.125,0,0,0,0.099999999999999867,-1,0 -0.93374999999999997,0.125,0,0,0,0.099999999999999867,-1,0 -0.93625000000000003,0.125,0,0,0,0.099999999999999867,-1,0 -0.93874999999999997,0.125,0,0,0,0.099999999999999867,-1,0 -0.94125000000000003,0.125,0,0,0,0.099999999999999867,-1,0 -0.94374999999999998,0.125,0,0,0,0.099999999999999867,-1,0 -0.94625000000000004,0.125,0,0,0,0.099999999999999867,-1,0 -0.94874999999999998,0.125,0,0,0,0.099999999999999867,-1,0 -0.95125000000000004,0.125,0,0,0,0.099999999999999867,-1,0 -0.95374999999999999,0.125,0,0,0,0.099999999999999867,-1,0 -0.95625000000000004,0.125,0,0,0,0.099999999999999867,-1,0 -0.95874999999999999,0.125,0,0,0,0.099999999999999867,-1,0 -0.96125000000000005,0.125,0,0,0,0.099999999999999867,-1,0 -0.96375,0.125,0,0,0,0.099999999999999867,-1,0 -0.96625000000000005,0.125,0,0,0,0.099999999999999867,-1,0 -0.96875,0.125,0,0,0,0.099999999999999867,-1,0 -0.97125000000000006,0.125,0,0,0,0.099999999999999867,-1,0 -0.97375,0.125,0,0,0,0.099999999999999867,-1,0 -0.97625000000000006,0.125,0,0,0,0.099999999999999867,-1,0 -0.97875000000000001,0.125,0,0,0,0.099999999999999867,-1,0 -0.98125000000000007,0.125,0,0,0,0.099999999999999867,-1,0 -0.98375000000000001,0.125,0,0,0,0.099999999999999867,-1,0 -0.98625000000000007,0.125,0,0,0,0.099999999999999867,-1,0 -0.98875000000000002,0.125,0,0,0,0.099999999999999867,-1,0 -0.99125000000000008,0.125,0,0,0,0.099999999999999867,-1,0 -0.99375000000000002,0.125,0,0,0,0.099999999999999867,-1,0 -0.99624999999999997,0.125,0,0,0,0.099999999999999867,-1,0 -0.99875000000000003,0.125,0,0,0,0.099999999999999867,-1,0 +0.0050000000000000001,1,0,0,0,1,1,0 +0.014999999999999999,1,0,0,0,1,1,0 +0.025000000000000001,1,0,0,0,1,1,0 +0.035000000000000003,1,0,0,0,1,1,0 +0.044999999999999998,1,0,0,0,1,1,0 +0.055,1,0,0,0,1,1,0 +0.065000000000000002,1,0,0,0,1,1,0 +0.074999999999999997,1,0,0,0,1,1,0 +0.085000000000000006,1,0,0,0,1,1,0 +0.095000000000000001,1,0,0,0,1,1,0 +0.105,1,0,0,0,1,1,0 +0.115,1,0,0,0,1,1,0 +0.125,1,0,0,0,1,1,0 +0.13500000000000001,1,0,0,0,1,1,0 +0.14499999999999999,1,0,0,0,1,1,0 +0.155,1,0,0,0,1,1,0 +0.16500000000000001,1,0,0,0,1,1,0 +0.17500000000000002,1,0,0,0,1,1,0 +0.185,1,0,0,0,1,1,0 +0.19500000000000001,1,0,0,0,1,1,0 +0.20500000000000002,1,0,0,0,1,1,0 +0.215,1,0,0,0,1,1,0 +0.22500000000000001,1,0,0,0,1,1,0 +0.23500000000000001,1,0,0,0,1,1,0 +0.245,1,0,0,0,1,1,0 +0.255,1,0,0,0,1,1,0 +0.26500000000000001,1,0,0,0,1,1,0 +0.27500000000000002,1,0,0,0,1,1,0 +0.28500000000000003,1,0,0,0,1,1,0 +0.29499999999999998,1,0,0,0,1,1,0 +0.30499999999999999,1,0,0,0,1,1,0 +0.315,0.99258917532833379,0.013274302361789324,-0.0037458540886650027,0,0.98532404108866567,0.99104740522973966,0 +0.32500000000000001,0.96954607581582897,0.054883618137207428,-0.015827325460063591,0,0.94023568077652442,0.96299689161606516,0 +0.33500000000000002,0.94025803324835733,0.10865479486043322,-0.031944255536031786,0,0.88435499782767446,0.92711462956015256,0 +0.34500000000000003,0.90897792466167582,0.16698841420781432,-0.050131763210425707,0,0.82652179164341721,0.88849866375884556,0 +0.35499999999999998,0.87725610844274526,0.2271603117432259,-0.069719685021130948,0,0.76985377322754589,0.84898878620884088,0 +0.36499999999999999,0.84566618167244145,0.28816698962982518,-0.090519447417695451,0,0.71541656913426399,0.80923410080538904,0 +0.375,0.81450435463148285,0.3494865276909434,-0.11251682956314066,0,0.66367321125402712,0.76950238387022263,0 +0.38500000000000001,0.78404538979850258,0.41062539085171551,-0.13575856770700617,0,0.61497905337973746,0.72997249890053162,0 +0.39500000000000002,0.75467120186953685,0.47083530429296916,-0.1602094195276916,0,0.56978778527926832,0.69094510148101218,0 +0.40500000000000003,0.72701668590610768,0.52870556766657628,-0.18539026277804579,0,0.52883750835390897,0.65319266964541056,0 +0.41500000000000004,0.70216500224646816,0.58153016354527853,-0.20973136326536138,0,0.4933637549672012,0.61876152226558601,0 +0.42499999999999999,0.68193441338380167,0.62487275671749021,-0.22845986767252549,0,0.46540195161446823,0.59219206428336624,0 +0.435,0.6666986977176832,0.65196598708089948,-0.23211489711409145,0,0.44490074049787121,0.58021922926273972,0 +0.44500000000000001,0.66015529724292976,0.66607074009479628,-0.22555655390938342,0,0.43615912199888263,0.58524191570556205,0 +0.45500000000000002,0.65997980757445474,0.66324409170331222,-0.23280516118974198,0,0.43727412310940939,0.5796363680769816,0 +0.46500000000000002,0.73349815599883794,0.60086667962898554,-0.62171855754180494,0,0.57886068825314341,0.27652712488086967,0 +0.47500000000000003,0.79237811897791921,0.46454032083596353,-1.2161018009267417,0,0.6842784144671038,-0.24404258805909654,0 +0.48499999999999999,0.74259318372203176,0.53084767864673321,-1.4743018340823315,0,0.60002741951352012,-0.44224666294204562,0 +0.495,0.69493377959694547,0.61399418172955245,-1.5431753009247675,0,0.54413704626033854,-0.54049642839751277,0 +0.505,0.70278259276020427,0.61662067481286442,-1.5872354257997463,0,0.52068648102692328,-0.56052646550215834,0 +0.51500000000000001,0.70390914156072559,0.6077114699355689,-1.6001701751263477,0,0.51193399003676154,-0.54226823182770345,0 +0.52500000000000002,0.69922181544266515,0.59340751947871018,-1.6046948629200928,0,0.51300004963251122,-0.52185059484429897,0 +0.53500000000000003,0.67807490745420074,0.5878535845789149,-1.6006935764888095,0,0.51466016361553968,-0.51621274881535362,0 +0.54500000000000004,0.60556902444692728,0.59045915738825405,-1.5906721688577199,0,0.51204702934936586,-0.52148853682254903,0 +0.55500000000000005,0.48266830107336006,0.59697028797374452,-1.5761776779942758,0,0.51057551463380291,-0.53191252428398161,0 +0.56500000000000006,0.34834934855591537,0.59188322457049136,-1.5687669989374082,0,0.5151520944223198,-0.54463835756014178,0 +0.57500000000000007,0.2451691037246034,0.59463166677984525,-1.5635053912378623,0,0.51994523862074438,-0.55151343157376009,0 +0.58499999999999996,0.22308154337733685,0.61421260394352284,-1.5558407025582697,0,0.51450769544894648,-0.54648231691723681,0 +0.59499999999999997,0.22390587217315483,0.62861601814674595,-1.555379908924208,0,0.51042675178345809,-0.53931383334019445,0 +0.60499999999999998,0.22786331744185459,0.61304302077924422,-1.5697800797404926,0,0.51789637516013132,-0.53999599169525736,0 +0.61499999999999999,0.23452030041149688,0.58777367268577241,-1.5968680437122895,0,0.53659755807779264,-0.54285121456661267,0 +0.625,0.23506241740122699,0.58441088978544375,-1.6180990627429224,0,0.5312595858066933,-0.53847776600605912,0 +0.63500000000000001,0.22912802575710367,0.64096361665071178,-1.5587196384023227,0,0.50180683386498415,-0.51954980419936259,0 +0.64500000000000002,0.20820170172948924,0.4429088168703938,-1.3138217298639516,0,0.4107172773448764,-0.63242114973177121,0 +0.65500000000000003,0.14280420150766387,0.0013572736674349979,-0.58334822550752841,0,0.15933600494306066,-0.82699909098420499,0 +0.66500000000000004,0.11735885521106922,-0.23309434559311201,-0.17605497312958984,0,0.088246122408452865,-0.90091689844612777,0 +0.67500000000000004,0.11691966169225833,-0.24239401825294279,-0.16901850205441424,0,0.087525697429624683,-0.90138999879178838,0 +0.68500000000000005,0.1168975018076187,-0.24275168390313129,-0.16913431059427403,0,0.087491282208618681,-0.90130727955920587,0 +0.69500000000000006,0.11688490837927806,-0.24293963466430563,-0.16922798396131322,0,0.087471166714507165,-0.90122308503037618,0 +0.70499999999999996,0.11687882431088358,-0.24305091000018803,-0.16930677036965813,0,0.087461000889423768,-0.90113549166198792,0 +0.71499999999999997,0.11688210335016401,-0.24310898990635241,-0.16941137635009459,0,0.087464485048653229,-0.90109713084582599,0 +0.72499999999999998,0.11688746427801196,-0.24311790246317952,-0.16948241337481523,0,0.087471346584835463,-0.90112657201926949,0 +0.73499999999999999,0.11689293842702393,-0.24301542095697384,-0.16941123056591925,0,0.087478382198893812,-0.90117181152414561,0 +0.745,0.11689754429437521,-0.24279548243457205,-0.16922004702154958,0,0.087484264982216398,-0.90123329716500089,0 +0.755,0.11690472407462463,-0.24244042822845885,-0.16894496953161006,0,0.087493985877884928,-0.90135933427866255,0 +0.76500000000000001,0.1169351752430936,-0.24164401100336819,-0.16834345193351358,0,0.087538755474644847,-0.90173628521210369,0 +0.77500000000000002,0.11702346553875453,-0.2389118539454739,-0.16634253632348067,0,0.087670236260091849,-0.90283181009609326,0 +0.78500000000000003,0.11723705803609173,-0.23241448265557926,-0.16159143199373074,0,0.087990348375741601,-0.90548092874079178,0 +0.79500000000000004,0.1176285175883393,-0.22051415125476836,-0.15292012220738538,0,0.088578608675684678,-0.91032952865801275,0 +0.80500000000000005,0.11822301685274909,-0.20247335890203855,-0.13985941063243096,0,0.089475764221054743,-0.91767747139414524,0 +0.81500000000000006,0.11901085894402198,-0.178638590244622,-0.12276084795550267,0,0.090670936816770853,-0.92738054886244792,0 +0.82500000000000007,0.11995507930331456,-0.15017685276699991,-0.10257309790892337,0,0.092113203419944889,-0.93896119897869035,0 +0.83499999999999996,0.12100582881114735,-0.1186354504616307,-0.080489249938489674,0,0.093731854039529328,-0.95178772370322251,0 +0.84499999999999997,0.12210948952666369,-0.085657286840511535,-0.057715619723010918,0,0.095446790184988584,-0.96519228251210643,0 +0.85499999999999998,0.12320528139333707,-0.053056324701219029,-0.035509818552657238,0,0.097164687932375315,-0.97843939905855704,0 +0.86499999999999999,0.12419939842673788,-0.023611385320102929,-0.015706138420103915,0,0.098733750673405729,-0.99040292502414518,0 +0.875,0.1248831018288558,-0.0034412091825772586,-0.0022747475485175887,0,0.099815318398622899,-0.99860261559100016,0 +0.88500000000000001,0.12500000000700623,2.0693358136986429e-10,1.3690028369419877e-10,0,0.10000000001121101,-1.0000000000838631,0 +0.89500000000000002,0.12500000000690034,2.0295860176552916e-10,1.3426844820417816e-10,0,0.10000000001104148,-1.0000000000825946,0 +0.90500000000000003,0.12500000000616657,1.8175890421477852e-10,1.2024374828573813e-10,0,0.10000000000986675,-1.0000000000738092,0 +0.91500000000000004,0.12500000000447511,1.3188042879502353e-10,8.7246950401911659e-11,0,0.10000000000716036,-1.0000000000535656,0 +0.92500000000000004,0.1250000000023313,6.8702813807084164e-11,4.5451087337373151e-11,0,0.10000000000372944,-1.0000000000279046,0 +0.93500000000000005,0.12500000000053466,1.575462353161844e-11,1.0423025405688057e-11,0,0.1000000000008554,-1.0000000000063987,0 +0.94500000000000006,0.125,0,0,0,0.099999999999999867,-1,0 +0.95500000000000007,0.125,0,0,0,0.099999999999999867,-1,0 +0.96499999999999997,0.125,0,0,0,0.099999999999999867,-1,0 +0.97499999999999998,0.125,0,0,0,0.099999999999999867,-1,0 +0.98499999999999999,0.125,0,0,0,0.099999999999999867,-1,0 +0.995,0.125,0,0,0,0.099999999999999867,-1,0 diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/test_public.py b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/test_public.py index 79cd798..19e2008 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/test_public.py +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/test_public.py @@ -57,10 +57,10 @@ def test_public_brio_wu_cli_matches_reference_grid() -> None: assert rows[0] == ["x", "rho", "u", "v", "w", "p", "by", "bz"] assert rows[0] == golden_rows[0] - assert len(rows) - 1 == 400 + assert len(rows) - 1 == 100 assert len(rows) == len(golden_rows) - dx = (1.0 - 0.0) / 400.0 + dx = (1.0 - 0.0) / 100.0 for index, (row, golden_row) in enumerate(zip(rows[1:], golden_rows[1:])): assert len(row) == 8 assert len(golden_row) == 8 diff --git a/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_fixture.json b/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_fixture.json index b76068a..2c318f6 100644 --- a/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_fixture.json +++ b/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_fixture.json @@ -23,7 +23,7 @@ "exclude_edge_adjacents_per_side": 2 }, "name": "brio_wu", - "nx": 400, + "nx": 100, "reference_csv": "brio_wu_reference.csv", "schema": [ "x", diff --git a/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_reference.csv b/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_reference.csv index 3b96ca0..e72dfa5 100644 --- a/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_reference.csv +++ b/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_reference.csv @@ -1,401 +1,101 @@ x,rho,u,v,w,p,by,bz -0.00125,1,0,0,0,1,1,0 -0.0037499999999999999,1,0,0,0,1,1,0 -0.0062500000000000003,1,0,0,0,1,1,0 -0.0087500000000000008,1,0,0,0,1,1,0 -0.01125,1,0,0,0,1,1,0 -0.01375,1,0,0,0,1,1,0 -0.016250000000000001,1,0,0,0,1,1,0 -0.018749999999999999,1,0,0,0,1,1,0 -0.021250000000000002,1,0,0,0,1,1,0 -0.02375,1,0,0,0,1,1,0 -0.026249999999999999,1,0,0,0,1,1,0 -0.028750000000000001,1,0,0,0,1,1,0 -0.03125,1,0,0,0,1,1,0 -0.033750000000000002,1,0,0,0,1,1,0 -0.036249999999999998,1,0,0,0,1,1,0 -0.03875,1,0,0,0,1,1,0 -0.041250000000000002,1,0,0,0,1,1,0 -0.043750000000000004,1,0,0,0,1,1,0 -0.046249999999999999,1,0,0,0,1,1,0 -0.048750000000000002,1,0,0,0,1,1,0 -0.051250000000000004,1,0,0,0,1,1,0 -0.053749999999999999,1,0,0,0,1,1,0 -0.056250000000000001,1,0,0,0,1,1,0 -0.058750000000000004,1,0,0,0,1,1,0 -0.061249999999999999,1,0,0,0,1,1,0 -0.063750000000000001,1,0,0,0,1,1,0 -0.066250000000000003,1,0,0,0,1,1,0 -0.068750000000000006,1,0,0,0,1,1,0 -0.071250000000000008,1,0,0,0,1,1,0 -0.073749999999999996,1,0,0,0,1,1,0 -0.076249999999999998,1,0,0,0,1,1,0 -0.078750000000000001,1,0,0,0,1,1,0 -0.081250000000000003,1,0,0,0,1,1,0 -0.083750000000000005,1,0,0,0,1,1,0 -0.086250000000000007,1,0,0,0,1,1,0 -0.088749999999999996,1,0,0,0,1,1,0 -0.091249999999999998,1,0,0,0,1,1,0 -0.09375,1,0,0,0,1,1,0 -0.096250000000000002,1,0,0,0,1,1,0 -0.098750000000000004,1,0,0,0,1,1,0 -0.10125000000000001,1,0,0,0,1,1,0 -0.10375000000000001,1,0,0,0,1,1,0 -0.10625,1,0,0,0,1,1,0 -0.10875,1,0,0,0,1,1,0 -0.11125,1,0,0,0,1,1,0 -0.11375,1,0,0,0,1,1,0 -0.11625000000000001,1,0,0,0,1,1,0 -0.11875000000000001,1,0,0,0,1,1,0 -0.12125,1,0,0,0,1,1,0 -0.12375,1,0,0,0,1,1,0 -0.12625,1,0,0,0,1,1,0 -0.12875,1,0,0,0,1,1,0 -0.13125000000000001,1,0,0,0,1,1,0 -0.13375000000000001,1,0,0,0,1,1,0 -0.13625000000000001,1,0,0,0,1,1,0 -0.13875000000000001,1,0,0,0,1,1,0 -0.14125000000000001,1,0,0,0,1,1,0 -0.14375000000000002,1,0,0,0,1,1,0 -0.14624999999999999,1,0,0,0,1,1,0 -0.14874999999999999,1,0,0,0,1,1,0 -0.15125,1,0,0,0,1,1,0 -0.15375,1,0,0,0,1,1,0 -0.15625,1,0,0,0,1,1,0 -0.15875,1,0,0,0,1,1,0 -0.16125,1,0,0,0,1,1,0 -0.16375000000000001,1,0,0,0,1,1,0 -0.16625000000000001,1,0,0,0,1,1,0 -0.16875000000000001,1,0,0,0,1,1,0 -0.17125000000000001,1,0,0,0,1,1,0 -0.17375000000000002,1,0,0,0,1,1,0 -0.17624999999999999,1,0,0,0,1,1,0 -0.17874999999999999,1,0,0,0,1,1,0 -0.18124999999999999,1,0,0,0,1,1,0 -0.18375,1,0,0,0,1,1,0 -0.18625,1,0,0,0,1,1,0 -0.18875,1,0,0,0,1,1,0 -0.19125,1,0,0,0,1,1,0 -0.19375000000000001,1,0,0,0,1,1,0 -0.19625000000000001,1,0,0,0,1,1,0 -0.19875000000000001,1,0,0,0,1,1,0 -0.20125000000000001,1,0,0,0,1,1,0 -0.20375000000000001,1,0,0,0,1,1,0 -0.20625000000000002,1,0,0,0,1,1,0 -0.20874999999999999,1,0,0,0,1,1,0 -0.21124999999999999,1,0,0,0,1,1,0 -0.21375,1,0,0,0,1,1,0 -0.21625,1,0,0,0,1,1,0 -0.21875,1,0,0,0,1,1,0 -0.22125,1,0,0,0,1,1,0 -0.22375,1,0,0,0,1,1,0 -0.22625000000000001,1,0,0,0,1,1,0 -0.22875000000000001,1,0,0,0,1,1,0 -0.23125000000000001,1,0,0,0,1,1,0 -0.23375000000000001,1,0,0,0,1,1,0 -0.23625000000000002,1,0,0,0,1,1,0 -0.23875000000000002,1,0,0,0,1,1,0 -0.24124999999999999,1,0,0,0,1,1,0 -0.24374999999999999,1,0,0,0,1,1,0 -0.24625,1,0,0,0,1,1,0 -0.24875,1,0,0,0,1,1,0 -0.25125000000000003,1,0,0,0,1,1,0 -0.25375000000000003,1,0,0,0,1,1,0 -0.25624999999999998,1,0,0,0,1,1,0 -0.25874999999999998,1,0,0,0,1,1,0 -0.26124999999999998,1,0,0,0,1,1,0 -0.26374999999999998,1,0,0,0,1,1,0 -0.26624999999999999,1,0,0,0,1,1,0 -0.26874999999999999,1,0,0,0,1,1,0 -0.27124999999999999,1,0,0,0,1,1,0 -0.27374999999999999,1,0,0,0,1,1,0 -0.27625,1,0,0,0,1,1,0 -0.27875,1,0,0,0,1,1,0 -0.28125,1,0,0,0,1,1,0 -0.28375,1,0,0,0,1,1,0 -0.28625,1,0,0,0,1,1,0 -0.28875000000000001,1,0,0,0,1,1,0 -0.29125000000000001,1,0,0,0,1,1,0 -0.29375000000000001,1,0,0,0,1,1,0 -0.29625000000000001,1,0,0,0,1,1,0 -0.29875000000000002,1,0,0,0,1,1,0 -0.30125000000000002,1,0,0,0,1,1,0 -0.30375000000000002,1,0,0,0,1,1,0 -0.30625000000000002,1,0,0,0,1,1,0 -0.30875000000000002,1,0,0,0,1,1,0 -0.31125000000000003,1,0,0,0,1,1,0 -0.31375000000000003,1,0,0,0,1,1,0 -0.31625000000000003,1,0,0,0,1,1,0 -0.31875000000000003,0.99780058962396134,0.0039418906960591756,-0.0011154453241734904,0,0.99561225261243114,0.99733567707147397,0 -0.32124999999999998,0.99173977278087055,0.014827394992909993,-0.0042179802180685351,0,0.98356266355471567,0.98997992685476155,0 -0.32374999999999998,0.98408158190126227,0.028640080174583915,-0.008186565338896416,0,0.96843552308248149,0.98067103174066461,0 -0.32624999999999998,0.97581885102428656,0.043602341839540863,-0.012527557906330034,0,0.95224184930138511,0.9706093820226751,0 -0.32874999999999999,0.9673086534619818,0.059076763367010128,-0.017064614864518685,0,0.93570643492573047,0.96022723966347923,0 -0.33124999999999999,0.95869600144853218,0.074807206835931742,-0.021727022813603607,0,0.91911880282946645,0.94969857357607346,0 -0.33374999999999999,0.95004304399744044,0.090682637384932041,-0.026484836248230038,0,0.90260259674571253,0.93909829176568671,0 -0.33624999999999999,0.9413754410079106,0.10665810127729088,-0.031327232997254678,0,0.88620791115317998,0.92845621902021158,0 -0.33875,0.93270899587811373,0.12270504519506864,-0.03624752773178725,0,0.86996537982749733,0.91779125844150933,0 -0.34125,0.92405269875686513,0.13880647959038991,-0.041242256453888439,0,0.85389282701112912,0.90711462369760387,0 -0.34375,0.9154136825409287,0.15495119344114,-0.046309690150731095,0,0.83800169918738354,0.89643357043624938,0 -0.34625,0.90679699082194087,0.1711306591640914,-0.051448892458540188,0,0.82230012152488841,0.88575334869586952,0 -0.34875,0.89820651629824644,0.18733853105308285,-0.056659474531035876,0,0.80679335763251014,0.87507771377132626,0 -0.35125000000000001,0.88964446790953033,0.20356990667607194,-0.061941601414340595,0,0.79148497989669941,0.86440935577409717,0 -0.35375000000000001,0.88111284307810034,0.21982084917897435,-0.067295796388280038,0,0.77637743892286348,0.85375027049037311,0 -0.35625000000000001,0.87261362352600136,0.23608821896065768,-0.072722798578283135,0,0.76147221221794026,0.84310187986499097,0 -0.35875000000000001,0.86414845253144101,0.25236949156988764,-0.078223462833881888,0,0.74677004107769829,0.83246518929651392,0 -0.36125000000000002,0.85571868777839477,0.26866265040738607,-0.083798844143742335,0,0.73227118643443889,0.82184083376251138,0 -0.36375000000000002,0.84732496311510741,0.28496610344607487,-0.089450235711247772,0,0.71797553105924117,0.81122913890977844,0 -0.36625000000000002,0.83896778349293599,0.30127856646716628,-0.095179100441626849,0,0.70388256773647151,0.80063021301524762,0 -0.36875000000000002,0.8306478120801315,0.31759896051856901,-0.10098705469020462,0,0.68999145285900165,0.79004396131671717,0 -0.37125000000000002,0.82236584881264441,0.33392634501819063,-0.10687586239677592,0,0.67630114289001086,0.77947010645164028,0 -0.37375000000000003,0.81412256288554841,0.35025987066405678,-0.11284737308244323,0,0.66281051894930754,0.76890827004788531,0 -0.37625000000000003,0.80591829672758197,0.36659869209219098,-0.11890344385945414,0,0.64951847025460407,0.75835806846801013,0 -0.37875000000000003,0.7977533251558977,0.38294181436792768,-0.1250459153773277,0,0.63642397465987577,0.74781916579237695,0 -0.38125000000000003,0.78962821661912974,0.39928793115627925,-0.13127661071624822,0,0.62352617265709931,0.73729131884178889,0 -0.38375000000000004,0.78154397302664014,0.4156353252154189,-0.137597311365595,0,0.61082441920290476,0.72677444954932158,0 -0.38624999999999998,0.77350187664333747,0.4319818381617635,-0.14400971569167417,0,0.59831831823337123,0.71626872248566942,0 -0.38874999999999998,0.76550325157545829,0.44832485729258581,-0.15051541230315177,0,0.58600775859846921,0.70577458163502815,0 -0.39124999999999999,0.75754943880637893,0.46466125358111438,-0.15711584492844621,0,0.57389295780390692,0.69529276621051095,0 -0.39374999999999999,0.749642062019785,0.48098718289031467,-0.16381220586479228,0,0.56197455525241757,0.68482439731157485,0 -0.39624999999999999,0.74178347298350644,0.49729755518791763,-0.17060518383658033,0,0.55025391036855997,0.67437128401935453,0 -0.39874999999999999,0.73397737021860543,0.51358474386151054,-0.17749439433254424,0,0.53873391674659166,0.66393672613728749,0 -0.40125,0.72622997539659639,0.52983568010877113,-0.18447707310794387,0,0.52742087697476669,0.65352736887877549,0 -0.40375,0.71855268032257813,0.54602571955173596,-0.19154520667480535,0,0.51632840511574407,0.64315715022632924,0 -0.40625,0.71096761592194024,0.5621064499054218,-0.19867965431348364,0,0.50548500567258359,0.6328551452014316,0 -0.40875,0.70351809004436872,0.57798308169709955,-0.20583896158449672,0,0.49494776946723229,0.62268010464122547,0 -0.41125,0.69628594147097289,0.59347633160710345,-0.21293993103100095,0,0.48482478256859951,0.61274502061463976,0 -0.41375000000000001,0.68941655050596484,0.60826664970343558,-0.2198280489776889,0,0.47530692274767161,0.60325335873851049,0 -0.41625000000000001,0.68314702755279999,0.62182858255524953,-0.22624129413552949,0,0.46670271369465616,0.59454169635904308,0 -0.41875000000000001,0.67782572058125357,0.63339457769432261,-0.23178305630796459,0,0.45946103196399823,0.58710648915432451,0 -0.42125000000000001,0.67385858441141333,0.64199490957099814,-0.23596698492475343,0,0.45409808373542004,0.58156684274258463,0 -0.42375000000000002,0.67176641453700525,0.6469162308341575,-0.238218557413787,0,0.45128138130309292,0.57843540789261583,0 -0.42625000000000002,0.67078052736841931,0.64804295449248306,-0.23931535115787175,0,0.44995578425706018,0.5776695501854906,0 -0.42875000000000002,0.67093258028176295,0.64820950444476044,-0.23909517669577307,0,0.45016128034403946,0.57748103832724251,0 -0.43125000000000002,0.67221331698599318,0.64592193639342732,-0.2376161466610561,0,0.45188502884855786,0.57898748077442441,0 -0.43375000000000002,0.67477583336680169,0.64045344684033523,-0.2349806577986025,0,0.45533846144962792,0.58257702054306215,0 -0.43625000000000003,0.67693879989409655,0.63537735860005662,-0.23276478266323203,0,0.45826311431502864,0.58589598309566848,0 -0.43875000000000003,0.67818046569816726,0.63258441699362578,-0.2316835745358842,0,0.4599465488616844,0.58788185575907725,0 -0.44125000000000003,0.67847095916753464,0.63140939827029008,-0.23102942178508992,0,0.46034108071841129,0.58814312979425298,0 -0.44375000000000003,0.67871878159900201,0.63146024939639389,-0.23068318935251569,0,0.46067790212396337,0.58810935677202825,0 -0.44625000000000004,0.67853915803526677,0.63196041084427279,-0.23090732826723964,0,0.46043473249792088,0.58787073205089513,0 -0.44874999999999998,0.67803863707314427,0.6330593415786836,-0.23162869925234153,0,0.45975750456026709,0.58736622158591256,0 -0.45124999999999998,0.6774195873474379,0.6343255739755016,-0.23239706197011983,0,0.45891948202187494,0.58672848893472662,0 -0.45374999999999999,0.67688810168571512,0.63542738781445673,-0.23285843166501846,0,0.45820017218025605,0.58601807885490564,0 -0.45624999999999999,0.67650547951151974,0.63625820689185419,-0.23305952359533008,0,0.45768328142375492,0.58533372699356645,0 -0.45874999999999999,0.67624477252807902,0.63679255704404425,-0.23324253509623569,0,0.45733207413345345,0.58480268867196805,0 -0.46124999999999999,0.67604050594546095,0.63714228317088684,-0.23351779035696307,0,0.45705721760805229,0.58451139535639995,0 -0.46375,0.67595854916299569,0.63738534647931233,-0.23385855445925771,0,0.45694869192262283,0.58435845445911683,0 -0.46625,0.68086254532175094,0.63419323611509804,-0.2627490595791831,0,0.46500839952917328,0.56267418748132525,0 -0.46875,0.75828705387253315,0.56658450267562666,-0.6403332654473326,0,0.60777176667783583,0.26462111543054406,0 -0.47125,0.81542143854087634,0.46255247850130804,-1.1427907505563049,0,0.70707779939421744,-0.17802741409121203,0 -0.47375,0.78443205530850979,0.50559776659531341,-1.332519156086944,0,0.65515890375877317,-0.354497000575831,0 -0.47625000000000001,0.76277455722849596,0.55111223050629143,-1.406110791322537,0,0.61702037783610542,-0.4194427333795091,0 -0.47875000000000001,0.74404469538178764,0.55656484646456639,-1.4611410690372477,0,0.58668848068932689,-0.45267168642034472,0 -0.48125000000000001,0.7245298456798609,0.56167647024027656,-1.5074627288434979,0,0.5571761881846935,-0.47268348346610961,0 -0.48375000000000001,0.71012228623973583,0.57027999536562946,-1.543873073536012,0,0.53528590863347425,-0.49264654415374082,0 -0.48625000000000002,0.70076710390286745,0.58241431931480048,-1.5678960177704355,0,0.52117059910324071,-0.5132537526592037,0 -0.48875000000000002,0.6958138120994154,0.59253804821509259,-1.5801243124025581,0,0.51407181012863212,-0.53018918731486608,0 -0.49125000000000002,0.69634185265480064,0.60450975725843215,-1.5824609035105774,0,0.51510350342232991,-0.54159264057279222,0 -0.49375000000000002,0.69850922424214601,0.60950400813475858,-1.585266082294966,0,0.51853234952912874,-0.54291597426192384,0 -0.49625000000000002,0.69955231023329034,0.60819583311918735,-1.5848885559239814,0,0.52027069329509679,-0.54068543052621187,0 -0.49875000000000003,0.69829488634001602,0.60250392950529474,-1.5842381917356738,0,0.51860605011188388,-0.53585805694441235,0 -0.50124999999999997,0.69473126010799702,0.59400974956106756,-1.5847165912172572,0,0.51356317210852487,-0.53134363710848087,0 -0.50375000000000003,0.69253382725834534,0.59010833084815906,-1.5851121479337069,0,0.51057824154374631,-0.53011921878496304,0 -0.50624999999999998,0.69237449532735207,0.59146895693409685,-1.5858564348296551,0,0.51054249757041459,-0.53082328680938162,0 -0.50875000000000004,0.69391541373744337,0.59634222339010579,-1.5857210122073861,0,0.51315096871714994,-0.53304618751484978,0 -0.51124999999999998,0.69634148593928047,0.60301378588754684,-1.5840840117480401,0,0.5171828111968485,-0.53600443230198036,0 -0.51375000000000004,0.69696988284642125,0.60598814490820407,-1.5822803421052867,0,0.51876741128969461,-0.53768126044759668,0 -0.51624999999999999,0.69590524459691183,0.605542191027717,-1.5815913052223451,0,0.51808417485694558,-0.53738593862540907,0 -0.51875000000000004,0.69339823569240289,0.60237234278329166,-1.5824338658055286,0,0.51564230319494531,-0.53568598390826916,0 -0.52124999999999999,0.69028268100633383,0.59775928333034656,-1.5849765752973617,0,0.51233921959100215,-0.53282107449038196,0 -0.52375000000000005,0.6885408627829227,0.59563473330607197,-1.586881633696186,0,0.51091135095358142,-0.53126090526540737,0 -0.52625,0.68845991210476676,0.59576153638350393,-1.5870959718421693,0,0.51139517765564346,-0.53172734059034754,0 -0.52875000000000005,0.68913132894514517,0.59780515337360185,-1.5859257457768372,0,0.51333149786491905,-0.53324119440484385,0 -0.53125,0.69035686600602486,0.60114183287377887,-1.583761079933232,0,0.51632762277454369,-0.53561028146436995,0 -0.53375000000000006,0.69063785151444135,0.60308915950915953,-1.5825950002547069,0,0.51816477333483568,-0.5367661728665245,0 -0.53625,0.68995642603783169,0.60271623463782054,-1.5827072676591285,0,0.51817213887569635,-0.5365529040050816,0 -0.53875000000000006,0.68912674904173354,0.60080970261747135,-1.5836585612290803,0,0.5170008482178291,-0.53535672389780986,0 -0.54125000000000001,0.68900935996710411,0.59744632555053778,-1.5849988566238742,0,0.51492442266233129,-0.53339274974699291,0 -0.54375000000000007,0.68992607319859989,0.59550495144079929,-1.5855642783840616,0,0.51380892115497334,-0.53231014634052964,0 -0.54625000000000001,0.69030209756719352,0.59574669701945138,-1.5855252584440067,0,0.51389062331612756,-0.53244809173629659,0 -0.54874999999999996,0.68902173862300931,0.59740836235396289,-1.5852477103136609,0,0.5146658368665229,-0.53339030207149196,0 -0.55125000000000002,0.68189342316100054,0.60020433676255158,-1.5844249654880713,0,0.51628053637696625,-0.53477165363768919,0 -0.55374999999999996,0.65276597713910334,0.60185672139983104,-1.5836528865010249,0,0.51743177517895211,-0.53527542396206562,0 -0.55625000000000002,0.58906478526618755,0.60185519401175147,-1.583053851614638,0,0.51755849582377766,-0.53486837400458076,0 -0.55874999999999997,0.49422558600892486,0.60118766199411133,-1.5832559126839811,0,0.5172228327206092,-0.53418658367731886,0 -0.56125000000000003,0.38247103041338487,0.59990157132174105,-1.5840925292397106,0,0.51620910738423487,-0.53342595162876671,0 -0.56374999999999997,0.28025492247104017,0.59846176638276449,-1.5851622199216584,0,0.5152364728981691,-0.53275468018860095,0 -0.56625000000000003,0.22868966508824234,0.59710231685960313,-1.5860977814707127,0,0.51481122129747781,-0.53239158687234311,0 -0.56874999999999998,0.2267856507919232,0.59640620540582956,-1.5864596507885937,0,0.51481550996877012,-0.53225943769555295,0 -0.57125000000000004,0.22713175101669475,0.59631043781086113,-1.5862941490337203,0,0.51512192557837366,-0.53221446943385053,0 -0.57374999999999998,0.22832982826697543,0.59690929717637031,-1.5856945341940099,0,0.51544195200245158,-0.53214053153219976,0 -0.57625000000000004,0.23006132532598028,0.5979765390095868,-1.5850598466399157,0,0.51604401482077034,-0.53235234485917893,0 -0.57874999999999999,0.23181956629299122,0.59934757674111083,-1.5845139129375743,0,0.51687736532492834,-0.53308886162542746,0 -0.58125000000000004,0.23316522477988719,0.60072662152561196,-1.5842849795297345,0,0.51772674090669124,-0.53394457396042982,0 -0.58374999999999999,0.23391908756041113,0.60223034496795813,-1.5839684765344821,0,0.51806461631752188,-0.53457035523447027,0 -0.58625000000000005,0.23431034941216394,0.60345350170797118,-1.5841973780115437,0,0.51789119722034871,-0.53460934483436429,0 -0.58875,0.23460990828752651,0.60387631345954085,-1.5843501276762757,0,0.51757915110632757,-0.53432910759567398,0 -0.59125000000000005,0.23506825902401635,0.60282288127804684,-1.585165115162972,0,0.51773081006565902,-0.53416645772176508,0 -0.59375,0.23554392868159077,0.60057139334604759,-1.5863553588391026,0,0.51774108981529299,-0.53376740267714529,0 -0.59625000000000006,0.23574376308649053,0.59888206501796171,-1.587249000037269,0,0.51718780070000137,-0.53273061481737882,0 -0.59875,0.2357083556292047,0.59836333208440606,-1.5873845267462028,0,0.51612520155316433,-0.53158021311167569,0 -0.60125000000000006,0.23567285891449777,0.59766263969440114,-1.5877771701611647,0,0.5153079104412206,-0.53069139651429365,0 -0.60375000000000001,0.23580149297303599,0.59664353703500261,-1.5883416830586965,0,0.51563852961964063,-0.53095430707000513,0 -0.60625000000000007,0.2361263695423006,0.59461828975577724,-1.5895049849613039,0,0.51671691867389946,-0.53190837659017298,0 -0.60875000000000001,0.23631854959443394,0.59598090215208221,-1.5892842142291126,0,0.51722476899470071,-0.53244556280972177,0 -0.61124999999999996,0.23614815457146857,0.60018906680370221,-1.5879979771038979,0,0.51632413595151727,-0.53176277681989537,0 -0.61375000000000002,0.23613289789183126,0.60417970975516422,-1.5866151046667705,0,0.51643954420713611,-0.53176024605848848,0 -0.61624999999999996,0.23636461460022473,0.60239051184144632,-1.5874214851519997,0,0.51800335570916167,-0.53290555450294708,0 -0.61875000000000002,0.23685612557714375,0.59917605052507494,-1.5887974386781778,0,0.5210289610697918,-0.53516232288950649,0 -0.62124999999999997,0.236629474827142,0.59900329149184894,-1.5883523685763601,0,0.52084906032944422,-0.53504397890458888,0 -0.62375000000000003,0.23553444051781158,0.6094416366857287,-1.5832404611606701,0,0.51646465152499421,-0.53125243577613324,0 -0.62624999999999997,0.23480711426766496,0.61276659011654855,-1.5820244559454961,0,0.51359689942899112,-0.52940636364944882,0 -0.62875000000000003,0.2356805197653731,0.59981103240692546,-1.5873723560682378,0,0.51775543844125527,-0.53341880855164581,0 -0.63124999999999998,0.23665817647544471,0.58339388331467124,-1.5915886744702512,0,0.52230143300038878,-0.53706058378831778,0 -0.63375000000000004,0.23624007285922682,0.58851017476723522,-1.59323247289284,0,0.52067660348375233,-0.5344840295515112,0 -0.63624999999999998,0.23248269439745392,0.62017067097041967,-1.5860539280724555,0,0.50441116285539445,-0.52566087023161623,0 -0.63875000000000004,0.23287406771008778,0.63021607264750734,-1.5714111287249182,0,0.50610033932647758,-0.51881227330971402,0 -0.64124999999999999,0.23535665099942626,0.54552436166512541,-1.5610957972782948,0,0.51620744848479627,-0.56037653795121478,0 -0.64375000000000004,0.20465921194562456,0.43550920292588785,-1.2461151516740705,0,0.38959320083362653,-0.65081895672509904,0 -0.64624999999999999,0.14009395039150022,-0.013620789581837623,-0.52852147362552981,0,0.14893940676494133,-0.84115443834590753,0 -0.64875000000000005,0.11751273289208522,-0.22437213354109883,-0.16226723635220483,0,0.088423364818236205,-0.90651157396572613,0 -0.65125,0.1172304349686725,-0.23055950413906093,-0.15834995998342491,0,0.087980641698620188,-0.90679519491120031,0 -0.65375000000000005,0.11725471096145602,-0.23125048663034239,-0.15988967480131078,0,0.088016824468717392,-0.90623225381858352,0 -0.65625,0.11717819471904142,-0.23427702280565715,-0.16309682007195445,0,0.087901314598951896,-0.90467584906756415,0 -0.65875000000000006,0.11701473008444113,-0.23931297733336335,-0.16679190788787737,0,0.087655777579992433,-0.90262825016899195,0 -0.66125,0.11682044790275041,-0.24514922075151147,-0.17096232324746935,0,0.087364026139568063,-0.90028034756782194,0 -0.66375000000000006,0.11664990465573849,-0.25033190821458962,-0.17474981564425235,0,0.087108330784376853,-0.89817521994953109,0 -0.66625000000000001,0.11659183681487016,-0.25210877535067339,-0.17606373800900416,0,0.087021072376205377,-0.89744964551230921,0 -0.66875000000000007,0.11659565313804586,-0.25199397498810977,-0.17597732617696363,0,0.087026305831300999,-0.89749741619551415,0 -0.67125000000000001,0.11663090160109492,-0.25091377282773697,-0.17517704012828506,0,0.087078794787367686,-0.89793883874353608,0 -0.67374999999999996,0.11672569071628684,-0.24801894198896796,-0.17304243161135532,0,0.087219942612219992,-0.89911964160362412,0 -0.67625000000000002,0.11687866962961335,-0.24335351965734039,-0.16961064512063617,0,0.087448451090979984,-0.90102219304187958,0 -0.67874999999999996,0.11706716457467407,-0.23761206836584889,-0.16539777355745228,0,0.087729984963327179,-0.903363295110168,0 -0.68125000000000002,0.11725531088500578,-0.23188499457250628,-0.16120570301525269,0,0.088011625486577039,-0.90569773785665264,0 -0.68374999999999997,0.1173869096123874,-0.22787830963670686,-0.15827892017451603,0,0.088208749864432612,-0.90733063517330292,0 -0.68625000000000003,0.11740612473963735,-0.22729629509711108,-0.15785255924099278,0,0.08823710550802899,-0.90756836804359509,0 -0.68874999999999997,0.1174043024511611,-0.22735052337058989,-0.15789017932834926,0,0.08823427512892934,-0.90754730073044609,0 -0.69125000000000003,0.117385586946818,-0.22792019819914602,-0.15830312721357306,0,0.088205717689737617,-0.90731579951421071,0 -0.69374999999999998,0.11733333794868246,-0.22950618589385671,-0.15945854815582666,0,0.088127191628521229,-0.90667017955692664,0 -0.69625000000000004,0.11723047219013001,-0.23263692843712594,-0.1617427414330794,0,0.087972319470910665,-0.90539536389292952,0 -0.69874999999999998,0.11707119965622731,-0.23748283866703485,-0.16528542583275169,0,0.087733351641583468,-0.90342149850150899,0 -0.70125000000000004,0.11687031669818926,-0.24360287346583834,-0.16977049665712179,0,0.087431835729061547,-0.90092842407432894,0 -0.70374999999999999,0.11665961352933606,-0.25002473062346064,-0.17448953235454481,0,0.087116281751007274,-0.89831176039494187,0 -0.70625000000000004,0.1165165302499433,-0.25439233792360777,-0.17770571675062352,0,0.086901806565141237,-0.89653255429149881,0 -0.70874999999999999,0.11650342706556212,-0.2547927709381313,-0.17799943043788108,0,0.086882001709442935,-0.89636978909070852,0 -0.71125000000000005,0.11651313327825538,-0.25449583971560935,-0.17777892983377314,0,0.086896257833543045,-0.8964912611982403,0 -0.71375,0.11657824875283614,-0.25250868159070106,-0.17631251476880538,0,0.086993320783096961,-0.8973018533821181,0 -0.71625000000000005,0.11670669297667058,-0.24859138314712292,-0.17342577474077817,0,0.087184751921271064,-0.89889931280557489,0 -0.71875,0.11691006489352132,-0.24238906844035901,-0.16886594442826247,0,0.087488817862619084,-0.90142781444796216,0 -0.72125000000000006,0.11715696037775949,-0.23486831445080303,-0.16335344395667553,0,0.087858057823719804,-0.90449340621863428,0 -0.72375,0.1174166577876183,-0.22696879682954138,-0.15758238759684895,0,0.08824723417305036,-0.9077124481337816,0 -0.72625000000000006,0.11761203623571825,-0.22103003047499958,-0.15325677844062333,0,0.088540228534066956,-0.9101327480055359,0 -0.72875000000000001,0.11764815223606326,-0.21993423708599183,-0.15245924851833104,0,0.08859412431248137,-0.91057953155824023,0 -0.73125000000000007,0.11764295241336808,-0.2200903293627689,-0.15257160911773979,0,0.088586337286039485,-0.91051617734452983,0 -0.73375000000000001,0.11759000660142679,-0.2217003081127347,-0.15374084437403135,0,0.088506338493284042,-0.90986082609014918,0 -0.73624999999999996,0.11746031345619404,-0.22563937809188131,-0.15660719388934993,0,0.088311340736592969,-0.90825665198961858,0 -0.73875000000000002,0.11723828372065292,-0.23239420472240171,-0.16153287456890622,0,0.087977168091466496,-0.9055058428394922,0 -0.74124999999999996,0.11695405872405729,-0.24104632732416764,-0.16786313884395296,0,0.087550606026847611,-0.90198118960069906,0 -0.74375000000000002,0.11667856642422411,-0.24944335338982396,-0.17402937906226756,0,0.087137125367697799,-0.89856002823076275,0 -0.74624999999999997,0.11652142847638322,-0.25424394334264461,-0.17756382750169244,0,0.086901454460314165,-0.89660456501140007,0 -0.74875000000000003,0.11651981293218819,-0.25428866572145908,-0.17759682581079278,0,0.086899302405564094,-0.89658628316293454,0 -0.75124999999999997,0.11654384178002924,-0.2535594566735877,-0.17705849552342462,0,0.086934742960429467,-0.89688401034771859,0 -0.75375000000000003,0.11663051640593858,-0.25091355302284074,-0.17510796984102217,0,0.08706432661997765,-0.89796267762001025,0 -0.75624999999999998,0.11678404277607407,-0.24623080770483949,-0.17166114194328411,0,0.087293311528364281,-0.89987155145629427,0 -0.75875000000000004,0.11700344302198436,-0.23954347013011862,-0.16675062625144083,0,0.087621451884493884,-0.90259743709333429,0 -0.76124999999999998,0.1172431937971754,-0.23224924863937169,-0.16141064996890825,0,0.087980008633671614,-0.90557089006933678,0 -0.76375000000000004,0.11745835723684928,-0.2257014011703927,-0.15663158785569858,0,0.088302688141607355,-0.90823890147105391,0 -0.76624999999999999,0.11754312622419839,-0.22312484757638981,-0.15475473896938308,0,0.088429763359914815,-0.90928903939657357,0 -0.76875000000000004,0.11754177990704494,-0.2231668919210899,-0.15478502917437109,0,0.08842756580276423,-0.90927164832488772,0 -0.77124999999999999,0.11752467556395679,-0.22368568226609817,-0.15516209375600826,0,0.088401836341015949,-0.90906068120615424,0 -0.77375000000000005,0.11746717207168339,-0.22543397607620042,-0.15643453805452581,0,0.088315305884747231,-0.90834911199205925,0 -0.77625,0.11736654278177328,-0.2284945234234321,-0.15866471296533163,0,0.088163952024696957,-0.90710265586110195,0 -0.77875000000000005,0.11722713361337955,-0.23273201682477188,-0.16175718703284839,0,0.087954401569682927,-0.90537555931713076,0 -0.78125,0.11707778782447791,-0.23727864076599559,-0.16508186697178692,0,0.087730265510702843,-0.90352339441354335,0 -0.78375000000000006,0.11694701926702723,-0.24126444712942194,-0.16800203883568809,0,0.087533988164180898,-0.90189987769505553,0 -0.78625,0.11687743963943051,-0.24338529654596849,-0.16955784803318272,0,0.087429820942728886,-0.90103669813034792,0 -0.78875000000000006,0.11687579781052707,-0.24343592181704782,-0.16959486107747798,0,0.08742728644424369,-0.90101601254263675,0 -0.79125000000000001,0.11687539900643468,-0.24344948224066379,-0.16960462180695862,0,0.087426474749633054,-0.90100969094006977,0 -0.79375000000000007,0.11687409481764938,-0.24348129085661555,-0.16962777224760861,0,0.087424696127569423,-0.90099540369582221,0 -0.79625000000000001,0.11687218858217306,-0.24354390911756213,-0.16967348339899166,0,0.087421752667664165,-0.90097160223299655,0 -0.79875000000000007,0.116870215752296,-0.24361058874898325,-0.1697220504681374,0,0.0874184896460376,-0.90094505886224741,0 -0.80125000000000002,0.11686946136924814,-0.2436294977483163,-0.16973560439458318,0,0.087417613977942565,-0.90093824717607751,0 -0.80374999999999996,0.11686962190859448,-0.24361757731467398,-0.16972658857626485,0,0.087417870797879327,-0.90094090262231019,0 -0.80625000000000002,0.11687356980470871,-0.24350583643941545,-0.16964422423269365,0,0.087423444046079268,-0.90098768473549895,0 -0.80874999999999997,0.11688754092326054,-0.24307479305630586,-0.16932756115966405,0,0.087444533924976753,-0.90116318958274499,0 -0.81125000000000003,0.11691972536277602,-0.24209343744922968,-0.16860707128114324,0,0.087492701479890633,-0.90156325665747283,0 -0.81374999999999997,0.11697942266283615,-0.24027908101633488,-0.16727614115169526,0,0.087581830141478023,-0.90230271944561291,0 -0.81625000000000003,0.11707126156401244,-0.23747712607290974,-0.16522305705840304,0,0.08771962969895275,-0.9034445863476972,0 -0.81874999999999998,0.11720175792642251,-0.23350615420116155,-0.16231792357714034,0,0.087915217578154237,-0.9050626671429971,0 -0.82125000000000004,0.1173736571942727,-0.22828036241638489,-0.1585025661792111,0,0.088173092622349736,-0.90719178038941839,0 -0.82374999999999998,0.11758753647266376,-0.22177196496693163,-0.15376313261251445,0,0.088495041188408119,-0.90984301103522469,0 -0.82625000000000004,0.11784277533584739,-0.21402503109325074,-0.14813976728812336,0,0.088879385731000071,-0.91299811129464448,0 -0.82874999999999999,0.11813596987373072,-0.205135924121809,-0.14171096949690176,0,0.08932189551312586,-0.91661764598071116,0 -0.83125000000000004,0.11846242009804758,-0.19523667455595015,-0.13458125038057758,0,0.089816668680236189,-0.9206475711390385,0 -0.83374999999999999,0.11881836690580111,-0.18447630678794286,-0.12686686204096317,0,0.090356823064338121,-0.92502691979325369,0 -0.83625000000000005,0.1191983441793935,-0.17300551327586872,-0.11868324695390486,0,0.090935254319816416,-0.92969427790399251,0 -0.83875,0.11959717551690868,-0.16096583965923558,-0.11013805167379476,0,0.091545418685837099,-0.93459181209615316,0 -0.84125000000000005,0.12001209755915153,-0.14848356585795672,-0.10132596582677481,0,0.092181264693114717,-0.93966810954166835,0 -0.84375,0.12043877950911509,-0.13566775697809377,-0.092327068649525487,0,0.09283750209918229,-0.94487908876250215,0 -0.84625000000000006,0.12087371396585696,-0.12260927689724001,-0.083209494160765118,0,0.093509933368980058,-0.95018748674767706,0 -0.84875,0.12131567129224743,-0.1093844697747413,-0.074028085304663455,0,0.094194471653768597,-0.95556248832995694,0 -0.85125000000000006,0.12176160189020308,-0.09605840550907592,-0.064827260654986854,0,0.094888110578776108,-0.96097800205309825,0 -0.85375000000000001,0.12220959195301018,-0.082687976622211293,-0.055648874909733553,0,0.095588128076847467,-0.96641042235416763,0 -0.85625000000000007,0.12265849289683448,-0.069328350882536471,-0.046529178998104978,0,0.096291008766648978,-0.97183799626406353,0 -0.85875000000000001,0.12310492382833711,-0.056055787146077833,-0.037517888038019767,0,0.09699339953981001,-0.97722987519548088,0 -0.86125000000000007,0.12354638322994141,-0.042956407473377395,-0.028674501720487335,0,0.09769052441735504,-0.98255051087648382,0 -0.86375000000000002,0.12397571444500097,-0.030246526919572154,-0.020138158560817101,0,0.098369693309683259,-0.9877136051082076,0 -0.86624999999999996,0.12438070565716236,-0.018268628225800106,-0.012133471567233139,0,0.099013662392659962,-0.99257887118158417,0 -0.86875000000000002,0.12473720330383267,-0.0077450726851307217,-0.0051335041220790375,0,0.099581171411821656,-0.9968532001498126,0 -0.87124999999999997,0.1249700817568199,-0.00088137321149738316,-0.00058273816183469274,0,0.099952225492064839,-0.99964210622385019,0 -0.87375000000000003,0.12500000000314493,9.2678072621328777e-11,6.1313650451563421e-11,0,0.10000000000503184,-1.0000000000376423,0 -0.87624999999999997,0.12500000000313061,9.2259592555934167e-11,6.1037663810628979e-11,0,0.10000000000500853,-1.0000000000374729,0 -0.87875000000000003,0.12500000000298683,8.8026904282191698e-11,5.823759252481918e-11,0,0.10000000000477915,-1.0000000000357536,0 -0.88124999999999998,0.12500000000268974,7.9267999569953049e-11,5.2440333555909956e-11,0,0.10000000000430354,-1.0000000000321956,0 -0.88375000000000004,0.12500000000219424,6.4666272335784794e-11,4.2780682699312474e-11,0,0.1000000000035105,-1.0000000000262652,0 -0.88624999999999998,0.1250000000015753,4.6425914963663502e-11,3.071392029557768e-11,0,0.10000000000252052,-1.0000000000188565,0 -0.88875000000000004,0.12500000000090811,2.6762103644077048e-11,1.7704741376541178e-11,0,0.10000000000145282,-1.0000000000108695,0 -0.89124999999999999,0.1250000000003243,9.5565777513424923e-12,6.3224980806181864e-12,0,0.10000000000051879,-1.0000000000038816,0 -0.89375000000000004,0.12500000000000178,5.2520950551592749e-14,3.481659405223961e-14,0,0.10000000000000264,-1.0000000000000213,0 -0.89624999999999999,0.125,0,0,0,0.099999999999999867,-1,0 -0.89875000000000005,0.125,0,0,0,0.099999999999999867,-1,0 -0.90125,0.125,0,0,0,0.099999999999999867,-1,0 -0.90375000000000005,0.125,0,0,0,0.099999999999999867,-1,0 -0.90625,0.125,0,0,0,0.099999999999999867,-1,0 -0.90875000000000006,0.125,0,0,0,0.099999999999999867,-1,0 -0.91125,0.125,0,0,0,0.099999999999999867,-1,0 -0.91375000000000006,0.125,0,0,0,0.099999999999999867,-1,0 -0.91625000000000001,0.125,0,0,0,0.099999999999999867,-1,0 -0.91875000000000007,0.125,0,0,0,0.099999999999999867,-1,0 -0.92125000000000001,0.125,0,0,0,0.099999999999999867,-1,0 -0.92375000000000007,0.125,0,0,0,0.099999999999999867,-1,0 -0.92625000000000002,0.125,0,0,0,0.099999999999999867,-1,0 -0.92874999999999996,0.125,0,0,0,0.099999999999999867,-1,0 -0.93125000000000002,0.125,0,0,0,0.099999999999999867,-1,0 -0.93374999999999997,0.125,0,0,0,0.099999999999999867,-1,0 -0.93625000000000003,0.125,0,0,0,0.099999999999999867,-1,0 -0.93874999999999997,0.125,0,0,0,0.099999999999999867,-1,0 -0.94125000000000003,0.125,0,0,0,0.099999999999999867,-1,0 -0.94374999999999998,0.125,0,0,0,0.099999999999999867,-1,0 -0.94625000000000004,0.125,0,0,0,0.099999999999999867,-1,0 -0.94874999999999998,0.125,0,0,0,0.099999999999999867,-1,0 -0.95125000000000004,0.125,0,0,0,0.099999999999999867,-1,0 -0.95374999999999999,0.125,0,0,0,0.099999999999999867,-1,0 -0.95625000000000004,0.125,0,0,0,0.099999999999999867,-1,0 -0.95874999999999999,0.125,0,0,0,0.099999999999999867,-1,0 -0.96125000000000005,0.125,0,0,0,0.099999999999999867,-1,0 -0.96375,0.125,0,0,0,0.099999999999999867,-1,0 -0.96625000000000005,0.125,0,0,0,0.099999999999999867,-1,0 -0.96875,0.125,0,0,0,0.099999999999999867,-1,0 -0.97125000000000006,0.125,0,0,0,0.099999999999999867,-1,0 -0.97375,0.125,0,0,0,0.099999999999999867,-1,0 -0.97625000000000006,0.125,0,0,0,0.099999999999999867,-1,0 -0.97875000000000001,0.125,0,0,0,0.099999999999999867,-1,0 -0.98125000000000007,0.125,0,0,0,0.099999999999999867,-1,0 -0.98375000000000001,0.125,0,0,0,0.099999999999999867,-1,0 -0.98625000000000007,0.125,0,0,0,0.099999999999999867,-1,0 -0.98875000000000002,0.125,0,0,0,0.099999999999999867,-1,0 -0.99125000000000008,0.125,0,0,0,0.099999999999999867,-1,0 -0.99375000000000002,0.125,0,0,0,0.099999999999999867,-1,0 -0.99624999999999997,0.125,0,0,0,0.099999999999999867,-1,0 -0.99875000000000003,0.125,0,0,0,0.099999999999999867,-1,0 +0.0050000000000000001,1,0,0,0,1,1,0 +0.014999999999999999,1,0,0,0,1,1,0 +0.025000000000000001,1,0,0,0,1,1,0 +0.035000000000000003,1,0,0,0,1,1,0 +0.044999999999999998,1,0,0,0,1,1,0 +0.055,1,0,0,0,1,1,0 +0.065000000000000002,1,0,0,0,1,1,0 +0.074999999999999997,1,0,0,0,1,1,0 +0.085000000000000006,1,0,0,0,1,1,0 +0.095000000000000001,1,0,0,0,1,1,0 +0.105,1,0,0,0,1,1,0 +0.115,1,0,0,0,1,1,0 +0.125,1,0,0,0,1,1,0 +0.13500000000000001,1,0,0,0,1,1,0 +0.14499999999999999,1,0,0,0,1,1,0 +0.155,1,0,0,0,1,1,0 +0.16500000000000001,1,0,0,0,1,1,0 +0.17500000000000002,1,0,0,0,1,1,0 +0.185,1,0,0,0,1,1,0 +0.19500000000000001,1,0,0,0,1,1,0 +0.20500000000000002,1,0,0,0,1,1,0 +0.215,1,0,0,0,1,1,0 +0.22500000000000001,1,0,0,0,1,1,0 +0.23500000000000001,1,0,0,0,1,1,0 +0.245,1,0,0,0,1,1,0 +0.255,1,0,0,0,1,1,0 +0.26500000000000001,1,0,0,0,1,1,0 +0.27500000000000002,1,0,0,0,1,1,0 +0.28500000000000003,1,0,0,0,1,1,0 +0.29499999999999998,1,0,0,0,1,1,0 +0.30499999999999999,1,0,0,0,1,1,0 +0.315,0.99258917532833379,0.013274302361789324,-0.0037458540886650027,0,0.98532404108866567,0.99104740522973966,0 +0.32500000000000001,0.96954607581582897,0.054883618137207428,-0.015827325460063591,0,0.94023568077652442,0.96299689161606516,0 +0.33500000000000002,0.94025803324835733,0.10865479486043322,-0.031944255536031786,0,0.88435499782767446,0.92711462956015256,0 +0.34500000000000003,0.90897792466167582,0.16698841420781432,-0.050131763210425707,0,0.82652179164341721,0.88849866375884556,0 +0.35499999999999998,0.87725610844274526,0.2271603117432259,-0.069719685021130948,0,0.76985377322754589,0.84898878620884088,0 +0.36499999999999999,0.84566618167244145,0.28816698962982518,-0.090519447417695451,0,0.71541656913426399,0.80923410080538904,0 +0.375,0.81450435463148285,0.3494865276909434,-0.11251682956314066,0,0.66367321125402712,0.76950238387022263,0 +0.38500000000000001,0.78404538979850258,0.41062539085171551,-0.13575856770700617,0,0.61497905337973746,0.72997249890053162,0 +0.39500000000000002,0.75467120186953685,0.47083530429296916,-0.1602094195276916,0,0.56978778527926832,0.69094510148101218,0 +0.40500000000000003,0.72701668590610768,0.52870556766657628,-0.18539026277804579,0,0.52883750835390897,0.65319266964541056,0 +0.41500000000000004,0.70216500224646816,0.58153016354527853,-0.20973136326536138,0,0.4933637549672012,0.61876152226558601,0 +0.42499999999999999,0.68193441338380167,0.62487275671749021,-0.22845986767252549,0,0.46540195161446823,0.59219206428336624,0 +0.435,0.6666986977176832,0.65196598708089948,-0.23211489711409145,0,0.44490074049787121,0.58021922926273972,0 +0.44500000000000001,0.66015529724292976,0.66607074009479628,-0.22555655390938342,0,0.43615912199888263,0.58524191570556205,0 +0.45500000000000002,0.65997980757445474,0.66324409170331222,-0.23280516118974198,0,0.43727412310940939,0.5796363680769816,0 +0.46500000000000002,0.73349815599883794,0.60086667962898554,-0.62171855754180494,0,0.57886068825314341,0.27652712488086967,0 +0.47500000000000003,0.79237811897791921,0.46454032083596353,-1.2161018009267417,0,0.6842784144671038,-0.24404258805909654,0 +0.48499999999999999,0.74259318372203176,0.53084767864673321,-1.4743018340823315,0,0.60002741951352012,-0.44224666294204562,0 +0.495,0.69493377959694547,0.61399418172955245,-1.5431753009247675,0,0.54413704626033854,-0.54049642839751277,0 +0.505,0.70278259276020427,0.61662067481286442,-1.5872354257997463,0,0.52068648102692328,-0.56052646550215834,0 +0.51500000000000001,0.70390914156072559,0.6077114699355689,-1.6001701751263477,0,0.51193399003676154,-0.54226823182770345,0 +0.52500000000000002,0.69922181544266515,0.59340751947871018,-1.6046948629200928,0,0.51300004963251122,-0.52185059484429897,0 +0.53500000000000003,0.67807490745420074,0.5878535845789149,-1.6006935764888095,0,0.51466016361553968,-0.51621274881535362,0 +0.54500000000000004,0.60556902444692728,0.59045915738825405,-1.5906721688577199,0,0.51204702934936586,-0.52148853682254903,0 +0.55500000000000005,0.48266830107336006,0.59697028797374452,-1.5761776779942758,0,0.51057551463380291,-0.53191252428398161,0 +0.56500000000000006,0.34834934855591537,0.59188322457049136,-1.5687669989374082,0,0.5151520944223198,-0.54463835756014178,0 +0.57500000000000007,0.2451691037246034,0.59463166677984525,-1.5635053912378623,0,0.51994523862074438,-0.55151343157376009,0 +0.58499999999999996,0.22308154337733685,0.61421260394352284,-1.5558407025582697,0,0.51450769544894648,-0.54648231691723681,0 +0.59499999999999997,0.22390587217315483,0.62861601814674595,-1.555379908924208,0,0.51042675178345809,-0.53931383334019445,0 +0.60499999999999998,0.22786331744185459,0.61304302077924422,-1.5697800797404926,0,0.51789637516013132,-0.53999599169525736,0 +0.61499999999999999,0.23452030041149688,0.58777367268577241,-1.5968680437122895,0,0.53659755807779264,-0.54285121456661267,0 +0.625,0.23506241740122699,0.58441088978544375,-1.6180990627429224,0,0.5312595858066933,-0.53847776600605912,0 +0.63500000000000001,0.22912802575710367,0.64096361665071178,-1.5587196384023227,0,0.50180683386498415,-0.51954980419936259,0 +0.64500000000000002,0.20820170172948924,0.4429088168703938,-1.3138217298639516,0,0.4107172773448764,-0.63242114973177121,0 +0.65500000000000003,0.14280420150766387,0.0013572736674349979,-0.58334822550752841,0,0.15933600494306066,-0.82699909098420499,0 +0.66500000000000004,0.11735885521106922,-0.23309434559311201,-0.17605497312958984,0,0.088246122408452865,-0.90091689844612777,0 +0.67500000000000004,0.11691966169225833,-0.24239401825294279,-0.16901850205441424,0,0.087525697429624683,-0.90138999879178838,0 +0.68500000000000005,0.1168975018076187,-0.24275168390313129,-0.16913431059427403,0,0.087491282208618681,-0.90130727955920587,0 +0.69500000000000006,0.11688490837927806,-0.24293963466430563,-0.16922798396131322,0,0.087471166714507165,-0.90122308503037618,0 +0.70499999999999996,0.11687882431088358,-0.24305091000018803,-0.16930677036965813,0,0.087461000889423768,-0.90113549166198792,0 +0.71499999999999997,0.11688210335016401,-0.24310898990635241,-0.16941137635009459,0,0.087464485048653229,-0.90109713084582599,0 +0.72499999999999998,0.11688746427801196,-0.24311790246317952,-0.16948241337481523,0,0.087471346584835463,-0.90112657201926949,0 +0.73499999999999999,0.11689293842702393,-0.24301542095697384,-0.16941123056591925,0,0.087478382198893812,-0.90117181152414561,0 +0.745,0.11689754429437521,-0.24279548243457205,-0.16922004702154958,0,0.087484264982216398,-0.90123329716500089,0 +0.755,0.11690472407462463,-0.24244042822845885,-0.16894496953161006,0,0.087493985877884928,-0.90135933427866255,0 +0.76500000000000001,0.1169351752430936,-0.24164401100336819,-0.16834345193351358,0,0.087538755474644847,-0.90173628521210369,0 +0.77500000000000002,0.11702346553875453,-0.2389118539454739,-0.16634253632348067,0,0.087670236260091849,-0.90283181009609326,0 +0.78500000000000003,0.11723705803609173,-0.23241448265557926,-0.16159143199373074,0,0.087990348375741601,-0.90548092874079178,0 +0.79500000000000004,0.1176285175883393,-0.22051415125476836,-0.15292012220738538,0,0.088578608675684678,-0.91032952865801275,0 +0.80500000000000005,0.11822301685274909,-0.20247335890203855,-0.13985941063243096,0,0.089475764221054743,-0.91767747139414524,0 +0.81500000000000006,0.11901085894402198,-0.178638590244622,-0.12276084795550267,0,0.090670936816770853,-0.92738054886244792,0 +0.82500000000000007,0.11995507930331456,-0.15017685276699991,-0.10257309790892337,0,0.092113203419944889,-0.93896119897869035,0 +0.83499999999999996,0.12100582881114735,-0.1186354504616307,-0.080489249938489674,0,0.093731854039529328,-0.95178772370322251,0 +0.84499999999999997,0.12210948952666369,-0.085657286840511535,-0.057715619723010918,0,0.095446790184988584,-0.96519228251210643,0 +0.85499999999999998,0.12320528139333707,-0.053056324701219029,-0.035509818552657238,0,0.097164687932375315,-0.97843939905855704,0 +0.86499999999999999,0.12419939842673788,-0.023611385320102929,-0.015706138420103915,0,0.098733750673405729,-0.99040292502414518,0 +0.875,0.1248831018288558,-0.0034412091825772586,-0.0022747475485175887,0,0.099815318398622899,-0.99860261559100016,0 +0.88500000000000001,0.12500000000700623,2.0693358136986429e-10,1.3690028369419877e-10,0,0.10000000001121101,-1.0000000000838631,0 +0.89500000000000002,0.12500000000690034,2.0295860176552916e-10,1.3426844820417816e-10,0,0.10000000001104148,-1.0000000000825946,0 +0.90500000000000003,0.12500000000616657,1.8175890421477852e-10,1.2024374828573813e-10,0,0.10000000000986675,-1.0000000000738092,0 +0.91500000000000004,0.12500000000447511,1.3188042879502353e-10,8.7246950401911659e-11,0,0.10000000000716036,-1.0000000000535656,0 +0.92500000000000004,0.1250000000023313,6.8702813807084164e-11,4.5451087337373151e-11,0,0.10000000000372944,-1.0000000000279046,0 +0.93500000000000005,0.12500000000053466,1.575462353161844e-11,1.0423025405688057e-11,0,0.1000000000008554,-1.0000000000063987,0 +0.94500000000000006,0.125,0,0,0,0.099999999999999867,-1,0 +0.95500000000000007,0.125,0,0,0,0.099999999999999867,-1,0 +0.96499999999999997,0.125,0,0,0,0.099999999999999867,-1,0 +0.97499999999999998,0.125,0,0,0,0.099999999999999867,-1,0 +0.98499999999999999,0.125,0,0,0,0.099999999999999867,-1,0 +0.995,0.125,0,0,0,0.099999999999999867,-1,0 From c782f7bcb0cfec842d26b9ec9da5e5ce85f74595 Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Thu, 2 Apr 2026 00:55:39 +0900 Subject: [PATCH 28/39] refactor(magnetohydrodynamics): move reference code into shared assets Split the Brio-Wu reference solver and its test fixtures into shared assets, remove the JSON-based helper path, and make the solver grid size configurable --- benchmarks/magnetohydrodynamics/README.md | 2 - .../eval/tests/test_hidden.py | 37 +- .../cpp-full-solver1d/workspace/src/main.cpp | 28 +- .../cpp-hlld/workspace/src/hlld.cpp | 8 +- .../shared/CMakeLists.txt | 29 + .../magnetohydrodynamics/shared/README.md | 33 + .../shared/eval/README.md | 54 +- .../eval/fixtures/mhd1d/brio_wu_reference.csv | 301 ++++-- .../shared/eval/mhd1d_reference.py | 877 ------------------ .../shared/eval/mhd1d_shared.py | 303 ------ .../shared/src/full_main.cpp | 74 ++ .../shared/src/full_mhd1d.cpp | 250 +++++ .../shared/src/full_mhd1d.hpp | 105 +++ .../magnetohydrodynamics/shared/src/hlld.cpp | 204 ++++ .../magnetohydrodynamics/shared/src/hlld.hpp | 8 + .../shared/tests/test_reference.py | 44 + .../workspace}/plot_solution.py | 31 +- 17 files changed, 1022 insertions(+), 1366 deletions(-) create mode 100644 benchmarks/magnetohydrodynamics/shared/CMakeLists.txt create mode 100644 benchmarks/magnetohydrodynamics/shared/README.md delete mode 100644 benchmarks/magnetohydrodynamics/shared/eval/mhd1d_reference.py delete mode 100644 benchmarks/magnetohydrodynamics/shared/eval/mhd1d_shared.py create mode 100644 benchmarks/magnetohydrodynamics/shared/src/full_main.cpp create mode 100644 benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.cpp create mode 100644 benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.hpp create mode 100644 benchmarks/magnetohydrodynamics/shared/src/hlld.cpp create mode 100644 benchmarks/magnetohydrodynamics/shared/src/hlld.hpp create mode 100644 benchmarks/magnetohydrodynamics/shared/tests/test_reference.py rename benchmarks/magnetohydrodynamics/{cpp-full-solver1d/workspace/scripts => shared/workspace}/plot_solution.py (73%) diff --git a/benchmarks/magnetohydrodynamics/README.md b/benchmarks/magnetohydrodynamics/README.md index ed4bcce..0721c24 100644 --- a/benchmarks/magnetohydrodynamics/README.md +++ b/benchmarks/magnetohydrodynamics/README.md @@ -9,8 +9,6 @@ This suite contains benchmark tasks for ideal magnetohydrodynamics solvers. - `cpp-hlld/`: C++ HLLD approximate Riemann solver task. - `cpp-full-solver1d/`: C++ full 1D ideal MHD solver (Brio-Wu benchmark). - `shared/eval/README.md`: hidden-eval contract for shared MHD scoring assets. -- `shared/eval/mhd1d_reference.py`: hidden reference generator for the 1D - full-solver task. - `shared/eval/mhd1d_shared.py`: shared helpers for CSV loading, score windows, and comparison metadata. - `shared/eval/fixtures/mhd1d/`: hidden fixtures for `cpp-full-solver1d`. diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/eval/tests/test_hidden.py b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/eval/tests/test_hidden.py index 9f567f0..f011767 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/eval/tests/test_hidden.py +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/eval/tests/test_hidden.py @@ -1,22 +1,18 @@ import math import os import subprocess -import sys from pathlib import Path -SHARED_EVAL_ROOT = Path(__file__).resolve().parents[3] / "shared" / "eval" -if str(SHARED_EVAL_ROOT) not in sys.path: - sys.path.insert(0, str(SHARED_EVAL_ROOT)) - -from mhd1d_shared import ( - CSV_HEADER, - compare_mhd1d_csv_against_fixture, - load_mhd1d_csv_profile, -) - - SOLVER_TARGET = "cpp_full_solver1d" WORKSPACE_ROOT = Path(__file__).resolve().parents[2] / "workspace" +REFERENCE_CSV_PATH = ( + Path(__file__).resolve().parents[3] + / "shared" + / "eval" + / "fixtures" + / "mhd1d" + / "brio_wu_reference.csv" +) def _build_solver(build_dir: Path) -> Path: @@ -40,19 +36,22 @@ def test_hidden_brio_wu_cli_matches_fixture(tmp_path: Path) -> None: output_csv_path = tmp_path / "brio_wu.csv" completed = subprocess.run( - [str(solver_path)], + [str(solver_path), "200"], check=True, capture_output=True, text=True, ) output_csv_path.write_text(completed.stdout, encoding="utf-8") - profile = load_mhd1d_csv_profile(output_csv_path) - assert profile.header == CSV_HEADER + output_rows = output_csv_path.read_text(encoding="utf-8").splitlines() + reference_rows = REFERENCE_CSV_PATH.read_text(encoding="utf-8").splitlines() - comparison = compare_mhd1d_csv_against_fixture(output_csv_path) - assert comparison.passed + assert len(output_rows) == len(reference_rows) + 1 + assert output_rows[1:] == reference_rows for column_name in ("v", "w", "bz"): - for row in profile.rows: - assert math.isfinite(row[column_name]) + for row in output_rows[1:]: + values = row.split(",") + assert len(values) == 8 + value = float(values[{"v": 3, "w": 4, "bz": 6}[column_name]]) + assert math.isfinite(value) diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp index 228c330..dcd509f 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp @@ -1,12 +1,13 @@ #include "mhd1d.hpp" +#include #include #include -#include +#include -constexpr int Nx = 100; -constexpr double Gamma = 2.0; -constexpr double Bx = 0.75; +constexpr int DefaultNx = 100; +constexpr double Gamma = 2.0; +constexpr double Bx = 0.75; constexpr mhd1d::StateVector LeftPrimitive{ 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, }; @@ -14,6 +15,20 @@ constexpr mhd1d::StateVector RightPrimitive{ 0.125, 0.0, 0.0, 0.0, 0.1, -1.0, 0.0, }; +int parse_nx(int argc, char** argv) +{ + if (argc <= 1) { + return DefaultNx; + } + + char* end = nullptr; + const long parsed = std::strtol(argv[1], &end, 10); + if (end == argv[1] || *end != '\0' || parsed <= 0) { + throw std::runtime_error("usage: solver [nx]"); + } + return static_cast(parsed); +} + mhd1d::SolverWorkspace initialize(int nx, double gamma, double bx, const mhd1d::StateVector& left_state, const mhd1d::StateVector& right_state) @@ -44,12 +59,13 @@ void write_csv(const mhd1d::SolverWorkspace& workspace, std::ostream& os) } } -int main() +int main(int argc, char** argv) { + const int nx = parse_nx(argc, argv); const double delt = 5.0e-4; const double tmax = 0.1; - auto workspace = initialize(Nx, Gamma, Bx, LeftPrimitive, RightPrimitive); + auto workspace = initialize(nx, Gamma, Bx, LeftPrimitive, RightPrimitive); mhd1d::evolve_ssp_rk3(workspace, delt, tmax); diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.cpp b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.cpp index c56aedc..38b3488 100644 --- a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.cpp @@ -6,7 +6,7 @@ namespace { -constexpr double kEps = 1.0e-40; +constexpr double epsilon = 1.0e-40; double sign_unit(double x) { @@ -110,7 +110,7 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& const double ptst = (rosdr * ptl - rosdl * ptr + rosdl * rosdr * (vxr - vxl)) * temp; const double temp_fst_l = rosdl * sdml - bxsq; - const double sign1_l = sign_unit(std::abs(temp_fst_l) - kEps); + const double sign1_l = sign_unit(std::abs(temp_fst_l) - epsilon); const double maxs1_l = std::max(0.0, sign1_l); const double mins1_l = std::min(0.0, sign1_l); const double itf_l = 1.0 / (temp_fst_l + mins1_l); @@ -134,7 +134,7 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& mins1_l * eel; const double temp_fst_r = rosdr * sdmr - bxsq; - const double sign1_r = sign_unit(std::abs(temp_fst_r) - kEps); + const double sign1_r = sign_unit(std::abs(temp_fst_r) - epsilon); const double maxs1_r = std::max(0.0, sign1_r); const double mins1_r = std::min(0.0, sign1_r); const double itf_r = 1.0 / (temp_fst_r + mins1_r); @@ -163,7 +163,7 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& const double slst = sm - abbx / sqrtrol; const double srst = sm + abbx / sqrtror; const double signbx = sign_unit(bxs); - const double sign1_b = sign_unit(abbx - kEps); + const double sign1_b = sign_unit(abbx - epsilon); const double maxs1_b = std::max(0.0, sign1_b); const double mins1_b = -std::min(0.0, sign1_b); const double invsumro = maxs1_b / (sqrtrol + sqrtror); diff --git a/benchmarks/magnetohydrodynamics/shared/CMakeLists.txt b/benchmarks/magnetohydrodynamics/shared/CMakeLists.txt new file mode 100644 index 0000000..1a02e85 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/shared/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.16) + +project(magnetohydrodynamics_shared_reference LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +add_library(mhd1d_reference + src/full_mhd1d.cpp + src/hlld.cpp +) + +target_include_directories(mhd1d_reference PUBLIC + src + ../../common/include +) + +add_executable(full_mhd1d_reference + src/full_main.cpp +) + +target_link_libraries(full_mhd1d_reference PRIVATE + mhd1d_reference +) + +set_target_properties(full_mhd1d_reference PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" +) diff --git a/benchmarks/magnetohydrodynamics/shared/README.md b/benchmarks/magnetohydrodynamics/shared/README.md new file mode 100644 index 0000000..35299f7 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/shared/README.md @@ -0,0 +1,33 @@ +# Magnetohydrodynamics Shared Assets + +This directory holds the shared reference implementations and the canonical +Brio-Wu fixtures used by the magnetohydrodynamics benchmarks. + +## Build the shared reference solver + +```bash +cmake -S benchmarks/magnetohydrodynamics/shared -B benchmarks/magnetohydrodynamics/shared/build +cmake --build benchmarks/magnetohydrodynamics/shared/build --target full_mhd1d_reference +``` + +## Run the shared reference solver + +```bash +benchmarks/magnetohydrodynamics/shared/build/bin/full_mhd1d_reference > benchmarks/magnetohydrodynamics/shared/build/solution.csv +``` + +## Plot the output + +Use the shared plot helper and write the image inside the repo: + +```bash +python3 benchmarks/magnetohydrodynamics/shared/workspace/plot_solution.py \ + benchmarks/magnetohydrodynamics/shared/build/solution.csv \ + benchmarks/magnetohydrodynamics/shared/build/solution.png +``` + +## Run the shared test + +```bash +python3 -m pytest -q benchmarks/magnetohydrodynamics/shared/tests/test_reference.py +``` diff --git a/benchmarks/magnetohydrodynamics/shared/eval/README.md b/benchmarks/magnetohydrodynamics/shared/eval/README.md index fc72403..56deb30 100644 --- a/benchmarks/magnetohydrodynamics/shared/eval/README.md +++ b/benchmarks/magnetohydrodynamics/shared/eval/README.md @@ -1,6 +1,6 @@ # Shared eval assets -This directory holds suite-wide hidden-eval documentation and helpers for +This directory holds suite-wide hidden-eval documentation for `cpp-full-solver1d`. ## Hidden reference lifecycle @@ -8,15 +8,10 @@ This directory holds suite-wide hidden-eval documentation and helpers for The full-solver task uses a shared hidden-eval contract anchored by these paths: -- `benchmarks/magnetohydrodynamics/shared/eval/mhd1d_reference.py` -- `benchmarks/magnetohydrodynamics/shared/eval/mhd1d_shared.py` - `benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/` -`mhd1d_reference.py` owns the hidden reference generation and comparison -entry points. `mhd1d_shared.py` provides the shared geometry, CSV parsing, -and score-window helpers used by both the task evaluator and the maintainer -regeneration workflow. Fixture files under `fixtures/mhd1d/` store the -reference outputs and comparison metadata needed to keep scoring deterministic. +Fixture files under `fixtures/mhd1d/` store the reference outputs needed to +keep scoring deterministic. ## Fixture contract @@ -26,49 +21,18 @@ reference outputs and comparison metadata needed to keep scoring deterministic. notation may still refer to the magnetic components as `By` and `Bz`. - Comparison window: interior cells only, excluding two edge-adjacent cells on each side -- Stored tolerances: fixture metadata records `abs_l1` and `abs_linf` - Regeneration: fixtures are regenerated from the hidden reference pipeline and - must preserve the schema, windowing rule, and tolerances above unless the - benchmark contract is intentionally revised + must preserve the schema and windowing rule above unless the benchmark + contract is intentionally revised ## Files -### `mhd1d_reference.py` - -Maintainer-only hidden reference implementation. Provides: - -- **Primitive/conservative conversion**: `primitive_to_conservative()`, `conservative_to_primitive()` -- **Cell geometry**: `cell_centers()`, `brio_wu_primitive_profile()`, `brio_wu_conservative_profile()` -- **Time evolution**: `evolve_brio_wu_reference_profile()`, `evolve_ssp_rk3_fixed_dt()` -- **Reconstruction**: `mc2_slopes()`, `reconstruct_mc2_interfaces()` -- **HLLD flux**: `hlld_flux_from_primitive()`, `hlld_flux_from_conservative()` -- **RHS computation**: `compute_semidiscrete_rhs()`, `brio_wu_semidiscrete_rhs()` -- **Fixture generation**: `write_brio_wu_reference_fixtures()` - -### `mhd1d_shared.py` - -Shared helpers for CSV loading and comparison: - -- **`load_mhd1d_csv_profile(csv_path)`**: Load and validate a CSV profile -- **`load_mhd1d_fixture(fixture_path)`**: Load fixture metadata and reference CSV -- **`compare_mhd1d_csv_against_fixture(solver_csv_path, fixture)`**: Compare solver output against fixture -- **`interior_cell_window_bounds(row_count, exclude_edge_adjacents_per_side)`**: Compute comparison window - ### `fixtures/mhd1d/` -- **`brio_wu_reference.csv`**: Reference solution for the canonical Brio-Wu problem (400 cells, `t_final=0.1`) -- **`brio_wu_fixture.json`**: Metadata including tolerances, schema, and scored variables +- **`brio_wu_reference.csv`**: Reference solution for the canonical Brio-Wu problem (200 cells, `t_final=0.1`) ## Regenerating fixtures -To regenerate the reference fixtures (maintainer only): - -```python -from mhd1d_reference import write_brio_wu_reference_fixtures -from pathlib import Path - -output_dir = Path("benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d") -write_brio_wu_reference_fixtures(output_dir) -``` - -This writes both the reference CSV and the fixture JSON with updated tolerances. +To regenerate the reference CSV (maintainer only), run the shared reference +binary with `200` and write its output to +`benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_reference.csv`. diff --git a/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_reference.csv b/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_reference.csv index e72dfa5..1071df9 100644 --- a/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_reference.csv +++ b/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_reference.csv @@ -1,101 +1,200 @@ -x,rho,u,v,w,p,by,bz -0.0050000000000000001,1,0,0,0,1,1,0 -0.014999999999999999,1,0,0,0,1,1,0 -0.025000000000000001,1,0,0,0,1,1,0 -0.035000000000000003,1,0,0,0,1,1,0 -0.044999999999999998,1,0,0,0,1,1,0 -0.055,1,0,0,0,1,1,0 -0.065000000000000002,1,0,0,0,1,1,0 -0.074999999999999997,1,0,0,0,1,1,0 -0.085000000000000006,1,0,0,0,1,1,0 -0.095000000000000001,1,0,0,0,1,1,0 -0.105,1,0,0,0,1,1,0 -0.115,1,0,0,0,1,1,0 -0.125,1,0,0,0,1,1,0 -0.13500000000000001,1,0,0,0,1,1,0 -0.14499999999999999,1,0,0,0,1,1,0 -0.155,1,0,0,0,1,1,0 -0.16500000000000001,1,0,0,0,1,1,0 -0.17500000000000002,1,0,0,0,1,1,0 -0.185,1,0,0,0,1,1,0 -0.19500000000000001,1,0,0,0,1,1,0 -0.20500000000000002,1,0,0,0,1,1,0 -0.215,1,0,0,0,1,1,0 -0.22500000000000001,1,0,0,0,1,1,0 -0.23500000000000001,1,0,0,0,1,1,0 -0.245,1,0,0,0,1,1,0 -0.255,1,0,0,0,1,1,0 -0.26500000000000001,1,0,0,0,1,1,0 -0.27500000000000002,1,0,0,0,1,1,0 -0.28500000000000003,1,0,0,0,1,1,0 -0.29499999999999998,1,0,0,0,1,1,0 -0.30499999999999999,1,0,0,0,1,1,0 -0.315,0.99258917532833379,0.013274302361789324,-0.0037458540886650027,0,0.98532404108866567,0.99104740522973966,0 -0.32500000000000001,0.96954607581582897,0.054883618137207428,-0.015827325460063591,0,0.94023568077652442,0.96299689161606516,0 -0.33500000000000002,0.94025803324835733,0.10865479486043322,-0.031944255536031786,0,0.88435499782767446,0.92711462956015256,0 -0.34500000000000003,0.90897792466167582,0.16698841420781432,-0.050131763210425707,0,0.82652179164341721,0.88849866375884556,0 -0.35499999999999998,0.87725610844274526,0.2271603117432259,-0.069719685021130948,0,0.76985377322754589,0.84898878620884088,0 -0.36499999999999999,0.84566618167244145,0.28816698962982518,-0.090519447417695451,0,0.71541656913426399,0.80923410080538904,0 -0.375,0.81450435463148285,0.3494865276909434,-0.11251682956314066,0,0.66367321125402712,0.76950238387022263,0 -0.38500000000000001,0.78404538979850258,0.41062539085171551,-0.13575856770700617,0,0.61497905337973746,0.72997249890053162,0 -0.39500000000000002,0.75467120186953685,0.47083530429296916,-0.1602094195276916,0,0.56978778527926832,0.69094510148101218,0 -0.40500000000000003,0.72701668590610768,0.52870556766657628,-0.18539026277804579,0,0.52883750835390897,0.65319266964541056,0 -0.41500000000000004,0.70216500224646816,0.58153016354527853,-0.20973136326536138,0,0.4933637549672012,0.61876152226558601,0 -0.42499999999999999,0.68193441338380167,0.62487275671749021,-0.22845986767252549,0,0.46540195161446823,0.59219206428336624,0 -0.435,0.6666986977176832,0.65196598708089948,-0.23211489711409145,0,0.44490074049787121,0.58021922926273972,0 -0.44500000000000001,0.66015529724292976,0.66607074009479628,-0.22555655390938342,0,0.43615912199888263,0.58524191570556205,0 -0.45500000000000002,0.65997980757445474,0.66324409170331222,-0.23280516118974198,0,0.43727412310940939,0.5796363680769816,0 -0.46500000000000002,0.73349815599883794,0.60086667962898554,-0.62171855754180494,0,0.57886068825314341,0.27652712488086967,0 -0.47500000000000003,0.79237811897791921,0.46454032083596353,-1.2161018009267417,0,0.6842784144671038,-0.24404258805909654,0 -0.48499999999999999,0.74259318372203176,0.53084767864673321,-1.4743018340823315,0,0.60002741951352012,-0.44224666294204562,0 -0.495,0.69493377959694547,0.61399418172955245,-1.5431753009247675,0,0.54413704626033854,-0.54049642839751277,0 -0.505,0.70278259276020427,0.61662067481286442,-1.5872354257997463,0,0.52068648102692328,-0.56052646550215834,0 -0.51500000000000001,0.70390914156072559,0.6077114699355689,-1.6001701751263477,0,0.51193399003676154,-0.54226823182770345,0 -0.52500000000000002,0.69922181544266515,0.59340751947871018,-1.6046948629200928,0,0.51300004963251122,-0.52185059484429897,0 -0.53500000000000003,0.67807490745420074,0.5878535845789149,-1.6006935764888095,0,0.51466016361553968,-0.51621274881535362,0 -0.54500000000000004,0.60556902444692728,0.59045915738825405,-1.5906721688577199,0,0.51204702934936586,-0.52148853682254903,0 -0.55500000000000005,0.48266830107336006,0.59697028797374452,-1.5761776779942758,0,0.51057551463380291,-0.53191252428398161,0 -0.56500000000000006,0.34834934855591537,0.59188322457049136,-1.5687669989374082,0,0.5151520944223198,-0.54463835756014178,0 -0.57500000000000007,0.2451691037246034,0.59463166677984525,-1.5635053912378623,0,0.51994523862074438,-0.55151343157376009,0 -0.58499999999999996,0.22308154337733685,0.61421260394352284,-1.5558407025582697,0,0.51450769544894648,-0.54648231691723681,0 -0.59499999999999997,0.22390587217315483,0.62861601814674595,-1.555379908924208,0,0.51042675178345809,-0.53931383334019445,0 -0.60499999999999998,0.22786331744185459,0.61304302077924422,-1.5697800797404926,0,0.51789637516013132,-0.53999599169525736,0 -0.61499999999999999,0.23452030041149688,0.58777367268577241,-1.5968680437122895,0,0.53659755807779264,-0.54285121456661267,0 -0.625,0.23506241740122699,0.58441088978544375,-1.6180990627429224,0,0.5312595858066933,-0.53847776600605912,0 -0.63500000000000001,0.22912802575710367,0.64096361665071178,-1.5587196384023227,0,0.50180683386498415,-0.51954980419936259,0 -0.64500000000000002,0.20820170172948924,0.4429088168703938,-1.3138217298639516,0,0.4107172773448764,-0.63242114973177121,0 -0.65500000000000003,0.14280420150766387,0.0013572736674349979,-0.58334822550752841,0,0.15933600494306066,-0.82699909098420499,0 -0.66500000000000004,0.11735885521106922,-0.23309434559311201,-0.17605497312958984,0,0.088246122408452865,-0.90091689844612777,0 -0.67500000000000004,0.11691966169225833,-0.24239401825294279,-0.16901850205441424,0,0.087525697429624683,-0.90138999879178838,0 -0.68500000000000005,0.1168975018076187,-0.24275168390313129,-0.16913431059427403,0,0.087491282208618681,-0.90130727955920587,0 -0.69500000000000006,0.11688490837927806,-0.24293963466430563,-0.16922798396131322,0,0.087471166714507165,-0.90122308503037618,0 -0.70499999999999996,0.11687882431088358,-0.24305091000018803,-0.16930677036965813,0,0.087461000889423768,-0.90113549166198792,0 -0.71499999999999997,0.11688210335016401,-0.24310898990635241,-0.16941137635009459,0,0.087464485048653229,-0.90109713084582599,0 -0.72499999999999998,0.11688746427801196,-0.24311790246317952,-0.16948241337481523,0,0.087471346584835463,-0.90112657201926949,0 -0.73499999999999999,0.11689293842702393,-0.24301542095697384,-0.16941123056591925,0,0.087478382198893812,-0.90117181152414561,0 -0.745,0.11689754429437521,-0.24279548243457205,-0.16922004702154958,0,0.087484264982216398,-0.90123329716500089,0 -0.755,0.11690472407462463,-0.24244042822845885,-0.16894496953161006,0,0.087493985877884928,-0.90135933427866255,0 -0.76500000000000001,0.1169351752430936,-0.24164401100336819,-0.16834345193351358,0,0.087538755474644847,-0.90173628521210369,0 -0.77500000000000002,0.11702346553875453,-0.2389118539454739,-0.16634253632348067,0,0.087670236260091849,-0.90283181009609326,0 -0.78500000000000003,0.11723705803609173,-0.23241448265557926,-0.16159143199373074,0,0.087990348375741601,-0.90548092874079178,0 -0.79500000000000004,0.1176285175883393,-0.22051415125476836,-0.15292012220738538,0,0.088578608675684678,-0.91032952865801275,0 -0.80500000000000005,0.11822301685274909,-0.20247335890203855,-0.13985941063243096,0,0.089475764221054743,-0.91767747139414524,0 -0.81500000000000006,0.11901085894402198,-0.178638590244622,-0.12276084795550267,0,0.090670936816770853,-0.92738054886244792,0 -0.82500000000000007,0.11995507930331456,-0.15017685276699991,-0.10257309790892337,0,0.092113203419944889,-0.93896119897869035,0 -0.83499999999999996,0.12100582881114735,-0.1186354504616307,-0.080489249938489674,0,0.093731854039529328,-0.95178772370322251,0 -0.84499999999999997,0.12210948952666369,-0.085657286840511535,-0.057715619723010918,0,0.095446790184988584,-0.96519228251210643,0 -0.85499999999999998,0.12320528139333707,-0.053056324701219029,-0.035509818552657238,0,0.097164687932375315,-0.97843939905855704,0 -0.86499999999999999,0.12419939842673788,-0.023611385320102929,-0.015706138420103915,0,0.098733750673405729,-0.99040292502414518,0 -0.875,0.1248831018288558,-0.0034412091825772586,-0.0022747475485175887,0,0.099815318398622899,-0.99860261559100016,0 -0.88500000000000001,0.12500000000700623,2.0693358136986429e-10,1.3690028369419877e-10,0,0.10000000001121101,-1.0000000000838631,0 -0.89500000000000002,0.12500000000690034,2.0295860176552916e-10,1.3426844820417816e-10,0,0.10000000001104148,-1.0000000000825946,0 -0.90500000000000003,0.12500000000616657,1.8175890421477852e-10,1.2024374828573813e-10,0,0.10000000000986675,-1.0000000000738092,0 -0.91500000000000004,0.12500000000447511,1.3188042879502353e-10,8.7246950401911659e-11,0,0.10000000000716036,-1.0000000000535656,0 -0.92500000000000004,0.1250000000023313,6.8702813807084164e-11,4.5451087337373151e-11,0,0.10000000000372944,-1.0000000000279046,0 -0.93500000000000005,0.12500000000053466,1.575462353161844e-11,1.0423025405688057e-11,0,0.1000000000008554,-1.0000000000063987,0 -0.94500000000000006,0.125,0,0,0,0.099999999999999867,-1,0 -0.95500000000000007,0.125,0,0,0,0.099999999999999867,-1,0 -0.96499999999999997,0.125,0,0,0,0.099999999999999867,-1,0 -0.97499999999999998,0.125,0,0,0,0.099999999999999867,-1,0 -0.98499999999999999,0.125,0,0,0,0.099999999999999867,-1,0 -0.995,0.125,0,0,0,0.099999999999999867,-1,0 +0.0025000000000000001,1,0,0,0,1,1,0 +0.0074999999999999997,1,0,0,0,1,1,0 +0.012500000000000001,1,0,0,0,1,1,0 +0.017500000000000002,1,0,0,0,1,1,0 +0.022499999999999999,1,0,0,0,1,1,0 +0.0275,1,0,0,0,1,1,0 +0.032500000000000001,1,0,0,0,1,1,0 +0.037499999999999999,1,0,0,0,1,1,0 +0.042500000000000003,1,0,0,0,1,1,0 +0.047500000000000001,1,0,0,0,1,1,0 +0.052499999999999998,1,0,0,0,1,1,0 +0.057500000000000002,1,0,0,0,1,1,0 +0.0625,1,0,0,0,1,1,0 +0.067500000000000004,1,0,0,0,1,1,0 +0.072499999999999995,1,0,0,0,1,1,0 +0.077499999999999999,1,0,0,0,1,1,0 +0.082500000000000004,1,0,0,0,1,1,0 +0.087500000000000008,1,0,0,0,1,1,0 +0.092499999999999999,1,0,0,0,1,1,0 +0.097500000000000003,1,0,0,0,1,1,0 +0.10250000000000001,1,0,0,0,1,1,0 +0.1075,1,0,0,0,1,1,0 +0.1125,1,0,0,0,1,1,0 +0.11750000000000001,1,0,0,0,1,1,0 +0.1225,1,0,0,0,1,1,0 +0.1275,1,0,0,0,1,1,0 +0.13250000000000001,1,0,0,0,1,1,0 +0.13750000000000001,1,0,0,0,1,1,0 +0.14250000000000002,1,0,0,0,1,1,0 +0.14749999999999999,1,0,0,0,1,1,0 +0.1525,1,0,0,0,1,1,0 +0.1575,1,0,0,0,1,1,0 +0.16250000000000001,1,0,0,0,1,1,0 +0.16750000000000001,1,0,0,0,1,1,0 +0.17250000000000001,1,0,0,0,1,1,0 +0.17749999999999999,1,0,0,0,1,1,0 +0.1825,1,0,0,0,1,1,0 +0.1875,1,0,0,0,1,1,0 +0.1925,1,0,0,0,1,1,0 +0.19750000000000001,1,0,0,0,1,1,0 +0.20250000000000001,1,0,0,0,1,1,0 +0.20750000000000002,1,0,0,0,1,1,0 +0.21249999999999999,1,0,0,0,1,1,0 +0.2175,1,0,0,0,1,1,0 +0.2225,1,0,0,0,1,1,0 +0.22750000000000001,1,0,0,0,1,1,0 +0.23250000000000001,1,0,0,0,1,1,0 +0.23750000000000002,1,0,0,0,1,1,0 +0.24249999999999999,1,0,0,0,1,1,0 +0.2475,1,0,0,0,1,1,0 +0.2525,1,0,0,0,1,1,0 +0.25750000000000001,1,0,0,0,1,1,0 +0.26250000000000001,1,0,0,0,1,1,0 +0.26750000000000002,1,0,0,0,1,1,0 +0.27250000000000002,1,0,0,0,1,1,0 +0.27750000000000002,1,0,0,0,1,1,0 +0.28250000000000003,1,0,0,0,1,1,0 +0.28750000000000003,1,0,0,0,1,1,0 +0.29249999999999998,1,0,0,0,1,1,0 +0.29749999999999999,1,0,0,0,1,1,0 +0.30249999999999999,1,0,0,0,1,1,0 +0.3075,1,0,0,0,1,1,0 +0.3125,0.99999616106296441,6.8218605150679938e-06,-1.629335642440668e-06,0,0.99999232327941856,0.99999566416503605,0 +0.3175,0.99560068549137515,0.0078843624165065886,-0.0022307064981435336,0,0.99124636392653631,0.99467429565967369,0 +0.32250000000000001,0.98353688945169881,0.029598025828916189,-0.0084627190065405377,0,0.96740300125799372,0.98001580530130683,0 +0.32750000000000001,0.96837732838015789,0.05711492307963683,-0.016488321600118205,0,0.93782681090500097,0.96153830413996133,0 +0.33250000000000002,0.95211065533562045,0.08687376004553142,-0.025340884306684217,0,0.90659226850159857,0.9416391285061726,0 +0.33750000000000002,0.9354673361460476,0.11758295597145299,-0.03467317160538614,0,0.87517584603477561,0.9211946768322925,0 +0.34250000000000003,0.91871718394782453,0.14876408314954759,-0.044363052905967301,0,0.84411769226174038,0.90052767707199355,0 +0.34750000000000003,0.90197078951363818,0.18022527854218023,-0.054366992352566521,0,0.81362498203456801,0.87976588730214367,0 +0.35249999999999998,0.88528078739957949,0.21187079330682687,-0.064670097539751836,0,0.78379400158707657,0.8589695086683371,0 +0.35749999999999998,0.86867910739122456,0.24364631893161978,-0.07526898825581857,0,0.75467281039391498,0.83817058039488479,0 +0.36249999999999999,0.85218625735593245,0.27551533794365413,-0.086165925398151544,0,0.72628825924799156,0.81738872876742574,0 +0.36749999999999999,0.83581667914061153,0.30745246166009871,-0.097367088841251212,0,0.69865388612813017,0.7966357191723874,0 +0.3725,0.81958109452109384,0.33943908417002161,-0.10888139563994977,0,0.67177480879334084,0.77591795858119794,0 +0.3775,0.80348741554278624,0.37146051600257746,-0.1207199694849094,0,0.64565110939024239,0.75523808653390023,0 +0.38250000000000001,0.7875445084338637,0.40350000122001395,-0.13289403440191852,0,0.62028291926991785,0.73459903988049102,0 +0.38750000000000001,0.77176732253101099,0.43552724865404702,-0.14541056405365715,0,0.59567915284429596,0.71401135925001946,0 +0.39250000000000002,0.75618662865505448,0.46747833845388209,-0.15826308205578452,0,0.57187085608759247,0.69350629751332449,0 +0.39750000000000002,0.74086333491683398,0.49922382920992259,-0.1714159845725442,0,0.54893025602556722,0.67315622872434921,0 +0.40250000000000002,0.72591127957332113,0.53051685817985217,-0.18477737401520411,0,0.52699952756086399,0.65310782756232943,0 +0.40750000000000003,0.71153792819892647,0.56090161794556215,-0.19815008755163185,0,0.50634126527317558,0.63364102400425049,0 +0.41250000000000003,0.69811514572358369,0.58954799451371021,-0.21114189870363537,0,0.4874249963437069,0.61527302327312272,0 +0.41749999999999998,0.68628746003287744,0.61503330090041819,-0.22302766944126134,0,0.47105684401465941,0.59892135357981213,0 +0.42249999999999999,0.67696251242649175,0.63513291356954815,-0.2326074173770955,0,0.45834791401272101,0.58598837050788355,0 +0.42749999999999999,0.67147463576702993,0.64779945118301063,-0.23846691522567326,0,0.45094670813117532,0.57820303829922137,0 +0.4325,0.6688796555738501,0.65110241055546891,-0.2410081467465312,0,0.44746033225767845,0.5753899843373016,0 +0.4375,0.66923632078057105,0.65190937533001247,-0.24110017994523736,0,0.44794907534325185,0.57444176371495947,0 +0.4425,0.67092296635432236,0.64955585559206386,-0.24054877369726702,0,0.45022622769647191,0.57572465421454055,0 +0.44750000000000001,0.6741213806450993,0.64344630049305807,-0.23854099129835965,0,0.45453459644722283,0.57947771182222196,0 +0.45250000000000001,0.67622598638333231,0.63780864306743901,-0.23448685862138482,0,0.45738500592687004,0.58438626477884326,0 +0.45750000000000002,0.67754413933073854,0.63405079125731079,-0.22959378848719866,0,0.45917700333007561,0.58929788380231585,0 +0.46250000000000002,0.68597164204564365,0.61952213982777449,-0.24653663418395505,0,0.47189617111806659,0.57922868126312688,0 +0.46750000000000003,0.75354858718752427,0.57292925776279291,-0.63081628168738757,0,0.60292314122276669,0.27209063114350734,0 +0.47250000000000003,0.80630536650231177,0.46293683334979041,-1.1759576407781362,0,0.69703548985821029,-0.20853604373803852,0 +0.47750000000000004,0.7638410805034388,0.51805820703977745,-1.3927632353963115,0,0.62805748621970625,-0.3981907442021011,0 +0.48249999999999998,0.73152958163331872,0.57826425255304303,-1.4832959440212241,0,0.57564691619642827,-0.47630190401752948,0 +0.48749999999999999,0.7091371949877272,0.59282038528643355,-1.5447516257458402,0,0.54057240122232608,-0.52152146798758336,0 +0.49249999999999999,0.69094050613943225,0.59503499024494011,-1.5888099484071434,0,0.51755764390120462,-0.52927763675904382,0 +0.4975,0.68445173626467959,0.59046857583704693,-1.6048335641093068,0,0.50638419398254775,-0.53146412709505564,0 +0.50250000000000006,0.68434384603578657,0.59230376347482205,-1.5982075803435103,0,0.50542098868729934,-0.53352729015156963,0 +0.50750000000000006,0.68707431747700531,0.59425987403200542,-1.5869958639330111,0,0.51033146073036029,-0.53448849532455134,0 +0.51249999999999996,0.68939472693221426,0.60137405638102948,-1.5798014603878261,0,0.51803593468141906,-0.53565082760707183,0 +0.51749999999999996,0.69132926018866214,0.60874084896105818,-1.5797632463390414,0,0.52436693339499907,-0.5359104689992632,0 +0.52249999999999996,0.69215217980589738,0.60970112925016673,-1.5824896135808113,0,0.52434513683953443,-0.5354819845059674,0 +0.52749999999999997,0.69444170391589999,0.60627151781387467,-1.5858651859518866,0,0.52162449544034473,-0.53457955249120248,0 +0.53249999999999997,0.69647681591950339,0.59800014203747298,-1.5883464457585819,0,0.51533551298586344,-0.53253950669423489,0 +0.53749999999999998,0.69477389476214069,0.59293397164493389,-1.5901196445037074,0,0.51174059849537212,-0.5304114113079087,0 +0.54249999999999998,0.68911228688697801,0.59380160058459075,-1.5903316488178545,0,0.51192732192152268,-0.52949995498960822,0 +0.54749999999999999,0.66719536897441889,0.59857474030644331,-1.5895216549318072,0,0.51429507796334395,-0.52929052879654892,0 +0.55249999999999999,0.60234055420437194,0.60371440419440114,-1.5885169423087238,0,0.5187332353048264,-0.53155866918735362,0 +0.5575,0.49290738445262527,0.60775103688327448,-1.5855974157471353,0,0.52066330116084492,-0.53424754867164737,0 +0.5625,0.36379960562925234,0.61145270056068901,-1.5836004669317623,0,0.51969239083206853,-0.53490394589485069,0 +0.5675,0.25794003992686892,0.61029128984346714,-1.5820890229303581,0,0.51813142258312772,-0.53525310083950484,0 +0.57250000000000001,0.22619669625294542,0.60434480627709164,-1.583239013708023,0,0.51937704488324277,-0.53667920987231343,0 +0.57750000000000001,0.22630840156123649,0.59827581714693934,-1.5861518811591599,0,0.51884369894384308,-0.53653660134365799,0 +0.58250000000000002,0.22711466733509919,0.59921584970885489,-1.5865907932320387,0,0.51663519067912,-0.5340362400001385,0 +0.58750000000000002,0.22848173751344047,0.60091449520075879,-1.5881448209869364,0,0.51354656892651396,-0.52979939734340753,0 +0.59250000000000003,0.23031920669352701,0.59922369951386523,-1.5926693039478363,0,0.51316449769217121,-0.52713616980108124,0 +0.59750000000000003,0.23243460374842745,0.59022749017803877,-1.5967363554938299,0,0.5171218957694993,-0.52858990082849489,0 +0.60250000000000004,0.23371045610745741,0.58557425058898349,-1.6007158568053828,0,0.5198767628355706,-0.5306097118265467,0 +0.60750000000000004,0.23346589711062016,0.59462702763778397,-1.5950312955893633,0,0.51701289109504156,-0.52896536404700278,0 +0.61250000000000004,0.23263653232779033,0.61187045984626132,-1.5834576247676977,0,0.51177702375221379,-0.52633641566767586,0 +0.61750000000000005,0.23321499947212285,0.61526177184194952,-1.5789252785842804,0,0.51201629462921838,-0.53124179083925394,0 +0.62250000000000005,0.23616745617017731,0.59110549784028277,-1.581549220607541,0,0.52255821054730711,-0.54281830257957719,0 +0.62750000000000006,0.23850998490201497,0.57982203884810612,-1.5800134018812597,0,0.52973514694150359,-0.54974364304552559,0 +0.63250000000000006,0.23549928160809872,0.60805510179030442,-1.5697422964899919,0,0.51469370924936686,-0.54625158631214921,0 +0.63750000000000007,0.23267730073699258,0.64764426075074666,-1.5303717022273871,0,0.50048958343353256,-0.53283346050863811,0 +0.64249999999999996,0.22589478256765788,0.51608311612092028,-1.4244966323443713,0,0.47215254213952862,-0.60337924172895407,0 +0.64749999999999996,0.16824385093540103,0.2019403880561518,-0.85229593508650303,0,0.24693902186307282,-0.76893242381717286,0 +0.65249999999999997,0.12072583773152777,-0.18183444417138045,-0.24105266177015217,0,0.095400355892026001,-0.89302992881503718,0 +0.65749999999999997,0.11601292282091824,-0.26459528318540043,-0.1814730538647312,0,0.086167195075565028,-0.89320114714371157,0 +0.66249999999999998,0.116048367245578,-0.26722541207620687,-0.18522210521227256,0,0.086217867928268577,-0.89201260813637107,0 +0.66749999999999998,0.11614130837574657,-0.26549235054019255,-0.18609509830657162,0,0.086355655034603629,-0.891902181568761,0 +0.67249999999999999,0.11631511438200227,-0.26085265286182824,-0.18311506509197725,0,0.086614152150550017,-0.89367317333644192,0 +0.67749999999999999,0.11662767049075361,-0.25099871037849603,-0.17536214658827623,0,0.087078445740005561,-0.8978274795799227,0 +0.6825,0.1170518312215577,-0.2381722667902374,-0.16579466075220212,0,0.087710449613822461,-0.90318269940017126,0 +0.6875,0.11746096698143836,-0.22586176858556523,-0.15680732789253898,0,0.088322007878451791,-0.90825069334609754,0 +0.6925,0.11767715987203248,-0.21896280887700917,-0.15179332435332796,0,0.088645332706841606,-0.91092215760728412,0 +0.69750000000000001,0.11768511349561916,-0.21852003035735557,-0.15146950280658006,0,0.088656537990149054,-0.91102013385933844,0 +0.70250000000000001,0.11768173540960905,-0.21911190725269286,-0.15189586068806646,0,0.088650899743895395,-0.91098098981221598,0 +0.70750000000000002,0.11762763379381724,-0.2205495383437531,-0.15293640182544183,0,0.088569191874156683,-0.91031519004692951,0 +0.71250000000000002,0.11751251674883506,-0.22407404665911851,-0.15549737468557176,0,0.088395415678045763,-0.90889140732316487,0 +0.71750000000000003,0.11734217026306956,-0.22923209052659663,-0.15925236589498573,0,0.088138555377449745,-0.90678117162710703,0 +0.72250000000000003,0.11714842121554768,-0.23510643408875742,-0.16353933245426788,0,0.087847174957777496,-0.90438202392384848,0 +0.72750000000000004,0.1169801447659943,-0.2402468788526454,-0.16730065580704034,0,0.08759435163307927,-0.9022965309078298,0 +0.73250000000000004,0.11690646094308876,-0.24252420707824915,-0.16896758133008036,0,0.087483274145631063,-0.901381475968559,0 +0.73750000000000004,0.11690536582831555,-0.24256297970713472,-0.16899337040831261,0,0.087481058709982462,-0.90136639345779135,0 +0.74250000000000005,0.11690416351837025,-0.24255759967720394,-0.16898805965890309,0,0.087479260585539786,-0.901355959768676,0 +0.74750000000000005,0.11690268830300561,-0.24256433968132488,-0.1689902511692872,0,0.087476844575879453,-0.90133971116149714,0 +0.75250000000000006,0.11690249149566564,-0.24263045674337938,-0.1690369990836007,0,0.087475993304401478,-0.90133579739871572,0 +0.75750000000000006,0.11690005841649749,-0.24273633487321142,-0.16911280871212495,0,0.087472007939943586,-0.90130651809972928,0 +0.76250000000000007,0.11689523976762291,-0.24284738859395841,-0.16919278965713455,0,0.087464802097937722,-0.90124869217347503,0 +0.76750000000000007,0.11689009550937005,-0.24294211733393109,-0.16926071280315277,0,0.087456699244402802,-0.90118542866037055,0 +0.77249999999999996,0.1168880938125931,-0.24302624712308077,-0.16932082611092356,0,0.087453261117748871,-0.90115780061563966,0 +0.77749999999999997,0.11688902120163681,-0.24306621660903155,-0.16935040473201921,0,0.08745446500405607,-0.90117291963133284,0 +0.78249999999999997,0.11689122011863207,-0.24300391365362053,-0.16930103423717782,0,0.08745781154989074,-0.90120105561337527,0 +0.78749999999999998,0.11689602107686169,-0.24276853710995247,-0.16912688892459521,0,0.087464414434553439,-0.90126023192649951,0 +0.79249999999999998,0.11691614491470963,-0.24220891469038228,-0.16871533218791021,0,0.087494250613795788,-0.9015098119657331,0 +0.79749999999999999,0.11696855155695048,-0.2405988356047073,-0.16753372147752355,0,0.087572799130735901,-0.90216329808472961,0 +0.80249999999999999,0.11707534180756879,-0.23734745289851361,-0.16515050554824207,0,0.087732641828922264,-0.90348892427237504,0 +0.8075,0.1172553580143333,-0.23187377620745053,-0.16114702890370325,0,0.088002312969811203,-0.90571948515068501,0 +0.8125,0.11752273565815201,-0.22374249463054305,-0.15521835735527145,0,0.088404020315360543,-0.90903234177390579,0 +0.8175,0.11788504329153121,-0.21273139165106736,-0.14722424729033728,0,0.088950161329339306,-0.91351723197970469,0 +0.82250000000000001,0.1183424161062748,-0.19886886175669347,-0.13721495011558987,0,0.089641293437578984,-0.91916169859620123,0 +0.82750000000000001,0.11888652447249262,-0.18241324922292035,-0.12541146812970011,0,0.090466824054350359,-0.92585977532177122,0 +0.83250000000000002,0.11950366948367314,-0.1637828406974208,-0.11215088119516084,0,0.091408372844463459,-0.93344004869433117,0 +0.83750000000000002,0.12017840890881823,-0.1434726819285532,-0.09781794530184125,0,0.092443075882257864,-0.94170037634875625,0 +0.84250000000000003,0.12089469678105615,-0.12198057865279255,-0.082786700196053442,0,0.093547607150673007,-0.95043832267570283,0 +0.84750000000000003,0.1216371976196647,-0.099767234362176133,-0.067394749995541334,0,0.094699706483174273,-0.95946680774581716,0 +0.85250000000000004,0.12239161658091287,-0.077260468431275015,-0.051947511873339444,0,0.095878018276146726,-0.96861198920602887,0 +0.85750000000000004,0.12314341274778251,-0.05490629533724703,-0.03674915962168223,0,0.097058875646527043,-0.97769350318200499,0 +0.86250000000000004,0.12386678297689156,-0.033461759001210456,-0.022298916108968211,0,0.098201102970602916,-0.98640512630263821,0 +0.86750000000000005,0.1245109747847933,-0.014416962267587185,-0.0095697786663570452,0,0.099223465212322837,-0.99414146906183942,0 +0.87250000000000005,0.12493817800639674,-0.0018204925661910309,-0.0012033527248810462,0,0.09990183090571092,-0.99926077800527913,0 +0.87750000000000006,0.12500000001219974,3.6363615818642719e-10,2.4056984550234209e-10,0,0.10000000001951947,-1.0000000001460236,0 +0.88250000000000006,0.12500000001221473,3.5619382255045683e-10,2.3564550308747709e-10,0,0.10000000001954346,-1.0000000001462062,0 +0.88750000000000007,0.12500000001137598,3.3563244772973727e-10,2.2204309500150842e-10,0,0.10000000001820109,-1.0000000001361644,0 +0.89250000000000007,0.12500000000941866,2.775282966192311e-10,1.8360388763520491e-10,0,0.10000000001507026,-1.0000000001127354,0 +0.89749999999999996,0.12500000000652875,1.9240316746228584e-10,1.2728653685957096e-10,0,0.10000000001044618,-1.0000000000781459,0 +0.90249999999999997,0.12500000000334643,9.8618158081562529e-11,6.5242655720636596e-11,0,0.1000000000053537,-1.0000000000400553,0 +0.90749999999999997,0.12500000000075906,2.2369069559482915e-11,1.4798814025978548e-11,0,0.10000000000121445,-1.0000000000090854,0 +0.91249999999999998,0.125,0,0,0,0.099999999999999867,-1,0 +0.91749999999999998,0.125,0,0,0,0.099999999999999867,-1,0 +0.92249999999999999,0.125,0,0,0,0.099999999999999867,-1,0 +0.92749999999999999,0.125,0,0,0,0.099999999999999867,-1,0 +0.9325,0.125,0,0,0,0.099999999999999867,-1,0 +0.9375,0.125,0,0,0,0.099999999999999867,-1,0 +0.9425,0.125,0,0,0,0.099999999999999867,-1,0 +0.94750000000000001,0.125,0,0,0,0.099999999999999867,-1,0 +0.95250000000000001,0.125,0,0,0,0.099999999999999867,-1,0 +0.95750000000000002,0.125,0,0,0,0.099999999999999867,-1,0 +0.96250000000000002,0.125,0,0,0,0.099999999999999867,-1,0 +0.96750000000000003,0.125,0,0,0,0.099999999999999867,-1,0 +0.97250000000000003,0.125,0,0,0,0.099999999999999867,-1,0 +0.97750000000000004,0.125,0,0,0,0.099999999999999867,-1,0 +0.98250000000000004,0.125,0,0,0,0.099999999999999867,-1,0 +0.98750000000000004,0.125,0,0,0,0.099999999999999867,-1,0 +0.99250000000000005,0.125,0,0,0,0.099999999999999867,-1,0 +0.99750000000000005,0.125,0,0,0,0.099999999999999867,-1,0 diff --git a/benchmarks/magnetohydrodynamics/shared/eval/mhd1d_reference.py b/benchmarks/magnetohydrodynamics/shared/eval/mhd1d_reference.py deleted file mode 100644 index 8fb1234..0000000 --- a/benchmarks/magnetohydrodynamics/shared/eval/mhd1d_reference.py +++ /dev/null @@ -1,877 +0,0 @@ -"""Maintainer-only hidden reference helpers for 1D Brio-Wu MHD.""" - -from __future__ import annotations - -import math -import csv -import json -from pathlib import Path - -import numpy as np - - -STATE_WIDTH = 7 -DOMAIN_LEFT = 0.0 -DOMAIN_RIGHT = 1.0 -DISCONTINUITY_X = 0.5 -DEFAULT_GAMMA = 2.0 -DEFAULT_BX = 0.75 -DEFAULT_GHOST_WIDTH = 2 -BRIO_WU_REFERENCE_NX = 400 -BRIO_WU_REFERENCE_T_FINAL = 0.1 -BRIO_WU_REFERENCE_DT = 5.0e-4 -BRIO_WU_REFERENCE_CSV_NAME = "brio_wu_reference.csv" -BRIO_WU_FIXTURE_JSON_NAME = "brio_wu_fixture.json" -BRIO_WU_REFERENCE_HEADER = ("x", "rho", "u", "v", "w", "p", "by", "bz") -BRIO_WU_SCORING_VARIABLES = ("rho", "u", "p", "by") -BRIO_WU_INNER_WINDOW_EXCLUDE = 2 - -PRIMITIVE_ORDER = ("rho", "u", "v", "w", "p", "By", "Bz") -CONSERVATIVE_ORDER = ("rho", "mx", "my", "mz", "E", "By", "Bz") - -BRIO_WU_LEFT_PRIMITIVE = np.array([1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0], dtype=np.float64) -BRIO_WU_RIGHT_PRIMITIVE = np.array( - [0.125, 0.0, 0.0, 0.0, 0.1, -1.0, 0.0], dtype=np.float64 -) - - -def _require_state_width(state: np.ndarray, *, name: str) -> np.ndarray: - array = np.asarray(state, dtype=np.float64) - if array.shape[-1] != STATE_WIDTH: - raise ValueError(f"{name} must have last dimension {STATE_WIDTH}") - return array - - -def _sign_unit(number: float) -> float: - return 1.0 if number >= 0.0 else -1.0 - - -def primitive_to_conservative( - primitive_state: np.ndarray, - bx: float = DEFAULT_BX, - gamma: float = DEFAULT_GAMMA, -) -> np.ndarray: - primitive = _require_state_width(primitive_state, name="primitive_state") - - rho = primitive[..., 0] - u = primitive[..., 1] - v = primitive[..., 2] - w = primitive[..., 3] - pressure = primitive[..., 4] - by = primitive[..., 5] - bz = primitive[..., 6] - - conservative = np.empty_like(primitive, dtype=np.float64) - conservative[..., 0] = rho - conservative[..., 1] = rho * u - conservative[..., 2] = rho * v - conservative[..., 3] = rho * w - conservative[..., 4] = pressure / (gamma - 1.0) + 0.5 * rho * ( - u * u + v * v + w * w - ) - conservative[..., 4] += 0.5 * (bx * bx + by * by + bz * bz) - conservative[..., 5] = by - conservative[..., 6] = bz - return conservative - - -def conservative_to_primitive( - conservative_state: np.ndarray, - bx: float = DEFAULT_BX, - gamma: float = DEFAULT_GAMMA, -) -> np.ndarray: - conservative = _require_state_width(conservative_state, name="conservative_state") - - rho = conservative[..., 0] - mx = conservative[..., 1] - my = conservative[..., 2] - mz = conservative[..., 3] - energy = conservative[..., 4] - by = conservative[..., 5] - bz = conservative[..., 6] - - u = mx / rho - v = my / rho - w = mz / rho - kinetic_energy = 0.5 * rho * (u * u + v * v + w * w) - magnetic_energy = 0.5 * (bx * bx + by * by + bz * bz) - pressure = (gamma - 1.0) * (energy - kinetic_energy - magnetic_energy) - - primitive = np.empty_like(conservative, dtype=np.float64) - primitive[..., 0] = rho - primitive[..., 1] = u - primitive[..., 2] = v - primitive[..., 3] = w - primitive[..., 4] = pressure - primitive[..., 5] = by - primitive[..., 6] = bz - return primitive - - -def cell_centers( - nx: int, - x_left: float = DOMAIN_LEFT, - x_right: float = DOMAIN_RIGHT, -) -> np.ndarray: - if nx <= 0: - raise ValueError("nx must be positive") - if x_right <= x_left: - raise ValueError("x_right must be greater than x_left") - - dx = (x_right - x_left) / float(nx) - centers = x_left + (np.arange(nx, dtype=np.float64) + 0.5) * dx - return centers - - -def brio_wu_primitive_profile( - nx: int, - x_left: float = DOMAIN_LEFT, - x_right: float = DOMAIN_RIGHT, - discontinuity_x: float = DISCONTINUITY_X, -) -> np.ndarray: - centers = cell_centers(nx, x_left=x_left, x_right=x_right) - primitive_profile = np.empty((nx, STATE_WIDTH), dtype=np.float64) - left_cells = centers < discontinuity_x - primitive_profile[left_cells] = BRIO_WU_LEFT_PRIMITIVE - primitive_profile[~left_cells] = BRIO_WU_RIGHT_PRIMITIVE - return primitive_profile - - -def brio_wu_conservative_profile( - nx: int, - x_left: float = DOMAIN_LEFT, - x_right: float = DOMAIN_RIGHT, - discontinuity_x: float = DISCONTINUITY_X, - bx: float = DEFAULT_BX, - gamma: float = DEFAULT_GAMMA, -) -> np.ndarray: - primitive_profile = brio_wu_primitive_profile( - nx, - x_left=x_left, - x_right=x_right, - discontinuity_x=discontinuity_x, - ) - return primitive_to_conservative(primitive_profile, bx=bx, gamma=gamma) - - -def evolve_brio_wu_reference_profile( - nx: int = BRIO_WU_REFERENCE_NX, - t_final: float = BRIO_WU_REFERENCE_T_FINAL, - dt: float = BRIO_WU_REFERENCE_DT, - bx: float = DEFAULT_BX, - gamma: float = DEFAULT_GAMMA, -) -> np.ndarray: - conservative_profile = brio_wu_conservative_profile(nx, bx=bx, gamma=gamma) - evolved_conservative = evolve_ssp_rk3_fixed_dt( - conservative_profile, - t_final=t_final, - dt=dt, - bx=bx, - gamma=gamma, - ) - return conservative_to_primitive(evolved_conservative, bx=bx, gamma=gamma) - - -def write_brio_wu_reference_fixtures(output_directory: str | Path) -> dict[str, Path]: - output_path = Path(output_directory) - output_path.mkdir(parents=True, exist_ok=True) - - reference_profile = evolve_brio_wu_reference_profile() - center_positions = cell_centers(reference_profile.shape[0]) - - csv_path = output_path / BRIO_WU_REFERENCE_CSV_NAME - with csv_path.open("w", newline="", encoding="utf-8") as csv_file: - writer = csv.writer(csv_file) - writer.writerow(BRIO_WU_REFERENCE_HEADER) - for position, primitive_state in zip( - center_positions, reference_profile, strict=True - ): - writer.writerow( - [ - f"{float(position):.17g}", - f"{float(primitive_state[0]):.17g}", - f"{float(primitive_state[1]):.17g}", - f"{float(primitive_state[2]):.17g}", - f"{float(primitive_state[3]):.17g}", - f"{float(primitive_state[4]):.17g}", - f"{float(primitive_state[5]):.17g}", - f"{float(primitive_state[6]):.17g}", - ] - ) - - tolerance_template = {variable: 0.0 for variable in BRIO_WU_SCORING_VARIABLES} - metadata = { - "name": "brio_wu", - "domain": [DOMAIN_LEFT, DOMAIN_RIGHT], - "discontinuity_x": DISCONTINUITY_X, - "gamma": DEFAULT_GAMMA, - "bx": DEFAULT_BX, - "nx": reference_profile.shape[0], - "t_final": BRIO_WU_REFERENCE_T_FINAL, - "dt": BRIO_WU_REFERENCE_DT, - "schema": list(BRIO_WU_REFERENCE_HEADER), - "scored_variables": list(BRIO_WU_SCORING_VARIABLES), - "interior_cell_window": { - "exclude_edge_adjacents_per_side": BRIO_WU_INNER_WINDOW_EXCLUDE, - }, - "abs_l1": tolerance_template, - "abs_linf": tolerance_template.copy(), - "reference_csv": BRIO_WU_REFERENCE_CSV_NAME, - } - - json_path = output_path / BRIO_WU_FIXTURE_JSON_NAME - with json_path.open("w", encoding="utf-8") as json_file: - json.dump(metadata, json_file, indent=2, sort_keys=True) - json_file.write("\n") - - return {"csv": csv_path, "json": json_path} - - -def fill_zero_gradient_ghost_cells( - cell_state: np.ndarray, - ghost_width: int = DEFAULT_GHOST_WIDTH, -) -> np.ndarray: - if ghost_width < 0: - raise ValueError("ghost_width must be non-negative") - - interior_state = _require_state_width(cell_state, name="cell_state") - if interior_state.ndim != 2: - raise ValueError("cell_state must be a 2D array with shape (nx, 7)") - if interior_state.shape[0] == 0: - raise ValueError("cell_state must contain at least one cell") - - padded_width = interior_state.shape[0] + 2 * ghost_width - padded_state = np.empty((padded_width, STATE_WIDTH), dtype=np.float64) - padded_state[ghost_width : ghost_width + interior_state.shape[0]] = interior_state - padded_state[:ghost_width] = interior_state[0] - padded_state[ghost_width + interior_state.shape[0] :] = interior_state[-1] - return padded_state - - -def _minmod3( - first_slope: np.ndarray, second_slope: np.ndarray, third_slope: np.ndarray -) -> np.ndarray: - same_sign = (first_slope * second_slope > 0.0) & (first_slope * third_slope > 0.0) - limited = np.sign(first_slope) * np.minimum( - np.minimum(np.abs(first_slope), np.abs(second_slope)), np.abs(third_slope) - ) - return np.where(same_sign, limited, 0.0) - - -def mc2_slopes(primitive_cells: np.ndarray) -> np.ndarray: - primitive = _require_state_width(primitive_cells, name="primitive_cells") - if primitive.ndim != 2: - raise ValueError("primitive_cells must be a 2D array with shape (n, 7)") - if primitive.shape[0] < 3: - raise ValueError("primitive_cells must contain at least three cells") - - slopes = np.zeros_like(primitive, dtype=np.float64) - left_difference = primitive[1:-1] - primitive[:-2] - right_difference = primitive[2:] - primitive[1:-1] - centered_difference = 0.5 * (primitive[2:] - primitive[:-2]) - slopes[1:-1] = _minmod3( - 2.0 * left_difference, - centered_difference, - 2.0 * right_difference, - ) - return slopes - - -def reconstruct_mc2_interfaces( - primitive_cells: np.ndarray, -) -> tuple[np.ndarray, np.ndarray]: - primitive = _require_state_width(primitive_cells, name="primitive_cells") - if primitive.ndim != 2: - raise ValueError("primitive_cells must be a 2D array with shape (n, 7)") - - slopes = mc2_slopes(primitive) - left_states = primitive[:-1] + 0.5 * slopes[:-1] - right_states = primitive[1:] - 0.5 * slopes[1:] - return left_states, right_states - - -def _physical_flux_from_primitive( - primitive_state: np.ndarray, - bx: float, - gamma: float, -) -> np.ndarray: - density = float(primitive_state[0]) - velocity_x = float(primitive_state[1]) - velocity_y = float(primitive_state[2]) - velocity_z = float(primitive_state[3]) - pressure = float(primitive_state[4]) - by = float(primitive_state[5]) - bz = float(primitive_state[6]) - - magnetic_pressure = 0.5 * (bx * bx + by * by + bz * bz) - total_pressure = pressure + magnetic_pressure - - momentum_x = density * velocity_x - momentum_y = density * velocity_y - momentum_z = density * velocity_z - energy = pressure / (gamma - 1.0) - energy += 0.5 * ( - momentum_x * velocity_x + momentum_y * velocity_y + momentum_z * velocity_z - ) - energy += magnetic_pressure - - return np.array( - [ - momentum_x, - momentum_x * velocity_x + total_pressure - bx * bx, - momentum_x * velocity_y - bx * by, - momentum_x * velocity_z - bx * bz, - velocity_x * (energy + total_pressure - bx * bx) - - bx * (velocity_y * by + velocity_z * bz), - by * velocity_x - bx * velocity_y, - bz * velocity_x - bx * velocity_z, - ], - dtype=np.float64, - ) - - -def _fast_magnetosonic_speed( - density: float, - pressure: float, - by: float, - bz: float, - bx: float, - gamma: float, -) -> float: - magnetic_pressure = 0.5 * (bx * bx + by * by + bz * bz) - gamma_pressure = gamma * pressure - gamma_plus_magnetic = gamma_pressure + 2.0 * magnetic_pressure - discriminant = math.sqrt( - (gamma_pressure - 2.0 * magnetic_pressure) - * (gamma_pressure - 2.0 * magnetic_pressure) - + 4.0 * gamma_pressure * (by * by + bz * bz) - ) - return math.sqrt((gamma_plus_magnetic + discriminant) * 0.5 / density) - - -def hlld_flux_from_primitive( - left_state: np.ndarray, - right_state: np.ndarray, - bx: float = DEFAULT_BX, - gamma: float = DEFAULT_GAMMA, -) -> np.ndarray: - left = _require_state_width(left_state, name="left_state") - right = _require_state_width(right_state, name="right_state") - if left.ndim != 1 or right.ndim != 1: - raise ValueError( - "left_state and right_state must be one-dimensional state vectors" - ) - - density_left = float(left[0]) - velocity_x_left = float(left[1]) - velocity_y_left = float(left[2]) - velocity_z_left = float(left[3]) - pressure_left = float(left[4]) - by_left = float(left[5]) - bz_left = float(left[6]) - - density_right = float(right[0]) - velocity_x_right = float(right[1]) - velocity_y_right = float(right[2]) - velocity_z_right = float(right[3]) - pressure_right = float(right[4]) - by_right = float(right[5]) - bz_right = float(right[6]) - - inverse_gamma_minus_one = 1.0 / (gamma - 1.0) - bx_square = bx * bx - - magnetic_pressure_left = 0.5 * (bx_square + by_left * by_left + bz_left * bz_left) - magnetic_pressure_right = 0.5 * ( - bx_square + by_right * by_right + bz_right * bz_right - ) - total_pressure_left = pressure_left + magnetic_pressure_left - total_pressure_right = pressure_right + magnetic_pressure_right - - momentum_x_left = density_left * velocity_x_left - momentum_y_left = density_left * velocity_y_left - momentum_z_left = density_left * velocity_z_left - momentum_x_right = density_right * velocity_x_right - momentum_y_right = density_right * velocity_y_right - momentum_z_right = density_right * velocity_z_right - - energy_left = ( - pressure_left * inverse_gamma_minus_one - + 0.5 - * ( - momentum_x_left * velocity_x_left - + momentum_y_left * velocity_y_left - + momentum_z_left * velocity_z_left - ) - + magnetic_pressure_left - ) - energy_right = ( - pressure_right * inverse_gamma_minus_one - + 0.5 - * ( - momentum_x_right * velocity_x_right - + momentum_y_right * velocity_y_right - + momentum_z_right * velocity_z_right - ) - + magnetic_pressure_right - ) - - left_fast_speed = _fast_magnetosonic_speed( - density_left, - pressure_left, - by_left, - bz_left, - bx, - gamma, - ) - right_fast_speed = _fast_magnetosonic_speed( - density_right, - pressure_right, - by_right, - bz_right, - bx, - gamma, - ) - - outer_left_speed = min(velocity_x_left, velocity_x_right) - max( - left_fast_speed, right_fast_speed - ) - outer_right_speed = max(velocity_x_left, velocity_x_right) + max( - left_fast_speed, right_fast_speed - ) - - left_flux = _physical_flux_from_primitive(left, bx=bx, gamma=gamma) - right_flux = _physical_flux_from_primitive(right, bx=bx, gamma=gamma) - - left_speed_gap = outer_left_speed - velocity_x_left - right_speed_gap = outer_right_speed - velocity_x_right - left_speed_factor = density_left * left_speed_gap - right_speed_factor = density_right * right_speed_gap - denominator = right_speed_factor - left_speed_factor - contact_speed = ( - right_speed_factor * velocity_x_right - - left_speed_factor * velocity_x_left - - total_pressure_right - + total_pressure_left - ) / denominator - left_contact_gap = outer_left_speed - contact_speed - right_contact_gap = outer_right_speed - contact_speed - star_total_pressure = ( - right_speed_factor * total_pressure_left - - left_speed_factor * total_pressure_right - + left_speed_factor * right_speed_factor * (velocity_x_right - velocity_x_left) - ) / denominator - - def build_star_state( - density: float, - velocity_x: float, - velocity_y: float, - velocity_z: float, - by: float, - bz: float, - total_pressure: float, - energy: float, - speed_gap: float, - contact_gap: float, - ) -> tuple[np.ndarray, float, float, float]: - epsilon = 1.0e-40 - - gap_times_density = density * speed_gap - raw_transverse_denom = gap_times_density * contact_gap - bx_square - denominator_sign = _sign_unit(abs(raw_transverse_denom) - epsilon) - positive_branch = max(0.0, denominator_sign) - negative_branch = min(0.0, denominator_sign) - inverse_transverse_denom = 1.0 / (raw_transverse_denom + negative_branch) - inverse_contact_gap = 1.0 / contact_gap - - transverse_velocity_scale = ( - bx * (speed_gap - contact_gap) * inverse_transverse_denom - ) - density_star = ( - positive_branch * (gap_times_density * inverse_contact_gap) - - negative_branch * density - ) - velocity_x_star = positive_branch * contact_speed - negative_branch * velocity_x - momentum_x_star = density_star * velocity_x_star - velocity_y_star = ( - positive_branch * (velocity_y - by * transverse_velocity_scale) - - negative_branch * velocity_y - ) - momentum_y_star = density_star * velocity_y_star - velocity_z_star = ( - positive_branch * (velocity_z - bz * transverse_velocity_scale) - - negative_branch * velocity_z - ) - momentum_z_star = density_star * velocity_z_star - by_scale = ( - gap_times_density * speed_gap - bx_square - ) * inverse_transverse_denom - by_star = positive_branch * (by * by_scale) - negative_branch * by - bz_star = positive_branch * (bz * by_scale) - negative_branch * bz - velocity_dot_b_star = ( - velocity_x_star * bx + velocity_y_star * by_star + velocity_z_star * bz_star - ) - velocity_dot_b_original = velocity_x * bx + velocity_y * by + velocity_z * bz - starred_energy = ( - positive_branch - * ( - ( - speed_gap * energy - - total_pressure * velocity_x - + star_total_pressure * contact_speed - + bx * (velocity_dot_b_original - velocity_dot_b_star) - ) - * inverse_contact_gap - ) - - negative_branch * energy - ) - star_state = np.array( - [ - density_star, - momentum_x_star, - momentum_y_star, - momentum_z_star, - starred_energy, - by_star, - bz_star, - ], - dtype=np.float64, - ) - return star_state, density_star, by_star, bz_star - - left_star_state, left_star_density, left_star_by, left_star_bz = build_star_state( - density_left, - velocity_x_left, - velocity_y_left, - velocity_z_left, - by_left, - bz_left, - total_pressure_left, - energy_left, - left_speed_gap, - left_contact_gap, - ) - right_star_state, right_star_density, right_star_by, right_star_bz = ( - build_star_state( - density_right, - velocity_x_right, - velocity_y_right, - velocity_z_right, - by_right, - bz_right, - total_pressure_right, - energy_right, - right_speed_gap, - right_contact_gap, - ) - ) - - left_star_velocity = left_star_state[1] / left_star_density - left_star_transverse_velocity_y = left_star_state[2] / left_star_density - left_star_transverse_velocity_z = left_star_state[3] / left_star_density - right_star_velocity = right_star_state[1] / right_star_density - right_star_transverse_velocity_y = right_star_state[2] / right_star_density - right_star_transverse_velocity_z = right_star_state[3] / right_star_density - - left_star_speed = contact_speed - abs(bx) / math.sqrt(left_star_density) - right_star_speed = contact_speed + abs(bx) / math.sqrt(right_star_density) - bx_sign = _sign_unit(bx) - bx_branch = _sign_unit(abs(bx) - 1.0e-40) - use_rotational_branch = max(0.0, bx_branch) - inverse_density_sum = use_rotational_branch / ( - math.sqrt(left_star_density) + math.sqrt(right_star_density) - ) - - shared_transverse_velocity_y = inverse_density_sum * ( - math.sqrt(left_star_density) * left_star_transverse_velocity_y - + math.sqrt(right_star_density) * right_star_transverse_velocity_y - + bx_sign * (right_star_by - left_star_by) - ) - shared_transverse_velocity_z = inverse_density_sum * ( - math.sqrt(left_star_density) * left_star_transverse_velocity_z - + math.sqrt(right_star_density) * right_star_transverse_velocity_z - + bx_sign * (right_star_bz - left_star_bz) - ) - shared_by = inverse_density_sum * ( - math.sqrt(left_star_density) * right_star_by - + math.sqrt(right_star_density) * left_star_by - + bx_sign - * math.sqrt(left_star_density) - * math.sqrt(right_star_density) - * (right_star_transverse_velocity_y - left_star_transverse_velocity_y) - ) - shared_bz = inverse_density_sum * ( - math.sqrt(left_star_density) * right_star_bz - + math.sqrt(right_star_density) * left_star_bz - + bx_sign - * math.sqrt(left_star_density) - * math.sqrt(right_star_density) - * (right_star_transverse_velocity_z - left_star_transverse_velocity_z) - ) - - left_double_star_state = np.array( - [ - left_star_density, - left_star_density * contact_speed, - left_star_density * shared_transverse_velocity_y, - left_star_density * shared_transverse_velocity_z, - left_star_state[4] - - math.sqrt(left_star_density) - * bx_sign - * ( - left_star_velocity * bx - + left_star_transverse_velocity_y * left_star_by - + left_star_transverse_velocity_z * left_star_bz - - ( - contact_speed * bx - + shared_transverse_velocity_y * shared_by - + shared_transverse_velocity_z * shared_bz - ) - ) - * use_rotational_branch, - shared_by, - shared_bz, - ], - dtype=np.float64, - ) - right_double_star_state = np.array( - [ - right_star_density, - right_star_density * contact_speed, - right_star_density * shared_transverse_velocity_y, - right_star_density * shared_transverse_velocity_z, - right_star_state[4] - + math.sqrt(right_star_density) - * bx_sign - * ( - right_star_velocity * bx - + right_star_transverse_velocity_y * right_star_by - + right_star_transverse_velocity_z * right_star_bz - - ( - contact_speed * bx - + shared_transverse_velocity_y * shared_by - + shared_transverse_velocity_z * shared_bz - ) - ) - * use_rotational_branch, - shared_by, - shared_bz, - ], - dtype=np.float64, - ) - - left_state_conservative = np.array( - [ - density_left, - momentum_x_left, - momentum_y_left, - momentum_z_left, - energy_left, - by_left, - bz_left, - ], - dtype=np.float64, - ) - right_state_conservative = np.array( - [ - density_right, - momentum_x_right, - momentum_y_right, - momentum_z_right, - energy_right, - by_right, - bz_right, - ], - dtype=np.float64, - ) - left_star_flux = left_flux + outer_left_speed * ( - left_star_state - left_state_conservative - ) - right_star_flux = right_flux + outer_right_speed * ( - right_star_state - right_state_conservative - ) - left_double_star_flux = left_star_flux + left_star_speed * ( - left_double_star_state - left_star_state - ) - right_double_star_flux = right_star_flux + right_star_speed * ( - right_double_star_state - right_star_state - ) - - left_wave_branch = outer_left_speed <= 0.0 <= left_star_speed - left_double_star_branch = left_star_speed <= 0.0 <= contact_speed - right_double_star_branch = contact_speed <= 0.0 <= right_star_speed - right_wave_branch = right_star_speed <= 0.0 <= outer_right_speed - - if 0.0 <= outer_left_speed: - return left_flux - if left_wave_branch: - return left_star_flux - if left_double_star_branch: - return left_double_star_flux - if right_double_star_branch: - return right_double_star_flux - if right_wave_branch: - return right_star_flux - return right_flux - - -def hlld_flux_from_conservative( - left_state: np.ndarray, - right_state: np.ndarray, - bx: float = DEFAULT_BX, - gamma: float = DEFAULT_GAMMA, -) -> np.ndarray: - left_primitive = conservative_to_primitive(left_state, bx=bx, gamma=gamma) - right_primitive = conservative_to_primitive(right_state, bx=bx, gamma=gamma) - return hlld_flux_from_primitive(left_primitive, right_primitive, bx=bx, gamma=gamma) - - -def compute_semidiscrete_rhs( - conservative_cells: np.ndarray, - dx: float | None = None, - bx: float = DEFAULT_BX, - gamma: float = DEFAULT_GAMMA, - ghost_width: int = DEFAULT_GHOST_WIDTH, -) -> np.ndarray: - if ghost_width < 2: - raise ValueError("ghost_width must be at least 2 for MC2 reconstruction") - - interior_conservative = _require_state_width( - conservative_cells, name="conservative_cells" - ) - if interior_conservative.ndim != 2: - raise ValueError("conservative_cells must be a 2D array with shape (nx, 7)") - if interior_conservative.shape[0] == 0: - raise ValueError("conservative_cells must contain at least one cell") - - if dx is None: - dx = (DOMAIN_RIGHT - DOMAIN_LEFT) / float(interior_conservative.shape[0]) - if dx <= 0.0: - raise ValueError("dx must be positive") - - padded_conservative = fill_zero_gradient_ghost_cells( - interior_conservative, - ghost_width=ghost_width, - ) - padded_primitive = conservative_to_primitive( - padded_conservative, bx=bx, gamma=gamma - ) - left_interface_states, right_interface_states = reconstruct_mc2_interfaces( - padded_primitive - ) - - interface_fluxes = np.empty_like(left_interface_states) - for interface_index in range(interface_fluxes.shape[0]): - interface_fluxes[interface_index] = hlld_flux_from_primitive( - left_interface_states[interface_index], - right_interface_states[interface_index], - bx=bx, - gamma=gamma, - ) - - cell_count = interior_conservative.shape[0] - rhs = ( - -( - interface_fluxes[ghost_width : ghost_width + cell_count] - - interface_fluxes[ghost_width - 1 : ghost_width - 1 + cell_count] - ) - / dx - ) - return rhs - - -def brio_wu_semidiscrete_rhs( - nx: int, - bx: float = DEFAULT_BX, - gamma: float = DEFAULT_GAMMA, -) -> np.ndarray: - conservative_profile = brio_wu_conservative_profile(nx, bx=bx, gamma=gamma) - dx = (DOMAIN_RIGHT - DOMAIN_LEFT) / float(nx) - return compute_semidiscrete_rhs(conservative_profile, dx=dx, bx=bx, gamma=gamma) - - -def ssp_rk3_step( - conservative_cells: np.ndarray, - dt: float, - dx: float | None = None, - bx: float = DEFAULT_BX, - gamma: float = DEFAULT_GAMMA, - ghost_width: int = DEFAULT_GHOST_WIDTH, -) -> np.ndarray: - interior_conservative = _require_state_width( - conservative_cells, name="conservative_cells" - ) - if interior_conservative.ndim != 2: - raise ValueError("conservative_cells must be a 2D array with shape (nx, 7)") - if interior_conservative.shape[0] == 0: - raise ValueError("conservative_cells must contain at least one cell") - if dt <= 0.0: - raise ValueError("dt must be positive") - - first_rhs = compute_semidiscrete_rhs( - interior_conservative, - dx=dx, - bx=bx, - gamma=gamma, - ghost_width=ghost_width, - ) - first_stage = interior_conservative + dt * first_rhs - - second_rhs = compute_semidiscrete_rhs( - first_stage, - dx=dx, - bx=bx, - gamma=gamma, - ghost_width=ghost_width, - ) - second_stage = 0.75 * interior_conservative + 0.25 * (first_stage + dt * second_rhs) - - third_rhs = compute_semidiscrete_rhs( - second_stage, - dx=dx, - bx=bx, - gamma=gamma, - ghost_width=ghost_width, - ) - next_state = (1.0 / 3.0) * interior_conservative + (2.0 / 3.0) * ( - second_stage + dt * third_rhs - ) - return next_state - - -def evolve_ssp_rk3_fixed_dt( - conservative_cells: np.ndarray, - t_final: float, - dt: float, - dx: float | None = None, - bx: float = DEFAULT_BX, - gamma: float = DEFAULT_GAMMA, - ghost_width: int = DEFAULT_GHOST_WIDTH, -) -> np.ndarray: - interior_conservative = _require_state_width( - conservative_cells, name="conservative_cells" - ) - if interior_conservative.ndim != 2: - raise ValueError("conservative_cells must be a 2D array with shape (nx, 7)") - if interior_conservative.shape[0] == 0: - raise ValueError("conservative_cells must contain at least one cell") - if t_final < 0.0: - raise ValueError("t_final must be non-negative") - if dt <= 0.0: - raise ValueError("dt must be positive") - - evolved_state = np.array(interior_conservative, dtype=np.float64, copy=True) - elapsed_time = 0.0 - while elapsed_time < t_final: - remaining_time = t_final - elapsed_time - step_dt = min(dt, remaining_time) - evolved_state = ssp_rk3_step( - evolved_state, - step_dt, - dx=dx, - bx=bx, - gamma=gamma, - ghost_width=ghost_width, - ) - elapsed_time = t_final if step_dt < dt else elapsed_time + step_dt - return evolved_state diff --git a/benchmarks/magnetohydrodynamics/shared/eval/mhd1d_shared.py b/benchmarks/magnetohydrodynamics/shared/eval/mhd1d_shared.py deleted file mode 100644 index ad1df11..0000000 --- a/benchmarks/magnetohydrodynamics/shared/eval/mhd1d_shared.py +++ /dev/null @@ -1,303 +0,0 @@ -"""Shared hidden-eval helpers for the canonical 1D Brio-Wu benchmark.""" - -from __future__ import annotations - -import csv -import json -from dataclasses import dataclass -from pathlib import Path -from typing import Mapping, Sequence - - -CSV_HEADER = ("x", "rho", "u", "v", "w", "p", "by", "bz") -SCORING_VARIABLES = ("rho", "u", "p", "by") -DEFAULT_EXCLUDE_EDGE_ADJACENTS_PER_SIDE = 2 -DEFAULT_FIXTURE_NAME = "brio_wu_fixture.json" - - -@dataclass(frozen=True) -class MHD1DCSVProfile: - """Parsed CSV profile with schema validation already applied.""" - - csv_path: Path - header: tuple[str, ...] - rows: list[dict[str, float]] - - -@dataclass(frozen=True) -class MHD1DFixture: - """Loaded Brio-Wu fixture metadata plus the reference CSV profile.""" - - fixture_path: Path - reference_csv_path: Path - schema: tuple[str, ...] - scored_variables: tuple[str, ...] - abs_l1: dict[str, float] - abs_linf: dict[str, float] - interior_cell_window_exclude_edge_adjacents_per_side: int - metadata: dict[str, object] - reference_profile: MHD1DCSVProfile - - -@dataclass(frozen=True) -class VariableComparison: - """Per-variable error summary for a solver profile.""" - - variable: str - l1: float - linf: float - abs_l1_tolerance: float - abs_linf_tolerance: float - - @property - def passed(self) -> bool: - return self.l1 <= self.abs_l1_tolerance and self.linf <= self.abs_linf_tolerance - - -@dataclass(frozen=True) -class MHD1DComparison: - """Comparison outcome for a solver CSV against the Brio-Wu fixture.""" - - solver_csv_path: Path - fixture: MHD1DFixture - compared_row_start: int - compared_row_stop: int - compared_row_count: int - variable_comparisons: dict[str, VariableComparison] - - @property - def passed(self) -> bool: - return all(result.passed for result in self.variable_comparisons.values()) - - -def _default_fixture_path() -> Path: - return Path(__file__).resolve().parent / "fixtures" / "mhd1d" / DEFAULT_FIXTURE_NAME - - -def _require_exact_header(header: Sequence[str], *, source: Path) -> None: - actual = tuple(header) - if actual != CSV_HEADER: - raise ValueError( - f"{source} must use the exact CSV header {','.join(CSV_HEADER)}" - ) - - -def _parse_float_cell( - raw_value: str, *, source: Path, row_number: int, column_name: str -) -> float: - try: - return float(raw_value) - except ValueError as exc: - raise ValueError( - f"{source} row {row_number} column {column_name} must be a floating-point value" - ) from exc - - -def load_mhd1d_csv_profile(csv_path: str | Path) -> MHD1DCSVProfile: - """Load and validate a Brio-Wu-style CSV profile.""" - - path = Path(csv_path) - with path.open("r", encoding="utf-8", newline="") as csv_file: - reader = csv.reader(csv_file) - try: - header = next(reader) - except StopIteration as exc: - raise ValueError(f"{path} is empty") from exc - - _require_exact_header(header, source=path) - - rows: list[dict[str, float]] = [] - for row_number, raw_row in enumerate(reader, start=2): - if len(raw_row) != len(CSV_HEADER): - raise ValueError( - f"{path} row {row_number} must have exactly {len(CSV_HEADER)} columns" - ) - parsed_row: dict[str, float] = {} - for column_name, raw_value in zip(CSV_HEADER, raw_row, strict=True): - parsed_row[column_name] = _parse_float_cell( - raw_value, - source=path, - row_number=row_number, - column_name=column_name, - ) - rows.append(parsed_row) - - return MHD1DCSVProfile(csv_path=path, header=tuple(header), rows=rows) - - -def _validate_fixture_metadata( - fixture_payload: Mapping[str, object], *, source: Path -) -> None: - schema = fixture_payload.get("schema") - if tuple(schema or ()) != CSV_HEADER: - raise ValueError( - f"{source} must declare the exact schema {','.join(CSV_HEADER)}" - ) - - scored_variables = fixture_payload.get("scored_variables") - if tuple(scored_variables or ()) != SCORING_VARIABLES: - raise ValueError( - f"{source} must declare scored_variables {','.join(SCORING_VARIABLES)}" - ) - - window = fixture_payload.get("interior_cell_window") - if not isinstance(window, Mapping): - raise ValueError(f"{source} must define interior_cell_window metadata") - - exclude = window.get("exclude_edge_adjacents_per_side") - if exclude != DEFAULT_EXCLUDE_EDGE_ADJACENTS_PER_SIDE: - raise ValueError( - f"{source} must exclude {DEFAULT_EXCLUDE_EDGE_ADJACENTS_PER_SIDE} edge-adjacent cells per side" - ) - - for key_name in ("abs_l1", "abs_linf"): - tolerances = fixture_payload.get(key_name) - if not isinstance(tolerances, Mapping): - raise ValueError(f"{source} must define {key_name} tolerances") - for variable_name in SCORING_VARIABLES: - if variable_name not in tolerances: - raise ValueError(f"{source} must define {key_name}.{variable_name}") - - -def load_mhd1d_fixture(fixture_path: str | Path | None = None) -> MHD1DFixture: - """Load the canonical Brio-Wu hidden fixture and its reference CSV profile.""" - - path = Path(fixture_path) if fixture_path is not None else _default_fixture_path() - with path.open("r", encoding="utf-8") as fixture_file: - payload = json.load(fixture_file) - - if not isinstance(payload, dict): - raise ValueError(f"{path} must contain a JSON object") - - _validate_fixture_metadata(payload, source=path) - - reference_csv_name = payload.get("reference_csv") - if not isinstance(reference_csv_name, str) or not reference_csv_name: - raise ValueError(f"{path} must declare a reference_csv file name") - - reference_csv_path = (path.parent / reference_csv_name).resolve() - reference_profile = load_mhd1d_csv_profile(reference_csv_path) - - return MHD1DFixture( - fixture_path=path, - reference_csv_path=reference_csv_path, - schema=tuple(payload["schema"]), - scored_variables=tuple(payload["scored_variables"]), - abs_l1={ - variable: float(value) for variable, value in payload["abs_l1"].items() - }, - abs_linf={ - variable: float(value) for variable, value in payload["abs_linf"].items() - }, - interior_cell_window_exclude_edge_adjacents_per_side=int( - payload["interior_cell_window"]["exclude_edge_adjacents_per_side"] - ), - metadata=payload, - reference_profile=reference_profile, - ) - - -def interior_cell_window_bounds( - row_count: int, - exclude_edge_adjacents_per_side: int = DEFAULT_EXCLUDE_EDGE_ADJACENTS_PER_SIDE, -) -> tuple[int, int]: - """Return the inclusive-start/exclusive-stop comparison window for a profile.""" - - if row_count <= 0: - raise ValueError("row_count must be positive") - if exclude_edge_adjacents_per_side < 0: - raise ValueError("exclude_edge_adjacents_per_side must be non-negative") - if row_count <= 2 * exclude_edge_adjacents_per_side: - raise ValueError("row_count is too small for the requested interior window") - return exclude_edge_adjacents_per_side, row_count - exclude_edge_adjacents_per_side - - -def _compare_variable( - solver_rows: Sequence[Mapping[str, float]], - reference_rows: Sequence[Mapping[str, float]], - variable_name: str, - row_start: int, - row_stop: int, - *, - abs_l1_tolerance: float, - abs_linf_tolerance: float, -) -> VariableComparison: - l1_error = 0.0 - linf_error = 0.0 - for row_index in range(row_start, row_stop): - delta = abs( - float(solver_rows[row_index][variable_name]) - - float(reference_rows[row_index][variable_name]) - ) - l1_error += delta - if delta > linf_error: - linf_error = delta - - return VariableComparison( - variable=variable_name, - l1=l1_error, - linf=linf_error, - abs_l1_tolerance=abs_l1_tolerance, - abs_linf_tolerance=abs_linf_tolerance, - ) - - -def compare_mhd1d_csv_against_fixture( - solver_csv_path: str | Path, - fixture: MHD1DFixture | None = None, -) -> MHD1DComparison: - """Compare a solver-produced CSV profile against the canonical Brio-Wu fixture.""" - - loaded_fixture = fixture if fixture is not None else load_mhd1d_fixture() - solver_profile = load_mhd1d_csv_profile(solver_csv_path) - - if solver_profile.header != loaded_fixture.schema: - raise ValueError("solver CSV header does not match the fixture schema") - - reference_rows = loaded_fixture.reference_profile.rows - solver_rows = solver_profile.rows - if len(solver_rows) != len(reference_rows): - raise ValueError( - "solver CSV row count does not match the fixture reference profile" - ) - - row_start, row_stop = interior_cell_window_bounds( - len(reference_rows), - loaded_fixture.interior_cell_window_exclude_edge_adjacents_per_side, - ) - - variable_comparisons: dict[str, VariableComparison] = {} - for variable_name in loaded_fixture.scored_variables: - variable_comparisons[variable_name] = _compare_variable( - solver_rows, - reference_rows, - variable_name, - row_start, - row_stop, - abs_l1_tolerance=loaded_fixture.abs_l1[variable_name], - abs_linf_tolerance=loaded_fixture.abs_linf[variable_name], - ) - - return MHD1DComparison( - solver_csv_path=solver_profile.csv_path, - fixture=loaded_fixture, - compared_row_start=row_start, - compared_row_stop=row_stop, - compared_row_count=row_stop - row_start, - variable_comparisons=variable_comparisons, - ) - - -__all__ = [ - "CSV_HEADER", - "SCORING_VARIABLES", - "DEFAULT_EXCLUDE_EDGE_ADJACENTS_PER_SIDE", - "MHD1DCSVProfile", - "MHD1DFixture", - "VariableComparison", - "MHD1DComparison", - "compare_mhd1d_csv_against_fixture", - "interior_cell_window_bounds", - "load_mhd1d_csv_profile", - "load_mhd1d_fixture", -] diff --git a/benchmarks/magnetohydrodynamics/shared/src/full_main.cpp b/benchmarks/magnetohydrodynamics/shared/src/full_main.cpp new file mode 100644 index 0000000..5876fad --- /dev/null +++ b/benchmarks/magnetohydrodynamics/shared/src/full_main.cpp @@ -0,0 +1,74 @@ +#include "full_mhd1d.hpp" + +#include +#include +#include +#include + +constexpr int Nx = 100; +constexpr double Gamma = 2.0; +constexpr double Bx = 0.75; +constexpr mhd1d::StateVector LeftPrimitive{ + 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, +}; +constexpr mhd1d::StateVector RightPrimitive{ + 0.125, 0.0, 0.0, 0.0, 0.1, -1.0, 0.0, +}; + +int parse_nx(int argc, char** argv) +{ + if (argc <= 1) { + return Nx; + } + + char* end = nullptr; + const long parsed = std::strtol(argv[1], &end, 10); + if (end == argv[1] || *end != '\0' || parsed <= 0) { + throw std::runtime_error("usage: solver [nx]"); + } + return static_cast(parsed); +} + +mhd1d::SolverWorkspace initialize(int nx, double gamma, double bx, + const mhd1d::StateVector& left_state, + const mhd1d::StateVector& right_state) +{ + mhd1d::SolverWorkspace workspace(nx, gamma, bx); + + for (int ix = workspace.Lbx; ix <= workspace.Ubx; ++ix) { + const mhd1d::StateVector& state = (workspace.x(ix) < 0.5) ? left_state : right_state; + for (int component = 0; component < mhd1d::N_Component; ++component) { + workspace.up(ix, component) = state[component]; + } + } + + mhd1d::set_boundary(workspace.up, workspace.up, workspace.Lbx, workspace.Ubx); + mhd1d::primitive_profile_to_conservative(workspace.up, workspace.uc, bx, gamma); + + return workspace; +} + +void write_csv(const mhd1d::SolverWorkspace& workspace, std::ostream& os) +{ + os << std::setprecision(17); + for (int ix = workspace.Lbx; ix <= workspace.Ubx; ++ix) { + os << workspace.x(ix) << ',' << workspace.up(ix, 0) << ',' << workspace.up(ix, 1) << ',' + << workspace.up(ix, 2) << ',' << workspace.up(ix, 3) << ',' << workspace.up(ix, 4) << ',' + << workspace.up(ix, 5) << ',' << workspace.up(ix, 6) << '\n'; + } +} + +int main(int argc, char** argv) +{ + const int nx = parse_nx(argc, argv); + const double delt = 5.0e-4; + const double tmax = 0.1; + + auto workspace = initialize(nx, Gamma, Bx, LeftPrimitive, RightPrimitive); + + mhd1d::evolve_ssp_rk3(workspace, delt, tmax); + + write_csv(workspace, std::cout); + + return 0; +} diff --git a/benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.cpp b/benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.cpp new file mode 100644 index 0000000..f2b7660 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.cpp @@ -0,0 +1,250 @@ +#include "full_mhd1d.hpp" +#include "hlld.hpp" + +#include +#include +#include +#include + +namespace mhd1d +{ + +namespace +{ + +double sign(const double x) +{ + return copysign(1.0, x); +} + +double mc2(double a, double b) +{ + return 0.5 * (sign(a) + sign(b)) * + std::min({2.0 * std::abs(a), 2.0 * std::abs(b), 0.5 * std::abs(a + b)}); +} + +StateVector row_to_state(ArrayView2D cells, int row) +{ + StateVector state{}; + for (int component = 0; component < N_Component; ++component) { + state[component] = cells(row, component); + } + return state; +} + +void state_to_row(const StateVector& state, ArrayView2D cells, int row) +{ + for (int component = 0; component < N_Component; ++component) { + cells(row, component) = state[component]; + } +} + +void copy_cells(ArrayView2D source, ArrayView2D destination) +{ + const int nx = source.extent(0); + for (int ix = 0; ix < nx; ++ix) { + for (int component = 0; component < N_Component; ++component) { + destination(ix, component) = source(ix, component); + } + } +} + +void convert_conservative_to_primitive(ArrayView2D conservative, ArrayView2D primitive, double bx, + double gamma) +{ + const int ix_min = 0; + const int ix_max = conservative.extent(0) - 1; + + for (int ix = ix_min; ix <= ix_max; ++ix) { + const StateVector up = conservative_to_primitive(row_to_state(conservative, ix), bx, gamma); + state_to_row(up, primitive, ix); + } +} + +} // namespace + +StateVector primitive_to_conservative(const StateVector& primitive, double bx, double gamma) +{ + const double rho = primitive[0]; + const double u = primitive[1]; + const double v = primitive[2]; + const double w = primitive[3]; + const double pressure = primitive[4]; + const double by = primitive[5]; + const double bz = primitive[6]; + + const double kinetic_energy = 0.5 * rho * (u * u + v * v + w * w); + const double magnetic_energy = 0.5 * (bx * bx + by * by + bz * bz); + + return StateVector{ + rho, rho * u, rho * v, rho * w, pressure / (gamma - 1.0) + kinetic_energy + magnetic_energy, + by, bz, + }; +} + +StateVector conservative_to_primitive(const StateVector& conservative, double bx, double gamma) +{ + const double rho = conservative[0]; + if (rho <= 0.0) { + throw std::runtime_error("density must be positive"); + } + + const double u = conservative[1] / rho; + const double v = conservative[2] / rho; + const double w = conservative[3] / rho; + const double by = conservative[5]; + const double bz = conservative[6]; + + const double kinetic_energy = 0.5 * rho * (u * u + v * v + w * w); + const double magnetic_energy = 0.5 * (bx * bx + by * by + bz * bz); + const double pressure = (gamma - 1.0) * (conservative[4] - kinetic_energy - magnetic_energy); + + return StateVector{rho, u, v, w, pressure, by, bz}; +} + +void primitive_profile_to_conservative(ArrayView2D primitive, ArrayView2D conservative, double bx, + double gamma) +{ + const int ix_min = 0; + const int ix_max = primitive.extent(0) - 1; + + for (int ix = ix_min; ix <= ix_max; ++ix) { + const StateVector uc = primitive_to_conservative(row_to_state(primitive, ix), bx, gamma); + state_to_row(uc, conservative, ix); + } +} + +void reconstruct_mc2(SolverWorkspace& workspace) +{ + const ArrayView2D up = workspace.up; + const ArrayView2D up_l = workspace.up_l; + const ArrayView2D up_r = workspace.up_r; + + const int lbx = workspace.Lbx; + const int ubx = workspace.Ubx; + for (int ix = lbx; ix <= ubx; ++ix) { + for (int component = 0; component < N_Component; ++component) { + const double slope_l = up(ix, component) - up(ix - 1, component); + const double slope_r = up(ix + 1, component) - up(ix, component); + const double slope = mc2(slope_l, slope_r); + up_l(ix, component) = up(ix, component) + 0.5 * slope; + up_r(ix, component) = up(ix, component) - 0.5 * slope; + } + } + + set_boundary_lb(up_l, up_r, lbx); + set_boundary_ub(up_r, up_l, ubx); +} + +void compute_flux_hlld(SolverWorkspace& workspace, double bx, double gamma) +{ + const ArrayView2D up_l = workspace.up_l; + const ArrayView2D up_r = workspace.up_r; + const ArrayView2D flux = workspace.flux; + + const int lbx = workspace.Lbx; + const int ubx = workspace.Ubx; + for (int ix = lbx - 1; ix <= ubx + 1; ++ix) { + const StateVector flux_hlld = + ::hlld_flux_from_primitive(row_to_state(up_l, ix), row_to_state(up_r, ix + 1), bx, gamma); + state_to_row(flux_hlld, flux, ix); + } +} + +void set_boundary_lb(ArrayView2D dst, ArrayView2D src, int lbx) +{ + const int ix_min = 0; + + for (int ix = ix_min; ix < lbx; ++ix) { + for (int component = 0; component < N_Component; ++component) { + dst(ix, component) = src(lbx, component); + } + } +} + +void set_boundary_ub(ArrayView2D dst, ArrayView2D src, int ubx) +{ + const int ix_max = dst.extent(0) - 1; + + for (int ix = ubx + 1; ix <= ix_max; ++ix) { + for (int component = 0; component < N_Component; ++component) { + dst(ix, component) = src(ubx, component); + } + } +} + +void set_boundary(ArrayView2D dst, ArrayView2D src, int lbx, int ubx) +{ + set_boundary_lb(dst, src, lbx); + set_boundary_ub(dst, src, ubx); +} + +void compute_rhs(SolverWorkspace& workspace) +{ + const ArrayView2D uc = workspace.uc; + const ArrayView2D up = workspace.up; + const ArrayView2D flux = workspace.flux; + const ArrayView2D rhs = workspace.rhs; + + set_boundary(uc, uc, workspace.Lbx, workspace.Ubx); + convert_conservative_to_primitive(uc, up, workspace.bx, workspace.gamma); + set_boundary(up, up, workspace.Lbx, workspace.Ubx); + reconstruct_mc2(workspace); + compute_flux_hlld(workspace, workspace.bx, workspace.gamma); + + const int lbx = workspace.Lbx; + const int ubx = workspace.Ubx; + for (int ix = lbx; ix <= ubx; ++ix) { + for (int component = 0; component < N_Component; ++component) { + rhs(ix, component) = -(flux(ix, component) - flux(ix - 1, component)) / workspace.dx; + } + } +} + +void push_ssp_rk3(SolverWorkspace& workspace, double dt) +{ + constexpr double coeffs[3][3] = { + {1.0, 0.0, 1.0}, + {3.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0}, + {1.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0}, + }; + + const ArrayView2D prev = workspace.prev; + const ArrayView2D rhs = workspace.rhs; + + copy_cells(workspace.uc, prev); + + for (int substep = 0; substep < 3; ++substep) { + compute_rhs(workspace); + + const double a = coeffs[substep][0]; + const double b = coeffs[substep][1]; + const double c = coeffs[substep][2]; + + const int lbx = workspace.Lbx; + const int ubx = workspace.Ubx; + for (int ix = lbx; ix <= ubx; ++ix) { + for (int component = 0; component < N_Component; ++component) { + workspace.uc(ix, component) = + a * prev(ix, component) + b * workspace.uc(ix, component) + c * dt * rhs(ix, component); + } + } + + set_boundary(workspace.uc, workspace.uc, workspace.Lbx, workspace.Ubx); + convert_conservative_to_primitive(workspace.uc, workspace.up, workspace.bx, workspace.gamma); + set_boundary(workspace.up, workspace.up, workspace.Lbx, workspace.Ubx); + } +} + +void evolve_ssp_rk3(SolverWorkspace& workspace, double dt, double t_final) +{ + double elapsed_time = 0.0; + while (elapsed_time < t_final) { + const double remaining_time = t_final - elapsed_time; + const double step_dt = std::min(dt, remaining_time); + push_ssp_rk3(workspace, step_dt); + elapsed_time = (step_dt < dt) ? t_final : (elapsed_time + step_dt); + } +} + +} // namespace mhd1d diff --git a/benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.hpp b/benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.hpp new file mode 100644 index 0000000..392751a --- /dev/null +++ b/benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.hpp @@ -0,0 +1,105 @@ +#pragma once + +#include +#include + +#include + +namespace mhd1d +{ + +namespace stdex = std::experimental; + +constexpr int N_Component = 7; +constexpr int N_margin = 1; + +using StateVector = std::array; +using ArrayView1D = stdex::mdspan>; +using ArrayView2D = stdex::mdspan>; + +struct SolverWorkspace { + explicit SolverWorkspace(int nx, double gamma, double bx) + : Nx(nx), Lbx(N_margin), Ubx(N_margin + nx - 1), dx(1.0 / static_cast(nx)), + gamma(gamma), bx(bx), storage(Nx + 2 * N_margin, N_Component) + { + init_views(Nx + 2 * N_margin, N_Component); + + for (int ix = Lbx; ix <= Ubx; ++ix) { + x(ix) = (static_cast(ix - Lbx) + 0.5) * dx; + } + } + + int Nx; + int Lbx; + int Ubx; + double dx; + double gamma; + double bx; + + ArrayView1D x; + ArrayView2D uc; + ArrayView2D up; + ArrayView2D up_l; + ArrayView2D up_r; + ArrayView2D rhs; + ArrayView2D prev; + ArrayView2D flux; + +private: + void init_views(int n_grid, int n_component) + { + x = ArrayView1D(storage.x.data(), n_grid); + uc = ArrayView2D(storage.uc.data(), n_grid, n_component); + up = ArrayView2D(storage.up.data(), n_grid, n_component); + up_l = ArrayView2D(storage.up_l.data(), n_grid, n_component); + up_r = ArrayView2D(storage.up_r.data(), n_grid, n_component); + rhs = ArrayView2D(storage.rhs.data(), n_grid, n_component); + prev = ArrayView2D(storage.prev.data(), n_grid, n_component); + flux = ArrayView2D(storage.flux.data(), n_grid, n_component); + } + + struct Storage { + explicit Storage(int n_grid, int n_component) + : x(n_grid), uc(n_grid * n_component), up(n_grid * n_component), up_l(n_grid * n_component), + up_r(n_grid * n_component), rhs(n_grid * n_component), prev(n_grid * n_component), + flux(n_grid * n_component) + { + } + + std::vector x; + std::vector uc; + std::vector up; + std::vector up_l; + std::vector up_r; + std::vector rhs; + std::vector prev; + std::vector flux; + }; + + Storage storage; +}; + +StateVector primitive_to_conservative(const StateVector& primitive, double bx, double gamma); + +StateVector conservative_to_primitive(const StateVector& conservative, double bx, double gamma); + +void primitive_profile_to_conservative(ArrayView2D primitive_cells, ArrayView2D conservative_cells, + double bx, double gamma); + +void set_boundary_lb(ArrayView2D dst, ArrayView2D src, int lbx); + +void set_boundary_ub(ArrayView2D dst, ArrayView2D src, int ubx); + +void set_boundary(ArrayView2D dst, ArrayView2D src, int lbx, int ubx); + +void reconstruct_mc2(SolverWorkspace& workspace); + +void compute_flux_hlld(SolverWorkspace& workspace, double bx, double gamma); + +void compute_rhs(SolverWorkspace& workspace); + +void push_ssp_rk3(SolverWorkspace& workspace, double dt); + +void evolve_ssp_rk3(SolverWorkspace& workspace, double dt, double t_final); + +} // namespace mhd1d diff --git a/benchmarks/magnetohydrodynamics/shared/src/hlld.cpp b/benchmarks/magnetohydrodynamics/shared/src/hlld.cpp new file mode 100644 index 0000000..afe83e8 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/shared/src/hlld.cpp @@ -0,0 +1,204 @@ +#include "hlld.hpp" + +#include +#include + +StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, + double gamma) +{ + constexpr double epsilon = 1.0e-40; + + const double rol = left[0]; + const double vxl = left[1]; + const double vyl = left[2]; + const double vzl = left[3]; + const double prl = left[4]; + const double byl = left[5]; + const double bzl = left[6]; + + const double ror = right[0]; + const double vxr = right[1]; + const double vyr = right[2]; + const double vzr = right[3]; + const double prr = right[4]; + const double byr = right[5]; + const double bzr = right[6]; + + const double igm = 1.0 / (gamma - 1.0); + const double bxs = bx; + const double bxsq = bxs * bxs; + + const double pbl = 0.5 * (bxsq + byl * byl + bzl * bzl); + const double pbr = 0.5 * (bxsq + byr * byr + bzr * bzr); + const double ptl = prl + pbl; + const double ptr = prr + pbr; + + const double rxl = rol * vxl; + const double ryl = rol * vyl; + const double rzl = rol * vzl; + const double rxr = ror * vxr; + const double ryr = ror * vyr; + const double rzr = ror * vzr; + + const double eel = prl * igm + 0.5 * (rxl * vxl + ryl * vyl + rzl * vzl) + pbl; + const double eer = prr * igm + 0.5 * (rxr * vxr + ryr * vyr + rzr * vzr) + pbr; + + const double gmpl = gamma * prl; + const double gmpr = gamma * prr; + const double gpbl = gmpl + 2.0 * pbl; + const double gpbr = gmpr + 2.0 * pbr; + + const double cfl = std::sqrt((gpbl + std::sqrt((gmpl - 2.0 * pbl) * (gmpl - 2.0 * pbl) + + 4.0 * gmpl * (byl * byl + bzl * bzl))) * + 0.5 / rol); + const double cfr = std::sqrt((gpbr + std::sqrt((gmpr - 2.0 * pbr) * (gmpr - 2.0 * pbr) + + 4.0 * gmpr * (byr * byr + bzr * bzr))) * + 0.5 / ror); + + const double sl = std::min(vxl, vxr) - std::max(cfl, cfr); + const double sr = std::max(vxl, vxr) + std::max(cfl, cfr); + + const StateVector fql{rxl, + rxl * vxl + ptl - bxsq, + rxl * vyl - bxs * byl, + rxl * vzl - bxs * bzl, + vxl * (eel + ptl - bxsq) - bxs * (vyl * byl + vzl * bzl), + byl * vxl - bxs * vyl, + bzl * vxl - bxs * vzl}; + const StateVector fqr{rxr, + rxr * vxr + ptr - bxsq, + rxr * vyr - bxs * byr, + rxr * vzr - bxs * bzr, + vxr * (eer + ptr - bxsq) - bxs * (vyr * byr + vzr * bzr), + byr * vxr - bxs * vyr, + bzr * vxr - bxs * vzr}; + + const double sdl = sl - vxl; + const double sdr = sr - vxr; + const double rosdl = rol * sdl; + const double rosdr = ror * sdr; + const double temp = 1.0 / (rosdr - rosdl); + const double sm = (rosdr * vxr - rosdl * vxl - ptr + ptl) * temp; + const double sdml = sl - sm; + const double sdmr = sr - sm; + const double ptst = (rosdr * ptl - rosdl * ptr + rosdl * rosdr * (vxr - vxl)) * temp; + + const double temp_fst_l = rosdl * sdml - bxsq; + const double sign1_l = std::copysign(1.0, std::abs(temp_fst_l) - epsilon); + const double maxs1_l = std::max(0.0, sign1_l); + const double mins1_l = std::min(0.0, sign1_l); + const double itf_l = 1.0 / (temp_fst_l + mins1_l); + const double isdml = 1.0 / sdml; + + const double temp_l = bxs * (sdl - sdml) * itf_l; + const double rolst = maxs1_l * (rosdl * isdml) - mins1_l * rol; + const double vxlst = maxs1_l * sm - mins1_l * vxl; + const double rxlst = rolst * vxlst; + const double vylst = maxs1_l * (vyl - byl * temp_l) - mins1_l * vyl; + const double rylst = rolst * vylst; + const double vzlst = maxs1_l * (vzl - bzl * temp_l) - mins1_l * vzl; + const double rzlst = rolst * vzlst; + const double temp_l_b = (rosdl * sdl - bxsq) * itf_l; + const double bylst = maxs1_l * (byl * temp_l_b) - mins1_l * byl; + const double bzlst = maxs1_l * (bzl * temp_l_b) - mins1_l * bzl; + const double vdbstl = vxlst * bxs + vylst * bylst + vzlst * bzlst; + const double eelst = maxs1_l * ((sdl * eel - ptl * vxl + ptst * sm + + bxs * (vxl * bxs + vyl * byl + vzl * bzl - vdbstl)) * + isdml) - + mins1_l * eel; + + const double temp_fst_r = rosdr * sdmr - bxsq; + const double sign1_r = std::copysign(1.0, std::abs(temp_fst_r) - epsilon); + const double maxs1_r = std::max(0.0, sign1_r); + const double mins1_r = std::min(0.0, sign1_r); + const double itf_r = 1.0 / (temp_fst_r + mins1_r); + const double isdmr = 1.0 / sdmr; + + const double temp_r = bxs * (sdr - sdmr) * itf_r; + const double rorst = maxs1_r * (rosdr * isdmr) - mins1_r * ror; + const double vxrst = maxs1_r * sm - mins1_r * vxr; + const double rxrst = rorst * vxrst; + const double vyrst = maxs1_r * (vyr - byr * temp_r) - mins1_r * vyr; + const double ryrst = rorst * vyrst; + const double vzrst = maxs1_r * (vzr - bzr * temp_r) - mins1_r * vzr; + const double rzrst = rorst * vzrst; + const double temp_r_b = (rosdr * sdr - bxsq) * itf_r; + const double byrst = maxs1_r * (byr * temp_r_b) - mins1_r * byr; + const double bzrst = maxs1_r * (bzr * temp_r_b) - mins1_r * bzr; + const double vdbstr = vxrst * bxs + vyrst * byrst + vzrst * bzrst; + const double eerst = maxs1_r * ((sdr * eer - ptr * vxr + ptst * sm + + bxs * (vxr * bxs + vyr * byr + vzr * bzr - vdbstr)) * + isdmr) - + mins1_r * eer; + + const double sqrtrol = std::sqrt(rolst); + const double sqrtror = std::sqrt(rorst); + const double abbx = std::abs(bxs); + const double slst = sm - abbx / sqrtrol; + const double srst = sm + abbx / sqrtror; + const double signbx = std::copysign(1.0, bxs); + const double sign1_b = std::copysign(1.0, abbx - epsilon); + const double maxs1_b = std::max(0.0, sign1_b); + const double mins1_b = -std::min(0.0, sign1_b); + const double invsumro = maxs1_b / (sqrtrol + sqrtror); + + const double roldst = rolst; + const double rordst = rorst; + const double rxldst = rxlst; + const double rxrdst = rxrst; + + const double vy_shared = + invsumro * (sqrtrol * vylst + sqrtror * vyrst + signbx * (byrst - bylst)); + const double ryldst = rylst * mins1_b + roldst * vy_shared; + const double ryrdst = ryrst * mins1_b + rordst * vy_shared; + + const double vz_shared = + invsumro * (sqrtrol * vzlst + sqrtror * vzrst + signbx * (bzrst - bzlst)); + const double rzldst = rzlst * mins1_b + roldst * vz_shared; + const double rzrdst = rzrst * mins1_b + rordst * vz_shared; + + const double by_shared = + invsumro * (sqrtrol * byrst + sqrtror * bylst + signbx * sqrtrol * sqrtror * (vyrst - vylst)); + const double byldst = bylst * mins1_b + by_shared; + const double byrdst = byrst * mins1_b + by_shared; + + const double bz_shared = + invsumro * (sqrtrol * bzrst + sqrtror * bzlst + signbx * sqrtrol * sqrtror * (vzrst - vzlst)); + const double bzldst = bzlst * mins1_b + bz_shared; + const double bzrdst = bzrst * mins1_b + bz_shared; + + const double vyldst = vylst * mins1_b + vy_shared; + const double vyrdst = vyrst * mins1_b + vy_shared; + const double vzldst = vzlst * mins1_b + vz_shared; + const double vzrdst = vzrst * mins1_b + vz_shared; + const double temp_dst = sm * bxs + vyldst * byldst + vzldst * bzldst; + const double eeldst = eelst - sqrtrol * signbx * (vdbstl - temp_dst) * maxs1_b; + const double eerdst = eerst + sqrtror * signbx * (vdbstr - temp_dst) * maxs1_b; + + const double sign1 = std::copysign(1.0, sm); + const double maxs1 = std::max(0.0, sign1); + const double mins1 = -std::min(0.0, sign1); + const double msl = std::min(sl, 0.0); + const double mslst = std::min(slst, 0.0); + const double msrst = std::max(srst, 0.0); + const double msr = std::max(sr, 0.0); + const double temp_flux_l = mslst - msl; + const double temp_flux_r = msrst - msr; + + return StateVector{ + (fql[0] - msl * rol - rolst * temp_flux_l + roldst * mslst) * maxs1 + + (fqr[0] - msr * ror - rorst * temp_flux_r + rordst * msrst) * mins1, + (fql[1] - msl * rxl - rxlst * temp_flux_l + rxldst * mslst) * maxs1 + + (fqr[1] - msr * rxr - rxrst * temp_flux_r + rxrdst * msrst) * mins1, + (fql[2] - msl * ryl - rylst * temp_flux_l + ryldst * mslst) * maxs1 + + (fqr[2] - msr * ryr - ryrst * temp_flux_r + ryrdst * msrst) * mins1, + (fql[3] - msl * rzl - rzlst * temp_flux_l + rzldst * mslst) * maxs1 + + (fqr[3] - msr * rzr - rzrst * temp_flux_r + rzrdst * msrst) * mins1, + (fql[4] - msl * eel - eelst * temp_flux_l + eeldst * mslst) * maxs1 + + (fqr[4] - msr * eer - eerst * temp_flux_r + eerdst * msrst) * mins1, + (fql[5] - msl * byl - bylst * temp_flux_l + byldst * mslst) * maxs1 + + (fqr[5] - msr * byr - byrst * temp_flux_r + byrdst * msrst) * mins1, + (fql[6] - msl * bzl - bzlst * temp_flux_l + bzldst * mslst) * maxs1 + + (fqr[6] - msr * bzr - bzrst * temp_flux_r + bzrdst * msrst) * mins1, + }; +} diff --git a/benchmarks/magnetohydrodynamics/shared/src/hlld.hpp b/benchmarks/magnetohydrodynamics/shared/src/hlld.hpp new file mode 100644 index 0000000..378f29f --- /dev/null +++ b/benchmarks/magnetohydrodynamics/shared/src/hlld.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +using StateVector = std::array; + +StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, + double gamma); diff --git a/benchmarks/magnetohydrodynamics/shared/tests/test_reference.py b/benchmarks/magnetohydrodynamics/shared/tests/test_reference.py new file mode 100644 index 0000000..65183ac --- /dev/null +++ b/benchmarks/magnetohydrodynamics/shared/tests/test_reference.py @@ -0,0 +1,44 @@ +from __future__ import annotations + +import os +import subprocess +from pathlib import Path + + +SHARED_ROOT = Path(__file__).resolve().parents[1] +FIXTURE_CSV_PATH = SHARED_ROOT / "eval" / "fixtures" / "mhd1d" / "brio_wu_reference.csv" + + +def _build_reference_solver() -> Path: + build_dir = SHARED_ROOT / "build" + subprocess.run(["cmake", "-S", str(SHARED_ROOT), "-B", str(build_dir)], check=True) + subprocess.run( + ["cmake", "--build", str(build_dir), "--target", "full_mhd1d_reference"], + check=True, + ) + + binary_name = ( + "full_mhd1d_reference.exe" if os.name == "nt" else "full_mhd1d_reference" + ) + binary_path = build_dir / "bin" / binary_name + assert binary_path.exists() + return binary_path + + +def test_shared_reference_solver_matches_fixture(tmp_path: Path) -> None: + solver_path = _build_reference_solver() + output_csv_path = tmp_path / "solution.csv" + + completed = subprocess.run( + [str(solver_path), "200"], + check=True, + capture_output=True, + text=True, + ) + output_csv_path.write_text(completed.stdout, encoding="utf-8") + + output_rows = output_csv_path.read_text(encoding="utf-8").splitlines() + reference_rows = FIXTURE_CSV_PATH.read_text(encoding="utf-8").splitlines() + + assert len(output_rows) == len(reference_rows) + assert output_rows == reference_rows diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/scripts/plot_solution.py b/benchmarks/magnetohydrodynamics/shared/workspace/plot_solution.py similarity index 73% rename from benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/scripts/plot_solution.py rename to benchmarks/magnetohydrodynamics/shared/workspace/plot_solution.py index 507bc68..f6cbaf4 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/scripts/plot_solution.py +++ b/benchmarks/magnetohydrodynamics/shared/workspace/plot_solution.py @@ -2,7 +2,7 @@ """Plot a Brio-Wu solver CSV and save an image. Usage: - python scripts/plot_solution.py [path/to/solution.csv] [path/to/output.png] + python plot_solution.py [path/to/solution.csv] [path/to/output.png] If no path is provided, the script looks for ``solution.csv`` in the current working directory and writes ``solution.png`` there. @@ -49,16 +49,29 @@ def parse_args() -> argparse.Namespace: def load_columns(csv_path: Path) -> dict[str, list[float]]: with csv_path.open(newline="", encoding="utf-8") as handle: - reader = csv.DictReader(handle) - if reader.fieldnames != EXPECTED_FIELDS: - raise ValueError( - f"expected CSV header x,rho,u,v,w,p,by,bz; got {reader.fieldnames!r}" - ) + reader = csv.reader(handle) + try: + first_row = next(reader) + except StopIteration as exc: + raise ValueError(f"{csv_path} is empty") from exc + + if first_row == EXPECTED_FIELDS: + rows = reader + else: + if len(first_row) != len(EXPECTED_FIELDS): + raise ValueError( + f"expected {len(EXPECTED_FIELDS)} CSV columns; got {len(first_row)}" + ) + rows = [first_row, *reader] columns: dict[str, list[float]] = {field: [] for field in EXPECTED_FIELDS} - for row in reader: - for field in EXPECTED_FIELDS: - columns[field].append(float(row[field])) + for raw_row in rows: + if len(raw_row) != len(EXPECTED_FIELDS): + raise ValueError( + f"expected {len(EXPECTED_FIELDS)} CSV columns; got {len(raw_row)}" + ) + for field, raw_value in zip(EXPECTED_FIELDS, raw_row, strict=True): + columns[field].append(float(raw_value)) return columns From 97944364f5520dc465690f4abe8e4ae47c47495a Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Thu, 2 Apr 2026 00:56:14 +0900 Subject: [PATCH 29/39] chore(magnetohydrodynamics): remove obsolete fixture json --- .../eval/fixtures/mhd1d/brio_wu_fixture.json | 45 ------------------- 1 file changed, 45 deletions(-) delete mode 100644 benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_fixture.json diff --git a/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_fixture.json b/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_fixture.json deleted file mode 100644 index 2c318f6..0000000 --- a/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/brio_wu_fixture.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "abs_l1": { - "by": 1e-12, - "p": 1e-12, - "rho": 1e-12, - "u": 1e-12 - }, - "abs_linf": { - "by": 1e-13, - "p": 1e-13, - "rho": 1e-13, - "u": 1e-13 - }, - "bx": 0.75, - "discontinuity_x": 0.5, - "domain": [ - 0.0, - 1.0 - ], - "dt": 0.0005, - "gamma": 2.0, - "interior_cell_window": { - "exclude_edge_adjacents_per_side": 2 - }, - "name": "brio_wu", - "nx": 100, - "reference_csv": "brio_wu_reference.csv", - "schema": [ - "x", - "rho", - "u", - "v", - "w", - "p", - "by", - "bz" - ], - "scored_variables": [ - "rho", - "u", - "p", - "by" - ], - "t_final": 0.1 -} From ddad41e440f9d74cb263170b25f2b6eee29635d9 Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Thu, 2 Apr 2026 10:18:26 +0900 Subject: [PATCH 30/39] refactor(magnetohydrodynamics): streamline shared solver interfaces --- .../shared/src/full_main.cpp | 2 +- .../shared/src/full_mhd1d.cpp | 161 ++++++++---------- .../shared/src/full_mhd1d.hpp | 14 +- .../magnetohydrodynamics/shared/src/hlld.cpp | 62 ++++--- .../magnetohydrodynamics/shared/src/hlld.hpp | 8 +- 5 files changed, 114 insertions(+), 133 deletions(-) diff --git a/benchmarks/magnetohydrodynamics/shared/src/full_main.cpp b/benchmarks/magnetohydrodynamics/shared/src/full_main.cpp index 5876fad..91864c3 100644 --- a/benchmarks/magnetohydrodynamics/shared/src/full_main.cpp +++ b/benchmarks/magnetohydrodynamics/shared/src/full_main.cpp @@ -43,7 +43,7 @@ mhd1d::SolverWorkspace initialize(int nx, double gamma, double bx, } mhd1d::set_boundary(workspace.up, workspace.up, workspace.Lbx, workspace.Ubx); - mhd1d::primitive_profile_to_conservative(workspace.up, workspace.uc, bx, gamma); + mhd1d::convert_primitive_to_conservative(workspace.up, workspace.uc, bx, gamma); return workspace; } diff --git a/benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.cpp b/benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.cpp index f2b7660..b43dde3 100644 --- a/benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.cpp +++ b/benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.cpp @@ -4,14 +4,10 @@ #include #include #include -#include namespace mhd1d { -namespace -{ - double sign(const double x) { return copysign(1.0, x); @@ -23,47 +19,8 @@ double mc2(double a, double b) std::min({2.0 * std::abs(a), 2.0 * std::abs(b), 0.5 * std::abs(a + b)}); } -StateVector row_to_state(ArrayView2D cells, int row) -{ - StateVector state{}; - for (int component = 0; component < N_Component; ++component) { - state[component] = cells(row, component); - } - return state; -} - -void state_to_row(const StateVector& state, ArrayView2D cells, int row) -{ - for (int component = 0; component < N_Component; ++component) { - cells(row, component) = state[component]; - } -} - -void copy_cells(ArrayView2D source, ArrayView2D destination) -{ - const int nx = source.extent(0); - for (int ix = 0; ix < nx; ++ix) { - for (int component = 0; component < N_Component; ++component) { - destination(ix, component) = source(ix, component); - } - } -} - -void convert_conservative_to_primitive(ArrayView2D conservative, ArrayView2D primitive, double bx, - double gamma) -{ - const int ix_min = 0; - const int ix_max = conservative.extent(0) - 1; - - for (int ix = ix_min; ix <= ix_max; ++ix) { - const StateVector up = conservative_to_primitive(row_to_state(conservative, ix), bx, gamma); - state_to_row(up, primitive, ix); - } -} - -} // namespace - -StateVector primitive_to_conservative(const StateVector& primitive, double bx, double gamma) +void primitive_to_conservative(const double* primitive, double* conservative, double bx, + double gamma) { const double rho = primitive[0]; const double u = primitive[1]; @@ -76,13 +33,17 @@ StateVector primitive_to_conservative(const StateVector& primitive, double bx, d const double kinetic_energy = 0.5 * rho * (u * u + v * v + w * w); const double magnetic_energy = 0.5 * (bx * bx + by * by + bz * bz); - return StateVector{ - rho, rho * u, rho * v, rho * w, pressure / (gamma - 1.0) + kinetic_energy + magnetic_energy, - by, bz, - }; + conservative[0] = rho; + conservative[1] = rho * u; + conservative[2] = rho * v; + conservative[3] = rho * w; + conservative[4] = pressure / (gamma - 1.0) + kinetic_energy + magnetic_energy; + conservative[5] = by; + conservative[6] = bz; } -StateVector conservative_to_primitive(const StateVector& conservative, double bx, double gamma) +void conservative_to_primitive(const double* conservative, double* primitive, double bx, + double gamma) { const double rho = conservative[0]; if (rho <= 0.0) { @@ -99,55 +60,34 @@ StateVector conservative_to_primitive(const StateVector& conservative, double bx const double magnetic_energy = 0.5 * (bx * bx + by * by + bz * bz); const double pressure = (gamma - 1.0) * (conservative[4] - kinetic_energy - magnetic_energy); - return StateVector{rho, u, v, w, pressure, by, bz}; + primitive[0] = rho; + primitive[1] = u; + primitive[2] = v; + primitive[3] = w; + primitive[4] = pressure; + primitive[5] = by; + primitive[6] = bz; } -void primitive_profile_to_conservative(ArrayView2D primitive, ArrayView2D conservative, double bx, +void convert_primitive_to_conservative(ArrayView2D primitive, ArrayView2D conservative, double bx, double gamma) { const int ix_min = 0; const int ix_max = primitive.extent(0) - 1; for (int ix = ix_min; ix <= ix_max; ++ix) { - const StateVector uc = primitive_to_conservative(row_to_state(primitive, ix), bx, gamma); - state_to_row(uc, conservative, ix); - } -} - -void reconstruct_mc2(SolverWorkspace& workspace) -{ - const ArrayView2D up = workspace.up; - const ArrayView2D up_l = workspace.up_l; - const ArrayView2D up_r = workspace.up_r; - - const int lbx = workspace.Lbx; - const int ubx = workspace.Ubx; - for (int ix = lbx; ix <= ubx; ++ix) { - for (int component = 0; component < N_Component; ++component) { - const double slope_l = up(ix, component) - up(ix - 1, component); - const double slope_r = up(ix + 1, component) - up(ix, component); - const double slope = mc2(slope_l, slope_r); - up_l(ix, component) = up(ix, component) + 0.5 * slope; - up_r(ix, component) = up(ix, component) - 0.5 * slope; - } + primitive_to_conservative(&primitive(ix, 0), &conservative(ix, 0), bx, gamma); } - - set_boundary_lb(up_l, up_r, lbx); - set_boundary_ub(up_r, up_l, ubx); } -void compute_flux_hlld(SolverWorkspace& workspace, double bx, double gamma) +void convert_conservative_to_primitive(ArrayView2D conservative, ArrayView2D primitive, double bx, + double gamma) { - const ArrayView2D up_l = workspace.up_l; - const ArrayView2D up_r = workspace.up_r; - const ArrayView2D flux = workspace.flux; + const int ix_min = 0; + const int ix_max = conservative.extent(0) - 1; - const int lbx = workspace.Lbx; - const int ubx = workspace.Ubx; - for (int ix = lbx - 1; ix <= ubx + 1; ++ix) { - const StateVector flux_hlld = - ::hlld_flux_from_primitive(row_to_state(up_l, ix), row_to_state(up_r, ix + 1), bx, gamma); - state_to_row(flux_hlld, flux, ix); + for (int ix = ix_min; ix <= ix_max; ++ix) { + conservative_to_primitive(&conservative(ix, 0), &primitive(ix, 0), bx, gamma); } } @@ -179,6 +119,41 @@ void set_boundary(ArrayView2D dst, ArrayView2D src, int lbx, int ubx) set_boundary_ub(dst, src, ubx); } +void compute_lr(SolverWorkspace& workspace) +{ + const ArrayView2D up = workspace.up; + const ArrayView2D up_l = workspace.up_l; + const ArrayView2D up_r = workspace.up_r; + + const int lbx = workspace.Lbx; + const int ubx = workspace.Ubx; + for (int ix = lbx; ix <= ubx; ++ix) { + for (int component = 0; component < N_Component; ++component) { + const double slope_l = up(ix, component) - up(ix - 1, component); + const double slope_r = up(ix + 1, component) - up(ix, component); + const double slope = mc2(slope_l, slope_r); + up_l(ix, component) = up(ix, component) + 0.5 * slope; + up_r(ix, component) = up(ix, component) - 0.5 * slope; + } + } + + set_boundary_lb(up_l, up_r, lbx); + set_boundary_ub(up_r, up_l, ubx); +} + +void compute_flux_hlld(SolverWorkspace& workspace, double bx, double gamma) +{ + const ArrayView2D up_l = workspace.up_l; + const ArrayView2D up_r = workspace.up_r; + const ArrayView2D flux = workspace.flux; + + const int lbx = workspace.Lbx; + const int ubx = workspace.Ubx; + for (int ix = lbx - 1; ix <= ubx + 1; ++ix) { + ::hlld_flux_from_primitive(&up_l(ix, 0), &up_r(ix + 1, 0), bx, gamma, &flux(ix, 0)); + } +} + void compute_rhs(SolverWorkspace& workspace) { const ArrayView2D uc = workspace.uc; @@ -189,7 +164,7 @@ void compute_rhs(SolverWorkspace& workspace) set_boundary(uc, uc, workspace.Lbx, workspace.Ubx); convert_conservative_to_primitive(uc, up, workspace.bx, workspace.gamma); set_boundary(up, up, workspace.Lbx, workspace.Ubx); - reconstruct_mc2(workspace); + compute_lr(workspace); compute_flux_hlld(workspace, workspace.bx, workspace.gamma); const int lbx = workspace.Lbx; @@ -201,6 +176,16 @@ void compute_rhs(SolverWorkspace& workspace) } } +void copy(ArrayView2D source, ArrayView2D destination) +{ + const int nx = source.extent(0); + for (int ix = 0; ix < nx; ++ix) { + for (int component = 0; component < N_Component; ++component) { + destination(ix, component) = source(ix, component); + } + } +} + void push_ssp_rk3(SolverWorkspace& workspace, double dt) { constexpr double coeffs[3][3] = { @@ -212,7 +197,7 @@ void push_ssp_rk3(SolverWorkspace& workspace, double dt) const ArrayView2D prev = workspace.prev; const ArrayView2D rhs = workspace.rhs; - copy_cells(workspace.uc, prev); + copy(workspace.uc, prev); for (int substep = 0; substep < 3; ++substep) { compute_rhs(workspace); diff --git a/benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.hpp b/benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.hpp index 392751a..6925629 100644 --- a/benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.hpp +++ b/benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.hpp @@ -14,8 +14,8 @@ constexpr int N_Component = 7; constexpr int N_margin = 1; using StateVector = std::array; -using ArrayView1D = stdex::mdspan>; -using ArrayView2D = stdex::mdspan>; +using ArrayView1D = stdex::mdspan, stdex::layout_right>; +using ArrayView2D = stdex::mdspan, stdex::layout_right>; struct SolverWorkspace { explicit SolverWorkspace(int nx, double gamma, double bx) @@ -79,11 +79,13 @@ struct SolverWorkspace { Storage storage; }; -StateVector primitive_to_conservative(const StateVector& primitive, double bx, double gamma); +void primitive_to_conservative(const double* primitive, double* conservative, double bx, + double gamma); -StateVector conservative_to_primitive(const StateVector& conservative, double bx, double gamma); +void conservative_to_primitive(const double* conservative, double* primitive, double bx, + double gamma); -void primitive_profile_to_conservative(ArrayView2D primitive_cells, ArrayView2D conservative_cells, +void convert_primitive_to_conservative(ArrayView2D primitive_cells, ArrayView2D conservative_cells, double bx, double gamma); void set_boundary_lb(ArrayView2D dst, ArrayView2D src, int lbx); @@ -92,7 +94,7 @@ void set_boundary_ub(ArrayView2D dst, ArrayView2D src, int ubx); void set_boundary(ArrayView2D dst, ArrayView2D src, int lbx, int ubx); -void reconstruct_mc2(SolverWorkspace& workspace); +void compute_lr(SolverWorkspace& workspace); void compute_flux_hlld(SolverWorkspace& workspace, double bx, double gamma); diff --git a/benchmarks/magnetohydrodynamics/shared/src/hlld.cpp b/benchmarks/magnetohydrodynamics/shared/src/hlld.cpp index afe83e8..f5f9c87 100644 --- a/benchmarks/magnetohydrodynamics/shared/src/hlld.cpp +++ b/benchmarks/magnetohydrodynamics/shared/src/hlld.cpp @@ -3,8 +3,8 @@ #include #include -StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, - double gamma) +void hlld_flux_from_primitive(const double* left, const double* right, double bx, double gamma, + double* flux) { constexpr double epsilon = 1.0e-40; @@ -58,20 +58,20 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& const double sl = std::min(vxl, vxr) - std::max(cfl, cfr); const double sr = std::max(vxl, vxr) + std::max(cfl, cfr); - const StateVector fql{rxl, - rxl * vxl + ptl - bxsq, - rxl * vyl - bxs * byl, - rxl * vzl - bxs * bzl, - vxl * (eel + ptl - bxsq) - bxs * (vyl * byl + vzl * bzl), - byl * vxl - bxs * vyl, - bzl * vxl - bxs * vzl}; - const StateVector fqr{rxr, - rxr * vxr + ptr - bxsq, - rxr * vyr - bxs * byr, - rxr * vzr - bxs * bzr, - vxr * (eer + ptr - bxsq) - bxs * (vyr * byr + vzr * bzr), - byr * vxr - bxs * vyr, - bzr * vxr - bxs * vzr}; + const double fql[7] = {rxl, + rxl * vxl + ptl - bxsq, + rxl * vyl - bxs * byl, + rxl * vzl - bxs * bzl, + vxl * (eel + ptl - bxsq) - bxs * (vyl * byl + vzl * bzl), + byl * vxl - bxs * vyl, + bzl * vxl - bxs * vzl}; + const double fqr[7] = {rxr, + rxr * vxr + ptr - bxsq, + rxr * vyr - bxs * byr, + rxr * vzr - bxs * bzr, + vxr * (eer + ptr - bxsq) - bxs * (vyr * byr + vzr * bzr), + byr * vxr - bxs * vyr, + bzr * vxr - bxs * vzr}; const double sdl = sl - vxl; const double sdr = sr - vxr; @@ -185,20 +185,18 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& const double temp_flux_l = mslst - msl; const double temp_flux_r = msrst - msr; - return StateVector{ - (fql[0] - msl * rol - rolst * temp_flux_l + roldst * mslst) * maxs1 + - (fqr[0] - msr * ror - rorst * temp_flux_r + rordst * msrst) * mins1, - (fql[1] - msl * rxl - rxlst * temp_flux_l + rxldst * mslst) * maxs1 + - (fqr[1] - msr * rxr - rxrst * temp_flux_r + rxrdst * msrst) * mins1, - (fql[2] - msl * ryl - rylst * temp_flux_l + ryldst * mslst) * maxs1 + - (fqr[2] - msr * ryr - ryrst * temp_flux_r + ryrdst * msrst) * mins1, - (fql[3] - msl * rzl - rzlst * temp_flux_l + rzldst * mslst) * maxs1 + - (fqr[3] - msr * rzr - rzrst * temp_flux_r + rzrdst * msrst) * mins1, - (fql[4] - msl * eel - eelst * temp_flux_l + eeldst * mslst) * maxs1 + - (fqr[4] - msr * eer - eerst * temp_flux_r + eerdst * msrst) * mins1, - (fql[5] - msl * byl - bylst * temp_flux_l + byldst * mslst) * maxs1 + - (fqr[5] - msr * byr - byrst * temp_flux_r + byrdst * msrst) * mins1, - (fql[6] - msl * bzl - bzlst * temp_flux_l + bzldst * mslst) * maxs1 + - (fqr[6] - msr * bzr - bzrst * temp_flux_r + bzrdst * msrst) * mins1, - }; + flux[0] = (fql[0] - msl * rol - rolst * temp_flux_l + roldst * mslst) * maxs1 + + (fqr[0] - msr * ror - rorst * temp_flux_r + rordst * msrst) * mins1; + flux[1] = (fql[1] - msl * rxl - rxlst * temp_flux_l + rxldst * mslst) * maxs1 + + (fqr[1] - msr * rxr - rxrst * temp_flux_r + rxrdst * msrst) * mins1; + flux[2] = (fql[2] - msl * ryl - rylst * temp_flux_l + ryldst * mslst) * maxs1 + + (fqr[2] - msr * ryr - ryrst * temp_flux_r + ryrdst * msrst) * mins1; + flux[3] = (fql[3] - msl * rzl - rzlst * temp_flux_l + rzldst * mslst) * maxs1 + + (fqr[3] - msr * rzr - rzrst * temp_flux_r + rzrdst * msrst) * mins1; + flux[4] = (fql[4] - msl * eel - eelst * temp_flux_l + eeldst * mslst) * maxs1 + + (fqr[4] - msr * eer - eerst * temp_flux_r + eerdst * msrst) * mins1; + flux[5] = (fql[5] - msl * byl - bylst * temp_flux_l + byldst * mslst) * maxs1 + + (fqr[5] - msr * byr - byrst * temp_flux_r + byrdst * msrst) * mins1; + flux[6] = (fql[6] - msl * bzl - bzlst * temp_flux_l + bzldst * mslst) * maxs1 + + (fqr[6] - msr * bzr - bzrst * temp_flux_r + bzrdst * msrst) * mins1; } diff --git a/benchmarks/magnetohydrodynamics/shared/src/hlld.hpp b/benchmarks/magnetohydrodynamics/shared/src/hlld.hpp index 378f29f..ae80ebd 100644 --- a/benchmarks/magnetohydrodynamics/shared/src/hlld.hpp +++ b/benchmarks/magnetohydrodynamics/shared/src/hlld.hpp @@ -1,8 +1,4 @@ #pragma once -#include - -using StateVector = std::array; - -StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, - double gamma); +void hlld_flux_from_primitive(const double* left, const double* right, double bx, double gamma, + double* flux); From 60e6af7b2fececf0d7c4555d7c71f2c7e94c4b8b Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Thu, 2 Apr 2026 10:54:24 +0900 Subject: [PATCH 31/39] refactor(magnetohydrodynamics): split cpp-hlld into 00/01 variants --- benchmarks/magnetohydrodynamics/README.md | 7 +- .../{cpp-hlld => cpp-hlld-00}/eval/run.sh | 0 .../eval/tests/cpp/hlld_reference.hpp | 24 +- .../eval/tests/cpp/test_hidden.cpp | 35 +- .../eval/tests/test_hidden.py | 0 .../magnetohydrodynamics/cpp-hlld-00/spec.md | 48 +++ .../{cpp-hlld => cpp-hlld-00}/task.toml | 2 +- .../workspace/CMakeLists.txt | 0 .../workspace/pyproject.toml | 0 .../cpp-hlld-00/workspace/src/hlld.cpp | 14 + .../cpp-hlld-00/workspace/src/hlld.hpp | 4 + .../workspace/tests/cpp/test_public.cpp | 56 ++-- .../workspace/tests/test_public.py | 0 .../cpp-hlld-01/eval/run.sh | 27 ++ .../eval/tests/cpp/hlld_reference.hpp} | 68 ++-- .../eval/tests/cpp/test_hidden.cpp | 166 ++++++++++ .../cpp-hlld-01/eval/tests/test_hidden.py | 36 +++ .../magnetohydrodynamics/cpp-hlld-01/spec.md | 29 ++ .../cpp-hlld-01/task.toml | 7 + .../cpp-hlld-01/workspace/CMakeLists.txt | 69 ++++ .../cpp-hlld-01/workspace/pyproject.toml | 7 + .../cpp-hlld-01/workspace/src/hlld.cpp | 14 + .../cpp-hlld-01/workspace/src/hlld.hpp | 4 + .../workspace/tests/cpp/test_public.cpp | 300 ++++++++++++++++++ .../workspace/tests/test_public.py | 24 ++ .../magnetohydrodynamics/cpp-hlld/spec.md | 40 --- .../cpp-hlld/workspace/src/hlld.hpp | 11 - .../shared/workspace/hlld.md | 28 -- 28 files changed, 841 insertions(+), 179 deletions(-) rename benchmarks/magnetohydrodynamics/{cpp-hlld => cpp-hlld-00}/eval/run.sh (100%) rename benchmarks/magnetohydrodynamics/{cpp-hlld => cpp-hlld-00}/eval/tests/cpp/hlld_reference.hpp (91%) rename benchmarks/magnetohydrodynamics/{cpp-hlld => cpp-hlld-00}/eval/tests/cpp/test_hidden.cpp (78%) rename benchmarks/magnetohydrodynamics/{cpp-hlld => cpp-hlld-00}/eval/tests/test_hidden.py (100%) create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld-00/spec.md rename benchmarks/magnetohydrodynamics/{cpp-hlld => cpp-hlld-00}/task.toml (92%) rename benchmarks/magnetohydrodynamics/{cpp-hlld => cpp-hlld-00}/workspace/CMakeLists.txt (100%) rename benchmarks/magnetohydrodynamics/{cpp-hlld => cpp-hlld-00}/workspace/pyproject.toml (100%) create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld-00/workspace/src/hlld.cpp create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld-00/workspace/src/hlld.hpp rename benchmarks/magnetohydrodynamics/{cpp-hlld => cpp-hlld-00}/workspace/tests/cpp/test_public.cpp (82%) rename benchmarks/magnetohydrodynamics/{cpp-hlld => cpp-hlld-00}/workspace/tests/test_public.py (100%) create mode 100755 benchmarks/magnetohydrodynamics/cpp-hlld-01/eval/run.sh rename benchmarks/magnetohydrodynamics/{cpp-hlld/workspace/src/hlld.cpp => cpp-hlld-01/eval/tests/cpp/hlld_reference.hpp} (85%) create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld-01/eval/tests/cpp/test_hidden.cpp create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld-01/eval/tests/test_hidden.py create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld-01/spec.md create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld-01/task.toml create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/CMakeLists.txt create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/pyproject.toml create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/src/hlld.cpp create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/src/hlld.hpp create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/tests/cpp/test_public.cpp create mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/tests/test_public.py delete mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld/spec.md delete mode 100644 benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.hpp diff --git a/benchmarks/magnetohydrodynamics/README.md b/benchmarks/magnetohydrodynamics/README.md index 0721c24..4aef14a 100644 --- a/benchmarks/magnetohydrodynamics/README.md +++ b/benchmarks/magnetohydrodynamics/README.md @@ -6,7 +6,8 @@ This suite contains benchmark tasks for ideal magnetohydrodynamics solvers. - `shared/workspace/basic_equations.md`: suite-wide notation and flux conventions. - `shared/workspace/hlld.md`: HLLD algorithm notes for solver tasks. -- `cpp-hlld/`: C++ HLLD approximate Riemann solver task. +- `cpp-hlld-00/`: default C++ HLLD task with detailed solver guidance in spec. +- `cpp-hlld-01/`: variant C++ HLLD task with reduced guidance but same test intent. - `cpp-full-solver1d/`: C++ full 1D ideal MHD solver (Brio-Wu benchmark). - `shared/eval/README.md`: hidden-eval contract for shared MHD scoring assets. - `shared/eval/mhd1d_shared.py`: shared helpers for CSV loading, score @@ -18,6 +19,10 @@ This suite contains benchmark tasks for ideal magnetohydrodynamics solvers. - Shared workspace files are visible to the agent during benchmark runs. - Keep maintainer-only derivations, generators, and hidden fixtures outside the shared workspace. +- `cpp-hlld-00` and `cpp-hlld-01` expose only + `hlld_flux_from_primitive(...)` in the public task API. +- `cpp-hlld-00` and `cpp-hlld-01` keep public/hidden test intent aligned; + the main difference is prompt detail level. - `cpp-full-solver1d` scores only the interior cells, excluding two edge-adjacent cells on each side, against the variables `rho`, `u`, `p`, and `by` using fixture-recorded `abs_l1` and `abs_linf` tolerances. The solver diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/eval/run.sh b/benchmarks/magnetohydrodynamics/cpp-hlld-00/eval/run.sh similarity index 100% rename from benchmarks/magnetohydrodynamics/cpp-hlld/eval/run.sh rename to benchmarks/magnetohydrodynamics/cpp-hlld-00/eval/run.sh diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/hlld_reference.hpp b/benchmarks/magnetohydrodynamics/cpp-hlld-00/eval/tests/cpp/hlld_reference.hpp similarity index 91% rename from benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/hlld_reference.hpp rename to benchmarks/magnetohydrodynamics/cpp-hlld-00/eval/tests/cpp/hlld_reference.hpp index 1849a16..4e3d3dc 100644 --- a/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/hlld_reference.hpp +++ b/benchmarks/magnetohydrodynamics/cpp-hlld-00/eval/tests/cpp/hlld_reference.hpp @@ -6,8 +6,11 @@ #include "../../../workspace/src/hlld.hpp" #endif +#include #include +using StateVector = std::array; + namespace hidden_reference { @@ -215,23 +218,12 @@ inline StateVector hlld_flux_from_primitive(const StateVector& left, const State }; } -inline StateVector hlld_flux_from_conservative(const StateVector& left, const StateVector& right, - double bx, double gamma) +inline StateVector solver_flux_from_primitive(const StateVector& left, const StateVector& right, + double bx, double gamma) { - const auto to_primitive = [bx, gamma](const StateVector& state) { - const double rho = state[0]; - const double u = state[1] / rho; - const double v = state[2] / rho; - const double w = state[3] / rho; - const double by = state[5]; - const double bz = state[6]; - const double kinetic = 0.5 * rho * (u * u + v * v + w * w); - const double magnetic = 0.5 * (bx * bx + by * by + bz * bz); - const double p = (gamma - 1.0) * (state[4] - kinetic - magnetic); - return StateVector{rho, u, v, w, p, by, bz}; - }; - - return hlld_flux_from_primitive(to_primitive(left), to_primitive(right), bx, gamma); + StateVector flux{}; + ::hlld_flux_from_primitive(left.data(), right.data(), bx, gamma, flux.data()); + return flux; } } // namespace hidden_reference diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/test_hidden.cpp b/benchmarks/magnetohydrodynamics/cpp-hlld-00/eval/tests/cpp/test_hidden.cpp similarity index 78% rename from benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/test_hidden.cpp rename to benchmarks/magnetohydrodynamics/cpp-hlld-00/eval/tests/cpp/test_hidden.cpp index 265fb1c..35d8074 100644 --- a/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/cpp/test_hidden.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-hlld-00/eval/tests/cpp/test_hidden.cpp @@ -12,8 +12,11 @@ #include "hlld_reference.hpp" +#include #include +using StateVector = std::array; + namespace { @@ -33,9 +36,7 @@ StateVector primitive_to_conservative(const StateVector& state, double bx, doubl const double magnetic = 0.5 * (bx * bx + by * by + bz * bz); const double energy = p / (gamma - 1.0) + kinetic + magnetic; - return StateVector{ - rho, rho * u, rho * v, rho * w, energy, by, bz, - }; + return StateVector{rho, rho * u, rho * v, rho * w, energy, by, bz}; } StateVector physical_flux_x(const StateVector& state, double bx, double gamma) @@ -74,17 +75,25 @@ void require_close(const StateVector& actual, const StateVector& expected) } } +StateVector solver_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, + double gamma) +{ + StateVector flux{}; + hlld_flux_from_primitive(left.data(), right.data(), bx, gamma, flux.data()); + return flux; +} + } // namespace -TEST_CASE("equal conservative states reduce to the physical flux") +TEST_CASE("equal primitive states reduce to the physical flux") { const double bx = 0.35; const double gamma = 1.4; - const StateVector primitive{0.9, -0.45, 0.2, 0.15, 0.8, -0.3, 0.55}; - const StateVector state = primitive_to_conservative(primitive, bx, gamma); + const StateVector state{0.9, -0.45, 0.2, 0.15, 0.8, -0.3, 0.55}; - const StateVector actual = hlld_flux_from_conservative(state, state, bx, gamma); - const StateVector expected = physical_flux_x(state, bx, gamma); + const StateVector actual = solver_flux_from_primitive(state, state, bx, gamma); + const StateVector expected = + physical_flux_x(primitive_to_conservative(state, bx, gamma), bx, gamma); require_close(actual, expected); } @@ -97,7 +106,7 @@ TEST_CASE("nontrivial primitive solve returns finite values") const StateVector left{1.08, 0.45, -0.12, 0.08, 0.95, 0.4, -0.3}; const StateVector right{0.72, -0.25, 0.16, -0.05, 0.58, -0.2, 0.35}; - const StateVector flux = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector flux = solver_flux_from_primitive(left, right, bx, gamma); for (double value : flux) { REQUIRE(std::isfinite(value)); @@ -113,7 +122,7 @@ TEST_CASE("hidden reference flux case 1 matches reference implementation") const StateVector right{0.72, -0.25, 0.16, -0.05, 0.58, -0.2, 0.35}; const StateVector expected = hidden_reference::hlld_flux_from_primitive(left, right, bx, gamma); - const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } @@ -126,7 +135,7 @@ TEST_CASE("hidden reference flux case 2 matches reference implementation") const StateVector right{1.15, 0.18, -0.12, -0.08, 1.05, 0.22, -0.4}; const StateVector expected = hidden_reference::hlld_flux_from_primitive(left, right, bx, gamma); - const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } @@ -139,7 +148,7 @@ TEST_CASE("small Bx near-degenerate reference case matches reference implementat const StateVector right{0.85, -0.3, -0.15, 0.25, 0.8, -0.35, 0.45}; const StateVector expected = hidden_reference::hlld_flux_from_primitive(left, right, bx, gamma); - const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } @@ -152,6 +161,6 @@ TEST_CASE("second Bx equals zero hydro case matches reference implementation") const StateVector right{1.2, -0.2, 0.0, 0.0, 1.3, 0.0, 0.0}; const StateVector expected = hidden_reference::hlld_flux_from_primitive(left, right, bx, gamma); - const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/test_hidden.py b/benchmarks/magnetohydrodynamics/cpp-hlld-00/eval/tests/test_hidden.py similarity index 100% rename from benchmarks/magnetohydrodynamics/cpp-hlld/eval/tests/test_hidden.py rename to benchmarks/magnetohydrodynamics/cpp-hlld-00/eval/tests/test_hidden.py diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld-00/spec.md b/benchmarks/magnetohydrodynamics/cpp-hlld-00/spec.md new file mode 100644 index 0000000..e4e3621 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld-00/spec.md @@ -0,0 +1,48 @@ +# cpp-hlld-00 + +Implement the HLLD approximate Riemann solver for 1D ideal MHD in C++. + +## Read first + +- `/work/basic_equations.md` +- `/work/hlld.md` + +## Task + +Edit `src/hlld.cpp` so that `hlld_flux_from_primitive(...)` is implemented correctly. + +The benchmark uses: + +- primitive-state ordering: `[rho, u, v, w, p, By, Bz]` +- flux ordering: `[F_rho, F_mx, F_my, F_mz, F_E, F_By, F_Bz]` +- the test suite includes `Bx = 0` hydro and magnetized degenerate cases +- the test suite also includes a small-`Bx` near-degenerate case, so handle + `Bx = 0`, small denominators in the starred-state formulas, and related + square-root/discriminant edge cases carefully + +Do not change the public function signatures in `src/hlld.hpp`. + +## Implementation hints + +- This benchmark follows one specific HLLD implementation convention rather than + an arbitrary mathematically equivalent variant. +- Small starred-state denominator (`D_alpha`): if `|D_alpha|` is extremely + small, avoid dividing by it and fall back to unchanged transverse starred + values (`v* = v`, `w* = w`, `By* = By`, `Bz* = Bz`). +- Small `Bx`: when `Bx = 0`, rotational waves collapse and double-star states + are unnecessary; do not use double-star states in flux selection in that + case. +- For this benchmark, a merely small nonzero `|Bx|` is still nondegenerate + unless another guarded quantity (such as `D_alpha`) becomes numerically + singular. +- Assume all benchmark inputs are admissible physical states. + +## Standards + +- C++17 + +## Local dev + +```bash +pytest -q +``` diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/task.toml b/benchmarks/magnetohydrodynamics/cpp-hlld-00/task.toml similarity index 92% rename from benchmarks/magnetohydrodynamics/cpp-hlld/task.toml rename to benchmarks/magnetohydrodynamics/cpp-hlld-00/task.toml index f58f5d8..2d7c0d1 100644 --- a/benchmarks/magnetohydrodynamics/cpp-hlld/task.toml +++ b/benchmarks/magnetohydrodynamics/cpp-hlld-00/task.toml @@ -1,4 +1,4 @@ -id = "cpp-hlld" +id = "cpp-hlld-00" suite = "magnetohydrodynamics" language = "cpp" time_limit_sec = 600 diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/CMakeLists.txt b/benchmarks/magnetohydrodynamics/cpp-hlld-00/workspace/CMakeLists.txt similarity index 100% rename from benchmarks/magnetohydrodynamics/cpp-hlld/workspace/CMakeLists.txt rename to benchmarks/magnetohydrodynamics/cpp-hlld-00/workspace/CMakeLists.txt diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/pyproject.toml b/benchmarks/magnetohydrodynamics/cpp-hlld-00/workspace/pyproject.toml similarity index 100% rename from benchmarks/magnetohydrodynamics/cpp-hlld/workspace/pyproject.toml rename to benchmarks/magnetohydrodynamics/cpp-hlld-00/workspace/pyproject.toml diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld-00/workspace/src/hlld.cpp b/benchmarks/magnetohydrodynamics/cpp-hlld-00/workspace/src/hlld.cpp new file mode 100644 index 0000000..b200baf --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld-00/workspace/src/hlld.cpp @@ -0,0 +1,14 @@ +#include "hlld.hpp" + +#include + +void hlld_flux_from_primitive(const double* left, const double* right, double bx, double gamma, + double* flux) +{ + (void)left; + (void)right; + (void)bx; + (void)gamma; + + std::fill(flux, flux + 7, 0.0); +} diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld-00/workspace/src/hlld.hpp b/benchmarks/magnetohydrodynamics/cpp-hlld-00/workspace/src/hlld.hpp new file mode 100644 index 0000000..ae80ebd --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld-00/workspace/src/hlld.hpp @@ -0,0 +1,4 @@ +#pragma once + +void hlld_flux_from_primitive(const double* left, const double* right, double bx, double gamma, + double* flux); diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/cpp/test_public.cpp b/benchmarks/magnetohydrodynamics/cpp-hlld-00/workspace/tests/cpp/test_public.cpp similarity index 82% rename from benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/cpp/test_public.cpp rename to benchmarks/magnetohydrodynamics/cpp-hlld-00/workspace/tests/cpp/test_public.cpp index abb9bf1..0c73c44 100644 --- a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/cpp/test_public.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-hlld-00/workspace/tests/cpp/test_public.cpp @@ -12,6 +12,10 @@ #include +#include + +using StateVector = std::array; + namespace { @@ -66,6 +70,14 @@ StateVector physical_flux_x(const StateVector& state, double bx, double gamma) }; } +StateVector solver_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, + double gamma) +{ + StateVector flux{}; + hlld_flux_from_primitive(left.data(), right.data(), bx, gamma, flux.data()); + return flux; +} + void require_close(const StateVector& actual, const StateVector& expected) { for (std::size_t i = 0; i < actual.size(); ++i) { @@ -82,30 +94,12 @@ TEST_CASE("equal primitive states reduce to the physical flux") const StateVector state{1.1, 0.2, -0.3, 0.4, 0.9, 0.5, -0.6}; const StateVector conservative = primitive_to_conservative(state, bx, gamma); - const StateVector actual = hlld_flux_from_primitive(state, state, bx, gamma); + const StateVector actual = solver_flux_from_primitive(state, state, bx, gamma); const StateVector expected = physical_flux_x(conservative, bx, gamma); require_close(actual, expected); } -TEST_CASE("primitive and conservative entry points agree") -{ - const double bx = -0.4; - const double gamma = 5.0 / 3.0; - - const StateVector left{1.0, 0.3, 0.1, -0.2, 1.0, 0.7, -0.5}; - const StateVector right{0.8, -0.1, -0.4, 0.25, 0.7, -0.2, 0.3}; - - const StateVector left_cons = primitive_to_conservative(left, bx, gamma); - const StateVector right_cons = primitive_to_conservative(right, bx, gamma); - - const StateVector from_primitive = hlld_flux_from_primitive(left, right, bx, gamma); - const StateVector from_conservative = - hlld_flux_from_conservative(left_cons, right_cons, bx, gamma); - - require_close(from_primitive, from_conservative); -} - TEST_CASE("right-going contact discontinuity is resolved exactly") { const double bx = 0.8; @@ -114,7 +108,7 @@ TEST_CASE("right-going contact discontinuity is resolved exactly") const StateVector left{1.0, 0.3, 0.2, -0.15, 1.0, 0.6, -0.3}; const StateVector right{0.7, 0.3, 0.2, -0.15, 1.0, 0.6, -0.3}; - const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); require_close(actual, physical_flux_x(primitive_to_conservative(left, bx, gamma), bx, gamma)); } @@ -126,7 +120,7 @@ TEST_CASE("left-going contact discontinuity is resolved exactly") const StateVector left{1.0, -0.25, 0.2, -0.15, 1.0, 0.6, -0.3}; const StateVector right{0.7, -0.25, 0.2, -0.15, 1.0, 0.6, -0.3}; - const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); require_close(actual, physical_flux_x(primitive_to_conservative(right, bx, gamma), bx, gamma)); } @@ -141,7 +135,7 @@ TEST_CASE("right-going rotational discontinuity is resolved exactly") 0.2, 1.04, -0.98, -0.04, 0.609, 0.1, 0.2, }; - const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } @@ -156,7 +150,7 @@ TEST_CASE("left-going rotational discontinuity is resolved exactly") 0.2, 1.04, -0.66, -0.68, 0.449, 0.42, -0.44, }; - const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } @@ -171,7 +165,7 @@ TEST_CASE("Bx equals zero hydro case matches reference flux") 0.92274146439449267, 1.3581095429585437, 0.0, 0.0, 3.1282919538345322, 0.0, 0.0, }; - const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } @@ -187,7 +181,7 @@ TEST_CASE("Bx equals zero magnetized case matches reference flux") 1.6980640537315086, 0.31370867365037713, -0.22407762403598386, }; - const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } @@ -203,7 +197,7 @@ TEST_CASE("small Bx near-degenerate case matches reference flux") 0.72345786285986069, 0.081493464279122407, -0.065194831423298072, }; - const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } @@ -223,7 +217,7 @@ TEST_CASE("Ryu and Jones shock tube matches reference flux") 3.9950643754664625, 0.67495208799031015, -0.062307582042232856, }; - const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } @@ -244,7 +238,7 @@ TEST_CASE("Brio and Wu shock tube matches reference flux") 0.0, }; - const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } @@ -265,7 +259,7 @@ TEST_CASE("Falle switch-off shock matches reference flux") 0.0, }; - const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } @@ -286,7 +280,7 @@ TEST_CASE("Falle switch-off rarefaction matches reference flux") 0.0, }; - const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } @@ -301,6 +295,6 @@ TEST_CASE("super-fast expansion matches reference flux") 0.0, -2.425, 0.0, 0.0, 0.0, 0.0, 0.0, }; - const StateVector actual = hlld_flux_from_primitive(left, right, bx, gamma); + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); require_close(actual, expected); } diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/test_public.py b/benchmarks/magnetohydrodynamics/cpp-hlld-00/workspace/tests/test_public.py similarity index 100% rename from benchmarks/magnetohydrodynamics/cpp-hlld/workspace/tests/test_public.py rename to benchmarks/magnetohydrodynamics/cpp-hlld-00/workspace/tests/test_public.py diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld-01/eval/run.sh b/benchmarks/magnetohydrodynamics/cpp-hlld-01/eval/run.sh new file mode 100755 index 0000000..c95929f --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld-01/eval/run.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -u -o pipefail + +cd /work + +status="passed" +score="1.0" + +python3 -m pytest -q /eval/tests +rc=$? +if [ "$rc" -ne 0 ]; then + status="failed" + score="0.0" +fi + +python3 - < +#include #include -namespace -{ - -constexpr double epsilon = 1.0e-40; +using StateVector = std::array; -double sign_unit(double x) +namespace hidden_reference { - return (x >= 0.0) ? 1.0 : -1.0; -} -StateVector primitive_from_conservative(const StateVector& state, double bx, double gamma) +inline StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, + double bx, double gamma) { - const double rho = state[0]; - const double u = state[1] / rho; - const double v = state[2] / rho; - const double w = state[3] / rho; - const double by = state[5]; - const double bz = state[6]; - - const double kinetic = 0.5 * rho * (u * u + v * v + w * w); - const double magnetic = 0.5 * (bx * bx + by * by + bz * bz); - const double p = (gamma - 1.0) * (state[4] - kinetic - magnetic); - - return StateVector{rho, u, v, w, p, by, bz}; -} + constexpr double eps = 1.0e-40; -} // namespace - -StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, - double gamma) -{ const double rol = left[0]; const double vxl = left[1]; const double vyl = left[2]; @@ -109,8 +94,10 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& const double sdmr = sr - sm; const double ptst = (rosdr * ptl - rosdl * ptr + rosdl * rosdr * (vxr - vxl)) * temp; + const auto sign_unit = [](double x) { return (x >= 0.0) ? 1.0 : -1.0; }; + const double temp_fst_l = rosdl * sdml - bxsq; - const double sign1_l = sign_unit(std::abs(temp_fst_l) - epsilon); + const double sign1_l = sign_unit(std::abs(temp_fst_l) - eps); const double maxs1_l = std::max(0.0, sign1_l); const double mins1_l = std::min(0.0, sign1_l); const double itf_l = 1.0 / (temp_fst_l + mins1_l); @@ -134,7 +121,7 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& mins1_l * eel; const double temp_fst_r = rosdr * sdmr - bxsq; - const double sign1_r = sign_unit(std::abs(temp_fst_r) - epsilon); + const double sign1_r = sign_unit(std::abs(temp_fst_r) - eps); const double maxs1_r = std::max(0.0, sign1_r); const double mins1_r = std::min(0.0, sign1_r); const double itf_r = 1.0 / (temp_fst_r + mins1_r); @@ -163,7 +150,7 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& const double slst = sm - abbx / sqrtrol; const double srst = sm + abbx / sqrtror; const double signbx = sign_unit(bxs); - const double sign1_b = sign_unit(abbx - epsilon); + const double sign1_b = sign_unit(abbx - eps); const double maxs1_b = std::max(0.0, sign1_b); const double mins1_b = -std::min(0.0, sign1_b); const double invsumro = maxs1_b / (sqrtrol + sqrtror); @@ -172,14 +159,20 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& const double rordst = rorst; const double rxldst = rxlst; const double rxrdst = rxrst; + const double vxldst = vxlst; + const double vxrdst = vxrst; const double vy_shared = invsumro * (sqrtrol * vylst + sqrtror * vyrst + signbx * (byrst - bylst)); + const double vyldst = vylst * mins1_b + vy_shared; + const double vyrdst = vyrst * mins1_b + vy_shared; const double ryldst = rylst * mins1_b + roldst * vy_shared; const double ryrdst = ryrst * mins1_b + rordst * vy_shared; const double vz_shared = invsumro * (sqrtrol * vzlst + sqrtror * vzrst + signbx * (bzrst - bzlst)); + const double vzldst = vzlst * mins1_b + vz_shared; + const double vzrdst = vzrst * mins1_b + vz_shared; const double rzldst = rzlst * mins1_b + roldst * vz_shared; const double rzrdst = rzrst * mins1_b + rordst * vz_shared; @@ -193,10 +186,6 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& const double bzldst = bzlst * mins1_b + bz_shared; const double bzrdst = bzrst * mins1_b + bz_shared; - const double vyldst = vylst * mins1_b + vy_shared; - const double vyrdst = vyrst * mins1_b + vy_shared; - const double vzldst = vzlst * mins1_b + vz_shared; - const double vzrdst = vzrst * mins1_b + vz_shared; const double temp_dst = sm * bxs + vyldst * byldst + vzldst * bzldst; const double eeldst = eelst - sqrtrol * signbx * (vdbstl - temp_dst) * maxs1_b; const double eerdst = eerst + sqrtror * signbx * (vdbstr - temp_dst) * maxs1_b; @@ -229,9 +218,12 @@ StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& }; } -StateVector hlld_flux_from_conservative(const StateVector& left, const StateVector& right, - double bx, double gamma) +inline StateVector solver_flux_from_primitive(const StateVector& left, const StateVector& right, + double bx, double gamma) { - return hlld_flux_from_primitive(primitive_from_conservative(left, bx, gamma), - primitive_from_conservative(right, bx, gamma), bx, gamma); + StateVector flux{}; + ::hlld_flux_from_primitive(left.data(), right.data(), bx, gamma, flux.data()); + return flux; } + +} // namespace hidden_reference diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld-01/eval/tests/cpp/test_hidden.cpp b/benchmarks/magnetohydrodynamics/cpp-hlld-01/eval/tests/cpp/test_hidden.cpp new file mode 100644 index 0000000..35d8074 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld-01/eval/tests/cpp/test_hidden.cpp @@ -0,0 +1,166 @@ +#if __has_include("hlld.hpp") +#include "hlld.hpp" +#else +#include "../../../workspace/src/hlld.hpp" +#endif + +#if __has_include() +#include +#else +#include "/usr/local/include/catch2/catch_test_macros.hpp" +#endif + +#include "hlld_reference.hpp" + +#include +#include + +using StateVector = std::array; + +namespace +{ + +constexpr double kTolerance = 1e-12; + +StateVector primitive_to_conservative(const StateVector& state, double bx, double gamma) +{ + const double rho = state[0]; + const double u = state[1]; + const double v = state[2]; + const double w = state[3]; + const double p = state[4]; + const double by = state[5]; + const double bz = state[6]; + + const double kinetic = 0.5 * rho * (u * u + v * v + w * w); + const double magnetic = 0.5 * (bx * bx + by * by + bz * bz); + const double energy = p / (gamma - 1.0) + kinetic + magnetic; + + return StateVector{rho, rho * u, rho * v, rho * w, energy, by, bz}; +} + +StateVector physical_flux_x(const StateVector& state, double bx, double gamma) +{ + const double rho = state[0]; + const double mx = state[1]; + const double my = state[2]; + const double mz = state[3]; + const double energy = state[4]; + const double by = state[5]; + const double bz = state[6]; + + const double u = mx / rho; + const double v = my / rho; + const double w = mz / rho; + const double kinetic = 0.5 * rho * (u * u + v * v + w * w); + const double magnetic = 0.5 * (bx * bx + by * by + bz * bz); + const double pressure = (gamma - 1.0) * (energy - kinetic - magnetic); + const double total_pressure = pressure + magnetic; + + return StateVector{ + rho * u, + rho * u * u + total_pressure - bx * bx, + rho * v * u - bx * by, + rho * w * u - bx * bz, + (energy + total_pressure) * u - bx * (u * bx + v * by + w * bz), + by * u - bx * v, + bz * u - bx * w, + }; +} + +void require_close(const StateVector& actual, const StateVector& expected) +{ + for (std::size_t i = 0; i < actual.size(); ++i) { + REQUIRE(std::abs(actual[i] - expected[i]) <= kTolerance); + } +} + +StateVector solver_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, + double gamma) +{ + StateVector flux{}; + hlld_flux_from_primitive(left.data(), right.data(), bx, gamma, flux.data()); + return flux; +} + +} // namespace + +TEST_CASE("equal primitive states reduce to the physical flux") +{ + const double bx = 0.35; + const double gamma = 1.4; + const StateVector state{0.9, -0.45, 0.2, 0.15, 0.8, -0.3, 0.55}; + + const StateVector actual = solver_flux_from_primitive(state, state, bx, gamma); + const StateVector expected = + physical_flux_x(primitive_to_conservative(state, bx, gamma), bx, gamma); + + require_close(actual, expected); +} + +TEST_CASE("nontrivial primitive solve returns finite values") +{ + const double bx = -0.65; + const double gamma = 5.0 / 3.0; + + const StateVector left{1.08, 0.45, -0.12, 0.08, 0.95, 0.4, -0.3}; + const StateVector right{0.72, -0.25, 0.16, -0.05, 0.58, -0.2, 0.35}; + + const StateVector flux = solver_flux_from_primitive(left, right, bx, gamma); + + for (double value : flux) { + REQUIRE(std::isfinite(value)); + } +} + +TEST_CASE("hidden reference flux case 1 matches reference implementation") +{ + const double bx = -0.65; + const double gamma = 5.0 / 3.0; + + const StateVector left{1.08, 0.45, -0.12, 0.08, 0.95, 0.4, -0.3}; + const StateVector right{0.72, -0.25, 0.16, -0.05, 0.58, -0.2, 0.35}; + const StateVector expected = hidden_reference::hlld_flux_from_primitive(left, right, bx, gamma); + + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("hidden reference flux case 2 matches reference implementation") +{ + const double bx = 0.35; + const double gamma = 1.4; + + const StateVector left{0.9, -0.45, 0.2, 0.15, 0.8, -0.3, 0.55}; + const StateVector right{1.15, 0.18, -0.12, -0.08, 1.05, 0.22, -0.4}; + const StateVector expected = hidden_reference::hlld_flux_from_primitive(left, right, bx, gamma); + + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("small Bx near-degenerate reference case matches reference implementation") +{ + const double bx = 1.0e-6; + const double gamma = 1.4; + + const StateVector left{1.0, 0.4, 0.2, -0.1, 1.0, 0.5, -0.4}; + const StateVector right{0.85, -0.3, -0.15, 0.25, 0.8, -0.35, 0.45}; + const StateVector expected = hidden_reference::hlld_flux_from_primitive(left, right, bx, gamma); + + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("second Bx equals zero hydro case matches reference implementation") +{ + const double bx = 0.0; + const double gamma = 1.4; + + const StateVector left{0.4, -1.1, 0.0, 0.0, 0.4, 0.0, 0.0}; + const StateVector right{1.2, -0.2, 0.0, 0.0, 1.3, 0.0, 0.0}; + const StateVector expected = hidden_reference::hlld_flux_from_primitive(left, right, bx, gamma); + + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld-01/eval/tests/test_hidden.py b/benchmarks/magnetohydrodynamics/cpp-hlld-01/eval/tests/test_hidden.py new file mode 100644 index 0000000..c0e0187 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld-01/eval/tests/test_hidden.py @@ -0,0 +1,36 @@ +import subprocess +from pathlib import Path + + +def _build_hidden_tests() -> Path: + hidden_source = Path("/eval/tests/cpp/test_hidden.cpp") + subprocess.run( + [ + "cmake", + "-S", + ".", + "-B", + "build", + "-DSIMBENCH_ENABLE_HIDDEN_TESTS=ON", + f"-DSIMBENCH_HIDDEN_TEST_SOURCE={hidden_source}", + ], + check=True, + ) + subprocess.run( + ["cmake", "--build", "build", "--target", "hlld_hidden_tests"], check=True + ) + exe = Path("build/tests/hlld_hidden_tests") + assert exe.exists() + return exe + + +def test_hidden_catch2_suite() -> None: + exe = _build_hidden_tests() + proc = subprocess.run( + [str(exe), "--reporter", "compact"], + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + check=False, + ) + assert proc.returncode == 0, proc.stdout + proc.stderr diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld-01/spec.md b/benchmarks/magnetohydrodynamics/cpp-hlld-01/spec.md new file mode 100644 index 0000000..fb106e9 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld-01/spec.md @@ -0,0 +1,29 @@ +# cpp-hlld-01 + +Implement the HLLD approximate Riemann solver for 1D ideal MHD in C++. + +## Read first + +- `/work/basic_equations.md` +- `/work/hlld.md` + +## Task + +Edit `src/hlld.cpp` so that `hlld_flux_from_primitive(...)` is implemented correctly. + +The benchmark uses: + +- primitive-state ordering: `[rho, u, v, w, p, By, Bz]` +- flux ordering: `[F_rho, F_mx, F_my, F_mz, F_E, F_By, F_Bz]` + +Do not change the public function signatures in `src/hlld.hpp`. + +## Standards + +- C++17 + +## Local dev + +```bash +pytest -q +``` diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld-01/task.toml b/benchmarks/magnetohydrodynamics/cpp-hlld-01/task.toml new file mode 100644 index 0000000..de31b95 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld-01/task.toml @@ -0,0 +1,7 @@ +id = "cpp-hlld-01" +suite = "magnetohydrodynamics" +language = "cpp" +time_limit_sec = 600 +eval_cmd = "/eval/run.sh" +prompt = "Read /run/spec.md, /work/basic_equations.md, and /work/hlld.md, then solve the task in /work." +use_shared_workspace = true diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/CMakeLists.txt b/benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/CMakeLists.txt new file mode 100644 index 0000000..097e6eb --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/CMakeLists.txt @@ -0,0 +1,69 @@ +cmake_minimum_required(VERSION 3.16) + +project(cpp_hlld LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +include(FetchContent) + +option(SIMBENCH_ENABLE_HIDDEN_TESTS "Build hidden Catch2 tests" OFF) +set( + SIMBENCH_HIDDEN_TEST_SOURCE + "" + CACHE FILEPATH + "Path to hidden Catch2 test source" +) + +find_package(Catch2 3 QUIET) + +if(NOT Catch2_FOUND) + FetchContent_Declare( + Catch2 + GIT_REPOSITORY https://github.com/catchorg/Catch2.git + GIT_TAG v3.13.0 + GIT_SHALLOW TRUE + ) + FetchContent_MakeAvailable(Catch2) +endif() + +add_library(hlld_solver + src/hlld.cpp +) + +target_include_directories(hlld_solver PUBLIC + src +) + +add_executable(hlld_public_tests + tests/cpp/test_public.cpp +) + +target_link_libraries(hlld_public_tests PRIVATE + hlld_solver + Catch2::Catch2WithMain +) + +set_target_properties(hlld_public_tests PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests" +) + +if(SIMBENCH_ENABLE_HIDDEN_TESTS) + if(NOT EXISTS "${SIMBENCH_HIDDEN_TEST_SOURCE}") + message(FATAL_ERROR "Hidden test source not found: ${SIMBENCH_HIDDEN_TEST_SOURCE}") + endif() + + add_executable(hlld_hidden_tests + "${SIMBENCH_HIDDEN_TEST_SOURCE}" + ) + + target_link_libraries(hlld_hidden_tests PRIVATE + hlld_solver + Catch2::Catch2WithMain + ) + + set_target_properties(hlld_hidden_tests PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests" + ) +endif() diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/pyproject.toml b/benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/pyproject.toml new file mode 100644 index 0000000..66bd2af --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/pyproject.toml @@ -0,0 +1,7 @@ +[project] +name = "magnetohydrodynamics-cpp-hlld" +version = "0.0.0" +requires-python = ">=3.10" + +[tool.pytest.ini_options] +testpaths = ["tests"] diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/src/hlld.cpp b/benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/src/hlld.cpp new file mode 100644 index 0000000..b200baf --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/src/hlld.cpp @@ -0,0 +1,14 @@ +#include "hlld.hpp" + +#include + +void hlld_flux_from_primitive(const double* left, const double* right, double bx, double gamma, + double* flux) +{ + (void)left; + (void)right; + (void)bx; + (void)gamma; + + std::fill(flux, flux + 7, 0.0); +} diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/src/hlld.hpp b/benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/src/hlld.hpp new file mode 100644 index 0000000..ae80ebd --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/src/hlld.hpp @@ -0,0 +1,4 @@ +#pragma once + +void hlld_flux_from_primitive(const double* left, const double* right, double bx, double gamma, + double* flux); diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/tests/cpp/test_public.cpp b/benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/tests/cpp/test_public.cpp new file mode 100644 index 0000000..0c73c44 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/tests/cpp/test_public.cpp @@ -0,0 +1,300 @@ +#if __has_include("hlld.hpp") +#include "hlld.hpp" +#else +#include "../../src/hlld.hpp" +#endif + +#if __has_include() +#include +#else +#include "/usr/local/include/catch2/catch_test_macros.hpp" +#endif + +#include + +#include + +using StateVector = std::array; + +namespace +{ + +constexpr double kTolerance = 1e-12; +constexpr double kPi = 3.14159265358979323846; + +StateVector primitive_to_conservative(const StateVector& state, double bx, double gamma) +{ + const double rho = state[0]; + const double u = state[1]; + const double v = state[2]; + const double w = state[3]; + const double p = state[4]; + const double by = state[5]; + const double bz = state[6]; + + const double kinetic = 0.5 * rho * (u * u + v * v + w * w); + const double magnetic = 0.5 * (bx * bx + by * by + bz * bz); + const double energy = p / (gamma - 1.0) + kinetic + magnetic; + + return StateVector{ + rho, rho * u, rho * v, rho * w, energy, by, bz, + }; +} + +StateVector physical_flux_x(const StateVector& state, double bx, double gamma) +{ + const double rho = state[0]; + const double mx = state[1]; + const double my = state[2]; + const double mz = state[3]; + const double energy = state[4]; + const double by = state[5]; + const double bz = state[6]; + + const double u = mx / rho; + const double v = my / rho; + const double w = mz / rho; + const double kinetic = 0.5 * rho * (u * u + v * v + w * w); + const double magnetic = 0.5 * (bx * bx + by * by + bz * bz); + const double pressure = (gamma - 1.0) * (energy - kinetic - magnetic); + const double total_pressure = pressure + magnetic; + + return StateVector{ + rho * u, + rho * u * u + total_pressure - bx * bx, + rho * v * u - bx * by, + rho * w * u - bx * bz, + (energy + total_pressure) * u - bx * (u * bx + v * by + w * bz), + by * u - bx * v, + bz * u - bx * w, + }; +} + +StateVector solver_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, + double gamma) +{ + StateVector flux{}; + hlld_flux_from_primitive(left.data(), right.data(), bx, gamma, flux.data()); + return flux; +} + +void require_close(const StateVector& actual, const StateVector& expected) +{ + for (std::size_t i = 0; i < actual.size(); ++i) { + REQUIRE(std::abs(actual[i] - expected[i]) <= kTolerance); + } +} + +} // namespace + +TEST_CASE("equal primitive states reduce to the physical flux") +{ + const double bx = 0.75; + const double gamma = 1.4; + const StateVector state{1.1, 0.2, -0.3, 0.4, 0.9, 0.5, -0.6}; + const StateVector conservative = primitive_to_conservative(state, bx, gamma); + + const StateVector actual = solver_flux_from_primitive(state, state, bx, gamma); + const StateVector expected = physical_flux_x(conservative, bx, gamma); + + require_close(actual, expected); +} + +TEST_CASE("right-going contact discontinuity is resolved exactly") +{ + const double bx = 0.8; + const double gamma = 5.0 / 3.0; + + const StateVector left{1.0, 0.3, 0.2, -0.15, 1.0, 0.6, -0.3}; + const StateVector right{0.7, 0.3, 0.2, -0.15, 1.0, 0.6, -0.3}; + + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); + require_close(actual, physical_flux_x(primitive_to_conservative(left, bx, gamma), bx, gamma)); +} + +TEST_CASE("left-going contact discontinuity is resolved exactly") +{ + const double bx = 0.8; + const double gamma = 5.0 / 3.0; + + const StateVector left{1.0, -0.25, 0.2, -0.15, 1.0, 0.6, -0.3}; + const StateVector right{0.7, -0.25, 0.2, -0.15, 1.0, 0.6, -0.3}; + + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); + require_close(actual, physical_flux_x(primitive_to_conservative(right, bx, gamma), bx, gamma)); +} + +TEST_CASE("right-going rotational discontinuity is resolved exactly") +{ + const double bx = 1.0; + const double gamma = 5.0 / 3.0; + + const StateVector left{1.0, 0.2, 0.1, -0.2, 1.0, 1.0, 0.0}; + const StateVector right{1.0, 0.2, 0.5, -1.0, 1.0, 0.6, 0.8}; + const StateVector expected{ + 0.2, 1.04, -0.98, -0.04, 0.609, 0.1, 0.2, + }; + + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("left-going rotational discontinuity is resolved exactly") +{ + const double bx = 1.0; + const double gamma = 5.0 / 3.0; + + const StateVector left{1.0, 0.2, 0.1, -0.2, 1.0, 1.0, 0.0}; + const StateVector right{1.0, 0.2, -0.3, 0.6, 1.0, 0.6, 0.8}; + const StateVector expected{ + 0.2, 1.04, -0.66, -0.68, 0.449, 0.42, -0.44, + }; + + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("Bx equals zero hydro case matches reference flux") +{ + const double bx = 0.0; + const double gamma = 1.4; + + const StateVector left{1.0, 0.75, 0.0, 0.0, 1.0, 0.0, 0.0}; + const StateVector right{0.125, 0.0, 0.0, 0.0, 0.1, 0.0, 0.0}; + const StateVector expected{ + 0.92274146439449267, 1.3581095429585437, 0.0, 0.0, 3.1282919538345322, 0.0, 0.0, + }; + + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("Bx equals zero magnetized case matches reference flux") +{ + const double bx = 0.0; + const double gamma = 5.0 / 3.0; + + const StateVector left{1.0, 0.6, 0.1, -0.2, 1.0, 0.7, -0.5}; + const StateVector right{0.7, -0.3, -0.15, 0.25, 0.5, -0.2, 0.4}; + const StateVector expected{ + 0.44815524807196727, 2.011116795062418, 0.044815524807196722, -0.089631049614393443, + 1.6980640537315086, 0.31370867365037713, -0.22407762403598386, + }; + + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("small Bx near-degenerate case matches reference flux") +{ + const double bx = 1.0e-6; + const double gamma = 1.4; + + const StateVector left{1.0, 0.4, 0.2, -0.1, 1.0, 0.5, -0.4}; + const StateVector right{0.85, -0.3, -0.15, 0.25, 0.8, -0.35, 0.45}; + const StateVector expected{ + 0.16298732855830989, 1.7549717390289374, 0.032596899426565185, -0.016298279827753587, + 0.72345786285986069, 0.081493464279122407, -0.065194831423298072, + }; + + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("Ryu and Jones shock tube matches reference flux") +{ + const double bx = 4.0 / std::sqrt(4.0 * kPi); + const double gamma = 5.0 / 3.0; + + const StateVector left{ + 1.08, 1.2, 0.01, 0.5, 0.95, 3.6 / std::sqrt(4.0 * kPi), 2.0 / std::sqrt(4.0 * kPi), + }; + const StateVector right{ + 1.0, 0.0, 0.0, 0.0, 1.0, 4.0 / std::sqrt(4.0 * kPi), 2.0 / std::sqrt(4.0 * kPi), + }; + const StateVector expected{ + 0.79485593966715773, 3.5458209484697329, -1.3572358551169827, -0.22185101509215432, + 3.9950643754664625, 0.67495208799031015, -0.062307582042232856, + }; + + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("Brio and Wu shock tube matches reference flux") +{ + const double bx = 0.75; + const double gamma = 5.0 / 3.0; + + const StateVector left{1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0}; + const StateVector right{0.125, 0.0, 0.0, 0.0, 0.1, -1.0, 0.0}; + const StateVector expected{ + 0.2063330447744266, + 0.4638678509599396, + 0.064186763013841408, + 0.0, + 0.16136546437466026, + 1.010233243594872, + 0.0, + }; + + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("Falle switch-off shock matches reference flux") +{ + const double bx = 1.0; + const double gamma = 5.0 / 3.0; + + const StateVector left{1.368, 0.269, 1.0, 0.0, 1.769, 0.0, 0.0}; + const StateVector right{1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0}; + const StateVector expected{ + 0.29721990694355238, + 1.4932992607654056, + 0.2893229270591654, + 0.0, + 1.1427267633652525, + -1.0066552479847843, + 0.0, + }; + + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("Falle switch-off rarefaction matches reference flux") +{ + const double bx = 1.0; + const double gamma = 5.0 / 3.0; + + const StateVector left{1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0}; + const StateVector right{0.2, 1.186, 2.967, 0.0, 0.1368, 1.6405, 0.0}; + const StateVector expected{ + 0.27717801577960577, + 0.28228035303750848, + -1.3364302412732558, + 0.0, + -1.5599793330037519, + -1.3806947854633354, + 0.0, + }; + + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} + +TEST_CASE("super-fast expansion matches reference flux") +{ + const double bx = 0.0; + const double gamma = 5.0 / 3.0; + + const StateVector left{1.0, -3.0, 0.0, 0.0, 0.45, 0.5, 0.0}; + const StateVector right{1.0, 3.0, 0.0, 0.0, 0.45, 0.5, 0.0}; + const StateVector expected{ + 0.0, -2.425, 0.0, 0.0, 0.0, 0.0, 0.0, + }; + + const StateVector actual = solver_flux_from_primitive(left, right, bx, gamma); + require_close(actual, expected); +} diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/tests/test_public.py b/benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/tests/test_public.py new file mode 100644 index 0000000..69b5cfa --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-hlld-01/workspace/tests/test_public.py @@ -0,0 +1,24 @@ +import subprocess +from pathlib import Path + + +def _build_public_tests() -> Path: + subprocess.run(["cmake", "-S", ".", "-B", "build"], check=True) + subprocess.run( + ["cmake", "--build", "build", "--target", "hlld_public_tests"], check=True + ) + exe = Path("build/tests/hlld_public_tests") + assert exe.exists() + return exe + + +def test_catch2_public_suite() -> None: + exe = _build_public_tests() + proc = subprocess.run( + [str(exe), "--reporter", "compact"], + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + check=False, + ) + assert proc.returncode == 0, proc.stdout + proc.stderr diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/spec.md b/benchmarks/magnetohydrodynamics/cpp-hlld/spec.md deleted file mode 100644 index 4fbd5e6..0000000 --- a/benchmarks/magnetohydrodynamics/cpp-hlld/spec.md +++ /dev/null @@ -1,40 +0,0 @@ -# cpp-hlld - -Implement the HLLD approximate Riemann solver for 1D ideal MHD in C++. - -## Read first - -- `/work/basic_equations.md` -- `/work/hlld.md` - -## Task - -Edit `src/hlld.cpp` so that these functions are implemented correctly: - -- `hlld_flux_from_primitive(...)` -- `hlld_flux_from_conservative(...)` - -The benchmark uses: - -- primitive-state ordering: `[rho, u, v, w, p, By, Bz]` -- conservative-state ordering: `[rho, mx, my, mz, E, By, Bz]` -- flux ordering: `[F_rho, F_mx, F_my, F_mz, F_E, F_By, F_Bz]` -- Lorentz-Heaviside units -- `Bx` passed separately from the state vectors -- the test suite includes `Bx = 0` hydro and magnetized degenerate cases -- the test suite also includes a small-`Bx` near-degenerate case, so handle - `Bx = 0`, small denominators in the starred-state formulas, and related - square-root/discriminant edge cases carefully - -Do not change the public function signatures in `src/hlld.hpp`. - -## Standards - -- C++17 -- Use `std::array` for the public API - -## Local dev - -```bash -pytest -q -``` diff --git a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.hpp b/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.hpp deleted file mode 100644 index 08d1c64..0000000 --- a/benchmarks/magnetohydrodynamics/cpp-hlld/workspace/src/hlld.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include - -using StateVector = std::array; - -StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, - double gamma); - -StateVector hlld_flux_from_conservative(const StateVector& left, const StateVector& right, - double bx, double gamma); diff --git a/benchmarks/magnetohydrodynamics/shared/workspace/hlld.md b/benchmarks/magnetohydrodynamics/shared/workspace/hlld.md index d6822fa..5633e0a 100644 --- a/benchmarks/magnetohydrodynamics/shared/workspace/hlld.md +++ b/benchmarks/magnetohydrodynamics/shared/workspace/hlld.md @@ -394,31 +394,3 @@ to the location of zero in the wave fan: All fluxes use the conservative component ordering defined in `basic_equations.md`. - -## Implementation notes - -- This benchmark follows one specific HLLD implementation convention rather than - an arbitrary mathematically equivalent variant. - -- Small starred-state denominator - If $|D_\alpha|$ is extremely small, do not apply the raw starred-state update - by dividing through that value. Instead, replace the starred transverse - updates with: - -```math -v_\alpha^\ast = v_\alpha, \quad -w_\alpha^\ast = w_\alpha, \quad -B_{y,\alpha}^\ast = B_{y,\alpha}, \quad -B_{z,\alpha}^\ast = B_{z,\alpha}. -``` - -- Small $B_x$ - When $B_x=0$, the rotational waves collapse and the double-star regions become - unnecessary. In that case, do not use the double-star states for flux - calculation. - - For this benchmark, a merely small nonzero $|B_x|$ should still be treated as - a nondegenerate case unless some other guarded quantity, such as $D_\alpha$, - becomes numerically singular. - -- Assume all benchmark inputs are admissible physical states. From 788cc05e84b8d88b4e9d2363f3bc857b4f9feb59 Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Thu, 2 Apr 2026 11:02:34 +0900 Subject: [PATCH 32/39] chore: add vscode workspace excludes --- .vscode/settings.json | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5ee38c9 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,35 @@ +{ + "files.exclude": { + "**/.git/objects/**": true, + "**/.git/refs/**": true, + "**/.pytest_cache/**": true, + "**/__pycache__": true, + "**/.ruff_cache/**": true, + "**/.venv/**": true, + "**/.opencode-data/**": true + }, + "files.watcherExclude": { + "**/runs/**": true, + "**/.git/objects/**": true, + "**/.git/refs/**": true, + "**/.ruff_cache/**": true, + "**/.venv/**": true, + "**/.opencode-data/**": true, + "**/node_modules/**": true, + "**/__pycache__/**": true, + "**/build/**": true + }, + "search.exclude": { + "**/runs/**": true, + "**/.git/**": true, + "**/.ruff_cache/**": true, + "**/.venv/**": true, + "**/.opencode-data/**": true, + "**/node_modules/**": true, + "**/__pycache__/**": true + }, + "C_Cpp.files.exclude": { + "**/build/**": true, + "**/runs/**": true + } +} From 6aac2fea4582610d7e6fc24005d1ae4bb236f11e Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Thu, 2 Apr 2026 12:14:31 +0900 Subject: [PATCH 33/39] chore: add uv lockfile --- uv.lock | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 uv.lock diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..99ffc7b --- /dev/null +++ b/uv.lock @@ -0,0 +1,123 @@ +version = 1 +revision = 3 +requires-python = ">=3.10" + +[[package]] +name = "configargparse" +version = "1.7.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3f/0b/30328302903c55218ffc5199646d0e9d28348ff26c02ba77b2ffc58d294a/configargparse-1.7.5.tar.gz", hash = "sha256:e3f9a7bb6be34d66b2e3c4a2f58e3045f8dfae47b0dc039f87bcfaa0f193fb0f", size = 53548, upload-time = "2026-03-11T02:19:38.144Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/19/3ba5e1b0bcc7b91aeab6c258afd70e4907d220fed3972febe38feb40db30/configargparse-1.7.5-py3-none-any.whl", hash = "sha256:1e63fdffedf94da9cd435fc13a1cd24777e76879dd2343912c1f871d4ac8c592", size = 27692, upload-time = "2026-03-11T02:19:36.442Z" }, +] + +[[package]] +name = "fprettify" +version = "0.3.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "configargparse" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/39/15/d88681bd2be4a375a78b52443b8e87608240913623d9be5c47e3c328b068/fprettify-0.3.7.tar.gz", hash = "sha256:1488a813f7e60a9e86c56fd0b82bd9df1b75bfb4bf2ee8e433c12f63b7e54057", size = 29639, upload-time = "2020-11-20T15:52:49.16Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/13/2c32d63574e116f8c933f56315df9135bf2fae7a88e9e7c6c4d37f48f4ef/fprettify-0.3.7-py3-none-any.whl", hash = "sha256:56f0a64c43dc47134ce32af2e5da8cd7a1584897be29d19289ec5d87510d1daf", size = 28095, upload-time = "2020-11-20T15:52:47.719Z" }, +] + +[[package]] +name = "ruff" +version = "0.15.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/14/b0/73cf7550861e2b4824950b8b52eebdcc5adc792a00c514406556c5b80817/ruff-0.15.8.tar.gz", hash = "sha256:995f11f63597ee362130d1d5a327a87cb6f3f5eae3094c620bcc632329a4d26e", size = 4610921, upload-time = "2026-03-26T18:39:38.675Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4a/92/c445b0cd6da6e7ae51e954939cb69f97e008dbe750cfca89b8cedc081be7/ruff-0.15.8-py3-none-linux_armv6l.whl", hash = "sha256:cbe05adeba76d58162762d6b239c9056f1a15a55bd4b346cfd21e26cd6ad7bc7", size = 10527394, upload-time = "2026-03-26T18:39:41.566Z" }, + { url = "https://files.pythonhosted.org/packages/eb/92/f1c662784d149ad1414cae450b082cf736430c12ca78367f20f5ed569d65/ruff-0.15.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d3e3d0b6ba8dca1b7ef9ab80a28e840a20070c4b62e56d675c24f366ef330570", size = 10905693, upload-time = "2026-03-26T18:39:30.364Z" }, + { url = "https://files.pythonhosted.org/packages/ca/f2/7a631a8af6d88bcef997eb1bf87cc3da158294c57044aafd3e17030613de/ruff-0.15.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6ee3ae5c65a42f273f126686353f2e08ff29927b7b7e203b711514370d500de3", size = 10323044, upload-time = "2026-03-26T18:39:33.37Z" }, + { url = "https://files.pythonhosted.org/packages/67/18/1bf38e20914a05e72ef3b9569b1d5c70a7ef26cd188d69e9ca8ef588d5bf/ruff-0.15.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdce027ada77baa448077ccc6ebb2fa9c3c62fd110d8659d601cf2f475858d94", size = 10629135, upload-time = "2026-03-26T18:39:44.142Z" }, + { url = "https://files.pythonhosted.org/packages/d2/e9/138c150ff9af60556121623d41aba18b7b57d95ac032e177b6a53789d279/ruff-0.15.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12e617fc01a95e5821648a6df341d80456bd627bfab8a829f7cfc26a14a4b4a3", size = 10348041, upload-time = "2026-03-26T18:39:52.178Z" }, + { url = "https://files.pythonhosted.org/packages/02/f1/5bfb9298d9c323f842c5ddeb85f1f10ef51516ac7a34ba446c9347d898df/ruff-0.15.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:432701303b26416d22ba696c39f2c6f12499b89093b61360abc34bcc9bf07762", size = 11121987, upload-time = "2026-03-26T18:39:55.195Z" }, + { url = "https://files.pythonhosted.org/packages/10/11/6da2e538704e753c04e8d86b1fc55712fdbdcc266af1a1ece7a51fff0d10/ruff-0.15.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d910ae974b7a06a33a057cb87d2a10792a3b2b3b35e33d2699fdf63ec8f6b17a", size = 11951057, upload-time = "2026-03-26T18:39:19.18Z" }, + { url = "https://files.pythonhosted.org/packages/83/f0/c9208c5fd5101bf87002fed774ff25a96eea313d305f1e5d5744698dc314/ruff-0.15.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2033f963c43949d51e6fdccd3946633c6b37c484f5f98c3035f49c27395a8ab8", size = 11464613, upload-time = "2026-03-26T18:40:06.301Z" }, + { url = "https://files.pythonhosted.org/packages/f8/22/d7f2fabdba4fae9f3b570e5605d5eb4500dcb7b770d3217dca4428484b17/ruff-0.15.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f29b989a55572fb885b77464cf24af05500806ab4edf9a0fd8977f9759d85b1", size = 11257557, upload-time = "2026-03-26T18:39:57.972Z" }, + { url = "https://files.pythonhosted.org/packages/71/8c/382a9620038cf6906446b23ce8632ab8c0811b8f9d3e764f58bedd0c9a6f/ruff-0.15.8-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:ac51d486bf457cdc985a412fb1801b2dfd1bd8838372fc55de64b1510eff4bec", size = 11169440, upload-time = "2026-03-26T18:39:22.205Z" }, + { url = "https://files.pythonhosted.org/packages/4d/0d/0994c802a7eaaf99380085e4e40c845f8e32a562e20a38ec06174b52ef24/ruff-0.15.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c9861eb959edab053c10ad62c278835ee69ca527b6dcd72b47d5c1e5648964f6", size = 10605963, upload-time = "2026-03-26T18:39:46.682Z" }, + { url = "https://files.pythonhosted.org/packages/19/aa/d624b86f5b0aad7cef6bbf9cd47a6a02dfdc4f72c92a337d724e39c9d14b/ruff-0.15.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8d9a5b8ea13f26ae90838afc33f91b547e61b794865374f114f349e9036835fb", size = 10357484, upload-time = "2026-03-26T18:39:49.176Z" }, + { url = "https://files.pythonhosted.org/packages/35/c3/e0b7835d23001f7d999f3895c6b569927c4d39912286897f625736e1fd04/ruff-0.15.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c2a33a529fb3cbc23a7124b5c6ff121e4d6228029cba374777bd7649cc8598b8", size = 10830426, upload-time = "2026-03-26T18:40:03.702Z" }, + { url = "https://files.pythonhosted.org/packages/f0/51/ab20b322f637b369383adc341d761eaaa0f0203d6b9a7421cd6e783d81b9/ruff-0.15.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:75e5cd06b1cf3f47a3996cfc999226b19aa92e7cce682dcd62f80d7035f98f49", size = 11345125, upload-time = "2026-03-26T18:39:27.799Z" }, + { url = "https://files.pythonhosted.org/packages/37/e6/90b2b33419f59d0f2c4c8a48a4b74b460709a557e8e0064cf33ad894f983/ruff-0.15.8-py3-none-win32.whl", hash = "sha256:bc1f0a51254ba21767bfa9a8b5013ca8149dcf38092e6a9eb704d876de94dc34", size = 10571959, upload-time = "2026-03-26T18:39:36.117Z" }, + { url = "https://files.pythonhosted.org/packages/1f/a2/ef467cb77099062317154c63f234b8a7baf7cb690b99af760c5b68b9ee7f/ruff-0.15.8-py3-none-win_amd64.whl", hash = "sha256:04f79eff02a72db209d47d665ba7ebcad609d8918a134f86cb13dd132159fc89", size = 11743893, upload-time = "2026-03-26T18:39:25.01Z" }, + { url = "https://files.pythonhosted.org/packages/15/e2/77be4fff062fa78d9b2a4dea85d14785dac5f1d0c1fb58ed52331f0ebe28/ruff-0.15.8-py3-none-win_arm64.whl", hash = "sha256:cf891fa8e3bb430c0e7fac93851a5978fc99c8fa2c053b57b118972866f8e5f2", size = 11048175, upload-time = "2026-03-26T18:40:01.06Z" }, +] + +[[package]] +name = "simbench" +version = "0.0.0" +source = { virtual = "." } + +[package.optional-dependencies] +dev = [ + { name = "fprettify" }, + { name = "ruff" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] + +[package.metadata] +requires-dist = [ + { name = "fprettify", marker = "extra == 'dev'", specifier = ">=0.3.7" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.11" }, + { name = "tomli", marker = "python_full_version < '3.11' and extra == 'dev'", specifier = ">=2.0" }, +] +provides-extras = ["dev"] + +[[package]] +name = "tomli" +version = "2.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/11/db3d5885d8528263d8adc260bb2d28ebf1270b96e98f0e0268d32b8d9900/tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30", size = 154704, upload-time = "2026-03-25T20:21:10.473Z" }, + { url = "https://files.pythonhosted.org/packages/6d/f7/675db52c7e46064a9aa928885a9b20f4124ecb9bc2e1ce74c9106648d202/tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a", size = 149454, upload-time = "2026-03-25T20:21:12.036Z" }, + { url = "https://files.pythonhosted.org/packages/61/71/81c50943cf953efa35bce7646caab3cf457a7d8c030b27cfb40d7235f9ee/tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076", size = 237561, upload-time = "2026-03-25T20:21:13.098Z" }, + { url = "https://files.pythonhosted.org/packages/48/c1/f41d9cb618acccca7df82aaf682f9b49013c9397212cb9f53219e3abac37/tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9", size = 243824, upload-time = "2026-03-25T20:21:14.569Z" }, + { url = "https://files.pythonhosted.org/packages/22/e4/5a816ecdd1f8ca51fb756ef684b90f2780afc52fc67f987e3c61d800a46d/tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c", size = 242227, upload-time = "2026-03-25T20:21:15.712Z" }, + { url = "https://files.pythonhosted.org/packages/6b/49/2b2a0ef529aa6eec245d25f0c703e020a73955ad7edf73e7f54ddc608aa5/tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc", size = 247859, upload-time = "2026-03-25T20:21:17.001Z" }, + { url = "https://files.pythonhosted.org/packages/83/bd/6c1a630eaca337e1e78c5903104f831bda934c426f9231429396ce3c3467/tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049", size = 97204, upload-time = "2026-03-25T20:21:18.079Z" }, + { url = "https://files.pythonhosted.org/packages/42/59/71461df1a885647e10b6bb7802d0b8e66480c61f3f43079e0dcd315b3954/tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e", size = 108084, upload-time = "2026-03-25T20:21:18.978Z" }, + { url = "https://files.pythonhosted.org/packages/b8/83/dceca96142499c069475b790e7913b1044c1a4337e700751f48ed723f883/tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece", size = 95285, upload-time = "2026-03-25T20:21:20.309Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload-time = "2026-03-25T20:21:21.626Z" }, + { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload-time = "2026-03-25T20:21:23.002Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload-time = "2026-03-25T20:21:24.04Z" }, + { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341, upload-time = "2026-03-25T20:21:25.177Z" }, + { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159, upload-time = "2026-03-25T20:21:26.364Z" }, + { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290, upload-time = "2026-03-25T20:21:27.46Z" }, + { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141, upload-time = "2026-03-25T20:21:28.492Z" }, + { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847, upload-time = "2026-03-25T20:21:29.386Z" }, + { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088, upload-time = "2026-03-25T20:21:30.677Z" }, + { url = "https://files.pythonhosted.org/packages/07/06/b823a7e818c756d9a7123ba2cda7d07bc2dd32835648d1a7b7b7a05d848d/tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54", size = 155866, upload-time = "2026-03-25T20:21:31.65Z" }, + { url = "https://files.pythonhosted.org/packages/14/6f/12645cf7f08e1a20c7eb8c297c6f11d31c1b50f316a7e7e1e1de6e2e7b7e/tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a", size = 149887, upload-time = "2026-03-25T20:21:33.028Z" }, + { url = "https://files.pythonhosted.org/packages/5c/e0/90637574e5e7212c09099c67ad349b04ec4d6020324539297b634a0192b0/tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897", size = 243704, upload-time = "2026-03-25T20:21:34.51Z" }, + { url = "https://files.pythonhosted.org/packages/10/8f/d3ddb16c5a4befdf31a23307f72828686ab2096f068eaf56631e136c1fdd/tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f", size = 251628, upload-time = "2026-03-25T20:21:36.012Z" }, + { url = "https://files.pythonhosted.org/packages/e3/f1/dbeeb9116715abee2485bf0a12d07a8f31af94d71608c171c45f64c0469d/tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d", size = 247180, upload-time = "2026-03-25T20:21:37.136Z" }, + { url = "https://files.pythonhosted.org/packages/d3/74/16336ffd19ed4da28a70959f92f506233bd7cfc2332b20bdb01591e8b1d1/tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5", size = 251674, upload-time = "2026-03-25T20:21:38.298Z" }, + { url = "https://files.pythonhosted.org/packages/16/f9/229fa3434c590ddf6c0aa9af64d3af4b752540686cace29e6281e3458469/tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd", size = 97976, upload-time = "2026-03-25T20:21:39.316Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1e/71dfd96bcc1c775420cb8befe7a9d35f2e5b1309798f009dca17b7708c1e/tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36", size = 108755, upload-time = "2026-03-25T20:21:40.248Z" }, + { url = "https://files.pythonhosted.org/packages/83/7a/d34f422a021d62420b78f5c538e5b102f62bea616d1d75a13f0a88acb04a/tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd", size = 95265, upload-time = "2026-03-25T20:21:41.219Z" }, + { url = "https://files.pythonhosted.org/packages/3c/fb/9a5c8d27dbab540869f7c1f8eb0abb3244189ce780ba9cd73f3770662072/tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf", size = 155726, upload-time = "2026-03-25T20:21:42.23Z" }, + { url = "https://files.pythonhosted.org/packages/62/05/d2f816630cc771ad836af54f5001f47a6f611d2d39535364f148b6a92d6b/tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac", size = 149859, upload-time = "2026-03-25T20:21:43.386Z" }, + { url = "https://files.pythonhosted.org/packages/ce/48/66341bdb858ad9bd0ceab5a86f90eddab127cf8b046418009f2125630ecb/tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662", size = 244713, upload-time = "2026-03-25T20:21:44.474Z" }, + { url = "https://files.pythonhosted.org/packages/df/6d/c5fad00d82b3c7a3ab6189bd4b10e60466f22cfe8a08a9394185c8a8111c/tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853", size = 252084, upload-time = "2026-03-25T20:21:45.62Z" }, + { url = "https://files.pythonhosted.org/packages/00/71/3a69e86f3eafe8c7a59d008d245888051005bd657760e96d5fbfb0b740c2/tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15", size = 247973, upload-time = "2026-03-25T20:21:46.937Z" }, + { url = "https://files.pythonhosted.org/packages/67/50/361e986652847fec4bd5e4a0208752fbe64689c603c7ae5ea7cb16b1c0ca/tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba", size = 256223, upload-time = "2026-03-25T20:21:48.467Z" }, + { url = "https://files.pythonhosted.org/packages/8c/9a/b4173689a9203472e5467217e0154b00e260621caa227b6fa01feab16998/tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6", size = 98973, upload-time = "2026-03-25T20:21:49.526Z" }, + { url = "https://files.pythonhosted.org/packages/14/58/640ac93bf230cd27d002462c9af0d837779f8773bc03dee06b5835208214/tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7", size = 109082, upload-time = "2026-03-25T20:21:50.506Z" }, + { url = "https://files.pythonhosted.org/packages/d5/2f/702d5e05b227401c1068f0d386d79a589bb12bf64c3d2c72ce0631e3bc49/tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232", size = 96490, upload-time = "2026-03-25T20:21:51.474Z" }, + { url = "https://files.pythonhosted.org/packages/45/4b/b877b05c8ba62927d9865dd980e34a755de541eb65fffba52b4cc495d4d2/tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4", size = 164263, upload-time = "2026-03-25T20:21:52.543Z" }, + { url = "https://files.pythonhosted.org/packages/24/79/6ab420d37a270b89f7195dec5448f79400d9e9c1826df982f3f8e97b24fd/tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c", size = 160736, upload-time = "2026-03-25T20:21:53.674Z" }, + { url = "https://files.pythonhosted.org/packages/02/e0/3630057d8eb170310785723ed5adcdfb7d50cb7e6455f85ba8a3deed642b/tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d", size = 270717, upload-time = "2026-03-25T20:21:55.129Z" }, + { url = "https://files.pythonhosted.org/packages/7a/b4/1613716072e544d1a7891f548d8f9ec6ce2faf42ca65acae01d76ea06bb0/tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41", size = 278461, upload-time = "2026-03-25T20:21:56.228Z" }, + { url = "https://files.pythonhosted.org/packages/05/38/30f541baf6a3f6df77b3df16b01ba319221389e2da59427e221ef417ac0c/tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c", size = 274855, upload-time = "2026-03-25T20:21:57.653Z" }, + { url = "https://files.pythonhosted.org/packages/77/a3/ec9dd4fd2c38e98de34223b995a3b34813e6bdadf86c75314c928350ed14/tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f", size = 283144, upload-time = "2026-03-25T20:21:59.089Z" }, + { url = "https://files.pythonhosted.org/packages/ef/be/605a6261cac79fba2ec0c9827e986e00323a1945700969b8ee0b30d85453/tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8", size = 108683, upload-time = "2026-03-25T20:22:00.214Z" }, + { url = "https://files.pythonhosted.org/packages/12/64/da524626d3b9cc40c168a13da8335fe1c51be12c0a63685cc6db7308daae/tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26", size = 121196, upload-time = "2026-03-25T20:22:01.169Z" }, + { url = "https://files.pythonhosted.org/packages/5a/cd/e80b62269fc78fc36c9af5a6b89c835baa8af28ff5ad28c7028d60860320/tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396", size = 100393, upload-time = "2026-03-25T20:22:02.137Z" }, + { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, +] From e2171fc4fc562465ba68ea5cc010cd89021cbe2e Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Thu, 2 Apr 2026 13:42:32 +0900 Subject: [PATCH 34/39] refactor(magnetohydrodynamics): replace full-solver task with cpp-full1d-00 --- benchmarks/magnetohydrodynamics/README.md | 12 +- .../cpp-full-solver1d/spec.md | 200 -------- .../cpp-full-solver1d/workspace/README.md | 3 - .../cpp-full-solver1d/workspace/src/mhd1d.cpp | 452 ------------------ .../workspace/tests/cpp/test_public.cpp | 268 ----------- .../workspace/tests/test_public.py | 79 --- .../eval/run.sh | 0 .../eval/tests/test_hidden.py | 27 +- .../cpp-full1d-00/spec.md | 74 +++ .../task.toml | 4 +- .../workspace/CMakeLists.txt | 1 + .../cpp-full1d-00/workspace/README.md | 7 + .../workspace/pyproject.toml | 2 +- .../cpp-full1d-00/workspace/src/hlld.cpp | 202 ++++++++ .../cpp-full1d-00/workspace/src/hlld.hpp | 4 + .../workspace/src/main.cpp | 10 +- .../cpp-full1d-00/workspace/src/mhd1d.cpp | 108 +++++ .../workspace/src/mhd1d.hpp} | 0 .../workspace/tests/cpp/test_public.cpp | 55 +++ .../workspace/tests/data/brio_wu_golden.csv | 0 .../workspace/tests/test_public.py | 85 ++++ .../shared/CMakeLists.txt | 16 +- .../magnetohydrodynamics/shared/README.md | 4 +- .../shared/eval/README.md | 2 +- .../shared/eval/fixtures/mhd1d/README.md | 4 +- .../shared/eval/mhd1d_shared.py | 27 ++ .../shared/src/{full_main.cpp => main.cpp} | 2 +- .../shared/src/{full_mhd1d.cpp => mhd1d.cpp} | 2 +- .../workspace => shared}/src/mhd1d.hpp | 18 +- .../shared/tests/test_reference.py | 28 +- 30 files changed, 635 insertions(+), 1061 deletions(-) delete mode 100644 benchmarks/magnetohydrodynamics/cpp-full-solver1d/spec.md delete mode 100644 benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/README.md delete mode 100644 benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp delete mode 100644 benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp delete mode 100644 benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/test_public.py rename benchmarks/magnetohydrodynamics/{cpp-full-solver1d => cpp-full1d-00}/eval/run.sh (100%) rename benchmarks/magnetohydrodynamics/{cpp-full-solver1d => cpp-full1d-00}/eval/tests/test_hidden.py (68%) create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-00/spec.md rename benchmarks/magnetohydrodynamics/{cpp-full-solver1d => cpp-full1d-00}/task.toml (53%) rename benchmarks/magnetohydrodynamics/{cpp-full-solver1d => cpp-full1d-00}/workspace/CMakeLists.txt (98%) create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/README.md rename benchmarks/magnetohydrodynamics/{cpp-full-solver1d => cpp-full1d-00}/workspace/pyproject.toml (68%) create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/src/hlld.cpp create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/src/hlld.hpp rename benchmarks/magnetohydrodynamics/{cpp-full-solver1d => cpp-full1d-00}/workspace/src/main.cpp (90%) create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/src/mhd1d.cpp rename benchmarks/magnetohydrodynamics/{shared/src/full_mhd1d.hpp => cpp-full1d-00/workspace/src/mhd1d.hpp} (100%) create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/tests/cpp/test_public.cpp rename benchmarks/magnetohydrodynamics/{cpp-full-solver1d => cpp-full1d-00}/workspace/tests/data/brio_wu_golden.csv (100%) create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/tests/test_public.py create mode 100644 benchmarks/magnetohydrodynamics/shared/eval/mhd1d_shared.py rename benchmarks/magnetohydrodynamics/shared/src/{full_main.cpp => main.cpp} (98%) rename benchmarks/magnetohydrodynamics/shared/src/{full_mhd1d.cpp => mhd1d.cpp} (99%) rename benchmarks/magnetohydrodynamics/{cpp-full-solver1d/workspace => shared}/src/mhd1d.hpp (85%) diff --git a/benchmarks/magnetohydrodynamics/README.md b/benchmarks/magnetohydrodynamics/README.md index 4aef14a..a9e84ac 100644 --- a/benchmarks/magnetohydrodynamics/README.md +++ b/benchmarks/magnetohydrodynamics/README.md @@ -8,11 +8,11 @@ This suite contains benchmark tasks for ideal magnetohydrodynamics solvers. - `shared/workspace/hlld.md`: HLLD algorithm notes for solver tasks. - `cpp-hlld-00/`: default C++ HLLD task with detailed solver guidance in spec. - `cpp-hlld-01/`: variant C++ HLLD task with reduced guidance but same test intent. -- `cpp-full-solver1d/`: C++ full 1D ideal MHD solver (Brio-Wu benchmark). +- `cpp-full1d-00/`: easiest C++ full 1D ideal MHD variant (main+HLLD provided, solver scaffolded). - `shared/eval/README.md`: hidden-eval contract for shared MHD scoring assets. - `shared/eval/mhd1d_shared.py`: shared helpers for CSV loading, score windows, and comparison metadata. -- `shared/eval/fixtures/mhd1d/`: hidden fixtures for `cpp-full-solver1d`. +- `shared/eval/fixtures/mhd1d/`: hidden fixtures for full 1D variants. ## Notes @@ -23,10 +23,10 @@ This suite contains benchmark tasks for ideal magnetohydrodynamics solvers. `hlld_flux_from_primitive(...)` in the public task API. - `cpp-hlld-00` and `cpp-hlld-01` keep public/hidden test intent aligned; the main difference is prompt detail level. -- `cpp-full-solver1d` scores only the interior cells, excluding two - edge-adjacent cells on each side, against the variables `rho`, `u`, `p`, and - `by` using fixture-recorded `abs_l1` and `abs_linf` tolerances. The solver - uses hardcoded Brio-Wu defaults and emits CSV with lowercase magnetic-field +- `cpp-full1d-00` public tests compare solver CSV output against a golden file + with numeric tolerance (`1.0e-12`), and hidden tests use `nx=200` against a + hidden reference CSV with the same numeric policy. +- Full 1D tasks score interior cells and emit CSV with lowercase magnetic-field headers (`by`, `bz`). ## Reference credit diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/spec.md b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/spec.md deleted file mode 100644 index 5796019..0000000 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/spec.md +++ /dev/null @@ -1,200 +0,0 @@ -# cpp-full-solver1d - -Implement a 1D ideal MHD full solver in C++. - -## Task - -The benchmark contract is fixed around these choices: - -- domain: `[0, 1]` -- initial discontinuity: `x = 0.5` -- conservative evolution -- primitive reconstruction: MC2 -- flux function: HLLD -- time integration: SSP-RK3 -- boundary conditions: zero-gradient -- output format: CSV with columns `x,rho,u,v,w,p,by,bz` -- default problem: Brio-Wu with `gamma = 2` and `Bx = 0.75` - -## Numerical method - -The solver implements the following numerical scheme: - -1. **Reconstruction**: MC2 (minmod with centered differences) for primitive variables -2. **Riemann solver**: HLLD approximate Riemann solver for ideal MHD fluxes -3. **Time integration**: SSP-RK3 (strong stability preserving Runge-Kutta, 3rd order) -4. **Boundary conditions**: Zero-gradient ghost cells (2 cells per side) - -### State ordering - -Primitive state vector (7 components): -``` -[rho, u, v, w, p, By, Bz] -``` - -Conservative state vector (7 components): -``` -[rho, mx, my, mz, E, By, Bz] -``` - -where `mx = rho * u`, `my = rho * v`, `mz = rho * w`, and total energy -`E = p/(gamma-1) + 0.5*rho*(u^2+v^2+w^2) + 0.5*(Bx^2+By^2+Bz^2)`. - -### Default constants - -| Parameter | Value | -|-----------|-------| -| `gamma` | 2.0 | -| `Bx` | 0.75 | -| `dt` | 5.0e-4 | -| `t_final` | 0.1 | -| `nx` | 100 | - -## Building - -```bash -mkdir build && cd build -cmake .. -cmake --build . -``` - -The solver executable is placed at `build/bin/cpp_full_solver1d`. - -## Usage - -```bash -./bin/cpp_full_solver1d -``` - -The solver uses hardcoded Brio-Wu defaults and writes CSV output to stdout. - -### Running and saving output - -```bash -./bin/cpp_full_solver1d > solution.csv -``` - -## Visualization - -A plot helper script is provided for quick inspection of results: - -```bash -python scripts/plot_solution.py solution.csv -``` - -This displays profiles for density (`rho`), velocity (`u`), pressure (`p`), and -magnetic field (`by`). - -## API reference - -### Core functions (`mhd1d.hpp`) - -Type aliases used by the API: - -- `StateVector = std::array` -- `ArrayView = std::experimental::mdspan>` -- `ConstArrayView = std::experimental::mdspan>` - -#### `StateVector primitive_to_conservative(const StateVector& primitive, double bx, double gamma)` - -Converts a primitive state vector to conservative form. - -**Parameters:** -- `primitive`: 7-component primitive state `[rho, u, v, w, p, By, Bz]` -- `bx`: Constant x-component of magnetic field -- `gamma`: Adiabatic index - -**Returns:** 7-component conservative state `[rho, mx, my, mz, E, By, Bz]` - -#### `StateVector conservative_to_primitive(const StateVector& conservative, double bx, double gamma)` - -Converts a conservative state vector to primitive form. - -**Parameters:** -- `conservative`: 7-component conservative state -- `bx`: Constant x-component of magnetic field -- `gamma`: Adiabatic index - -**Returns:** 7-component primitive state - -#### `void pad_zero_gradient_ghost_cells(ConstArrayView cells, ArrayView padded)` - -Fills the padded array with two zero-gradient ghost cells on each side. - -**Parameters:** -- `cells`: interior cell-centered states with shape `(nx, 7)` -- `padded`: output with shape `(nx + 4, 7)` - -#### `void mc2_slopes(ConstArrayView primitive_cells, ArrayView slopes)` - -Computes MC2-limited slopes for primitive variables. - -**Parameters:** -- `primitive_cells`: primitive states with shape `(nx, 7)` -- `slopes`: output slopes with shape `(nx, 7)` - -#### `void reconstruct_mc2_interfaces(ConstArrayView primitive_cells, ArrayView left_states, ArrayView right_states)` - -Performs MC2 reconstruction at interfaces. - -**Parameters:** -- `primitive_cells`: primitive states with shape `(nx, 7)` -- `left_states`: left interface states with shape `(nx - 1, 7)` -- `right_states`: right interface states with shape `(nx - 1, 7)` - -#### `StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, double gamma)` - -Computes the HLLD numerical flux given left and right primitive states. - -**Parameters:** -- `left`: Left primitive state at interface -- `right`: Right primitive state at interface -- `bx`: Constant x-component of magnetic field -- `gamma`: Adiabatic index - -**Returns:** Numerical flux vector - -#### `void compute_semidiscrete_rhs(ConstArrayView conservative_cells, ArrayView rhs, double dx, double bx = 0.75, double gamma = 2.0)` - -Computes the semidiscrete RHS with an explicit cell width. - -**Parameters:** -- `conservative_cells`: conservative states with shape `(nx, 7)` -- `rhs`: output RHS with shape `(nx, 7)` -- `dx`: cell width -- `bx`: constant `Bx` -- `gamma`: adiabatic index - -#### `void ssp_rk3_step(ConstArrayView conservative_cells, ArrayView output, double dt, double dx, double bx = 0.75, double gamma = 2.0)` - -Performs one SSP-RK3 time step. - -**Parameters:** -- `conservative_cells`: input conservative states with shape `(nx, 7)` -- `output`: output conservative states with shape `(nx, 7)` -- `dt`: time step -- `dx`: cell width -- `bx`: constant `Bx` -- `gamma`: adiabatic index - -#### `void evolve_ssp_rk3_fixed_dt(ConstArrayView conservative_cells, ArrayView output, double t_final, double dt, double dx, double bx = 0.75, double gamma = 2.0)` - -Runs repeated SSP-RK3 updates with fixed `dt` until `t_final`. - -**Parameters:** -- `conservative_cells`: input conservative states with shape `(nx, 7)` -- `output`: output conservative states with shape `(nx, 7)` -- `t_final`: final time -- `dt`: fixed time step (final step is clipped to hit `t_final`) -- `dx`: cell width -- `bx`: constant `Bx` -- `gamma`: adiabatic index - -## Evaluation - -The hidden evaluation compares solver output against a reference solution using: - -- **Scored variables**: `rho`, `u`, `p`, `by` -- **Comparison window**: Interior cells only (excludes 2 edge-adjacent cells per side) -- **Metrics**: L1 and Linf absolute errors -- **Tolerances**: Defined in `shared/eval/fixtures/mhd1d/brio_wu_fixture.json` diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/README.md b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/README.md deleted file mode 100644 index 38acf77..0000000 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/README.md +++ /dev/null @@ -1,3 +0,0 @@ -The public C++ workspace now contains the hardcoded Brio-Wu solver. - -Shared workspace docs are already mounted for this benchmark. diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp deleted file mode 100644 index c2622ef..0000000 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.cpp +++ /dev/null @@ -1,452 +0,0 @@ -#include "mhd1d.hpp" - -#include -#include -#include -#include - -namespace mhd1d -{ - -namespace -{ - -constexpr double HLLD_EPS = 1.0e-40; - -double sign(const double x) -{ - return copysign(1.0, x); -} - -double mc2(double a, double b) -{ - return 0.5 * (sign(a) + sign(b)) * - std::min({2.0 * std::abs(a), 2.0 * std::abs(b), 0.5 * std::abs(a + b)}); -} - -StateVector row_to_state(ArrayView2D cells, int row) -{ - StateVector state{}; - for (int component = 0; component < N_Component; ++component) { - state[component] = cells(row, component); - } - return state; -} - -void state_to_row(const StateVector& state, ArrayView2D cells, int row) -{ - for (int component = 0; component < N_Component; ++component) { - cells(row, component) = state[component]; - } -} - -void copy_cells(ArrayView2D source, ArrayView2D destination) -{ - const int nx = source.extent(0); - for (int ix = 0; ix < nx; ++ix) { - for (int component = 0; component < N_Component; ++component) { - destination(ix, component) = source(ix, component); - } - } -} - -void convert_conservative_to_primitive(ArrayView2D conservative, ArrayView2D primitive, double bx, - double gamma) -{ - const int ix_min = 0; - const int ix_max = conservative.extent(0) - 1; - - for (int ix = ix_min; ix <= ix_max; ++ix) { - const StateVector up = conservative_to_primitive(row_to_state(conservative, ix), bx, gamma); - state_to_row(up, primitive, ix); - } -} - -} // namespace - -StateVector primitive_to_conservative(const StateVector& primitive, double bx, double gamma) -{ - const double rho = primitive[0]; - const double u = primitive[1]; - const double v = primitive[2]; - const double w = primitive[3]; - const double pressure = primitive[4]; - const double by = primitive[5]; - const double bz = primitive[6]; - - const double kinetic_energy = 0.5 * rho * (u * u + v * v + w * w); - const double magnetic_energy = 0.5 * (bx * bx + by * by + bz * bz); - - return StateVector{ - rho, rho * u, rho * v, rho * w, pressure / (gamma - 1.0) + kinetic_energy + magnetic_energy, - by, bz, - }; -} - -StateVector conservative_to_primitive(const StateVector& conservative, double bx, double gamma) -{ - const double rho = conservative[0]; - if (rho <= 0.0) { - throw std::runtime_error("density must be positive"); - } - - const double u = conservative[1] / rho; - const double v = conservative[2] / rho; - const double w = conservative[3] / rho; - const double by = conservative[5]; - const double bz = conservative[6]; - - const double kinetic_energy = 0.5 * rho * (u * u + v * v + w * w); - const double magnetic_energy = 0.5 * (bx * bx + by * by + bz * bz); - const double pressure = (gamma - 1.0) * (conservative[4] - kinetic_energy - magnetic_energy); - - return StateVector{rho, u, v, w, pressure, by, bz}; -} - -void primitive_profile_to_conservative(ArrayView2D primitive, ArrayView2D conservative, double bx, - double gamma) -{ - const int ix_min = 0; - const int ix_max = primitive.extent(0) - 1; - - for (int ix = ix_min; ix <= ix_max; ++ix) { - const StateVector uc = primitive_to_conservative(row_to_state(primitive, ix), bx, gamma); - state_to_row(uc, conservative, ix); - } -} - -StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, - double gamma); - -void reconstruct_mc2(SolverWorkspace& workspace) -{ - const ArrayView2D up = workspace.up; - const ArrayView2D up_l = workspace.up_l; - const ArrayView2D up_r = workspace.up_r; - - const int lbx = workspace.Lbx; - const int ubx = workspace.Ubx; - for (int ix = lbx; ix <= ubx; ++ix) { - for (int component = 0; component < N_Component; ++component) { - const double slope_l = up(ix, component) - up(ix - 1, component); - const double slope_r = up(ix + 1, component) - up(ix, component); - const double slope = mc2(slope_l, slope_r); - up_l(ix, component) = up(ix, component) + 0.5 * slope; - up_r(ix, component) = up(ix, component) - 0.5 * slope; - } - } - - set_boundary_lb(up_l, up_r, lbx); - set_boundary_ub(up_r, up_l, ubx); -} - -void compute_flux_hlld(SolverWorkspace& workspace, double bx, double gamma) -{ - const ArrayView2D up_l = workspace.up_l; - const ArrayView2D up_r = workspace.up_r; - const ArrayView2D flux = workspace.flux; - - const int lbx = workspace.Lbx; - const int ubx = workspace.Ubx; - for (int ix = lbx - 1; ix <= ubx + 1; ++ix) { - const StateVector flux_hlld = - hlld_flux_from_primitive(row_to_state(up_l, ix), row_to_state(up_r, ix + 1), bx, gamma); - state_to_row(flux_hlld, flux, ix); - } -} - -StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, - double gamma) -{ - const double rol = left[0]; - const double vxl = left[1]; - const double vyl = left[2]; - const double vzl = left[3]; - const double prl = left[4]; - const double byl = left[5]; - const double bzl = left[6]; - - const double ror = right[0]; - const double vxr = right[1]; - const double vyr = right[2]; - const double vzr = right[3]; - const double prr = right[4]; - const double byr = right[5]; - const double bzr = right[6]; - - const double igm = 1.0 / (gamma - 1.0); - const double bxs = bx; - const double bxsq = bxs * bxs; - - const double pbl = 0.5 * (bxsq + byl * byl + bzl * bzl); - const double pbr = 0.5 * (bxsq + byr * byr + bzr * bzr); - const double ptl = prl + pbl; - const double ptr = prr + pbr; - - const double rxl = rol * vxl; - const double ryl = rol * vyl; - const double rzl = rol * vzl; - const double rxr = ror * vxr; - const double ryr = ror * vyr; - const double rzr = ror * vzr; - - const double eel = prl * igm + 0.5 * (rxl * vxl + ryl * vyl + rzl * vzl) + pbl; - const double eer = prr * igm + 0.5 * (rxr * vxr + ryr * vyr + rzr * vzr) + pbr; - - const double gmpl = gamma * prl; - const double gmpr = gamma * prr; - const double gpbl = gmpl + 2.0 * pbl; - const double gpbr = gmpr + 2.0 * pbr; - - const double cfl = std::sqrt((gpbl + std::sqrt((gmpl - 2.0 * pbl) * (gmpl - 2.0 * pbl) + - 4.0 * gmpl * (byl * byl + bzl * bzl))) * - 0.5 / rol); - const double cfr = std::sqrt((gpbr + std::sqrt((gmpr - 2.0 * pbr) * (gmpr - 2.0 * pbr) + - 4.0 * gmpr * (byr * byr + bzr * bzr))) * - 0.5 / ror); - - const double sl = std::min(vxl, vxr) - std::max(cfl, cfr); - const double sr = std::max(vxl, vxr) + std::max(cfl, cfr); - - const StateVector fql{rxl, - rxl * vxl + ptl - bxsq, - rxl * vyl - bxs * byl, - rxl * vzl - bxs * bzl, - vxl * (eel + ptl - bxsq) - bxs * (vyl * byl + vzl * bzl), - byl * vxl - bxs * vyl, - bzl * vxl - bxs * vzl}; - const StateVector fqr{rxr, - rxr * vxr + ptr - bxsq, - rxr * vyr - bxs * byr, - rxr * vzr - bxs * bzr, - vxr * (eer + ptr - bxsq) - bxs * (vyr * byr + vzr * bzr), - byr * vxr - bxs * vyr, - bzr * vxr - bxs * vzr}; - - const double sdl = sl - vxl; - const double sdr = sr - vxr; - const double rosdl = rol * sdl; - const double rosdr = ror * sdr; - const double temp = 1.0 / (rosdr - rosdl); - const double sm = (rosdr * vxr - rosdl * vxl - ptr + ptl) * temp; - const double sdml = sl - sm; - const double sdmr = sr - sm; - const double ptst = (rosdr * ptl - rosdl * ptr + rosdl * rosdr * (vxr - vxl)) * temp; - - const double temp_fst_l = rosdl * sdml - bxsq; - const double sign1_l = std::copysign(1.0, std::abs(temp_fst_l) - HLLD_EPS); - const double maxs1_l = std::max(0.0, sign1_l); - const double mins1_l = std::min(0.0, sign1_l); - const double itf_l = 1.0 / (temp_fst_l + mins1_l); - const double isdml = 1.0 / sdml; - - const double temp_l = bxs * (sdl - sdml) * itf_l; - const double rolst = maxs1_l * (rosdl * isdml) - mins1_l * rol; - const double vxlst = maxs1_l * sm - mins1_l * vxl; - const double rxlst = rolst * vxlst; - const double vylst = maxs1_l * (vyl - byl * temp_l) - mins1_l * vyl; - const double rylst = rolst * vylst; - const double vzlst = maxs1_l * (vzl - bzl * temp_l) - mins1_l * vzl; - const double rzlst = rolst * vzlst; - const double temp_l_b = (rosdl * sdl - bxsq) * itf_l; - const double bylst = maxs1_l * (byl * temp_l_b) - mins1_l * byl; - const double bzlst = maxs1_l * (bzl * temp_l_b) - mins1_l * bzl; - const double vdbstl = vxlst * bxs + vylst * bylst + vzlst * bzlst; - const double eelst = maxs1_l * ((sdl * eel - ptl * vxl + ptst * sm + - bxs * (vxl * bxs + vyl * byl + vzl * bzl - vdbstl)) * - isdml) - - mins1_l * eel; - - const double temp_fst_r = rosdr * sdmr - bxsq; - const double sign1_r = std::copysign(1.0, std::abs(temp_fst_r) - HLLD_EPS); - const double maxs1_r = std::max(0.0, sign1_r); - const double mins1_r = std::min(0.0, sign1_r); - const double itf_r = 1.0 / (temp_fst_r + mins1_r); - const double isdmr = 1.0 / sdmr; - - const double temp_r = bxs * (sdr - sdmr) * itf_r; - const double rorst = maxs1_r * (rosdr * isdmr) - mins1_r * ror; - const double vxrst = maxs1_r * sm - mins1_r * vxr; - const double rxrst = rorst * vxrst; - const double vyrst = maxs1_r * (vyr - byr * temp_r) - mins1_r * vyr; - const double ryrst = rorst * vyrst; - const double vzrst = maxs1_r * (vzr - bzr * temp_r) - mins1_r * vzr; - const double rzrst = rorst * vzrst; - const double temp_r_b = (rosdr * sdr - bxsq) * itf_r; - const double byrst = maxs1_r * (byr * temp_r_b) - mins1_r * byr; - const double bzrst = maxs1_r * (bzr * temp_r_b) - mins1_r * bzr; - const double vdbstr = vxrst * bxs + vyrst * byrst + vzrst * bzrst; - const double eerst = maxs1_r * ((sdr * eer - ptr * vxr + ptst * sm + - bxs * (vxr * bxs + vyr * byr + vzr * bzr - vdbstr)) * - isdmr) - - mins1_r * eer; - - const double sqrtrol = std::sqrt(rolst); - const double sqrtror = std::sqrt(rorst); - const double abbx = std::abs(bxs); - const double slst = sm - abbx / sqrtrol; - const double srst = sm + abbx / sqrtror; - const double signbx = std::copysign(1.0, bxs); - const double sign1_b = std::copysign(1.0, abbx - HLLD_EPS); - const double maxs1_b = std::max(0.0, sign1_b); - const double mins1_b = -std::min(0.0, sign1_b); - const double invsumro = maxs1_b / (sqrtrol + sqrtror); - - const double roldst = rolst; - const double rordst = rorst; - const double rxldst = rxlst; - const double rxrdst = rxrst; - - const double vy_shared = - invsumro * (sqrtrol * vylst + sqrtror * vyrst + signbx * (byrst - bylst)); - const double ryldst = rylst * mins1_b + roldst * vy_shared; - const double ryrdst = ryrst * mins1_b + rordst * vy_shared; - - const double vz_shared = - invsumro * (sqrtrol * vzlst + sqrtror * vzrst + signbx * (bzrst - bzlst)); - const double rzldst = rzlst * mins1_b + roldst * vz_shared; - const double rzrdst = rzrst * mins1_b + rordst * vz_shared; - - const double by_shared = - invsumro * (sqrtrol * byrst + sqrtror * bylst + signbx * sqrtrol * sqrtror * (vyrst - vylst)); - const double byldst = bylst * mins1_b + by_shared; - const double byrdst = byrst * mins1_b + by_shared; - - const double bz_shared = - invsumro * (sqrtrol * bzrst + sqrtror * bzlst + signbx * sqrtrol * sqrtror * (vzrst - vzlst)); - const double bzldst = bzlst * mins1_b + bz_shared; - const double bzrdst = bzrst * mins1_b + bz_shared; - - const double vyldst = vylst * mins1_b + vy_shared; - const double vyrdst = vyrst * mins1_b + vy_shared; - const double vzldst = vzlst * mins1_b + vz_shared; - const double vzrdst = vzrst * mins1_b + vz_shared; - const double temp_dst = sm * bxs + vyldst * byldst + vzldst * bzldst; - const double eeldst = eelst - sqrtrol * signbx * (vdbstl - temp_dst) * maxs1_b; - const double eerdst = eerst + sqrtror * signbx * (vdbstr - temp_dst) * maxs1_b; - - const double sign1 = std::copysign(1.0, sm); - const double maxs1 = std::max(0.0, sign1); - const double mins1 = -std::min(0.0, sign1); - const double msl = std::min(sl, 0.0); - const double mslst = std::min(slst, 0.0); - const double msrst = std::max(srst, 0.0); - const double msr = std::max(sr, 0.0); - const double temp_flux_l = mslst - msl; - const double temp_flux_r = msrst - msr; - - return StateVector{ - (fql[0] - msl * rol - rolst * temp_flux_l + roldst * mslst) * maxs1 + - (fqr[0] - msr * ror - rorst * temp_flux_r + rordst * msrst) * mins1, - (fql[1] - msl * rxl - rxlst * temp_flux_l + rxldst * mslst) * maxs1 + - (fqr[1] - msr * rxr - rxrst * temp_flux_r + rxrdst * msrst) * mins1, - (fql[2] - msl * ryl - rylst * temp_flux_l + ryldst * mslst) * maxs1 + - (fqr[2] - msr * ryr - ryrst * temp_flux_r + ryrdst * msrst) * mins1, - (fql[3] - msl * rzl - rzlst * temp_flux_l + rzldst * mslst) * maxs1 + - (fqr[3] - msr * rzr - rzrst * temp_flux_r + rzrdst * msrst) * mins1, - (fql[4] - msl * eel - eelst * temp_flux_l + eeldst * mslst) * maxs1 + - (fqr[4] - msr * eer - eerst * temp_flux_r + eerdst * msrst) * mins1, - (fql[5] - msl * byl - bylst * temp_flux_l + byldst * mslst) * maxs1 + - (fqr[5] - msr * byr - byrst * temp_flux_r + byrdst * msrst) * mins1, - (fql[6] - msl * bzl - bzlst * temp_flux_l + bzldst * mslst) * maxs1 + - (fqr[6] - msr * bzr - bzrst * temp_flux_r + bzrdst * msrst) * mins1, - }; -} - -void set_boundary_lb(ArrayView2D dst, ArrayView2D src, int lbx) -{ - const int ix_min = 0; - - for (int ix = ix_min; ix < lbx; ++ix) { - for (int component = 0; component < N_Component; ++component) { - dst(ix, component) = src(lbx, component); - } - } -} - -void set_boundary_ub(ArrayView2D dst, ArrayView2D src, int ubx) -{ - const int ix_max = dst.extent(0) - 1; - - for (int ix = ubx + 1; ix <= ix_max; ++ix) { - for (int component = 0; component < N_Component; ++component) { - dst(ix, component) = src(ubx, component); - } - } -} - -void set_boundary(ArrayView2D dst, ArrayView2D src, int lbx, int ubx) -{ - set_boundary_lb(dst, src, lbx); - set_boundary_ub(dst, src, ubx); -} - -void compute_rhs(SolverWorkspace& workspace) -{ - const ArrayView2D uc = workspace.uc; - const ArrayView2D up = workspace.up; - const ArrayView2D flux = workspace.flux; - const ArrayView2D rhs = workspace.rhs; - - set_boundary(uc, uc, workspace.Lbx, workspace.Ubx); - convert_conservative_to_primitive(uc, up, workspace.bx, workspace.gamma); - set_boundary(up, up, workspace.Lbx, workspace.Ubx); - reconstruct_mc2(workspace); - compute_flux_hlld(workspace, workspace.bx, workspace.gamma); - - const int lbx = workspace.Lbx; - const int ubx = workspace.Ubx; - for (int ix = lbx; ix <= ubx; ++ix) { - for (int component = 0; component < N_Component; ++component) { - rhs(ix, component) = -(flux(ix, component) - flux(ix - 1, component)) / workspace.dx; - } - } -} - -void push_ssp_rk3(SolverWorkspace& workspace, double dt) -{ - constexpr double coeffs[3][3] = { - {1.0, 0.0, 1.0}, - {3.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0}, - {1.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0}, - }; - - const ArrayView2D prev = workspace.prev; - const ArrayView2D rhs = workspace.rhs; - - copy_cells(workspace.uc, prev); - - for (int substep = 0; substep < 3; ++substep) { - compute_rhs(workspace); - - const double a = coeffs[substep][0]; - const double b = coeffs[substep][1]; - const double c = coeffs[substep][2]; - - const int lbx = workspace.Lbx; - const int ubx = workspace.Ubx; - for (int ix = lbx; ix <= ubx; ++ix) { - for (int component = 0; component < N_Component; ++component) { - workspace.uc(ix, component) = - a * prev(ix, component) + b * workspace.uc(ix, component) + c * dt * rhs(ix, component); - } - } - - set_boundary(workspace.uc, workspace.uc, workspace.Lbx, workspace.Ubx); - convert_conservative_to_primitive(workspace.uc, workspace.up, workspace.bx, workspace.gamma); - set_boundary(workspace.up, workspace.up, workspace.Lbx, workspace.Ubx); - } -} - -void evolve_ssp_rk3(SolverWorkspace& workspace, double dt, double t_final) -{ - double elapsed_time = 0.0; - while (elapsed_time < t_final) { - const double remaining_time = t_final - elapsed_time; - const double step_dt = std::min(dt, remaining_time); - push_ssp_rk3(workspace, step_dt); - elapsed_time = (step_dt < dt) ? t_final : (elapsed_time + step_dt); - } -} - -} // namespace mhd1d diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp deleted file mode 100644 index 82a442f..0000000 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/cpp/test_public.cpp +++ /dev/null @@ -1,268 +0,0 @@ -#include - -#include -#include - -#include "mhd1d.hpp" - -namespace -{ - -constexpr double kTolerance = 1.0e-12; - -mhd1d::StateVector row_to_state(mhd1d::ArrayView2D cells, int row) -{ - mhd1d::StateVector state{}; - for (int component = 0; component < mhd1d::N_Component; ++component) { - state[component] = cells(row, component); - } - return state; -} - -void state_to_row(mhd1d::ArrayView2D cells, int row, const mhd1d::StateVector& state) -{ - for (int component = 0; component < mhd1d::N_Component; ++component) { - cells(row, component) = state[component]; - } -} - -void require_state_vector_close(const mhd1d::StateVector& actual, - const mhd1d::StateVector& expected) -{ - for (int component = 0; component < mhd1d::N_Component; ++component) { - REQUIRE(std::fabs(actual[component] - expected[component]) <= kTolerance); - } -} - -} // namespace - -TEST_CASE("primitive_to_conservative converts a known state", "[mhd1d][conversion]") -{ - const double bx = 0.75; - const double gamma = 2.0; - const auto state = mhd1d::StateVector{1.5, 2.0, -1.0, 0.5, 3.0, 0.25, -0.5}; - const auto actual = mhd1d::primitive_to_conservative(state, bx, gamma); - - const auto expected = mhd1d::StateVector{1.5, 3.0, -1.5, 0.75, 7.375, 0.25, -0.5}; - require_state_vector_close(actual, expected); -} - -TEST_CASE("conservative_to_primitive converts a known state", "[mhd1d][conversion]") -{ - const double bx = 0.75; - const double gamma = 2.0; - const auto state = mhd1d::StateVector{1.5, 3.0, -1.5, 0.75, 7.375, 0.25, -0.5}; - const auto actual = mhd1d::conservative_to_primitive(state, bx, gamma); - - const auto expected = mhd1d::StateVector{1.5, 2.0, -1.0, 0.5, 3.0, 0.25, -0.5}; - require_state_vector_close(actual, expected); -} - -TEST_CASE("primitive and conservative states round-trip", "[mhd1d][conversion]") -{ - const double bx = 0.75; - const double gamma = 2.0; - const auto input = mhd1d::StateVector{0.875, -1.25, 0.5, 0.75, 2.125, -0.2, 0.35}; - - const auto conservative = mhd1d::primitive_to_conservative(input, bx, gamma); - const auto output = mhd1d::conservative_to_primitive(conservative, bx, gamma); - - require_state_vector_close(output, input); -} - -TEST_CASE("reconstruct_mc2 preserves a constant primitive state exactly", "[mhd1d][reconstruction]") -{ - mhd1d::SolverWorkspace workspace(4, 2.0, 0.75); - const auto constant_state = mhd1d::StateVector{0.9, 0.3, -0.2, 0.1, 1.8, -0.45, 0.6}; - - for (int index = 0; index < static_cast(workspace.uc.extent(0)); ++index) { - state_to_row(workspace.up, index, constant_state); - } - - mhd1d::reconstruct_mc2(workspace); - - for (int index = workspace.Lbx; index <= workspace.Ubx; ++index) { - require_state_vector_close(row_to_state(workspace.up_l, index), constant_state); - require_state_vector_close(row_to_state(workspace.up_r, index), constant_state); - } - - require_state_vector_close(row_to_state(workspace.up_l, workspace.Lbx - 1), - row_to_state(workspace.up_r, workspace.Lbx)); - require_state_vector_close(row_to_state(workspace.up_r, workspace.Ubx + 1), - row_to_state(workspace.up_l, workspace.Ubx)); -} - -TEST_CASE("hlld_flux_from_primitive matches the physical flux for identical states", - "[mhd1d][flux]") -{ - const double bx = 0.75; - const double gamma = 2.0; - const auto state = mhd1d::StateVector{1.4, -0.6, 0.25, 0.1, 1.9, -0.35, 0.5}; - const auto actual = mhd1d::hlld_flux_from_primitive(state, state, bx, gamma); - - const double rho = state[0]; - const double u = state[1]; - const double v = state[2]; - const double w = state[3]; - const double p = state[4]; - const double by = state[5]; - const double bz = state[6]; - const double bx2 = bx * bx; - const double pt = p + 0.5 * (bx2 + by * by + bz * bz); - const double e = - p / (gamma - 1.0) + 0.5 * rho * (u * u + v * v + w * w) + 0.5 * (bx2 + by * by + bz * bz); - - const auto expected = mhd1d::StateVector{ - rho * u, - rho * u * u + pt - bx2, - rho * u * v - bx * by, - rho * u * w - bx * bz, - u * (e + pt - bx2) - bx * (v * by + w * bz), - by * u - bx * v, - bz * u - bx * w, - }; - - require_state_vector_close(actual, expected); -} - -TEST_CASE("set_boundary duplicates edge states on both sides", "[mhd1d][boundary]") -{ - std::vector padded_buffer(4 * mhd1d::N_Component, 0.0); - const mhd1d::ArrayView2D padded(padded_buffer.data(), 4, mhd1d::N_Component); - state_to_row(padded, 2, mhd1d::StateVector{1.0, 0.5, -0.25, 0.125, 2.0, 0.1, -0.05}); - state_to_row(padded, 1, mhd1d::StateVector{1.2, 0.6, -0.2, 0.15, 2.2, 0.12, -0.02}); - state_to_row(padded, 2, mhd1d::StateVector{1.4, 0.7, -0.15, 0.175, 2.4, 0.14, 0.01}); - - mhd1d::set_boundary_lb(padded, padded, 1); - mhd1d::set_boundary_ub(padded, padded, 2); - - require_state_vector_close(row_to_state(padded, 0), row_to_state(padded, 1)); - require_state_vector_close(row_to_state(padded, 1), row_to_state(padded, 1)); - require_state_vector_close(row_to_state(padded, 2), row_to_state(padded, 2)); - require_state_vector_close(row_to_state(padded, 3), row_to_state(padded, 2)); -} - -TEST_CASE("set_boundary handles a single interior cell", "[mhd1d][boundary]") -{ - std::vector padded_buffer(3 * mhd1d::N_Component, 0.0); - const mhd1d::ArrayView2D padded(padded_buffer.data(), 3, mhd1d::N_Component); - const auto cell = mhd1d::StateVector{1.5, -0.75, 0.25, 0.0, 3.5, -0.1, 0.2}; - state_to_row(padded, 1, cell); - mhd1d::set_boundary_lb(padded, padded, 1); - mhd1d::set_boundary_ub(padded, padded, 1); - - for (int index = 0; index < 3; ++index) { - require_state_vector_close(row_to_state(padded, index), cell); - } -} - -TEST_CASE("set_boundary overwrites ghost cells from interior boundary", "[mhd1d][boundary]") -{ - std::vector cells_buffer(4 * mhd1d::N_Component, 0.0); - const mhd1d::ArrayView2D cells(cells_buffer.data(), 4, mhd1d::N_Component); - - state_to_row(cells, 0, mhd1d::StateVector{-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0}); - state_to_row(cells, 1, mhd1d::StateVector{1.0, 0.1, 0.2, 0.3, 2.0, 0.4, 0.5}); - state_to_row(cells, 2, mhd1d::StateVector{2.0, 0.2, 0.3, 0.4, 2.1, 0.5, 0.6}); - state_to_row(cells, 3, mhd1d::StateVector{-2.0, -2.0, -2.0, -2.0, -2.0, -2.0, -2.0}); - - const mhd1d::StateVector interior_left = row_to_state(cells, 1); - const mhd1d::StateVector interior_right = row_to_state(cells, 2); - - mhd1d::set_boundary_lb(cells, cells, 1); - mhd1d::set_boundary_ub(cells, cells, 2); - - require_state_vector_close(row_to_state(cells, 0), interior_left); - require_state_vector_close(row_to_state(cells, 3), interior_right); - require_state_vector_close(row_to_state(cells, 1), interior_left); -} - -std::vector make_sample_conservative_cells() -{ - std::vector conservative_cells(4 * mhd1d::N_Component, 0.0); - const mhd1d::ArrayView2D view(conservative_cells.data(), 4, mhd1d::N_Component); - state_to_row(view, 0, mhd1d::StateVector{1.0, 0.1, 0.0, 0.0, 1.6, 0.20, 0.00}); - state_to_row(view, 1, mhd1d::StateVector{0.9, 0.0, 0.1, 0.0, 1.3, 0.15, 0.05}); - state_to_row(view, 2, mhd1d::StateVector{0.8, -0.1, 0.0, 0.1, 1.1, 0.10, 0.10}); - state_to_row(view, 3, mhd1d::StateVector{0.7, -0.2, -0.1, 0.0, 0.9, 0.05, 0.15}); - return conservative_cells; -} - -TEST_CASE("compute_rhs returns finite values", "[mhd1d][evolution]") -{ - const int nx = 4; - mhd1d::SolverWorkspace workspace(nx, 2.0, 0.75); - - const std::vector conservative_cells = make_sample_conservative_cells(); - for (int row = 0; row < nx; ++row) { - for (int component = 0; component < mhd1d::N_Component; ++component) { - workspace.uc(workspace.Lbx + row, component) = - conservative_cells[static_cast(row * mhd1d::N_Component + component)]; - } - } - - mhd1d::compute_rhs(workspace); - for (int row = workspace.Lbx; row <= workspace.Ubx; ++row) { - for (int component = 0; component < mhd1d::N_Component; ++component) { - REQUIRE(std::isfinite(workspace.rhs(row, component))); - } - } -} - -TEST_CASE("push_ssp_rk3 evolves state with finite conservative values", "[mhd1d][evolution]") -{ - const int nx = 4; - mhd1d::SolverWorkspace workspace(nx, 2.0, 0.75); - - const std::vector conservative_cells = make_sample_conservative_cells(); - for (int row = 0; row < nx; ++row) { - for (int component = 0; component < mhd1d::N_Component; ++component) { - workspace.uc(workspace.Lbx + row, component) = - conservative_cells[static_cast(row * mhd1d::N_Component + component)]; - } - } - - mhd1d::push_ssp_rk3(workspace, 1.0e-4); - - for (int row = workspace.Lbx; row <= workspace.Ubx; ++row) { - const double rho = workspace.uc(row, 0); - for (int component = 0; component < mhd1d::N_Component; ++component) { - REQUIRE(std::isfinite(workspace.uc(row, component))); - } - REQUIRE(rho > 0.0); - } -} - -TEST_CASE("evolve_ssp_rk3 matches repeated push_ssp_rk3 calls", "[mhd1d][evolution]") -{ - const int nx = 4; - const double dt = 1.0e-4; - const double t_final = 2.0e-4; - - mhd1d::SolverWorkspace evolved_workspace(nx, 2.0, 0.75); - mhd1d::SolverWorkspace manual_workspace(nx, 2.0, 0.75); - - const std::vector conservative_cells = make_sample_conservative_cells(); - for (int row = 0; row < nx; ++row) { - for (int component = 0; component < mhd1d::N_Component; ++component) { - const double value = - conservative_cells[static_cast(row * mhd1d::N_Component + component)]; - evolved_workspace.uc(evolved_workspace.Lbx + row, component) = value; - manual_workspace.uc(manual_workspace.Lbx + row, component) = value; - } - } - - mhd1d::evolve_ssp_rk3(evolved_workspace, dt, t_final); - - for (int step = 0; step < 2; ++step) { - mhd1d::push_ssp_rk3(manual_workspace, dt); - } - - for (int row = 0; row < nx; ++row) { - const int i = evolved_workspace.Lbx + row; - for (int component = 0; component < mhd1d::N_Component; ++component) { - REQUIRE(std::fabs(manual_workspace.uc(i, component) - evolved_workspace.uc(i, component)) <= - kTolerance); - } - } -} diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/test_public.py b/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/test_public.py deleted file mode 100644 index 19e2008..0000000 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/test_public.py +++ /dev/null @@ -1,79 +0,0 @@ -import csv -import math -import os -import subprocess -from pathlib import Path - - -PUBLIC_TEST_TARGET = "cpp_full_solver1d_public_tests" -GOLDEN_CSV_PATH = Path(__file__).resolve().parents[1] / "tests/data/brio_wu_golden.csv" -GOLDEN_TOLERANCE = 1.0e-12 -WORKSPACE_ROOT = Path(__file__).resolve().parents[1] - - -def _build_public_tests() -> Path: - subprocess.run(["cmake", "-S", ".", "-B", "build"], check=True, cwd=WORKSPACE_ROOT) - subprocess.run( - [ - "cmake", - "--build", - "build", - "--target", - "cpp_full_solver1d", - PUBLIC_TEST_TARGET, - ], - check=True, - cwd=WORKSPACE_ROOT, - ) - - binary_name = f"{PUBLIC_TEST_TARGET}.exe" if os.name == "nt" else PUBLIC_TEST_TARGET - executable_path = WORKSPACE_ROOT / "build/tests" / binary_name - assert executable_path.exists() - return executable_path - - -def test_public_catch2_target_builds() -> None: - _build_public_tests() - - -def test_public_brio_wu_cli_matches_reference_grid() -> None: - _build_public_tests() - - solver_name = "cpp_full_solver1d.exe" if os.name == "nt" else "cpp_full_solver1d" - solver_path = WORKSPACE_ROOT / "build/bin" / solver_name - assert solver_path.exists() - - completed = subprocess.run( - [str(solver_path)], - check=True, - capture_output=True, - text=True, - ) - - rows = list(csv.reader(completed.stdout.splitlines())) - golden_rows = list( - csv.reader(GOLDEN_CSV_PATH.read_text(encoding="utf-8").splitlines()) - ) - - assert rows[0] == ["x", "rho", "u", "v", "w", "p", "by", "bz"] - assert rows[0] == golden_rows[0] - assert len(rows) - 1 == 100 - assert len(rows) == len(golden_rows) - - dx = (1.0 - 0.0) / 100.0 - for index, (row, golden_row) in enumerate(zip(rows[1:], golden_rows[1:])): - assert len(row) == 8 - assert len(golden_row) == 8 - - x_value = float(row[0]) - expected_x = 0.0 + (index + 0.5) * dx - assert x_value == expected_x - assert abs(x_value - float(golden_row[0])) <= GOLDEN_TOLERANCE - - numeric_values = [float(component) for component in row[1:]] - golden_numeric_values = [float(component) for component in golden_row[1:]] - assert all(math.isfinite(component) for component in [x_value, *numeric_values]) - assert numeric_values[0] > 0.0 - assert numeric_values[4] > 0.0 - for component, golden_component in zip(numeric_values, golden_numeric_values): - assert abs(component - golden_component) <= GOLDEN_TOLERANCE diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/eval/run.sh b/benchmarks/magnetohydrodynamics/cpp-full1d-00/eval/run.sh similarity index 100% rename from benchmarks/magnetohydrodynamics/cpp-full-solver1d/eval/run.sh rename to benchmarks/magnetohydrodynamics/cpp-full1d-00/eval/run.sh diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/eval/tests/test_hidden.py b/benchmarks/magnetohydrodynamics/cpp-full1d-00/eval/tests/test_hidden.py similarity index 68% rename from benchmarks/magnetohydrodynamics/cpp-full-solver1d/eval/tests/test_hidden.py rename to benchmarks/magnetohydrodynamics/cpp-full1d-00/eval/tests/test_hidden.py index f011767..6b91e7e 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/eval/tests/test_hidden.py +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-00/eval/tests/test_hidden.py @@ -1,8 +1,10 @@ -import math +import csv import os import subprocess from pathlib import Path +from mhd1d_shared import TOLERANCE, assert_csv_rows_close + SOLVER_TARGET = "cpp_full_solver1d" WORKSPACE_ROOT = Path(__file__).resolve().parents[2] / "workspace" REFERENCE_CSV_PATH = ( @@ -43,15 +45,16 @@ def test_hidden_brio_wu_cli_matches_fixture(tmp_path: Path) -> None: ) output_csv_path.write_text(completed.stdout, encoding="utf-8") - output_rows = output_csv_path.read_text(encoding="utf-8").splitlines() - reference_rows = REFERENCE_CSV_PATH.read_text(encoding="utf-8").splitlines() - - assert len(output_rows) == len(reference_rows) + 1 - assert output_rows[1:] == reference_rows + output_rows = list( + csv.reader(output_csv_path.read_text(encoding="utf-8").splitlines()) + ) + reference_rows = list( + csv.reader(REFERENCE_CSV_PATH.read_text(encoding="utf-8").splitlines()) + ) - for column_name in ("v", "w", "bz"): - for row in output_rows[1:]: - values = row.split(",") - assert len(values) == 8 - value = float(values[{"v": 3, "w": 4, "bz": 6}[column_name]]) - assert math.isfinite(value) + assert_csv_rows_close( + output_rows, + reference_rows, + tolerance=TOLERANCE, + expected_header=["x", "rho", "u", "v", "w", "p", "by", "bz"], + ) diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-00/spec.md b/benchmarks/magnetohydrodynamics/cpp-full1d-00/spec.md new file mode 100644 index 0000000..05a3301 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-00/spec.md @@ -0,0 +1,74 @@ +# cpp-full1d-00 + +Implement a 1D ideal-MHD solver CLI in C++. + +## Read first + +- `/work/basic_equations.md` +- `/work/hlld.md` + +## Task + +The command-line entrypoint and the HLLD Riemann solver are already provided. +The CLI accepts an integer `nx` argument for the number of grid points, performs the Brio-Wu Riemann problem, and writes the solution to stdout in CSV format. +Your main task is to complete the solver implementation in `src/mhd1d.cpp`. + +The CLI output must match the provided golden CSV for `nx=100` within numeric tolerance (`1.0e-12`). + +## How to test + +Run the public checks from the workspace: + +```bash +python3 -m pytest -q tests/test_public.py +``` + +## Local dev + +```bash +pytest -q +``` + +To build manually: + +```bash +cmake -S . -B build +cmake --build build +./build/bin/cpp_full_solver1d +``` + +## Numerical Algorithm + +- Riemann solver: HLLD +- Primitive variables reconstruction: piecewise linear with MC2 slope limiter +- Time integration: SSP-RK3 +- Boundary condition: symmetric (zero-gradient) + +## Files + +- `src/main.cpp`: complete CLI (already done) +- `src/hlld.hpp`, `src/hlld.cpp`: complete HLLD implementation (already done) +- `src/mhd1d.hpp`, `src/mhd1d.cpp`: solver scaffolding to complete + +## Functions to complete (in `src/mhd1d.cpp`) + +The easiest path is to implement these functions first: + +1. `primitive_to_conservative(...)` +2. `conservative_to_primitive(...)` +3. `compute_lr(...)` +4. `compute_rhs(...)` +5. `push_ssp_rk3(...)` +6. `evolve_ssp_rk3(...)` + +Recommended implementation order: + +1. Reconstruction (`compute_lr`) +2. Flux loop (`compute_flux_hlld` already calls provided HLLD) +3. RHS assembly (`compute_rhs`) +4. One RK3 step (`push_ssp_rk3`) +5. Time loop (`evolve_ssp_rk3`) + +## Standards + +- C++17 diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/task.toml b/benchmarks/magnetohydrodynamics/cpp-full1d-00/task.toml similarity index 53% rename from benchmarks/magnetohydrodynamics/cpp-full-solver1d/task.toml rename to benchmarks/magnetohydrodynamics/cpp-full1d-00/task.toml index 3c4cb26..171ed4e 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/task.toml +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-00/task.toml @@ -1,8 +1,8 @@ -id = "cpp-full-solver1d" +id = "cpp-full1d-00" suite = "magnetohydrodynamics" language = "cpp" time_limit_sec = 600 eval_cmd = "/eval/run.sh" -prompt = "Read /run/spec.md and solve the task in /work." +prompt = "Read /run/spec.md, /work/basic_equations.md, and /work/hlld.md, then solve the task in /work." use_shared_workspace = true use_shared_eval = true diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/CMakeLists.txt b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/CMakeLists.txt similarity index 98% rename from benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/CMakeLists.txt rename to benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/CMakeLists.txt index e4889f2..1375922 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/CMakeLists.txt +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/CMakeLists.txt @@ -22,6 +22,7 @@ endif() add_library(mhd1d_solver src/mhd1d.cpp + src/hlld.cpp ) target_include_directories(mhd1d_solver PUBLIC diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/README.md b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/README.md new file mode 100644 index 0000000..bda64ad --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/README.md @@ -0,0 +1,7 @@ +The public C++ workspace contains a Brio-Wu solver scaffold. + +- `src/main.cpp` is complete. +- `src/hlld.cpp` is complete. +- `src/mhd1d.cpp` contains TODO sections to implement. + +Shared workspace docs are already mounted for this benchmark. diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/pyproject.toml b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/pyproject.toml similarity index 68% rename from benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/pyproject.toml rename to benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/pyproject.toml index 8eee297..137476d 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/pyproject.toml +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/pyproject.toml @@ -1,5 +1,5 @@ [project] -name = "magnetohydrodynamics-cpp-full-solver1d" +name = "magnetohydrodynamics-cpp-full1d-00" version = "0.0.0" requires-python = ">=3.10" diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/src/hlld.cpp b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/src/hlld.cpp new file mode 100644 index 0000000..f5f9c87 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/src/hlld.cpp @@ -0,0 +1,202 @@ +#include "hlld.hpp" + +#include +#include + +void hlld_flux_from_primitive(const double* left, const double* right, double bx, double gamma, + double* flux) +{ + constexpr double epsilon = 1.0e-40; + + const double rol = left[0]; + const double vxl = left[1]; + const double vyl = left[2]; + const double vzl = left[3]; + const double prl = left[4]; + const double byl = left[5]; + const double bzl = left[6]; + + const double ror = right[0]; + const double vxr = right[1]; + const double vyr = right[2]; + const double vzr = right[3]; + const double prr = right[4]; + const double byr = right[5]; + const double bzr = right[6]; + + const double igm = 1.0 / (gamma - 1.0); + const double bxs = bx; + const double bxsq = bxs * bxs; + + const double pbl = 0.5 * (bxsq + byl * byl + bzl * bzl); + const double pbr = 0.5 * (bxsq + byr * byr + bzr * bzr); + const double ptl = prl + pbl; + const double ptr = prr + pbr; + + const double rxl = rol * vxl; + const double ryl = rol * vyl; + const double rzl = rol * vzl; + const double rxr = ror * vxr; + const double ryr = ror * vyr; + const double rzr = ror * vzr; + + const double eel = prl * igm + 0.5 * (rxl * vxl + ryl * vyl + rzl * vzl) + pbl; + const double eer = prr * igm + 0.5 * (rxr * vxr + ryr * vyr + rzr * vzr) + pbr; + + const double gmpl = gamma * prl; + const double gmpr = gamma * prr; + const double gpbl = gmpl + 2.0 * pbl; + const double gpbr = gmpr + 2.0 * pbr; + + const double cfl = std::sqrt((gpbl + std::sqrt((gmpl - 2.0 * pbl) * (gmpl - 2.0 * pbl) + + 4.0 * gmpl * (byl * byl + bzl * bzl))) * + 0.5 / rol); + const double cfr = std::sqrt((gpbr + std::sqrt((gmpr - 2.0 * pbr) * (gmpr - 2.0 * pbr) + + 4.0 * gmpr * (byr * byr + bzr * bzr))) * + 0.5 / ror); + + const double sl = std::min(vxl, vxr) - std::max(cfl, cfr); + const double sr = std::max(vxl, vxr) + std::max(cfl, cfr); + + const double fql[7] = {rxl, + rxl * vxl + ptl - bxsq, + rxl * vyl - bxs * byl, + rxl * vzl - bxs * bzl, + vxl * (eel + ptl - bxsq) - bxs * (vyl * byl + vzl * bzl), + byl * vxl - bxs * vyl, + bzl * vxl - bxs * vzl}; + const double fqr[7] = {rxr, + rxr * vxr + ptr - bxsq, + rxr * vyr - bxs * byr, + rxr * vzr - bxs * bzr, + vxr * (eer + ptr - bxsq) - bxs * (vyr * byr + vzr * bzr), + byr * vxr - bxs * vyr, + bzr * vxr - bxs * vzr}; + + const double sdl = sl - vxl; + const double sdr = sr - vxr; + const double rosdl = rol * sdl; + const double rosdr = ror * sdr; + const double temp = 1.0 / (rosdr - rosdl); + const double sm = (rosdr * vxr - rosdl * vxl - ptr + ptl) * temp; + const double sdml = sl - sm; + const double sdmr = sr - sm; + const double ptst = (rosdr * ptl - rosdl * ptr + rosdl * rosdr * (vxr - vxl)) * temp; + + const double temp_fst_l = rosdl * sdml - bxsq; + const double sign1_l = std::copysign(1.0, std::abs(temp_fst_l) - epsilon); + const double maxs1_l = std::max(0.0, sign1_l); + const double mins1_l = std::min(0.0, sign1_l); + const double itf_l = 1.0 / (temp_fst_l + mins1_l); + const double isdml = 1.0 / sdml; + + const double temp_l = bxs * (sdl - sdml) * itf_l; + const double rolst = maxs1_l * (rosdl * isdml) - mins1_l * rol; + const double vxlst = maxs1_l * sm - mins1_l * vxl; + const double rxlst = rolst * vxlst; + const double vylst = maxs1_l * (vyl - byl * temp_l) - mins1_l * vyl; + const double rylst = rolst * vylst; + const double vzlst = maxs1_l * (vzl - bzl * temp_l) - mins1_l * vzl; + const double rzlst = rolst * vzlst; + const double temp_l_b = (rosdl * sdl - bxsq) * itf_l; + const double bylst = maxs1_l * (byl * temp_l_b) - mins1_l * byl; + const double bzlst = maxs1_l * (bzl * temp_l_b) - mins1_l * bzl; + const double vdbstl = vxlst * bxs + vylst * bylst + vzlst * bzlst; + const double eelst = maxs1_l * ((sdl * eel - ptl * vxl + ptst * sm + + bxs * (vxl * bxs + vyl * byl + vzl * bzl - vdbstl)) * + isdml) - + mins1_l * eel; + + const double temp_fst_r = rosdr * sdmr - bxsq; + const double sign1_r = std::copysign(1.0, std::abs(temp_fst_r) - epsilon); + const double maxs1_r = std::max(0.0, sign1_r); + const double mins1_r = std::min(0.0, sign1_r); + const double itf_r = 1.0 / (temp_fst_r + mins1_r); + const double isdmr = 1.0 / sdmr; + + const double temp_r = bxs * (sdr - sdmr) * itf_r; + const double rorst = maxs1_r * (rosdr * isdmr) - mins1_r * ror; + const double vxrst = maxs1_r * sm - mins1_r * vxr; + const double rxrst = rorst * vxrst; + const double vyrst = maxs1_r * (vyr - byr * temp_r) - mins1_r * vyr; + const double ryrst = rorst * vyrst; + const double vzrst = maxs1_r * (vzr - bzr * temp_r) - mins1_r * vzr; + const double rzrst = rorst * vzrst; + const double temp_r_b = (rosdr * sdr - bxsq) * itf_r; + const double byrst = maxs1_r * (byr * temp_r_b) - mins1_r * byr; + const double bzrst = maxs1_r * (bzr * temp_r_b) - mins1_r * bzr; + const double vdbstr = vxrst * bxs + vyrst * byrst + vzrst * bzrst; + const double eerst = maxs1_r * ((sdr * eer - ptr * vxr + ptst * sm + + bxs * (vxr * bxs + vyr * byr + vzr * bzr - vdbstr)) * + isdmr) - + mins1_r * eer; + + const double sqrtrol = std::sqrt(rolst); + const double sqrtror = std::sqrt(rorst); + const double abbx = std::abs(bxs); + const double slst = sm - abbx / sqrtrol; + const double srst = sm + abbx / sqrtror; + const double signbx = std::copysign(1.0, bxs); + const double sign1_b = std::copysign(1.0, abbx - epsilon); + const double maxs1_b = std::max(0.0, sign1_b); + const double mins1_b = -std::min(0.0, sign1_b); + const double invsumro = maxs1_b / (sqrtrol + sqrtror); + + const double roldst = rolst; + const double rordst = rorst; + const double rxldst = rxlst; + const double rxrdst = rxrst; + + const double vy_shared = + invsumro * (sqrtrol * vylst + sqrtror * vyrst + signbx * (byrst - bylst)); + const double ryldst = rylst * mins1_b + roldst * vy_shared; + const double ryrdst = ryrst * mins1_b + rordst * vy_shared; + + const double vz_shared = + invsumro * (sqrtrol * vzlst + sqrtror * vzrst + signbx * (bzrst - bzlst)); + const double rzldst = rzlst * mins1_b + roldst * vz_shared; + const double rzrdst = rzrst * mins1_b + rordst * vz_shared; + + const double by_shared = + invsumro * (sqrtrol * byrst + sqrtror * bylst + signbx * sqrtrol * sqrtror * (vyrst - vylst)); + const double byldst = bylst * mins1_b + by_shared; + const double byrdst = byrst * mins1_b + by_shared; + + const double bz_shared = + invsumro * (sqrtrol * bzrst + sqrtror * bzlst + signbx * sqrtrol * sqrtror * (vzrst - vzlst)); + const double bzldst = bzlst * mins1_b + bz_shared; + const double bzrdst = bzrst * mins1_b + bz_shared; + + const double vyldst = vylst * mins1_b + vy_shared; + const double vyrdst = vyrst * mins1_b + vy_shared; + const double vzldst = vzlst * mins1_b + vz_shared; + const double vzrdst = vzrst * mins1_b + vz_shared; + const double temp_dst = sm * bxs + vyldst * byldst + vzldst * bzldst; + const double eeldst = eelst - sqrtrol * signbx * (vdbstl - temp_dst) * maxs1_b; + const double eerdst = eerst + sqrtror * signbx * (vdbstr - temp_dst) * maxs1_b; + + const double sign1 = std::copysign(1.0, sm); + const double maxs1 = std::max(0.0, sign1); + const double mins1 = -std::min(0.0, sign1); + const double msl = std::min(sl, 0.0); + const double mslst = std::min(slst, 0.0); + const double msrst = std::max(srst, 0.0); + const double msr = std::max(sr, 0.0); + const double temp_flux_l = mslst - msl; + const double temp_flux_r = msrst - msr; + + flux[0] = (fql[0] - msl * rol - rolst * temp_flux_l + roldst * mslst) * maxs1 + + (fqr[0] - msr * ror - rorst * temp_flux_r + rordst * msrst) * mins1; + flux[1] = (fql[1] - msl * rxl - rxlst * temp_flux_l + rxldst * mslst) * maxs1 + + (fqr[1] - msr * rxr - rxrst * temp_flux_r + rxrdst * msrst) * mins1; + flux[2] = (fql[2] - msl * ryl - rylst * temp_flux_l + ryldst * mslst) * maxs1 + + (fqr[2] - msr * ryr - ryrst * temp_flux_r + ryrdst * msrst) * mins1; + flux[3] = (fql[3] - msl * rzl - rzlst * temp_flux_l + rzldst * mslst) * maxs1 + + (fqr[3] - msr * rzr - rzrst * temp_flux_r + rzrdst * msrst) * mins1; + flux[4] = (fql[4] - msl * eel - eelst * temp_flux_l + eeldst * mslst) * maxs1 + + (fqr[4] - msr * eer - eerst * temp_flux_r + eerdst * msrst) * mins1; + flux[5] = (fql[5] - msl * byl - bylst * temp_flux_l + byldst * mslst) * maxs1 + + (fqr[5] - msr * byr - byrst * temp_flux_r + byrdst * msrst) * mins1; + flux[6] = (fql[6] - msl * bzl - bzlst * temp_flux_l + bzldst * mslst) * maxs1 + + (fqr[6] - msr * bzr - bzrst * temp_flux_r + bzrdst * msrst) * mins1; +} diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/src/hlld.hpp b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/src/hlld.hpp new file mode 100644 index 0000000..ae80ebd --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/src/hlld.hpp @@ -0,0 +1,4 @@ +#pragma once + +void hlld_flux_from_primitive(const double* left, const double* right, double bx, double gamma, + double* flux); diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/src/main.cpp similarity index 90% rename from benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp rename to benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/src/main.cpp index dcd509f..82e0f5a 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/main.cpp +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/src/main.cpp @@ -5,9 +5,9 @@ #include #include -constexpr int DefaultNx = 100; -constexpr double Gamma = 2.0; -constexpr double Bx = 0.75; +constexpr int Nx = 100; +constexpr double Gamma = 2.0; +constexpr double Bx = 0.75; constexpr mhd1d::StateVector LeftPrimitive{ 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, }; @@ -18,7 +18,7 @@ constexpr mhd1d::StateVector RightPrimitive{ int parse_nx(int argc, char** argv) { if (argc <= 1) { - return DefaultNx; + return Nx; } char* end = nullptr; @@ -43,7 +43,7 @@ mhd1d::SolverWorkspace initialize(int nx, double gamma, double bx, } mhd1d::set_boundary(workspace.up, workspace.up, workspace.Lbx, workspace.Ubx); - mhd1d::primitive_profile_to_conservative(workspace.up, workspace.uc, bx, gamma); + mhd1d::convert_primitive_to_conservative(workspace.up, workspace.uc, bx, gamma); return workspace; } diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/src/mhd1d.cpp b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/src/mhd1d.cpp new file mode 100644 index 0000000..00e85fa --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/src/mhd1d.cpp @@ -0,0 +1,108 @@ +#include "mhd1d.hpp" + +namespace mhd1d +{ + +void primitive_to_conservative(const double* primitive, double* conservative, double bx, + double gamma) +{ + (void)primitive; + (void)conservative; + (void)bx; + (void)gamma; + // TODO(student): convert one primitive state [rho,u,v,w,p,By,Bz] to + // conservative [rho,mx,my,mz,E,By,Bz]. +} + +void conservative_to_primitive(const double* conservative, double* primitive, double bx, + double gamma) +{ + (void)conservative; + (void)primitive; + (void)bx; + (void)gamma; + // TODO(student): recover primitive variables from one conservative state. + // Enforce positive density and compute pressure from total energy. +} + +void convert_primitive_to_conservative(ArrayView2D primitive, ArrayView2D conservative, double bx, + double gamma) +{ + (void)primitive; + (void)conservative; + (void)bx; + (void)gamma; + // TODO(student): loop over cells and call primitive_to_conservative. +} + +void convert_conservative_to_primitive(ArrayView2D conservative, ArrayView2D primitive, double bx, + double gamma) +{ + (void)conservative; + (void)primitive; + (void)bx; + (void)gamma; + // TODO(student): loop over cells and call conservative_to_primitive. +} + +void set_boundary_lb(ArrayView2D dst, ArrayView2D src, int lbx) +{ + (void)dst; + (void)src; + (void)lbx; + // TODO(student): copy left interior boundary state into left ghost cells. +} + +void set_boundary_ub(ArrayView2D dst, ArrayView2D src, int ubx) +{ + (void)dst; + (void)src; + (void)ubx; + // TODO(student): copy right interior boundary state into right ghost cells. +} + +void set_boundary(ArrayView2D dst, ArrayView2D src, int lbx, int ubx) +{ + (void)dst; + (void)src; + (void)lbx; + (void)ubx; + // TODO(student): apply both lower and upper zero-gradient boundaries. +} + +void compute_lr(SolverWorkspace& workspace) +{ + (void)workspace; + // TODO(student): compute MC2 reconstructed left/right primitive states on each cell. +} + +void compute_flux_hlld(SolverWorkspace& workspace, double bx, double gamma) +{ + (void)workspace; + (void)bx; + (void)gamma; + // TODO(student): evaluate HLLD interface fluxes using provided hlld_flux_from_primitive. +} + +void compute_rhs(SolverWorkspace& workspace) +{ + (void)workspace; + // TODO(student): build semidiscrete RHS from flux differences and cell width dx. +} + +void push_ssp_rk3(SolverWorkspace& workspace, double dt) +{ + (void)workspace; + (void)dt; + // TODO(student): implement one full SSP-RK3 step (3 substeps). +} + +void evolve_ssp_rk3(SolverWorkspace& workspace, double dt, double t_final) +{ + (void)workspace; + (void)dt; + (void)t_final; + // TODO(student): repeatedly call push_ssp_rk3 until t_final (clip final dt). +} + +} // namespace mhd1d diff --git a/benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.hpp b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/src/mhd1d.hpp similarity index 100% rename from benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.hpp rename to benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/src/mhd1d.hpp diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/tests/cpp/test_public.cpp b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/tests/cpp/test_public.cpp new file mode 100644 index 0000000..b4f822f --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/tests/cpp/test_public.cpp @@ -0,0 +1,55 @@ +#include + +#include +#include + +#include "mhd1d.hpp" + +TEST_CASE("set_boundary duplicates edge states on both sides", "[mhd1d][boundary]") +{ + std::vector padded_buffer(4 * mhd1d::N_Component, 0.0); + const mhd1d::ArrayView2D padded(padded_buffer.data(), 4, mhd1d::N_Component); + + padded(1, 0) = 1.2; + padded(2, 0) = 1.4; + + mhd1d::set_boundary_lb(padded, padded, 1); + mhd1d::set_boundary_ub(padded, padded, 2); + + REQUIRE(padded(0, 0) == padded(1, 0)); + REQUIRE(padded(3, 0) == padded(2, 0)); +} + +TEST_CASE("compute_flux_hlld fills finite interface values", "[mhd1d][flux]") +{ + mhd1d::SolverWorkspace workspace(4, 2.0, 0.75); + + for (int ix = workspace.Lbx; ix <= workspace.Ubx; ++ix) { + workspace.up_l(ix, 0) = 1.0; + workspace.up_l(ix, 1) = 0.0; + workspace.up_l(ix, 2) = 0.0; + workspace.up_l(ix, 3) = 0.0; + workspace.up_l(ix, 4) = 1.0; + workspace.up_l(ix, 5) = 0.5; + workspace.up_l(ix, 6) = 0.0; + + workspace.up_r(ix, 0) = 0.9; + workspace.up_r(ix, 1) = 0.0; + workspace.up_r(ix, 2) = 0.0; + workspace.up_r(ix, 3) = 0.0; + workspace.up_r(ix, 4) = 0.9; + workspace.up_r(ix, 5) = 0.4; + workspace.up_r(ix, 6) = 0.0; + } + + mhd1d::set_boundary_lb(workspace.up_l, workspace.up_l, workspace.Lbx); + mhd1d::set_boundary_ub(workspace.up_l, workspace.up_l, workspace.Ubx); + mhd1d::set_boundary_lb(workspace.up_r, workspace.up_r, workspace.Lbx); + mhd1d::set_boundary_ub(workspace.up_r, workspace.up_r, workspace.Ubx); + + mhd1d::compute_flux_hlld(workspace, 0.75, 2.0); + + for (int ix = workspace.Lbx - 1; ix <= workspace.Ubx + 1; ++ix) { + REQUIRE(std::isfinite(workspace.flux(ix, 0))); + } +} diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/data/brio_wu_golden.csv b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/tests/data/brio_wu_golden.csv similarity index 100% rename from benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/tests/data/brio_wu_golden.csv rename to benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/tests/data/brio_wu_golden.csv diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/tests/test_public.py b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/tests/test_public.py new file mode 100644 index 0000000..d63006e --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/tests/test_public.py @@ -0,0 +1,85 @@ +import csv +import os +import subprocess +from pathlib import Path + +PUBLIC_TEST_TARGET = "cpp_full_solver1d_public_tests" +GOLDEN_CSV_PATH = Path(__file__).resolve().parents[1] / "tests/data/brio_wu_golden.csv" +TOLERANCE = 1.0e-12 +WORKSPACE_ROOT = Path(__file__).resolve().parents[1] + + +def assert_csv_rows_close( + output_rows: list[list[str]], + reference_rows: list[list[str]], + *, + tolerance: float = TOLERANCE, + expected_header: list[str] | None = None, +) -> None: + if expected_header is not None: + assert output_rows[0] == expected_header + output_rows = output_rows[1:] + + assert len(output_rows) == len(reference_rows) + + for output_row, reference_row in zip(output_rows, reference_rows): + assert len(output_row) == len(reference_row) + for output_value, reference_value in zip(output_row, reference_row): + assert abs(float(output_value) - float(reference_value)) <= tolerance + + +def _build_public_tests() -> Path: + build_dir = "build_public" + subprocess.run( + ["cmake", "-S", ".", "-B", build_dir], check=True, cwd=WORKSPACE_ROOT + ) + subprocess.run( + [ + "cmake", + "--build", + build_dir, + "--target", + "cpp_full_solver1d", + PUBLIC_TEST_TARGET, + ], + check=True, + cwd=WORKSPACE_ROOT, + ) + + binary_name = f"{PUBLIC_TEST_TARGET}.exe" if os.name == "nt" else PUBLIC_TEST_TARGET + executable_path = WORKSPACE_ROOT / build_dir / "tests" / binary_name + assert executable_path.exists() + return executable_path + + +def test_public_catch2_target_builds() -> None: + _build_public_tests() + + +def test_public_brio_wu_cli_matches_reference_grid() -> None: + _build_public_tests() + + solver_name = "cpp_full_solver1d.exe" if os.name == "nt" else "cpp_full_solver1d" + solver_path = WORKSPACE_ROOT / "build_public/bin" / solver_name + assert solver_path.exists() + + completed = subprocess.run( + [str(solver_path)], + check=True, + capture_output=True, + text=True, + ) + + rows = list(csv.reader(completed.stdout.splitlines())) + golden_rows = list( + csv.reader(GOLDEN_CSV_PATH.read_text(encoding="utf-8").splitlines()) + ) + + assert golden_rows[0] == ["x", "rho", "u", "v", "w", "p", "by", "bz"] + + assert_csv_rows_close( + rows, + golden_rows[1:], + tolerance=TOLERANCE, + expected_header=["x", "rho", "u", "v", "w", "p", "by", "bz"], + ) diff --git a/benchmarks/magnetohydrodynamics/shared/CMakeLists.txt b/benchmarks/magnetohydrodynamics/shared/CMakeLists.txt index 1a02e85..cf98002 100644 --- a/benchmarks/magnetohydrodynamics/shared/CMakeLists.txt +++ b/benchmarks/magnetohydrodynamics/shared/CMakeLists.txt @@ -6,24 +6,24 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -add_library(mhd1d_reference - src/full_mhd1d.cpp +add_library(mhd1d_reference_lib + src/mhd1d.cpp src/hlld.cpp ) -target_include_directories(mhd1d_reference PUBLIC +target_include_directories(mhd1d_reference_lib PUBLIC src ../../common/include ) -add_executable(full_mhd1d_reference - src/full_main.cpp +add_executable(mhd1d_reference + src/main.cpp ) -target_link_libraries(full_mhd1d_reference PRIVATE - mhd1d_reference +target_link_libraries(mhd1d_reference PRIVATE + mhd1d_reference_lib ) -set_target_properties(full_mhd1d_reference PROPERTIES +set_target_properties(mhd1d_reference PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" ) diff --git a/benchmarks/magnetohydrodynamics/shared/README.md b/benchmarks/magnetohydrodynamics/shared/README.md index 35299f7..25ba805 100644 --- a/benchmarks/magnetohydrodynamics/shared/README.md +++ b/benchmarks/magnetohydrodynamics/shared/README.md @@ -7,13 +7,13 @@ Brio-Wu fixtures used by the magnetohydrodynamics benchmarks. ```bash cmake -S benchmarks/magnetohydrodynamics/shared -B benchmarks/magnetohydrodynamics/shared/build -cmake --build benchmarks/magnetohydrodynamics/shared/build --target full_mhd1d_reference +cmake --build benchmarks/magnetohydrodynamics/shared/build --target mhd1d_reference ``` ## Run the shared reference solver ```bash -benchmarks/magnetohydrodynamics/shared/build/bin/full_mhd1d_reference > benchmarks/magnetohydrodynamics/shared/build/solution.csv +benchmarks/magnetohydrodynamics/shared/build/bin/mhd1d_reference > benchmarks/magnetohydrodynamics/shared/build/solution.csv ``` ## Plot the output diff --git a/benchmarks/magnetohydrodynamics/shared/eval/README.md b/benchmarks/magnetohydrodynamics/shared/eval/README.md index 56deb30..3740465 100644 --- a/benchmarks/magnetohydrodynamics/shared/eval/README.md +++ b/benchmarks/magnetohydrodynamics/shared/eval/README.md @@ -1,7 +1,7 @@ # Shared eval assets This directory holds suite-wide hidden-eval documentation for -`cpp-full-solver1d`. +the full 1D MHD variants (starting with `cpp-full1d-00`). ## Hidden reference lifecycle diff --git a/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/README.md b/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/README.md index bfb2141..bdf8018 100644 --- a/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/README.md +++ b/benchmarks/magnetohydrodynamics/shared/eval/fixtures/mhd1d/README.md @@ -1,7 +1,7 @@ # mhd1d hidden fixtures -This directory will store the hidden reference fixtures for -`cpp-full-solver1d`. +This directory stores the hidden reference fixtures for +the full 1D MHD variants (starting with `cpp-full1d-00`). ## Contents diff --git a/benchmarks/magnetohydrodynamics/shared/eval/mhd1d_shared.py b/benchmarks/magnetohydrodynamics/shared/eval/mhd1d_shared.py new file mode 100644 index 0000000..94f8424 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/shared/eval/mhd1d_shared.py @@ -0,0 +1,27 @@ +from __future__ import annotations + +from typing import Sequence + + +TOLERANCE = 1.0e-12 + + +def assert_csv_rows_close( + output_rows: Sequence[Sequence[str]], + reference_rows: Sequence[Sequence[str]], + *, + tolerance: float = TOLERANCE, + expected_header: Sequence[str] | None = None, +) -> None: + if expected_header is not None: + assert list(output_rows[0]) == list(expected_header) + output_rows = output_rows[1:] + + assert len(output_rows) == len(reference_rows) + + for output_row, reference_row in zip(output_rows, reference_rows): + assert len(output_row) == len(reference_row) + for output_value, reference_value in zip(output_row, reference_row): + output_float = float(output_value) + reference_float = float(reference_value) + assert abs(output_float - reference_float) <= tolerance diff --git a/benchmarks/magnetohydrodynamics/shared/src/full_main.cpp b/benchmarks/magnetohydrodynamics/shared/src/main.cpp similarity index 98% rename from benchmarks/magnetohydrodynamics/shared/src/full_main.cpp rename to benchmarks/magnetohydrodynamics/shared/src/main.cpp index 91864c3..335945f 100644 --- a/benchmarks/magnetohydrodynamics/shared/src/full_main.cpp +++ b/benchmarks/magnetohydrodynamics/shared/src/main.cpp @@ -1,4 +1,4 @@ -#include "full_mhd1d.hpp" +#include "mhd1d.hpp" #include #include diff --git a/benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.cpp b/benchmarks/magnetohydrodynamics/shared/src/mhd1d.cpp similarity index 99% rename from benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.cpp rename to benchmarks/magnetohydrodynamics/shared/src/mhd1d.cpp index b43dde3..10e80a2 100644 --- a/benchmarks/magnetohydrodynamics/shared/src/full_mhd1d.cpp +++ b/benchmarks/magnetohydrodynamics/shared/src/mhd1d.cpp @@ -1,4 +1,4 @@ -#include "full_mhd1d.hpp" +#include "mhd1d.hpp" #include "hlld.hpp" #include diff --git a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp b/benchmarks/magnetohydrodynamics/shared/src/mhd1d.hpp similarity index 85% rename from benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp rename to benchmarks/magnetohydrodynamics/shared/src/mhd1d.hpp index 8e56eca..6925629 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full-solver1d/workspace/src/mhd1d.hpp +++ b/benchmarks/magnetohydrodynamics/shared/src/mhd1d.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include @@ -15,8 +14,8 @@ constexpr int N_Component = 7; constexpr int N_margin = 1; using StateVector = std::array; -using ArrayView1D = stdex::mdspan>; -using ArrayView2D = stdex::mdspan>; +using ArrayView1D = stdex::mdspan, stdex::layout_right>; +using ArrayView2D = stdex::mdspan, stdex::layout_right>; struct SolverWorkspace { explicit SolverWorkspace(int nx, double gamma, double bx) @@ -80,11 +79,13 @@ struct SolverWorkspace { Storage storage; }; -StateVector primitive_to_conservative(const StateVector& primitive, double bx, double gamma); +void primitive_to_conservative(const double* primitive, double* conservative, double bx, + double gamma); -StateVector conservative_to_primitive(const StateVector& conservative, double bx, double gamma); +void conservative_to_primitive(const double* conservative, double* primitive, double bx, + double gamma); -void primitive_profile_to_conservative(ArrayView2D primitive_cells, ArrayView2D conservative_cells, +void convert_primitive_to_conservative(ArrayView2D primitive_cells, ArrayView2D conservative_cells, double bx, double gamma); void set_boundary_lb(ArrayView2D dst, ArrayView2D src, int lbx); @@ -93,10 +94,7 @@ void set_boundary_ub(ArrayView2D dst, ArrayView2D src, int ubx); void set_boundary(ArrayView2D dst, ArrayView2D src, int lbx, int ubx); -StateVector hlld_flux_from_primitive(const StateVector& left, const StateVector& right, double bx, - double gamma); - -void reconstruct_mc2(SolverWorkspace& workspace); +void compute_lr(SolverWorkspace& workspace); void compute_flux_hlld(SolverWorkspace& workspace, double bx, double gamma); diff --git a/benchmarks/magnetohydrodynamics/shared/tests/test_reference.py b/benchmarks/magnetohydrodynamics/shared/tests/test_reference.py index 65183ac..5e0426e 100644 --- a/benchmarks/magnetohydrodynamics/shared/tests/test_reference.py +++ b/benchmarks/magnetohydrodynamics/shared/tests/test_reference.py @@ -1,9 +1,20 @@ from __future__ import annotations +import csv import os +import sys import subprocess from pathlib import Path +REPO_ROOT = Path(__file__).resolve().parents[4] +if str(REPO_ROOT) not in sys.path: + sys.path.insert(0, str(REPO_ROOT)) + +from benchmarks.magnetohydrodynamics.shared.eval.mhd1d_shared import ( + TOLERANCE, + assert_csv_rows_close, +) + SHARED_ROOT = Path(__file__).resolve().parents[1] FIXTURE_CSV_PATH = SHARED_ROOT / "eval" / "fixtures" / "mhd1d" / "brio_wu_reference.csv" @@ -13,13 +24,11 @@ def _build_reference_solver() -> Path: build_dir = SHARED_ROOT / "build" subprocess.run(["cmake", "-S", str(SHARED_ROOT), "-B", str(build_dir)], check=True) subprocess.run( - ["cmake", "--build", str(build_dir), "--target", "full_mhd1d_reference"], + ["cmake", "--build", str(build_dir), "--target", "mhd1d_reference"], check=True, ) - binary_name = ( - "full_mhd1d_reference.exe" if os.name == "nt" else "full_mhd1d_reference" - ) + binary_name = "mhd1d_reference.exe" if os.name == "nt" else "mhd1d_reference" binary_path = build_dir / "bin" / binary_name assert binary_path.exists() return binary_path @@ -37,8 +46,11 @@ def test_shared_reference_solver_matches_fixture(tmp_path: Path) -> None: ) output_csv_path.write_text(completed.stdout, encoding="utf-8") - output_rows = output_csv_path.read_text(encoding="utf-8").splitlines() - reference_rows = FIXTURE_CSV_PATH.read_text(encoding="utf-8").splitlines() + output_rows = list( + csv.reader(output_csv_path.read_text(encoding="utf-8").splitlines()) + ) + reference_rows = list( + csv.reader(FIXTURE_CSV_PATH.read_text(encoding="utf-8").splitlines()) + ) - assert len(output_rows) == len(reference_rows) - assert output_rows == reference_rows + assert_csv_rows_close(output_rows, reference_rows, tolerance=TOLERANCE) From db0bf446ee7abb0dd63beda1314c8ec6c61fbab1 Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Thu, 2 Apr 2026 14:03:45 +0900 Subject: [PATCH 35/39] feat(magnetohydrodynamics): add cpp-full1d-01 variant with minimal API - cpp-full1d-01 exposes only evolve_ssp_rk3(...) as public solver entrypoint - HLLD and CLI remain provided, same as cpp-full1d-00 - Public C++ tests adapted to reduced scaffolding - Fixed hidden eval path in both 00 and 01 to use /eval_shared mount Co-authored-by: OpenCode Assistant --- benchmarks/magnetohydrodynamics/README.md | 1 + .../cpp-full1d-00/eval/tests/test_hidden.py | 7 +- .../cpp-full1d-01/eval/run.sh | 28 +++ .../cpp-full1d-01/eval/tests/test_hidden.py | 55 +++++ .../cpp-full1d-01/spec.md | 62 ++++++ .../cpp-full1d-01/task.toml | 8 + .../cpp-full1d-01/workspace/CMakeLists.txt | 61 ++++++ .../cpp-full1d-01/workspace/README.md | 7 + .../cpp-full1d-01/workspace/pyproject.toml | 7 + .../cpp-full1d-01/workspace/src/hlld.cpp | 202 ++++++++++++++++++ .../cpp-full1d-01/workspace/src/hlld.hpp | 4 + .../cpp-full1d-01/workspace/src/main.cpp | 89 ++++++++ .../cpp-full1d-01/workspace/src/mhd1d.cpp | 14 ++ .../cpp-full1d-01/workspace/src/mhd1d.hpp | 84 ++++++++ .../workspace/tests/cpp/test_public.cpp | 27 +++ .../workspace/tests/data/brio_wu_golden.csv | 101 +++++++++ .../workspace/tests/test_public.py | 85 ++++++++ 17 files changed, 836 insertions(+), 6 deletions(-) create mode 100755 benchmarks/magnetohydrodynamics/cpp-full1d-01/eval/run.sh create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-01/eval/tests/test_hidden.py create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-01/spec.md create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-01/task.toml create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/CMakeLists.txt create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/README.md create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/pyproject.toml create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/src/hlld.cpp create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/src/hlld.hpp create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/src/main.cpp create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/src/mhd1d.cpp create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/src/mhd1d.hpp create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/tests/cpp/test_public.cpp create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/tests/data/brio_wu_golden.csv create mode 100644 benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/tests/test_public.py diff --git a/benchmarks/magnetohydrodynamics/README.md b/benchmarks/magnetohydrodynamics/README.md index a9e84ac..25db847 100644 --- a/benchmarks/magnetohydrodynamics/README.md +++ b/benchmarks/magnetohydrodynamics/README.md @@ -9,6 +9,7 @@ This suite contains benchmark tasks for ideal magnetohydrodynamics solvers. - `cpp-hlld-00/`: default C++ HLLD task with detailed solver guidance in spec. - `cpp-hlld-01/`: variant C++ HLLD task with reduced guidance but same test intent. - `cpp-full1d-00/`: easiest C++ full 1D ideal MHD variant (main+HLLD provided, solver scaffolded). +- `cpp-full1d-01/`: reduced-guidance full 1D variant with only `evolve_ssp_rk3(...)` exposed. - `shared/eval/README.md`: hidden-eval contract for shared MHD scoring assets. - `shared/eval/mhd1d_shared.py`: shared helpers for CSV loading, score windows, and comparison metadata. diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-00/eval/tests/test_hidden.py b/benchmarks/magnetohydrodynamics/cpp-full1d-00/eval/tests/test_hidden.py index 6b91e7e..2b3127f 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full1d-00/eval/tests/test_hidden.py +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-00/eval/tests/test_hidden.py @@ -8,12 +8,7 @@ SOLVER_TARGET = "cpp_full_solver1d" WORKSPACE_ROOT = Path(__file__).resolve().parents[2] / "workspace" REFERENCE_CSV_PATH = ( - Path(__file__).resolve().parents[3] - / "shared" - / "eval" - / "fixtures" - / "mhd1d" - / "brio_wu_reference.csv" + Path("/eval_shared") / "fixtures" / "mhd1d" / "brio_wu_reference.csv" ) diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-01/eval/run.sh b/benchmarks/magnetohydrodynamics/cpp-full1d-01/eval/run.sh new file mode 100755 index 0000000..5132b67 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-01/eval/run.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -u -o pipefail + +cd /work +export PYTHONPATH="/work:/eval_shared" + +status="passed" +score="1.0" + +python3 -m pytest -q /eval/tests +rc=$? +if [ "$rc" -ne 0 ]; then + status="failed" + score="0.0" +fi + +python3 - < Path: + subprocess.run( + ["cmake", "-S", ".", "-B", str(build_dir)], check=True, cwd=WORKSPACE_ROOT + ) + subprocess.run( + ["cmake", "--build", str(build_dir), "--target", SOLVER_TARGET], + check=True, + cwd=WORKSPACE_ROOT, + ) + + binary_name = f"{SOLVER_TARGET}.exe" if os.name == "nt" else SOLVER_TARGET + solver_path = build_dir / "bin" / binary_name + assert solver_path.exists() + return solver_path + + +def test_hidden_brio_wu_cli_matches_fixture(tmp_path: Path) -> None: + solver_path = _build_solver(tmp_path / "build") + output_csv_path = tmp_path / "brio_wu.csv" + + completed = subprocess.run( + [str(solver_path), "200"], + check=True, + capture_output=True, + text=True, + ) + output_csv_path.write_text(completed.stdout, encoding="utf-8") + + output_rows = list( + csv.reader(output_csv_path.read_text(encoding="utf-8").splitlines()) + ) + reference_rows = list( + csv.reader(REFERENCE_CSV_PATH.read_text(encoding="utf-8").splitlines()) + ) + + assert_csv_rows_close( + output_rows, + reference_rows, + tolerance=TOLERANCE, + expected_header=["x", "rho", "u", "v", "w", "p", "by", "bz"], + ) diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-01/spec.md b/benchmarks/magnetohydrodynamics/cpp-full1d-01/spec.md new file mode 100644 index 0000000..3f5ae01 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-01/spec.md @@ -0,0 +1,62 @@ +# cpp-full1d-01 + +Implement a 1D ideal-MHD solver CLI in C++. + +## Read first + +- `/work/basic_equations.md` +- `/work/hlld.md` + +## Task + +The command-line entrypoint and the HLLD Riemann solver are already provided. +The CLI accepts an integer `nx` argument for the number of grid points, performs the Brio-Wu Riemann problem, and writes the solution to stdout in CSV format. +Your main task is to complete the solver implementation in `src/mhd1d.cpp`. + +The CLI output must match the provided golden CSV for `nx=100` within numeric tolerance (`1.0e-12`). + +## How to test + +Run the public checks from the workspace: + +```bash +python3 -m pytest -q tests/test_public.py +``` + +## Local dev + +```bash +pytest -q +``` + +To build manually: + +```bash +cmake -S . -B build +cmake --build build +./build/bin/cpp_full_solver1d +``` + +## Numerical Algorithm + +- Riemann solver: HLLD +- Primitive variables reconstruction: piecewise linear with MC2 slope limiter +- Time integration: SSP-RK3 +- Boundary condition: symmetric (zero-gradient) + +## Files + +- `src/main.cpp`: complete CLI (already done) +- `src/hlld.hpp`, `src/hlld.cpp`: complete HLLD implementation (already done) +- `src/mhd1d.hpp`: provides the workspace data structure and solver entrypoint declaration +- `src/mhd1d.cpp`: contains only an empty `evolve_ssp_rk3(...)` implementation to complete + +## Functions to complete (in `src/mhd1d.cpp`) + +- `evolve_ssp_rk3(SolverWorkspace& workspace, double dt, double t_final)` + +All other helper functions and internal organization are up to you. + +## Standards + +- C++17 diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-01/task.toml b/benchmarks/magnetohydrodynamics/cpp-full1d-01/task.toml new file mode 100644 index 0000000..c86d996 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-01/task.toml @@ -0,0 +1,8 @@ +id = "cpp-full1d-01" +suite = "magnetohydrodynamics" +language = "cpp" +time_limit_sec = 600 +eval_cmd = "/eval/run.sh" +prompt = "Read /run/spec.md, /work/basic_equations.md, and /work/hlld.md, then solve the task in /work." +use_shared_workspace = true +use_shared_eval = true diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/CMakeLists.txt b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/CMakeLists.txt new file mode 100644 index 0000000..1375922 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/CMakeLists.txt @@ -0,0 +1,61 @@ +cmake_minimum_required(VERSION 3.16) + +project(cpp_full_solver1d LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +include(FetchContent) + +find_package(Catch2 3 QUIET) + +if(NOT Catch2_FOUND) + FetchContent_Declare( + Catch2 + GIT_REPOSITORY https://github.com/catchorg/Catch2.git + GIT_TAG v3.13.0 + GIT_SHALLOW TRUE + ) + FetchContent_MakeAvailable(Catch2) +endif() + +add_library(mhd1d_solver + src/mhd1d.cpp + src/hlld.cpp +) + +target_include_directories(mhd1d_solver PUBLIC + src + ../../../common/include +) + +add_executable(cpp_full_solver1d + src/main.cpp +) + +target_link_libraries(cpp_full_solver1d PRIVATE + mhd1d_solver +) + +set_target_properties(cpp_full_solver1d PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" +) + +add_executable(cpp_full_solver1d_public_tests + tests/cpp/test_public.cpp +) + +target_link_libraries(cpp_full_solver1d_public_tests PRIVATE + mhd1d_solver + Catch2::Catch2WithMain +) + +target_include_directories(cpp_full_solver1d_public_tests PRIVATE + src + ../../../common/include +) + +set_target_properties(cpp_full_solver1d_public_tests PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests" +) diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/README.md b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/README.md new file mode 100644 index 0000000..df83a53 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/README.md @@ -0,0 +1,7 @@ +The public C++ workspace contains a Brio-Wu solver scaffold. + +- `src/main.cpp` is complete. +- `src/hlld.cpp` is complete. +- `src/mhd1d.cpp` exposes only an empty `evolve_ssp_rk3(...)` to implement. + +Shared workspace docs are already mounted for this benchmark. diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/pyproject.toml b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/pyproject.toml new file mode 100644 index 0000000..b38b758 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/pyproject.toml @@ -0,0 +1,7 @@ +[project] +name = "magnetohydrodynamics-cpp-full1d-01" +version = "0.0.0" +requires-python = ">=3.10" + +[tool.pytest.ini_options] +testpaths = ["tests"] diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/src/hlld.cpp b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/src/hlld.cpp new file mode 100644 index 0000000..f5f9c87 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/src/hlld.cpp @@ -0,0 +1,202 @@ +#include "hlld.hpp" + +#include +#include + +void hlld_flux_from_primitive(const double* left, const double* right, double bx, double gamma, + double* flux) +{ + constexpr double epsilon = 1.0e-40; + + const double rol = left[0]; + const double vxl = left[1]; + const double vyl = left[2]; + const double vzl = left[3]; + const double prl = left[4]; + const double byl = left[5]; + const double bzl = left[6]; + + const double ror = right[0]; + const double vxr = right[1]; + const double vyr = right[2]; + const double vzr = right[3]; + const double prr = right[4]; + const double byr = right[5]; + const double bzr = right[6]; + + const double igm = 1.0 / (gamma - 1.0); + const double bxs = bx; + const double bxsq = bxs * bxs; + + const double pbl = 0.5 * (bxsq + byl * byl + bzl * bzl); + const double pbr = 0.5 * (bxsq + byr * byr + bzr * bzr); + const double ptl = prl + pbl; + const double ptr = prr + pbr; + + const double rxl = rol * vxl; + const double ryl = rol * vyl; + const double rzl = rol * vzl; + const double rxr = ror * vxr; + const double ryr = ror * vyr; + const double rzr = ror * vzr; + + const double eel = prl * igm + 0.5 * (rxl * vxl + ryl * vyl + rzl * vzl) + pbl; + const double eer = prr * igm + 0.5 * (rxr * vxr + ryr * vyr + rzr * vzr) + pbr; + + const double gmpl = gamma * prl; + const double gmpr = gamma * prr; + const double gpbl = gmpl + 2.0 * pbl; + const double gpbr = gmpr + 2.0 * pbr; + + const double cfl = std::sqrt((gpbl + std::sqrt((gmpl - 2.0 * pbl) * (gmpl - 2.0 * pbl) + + 4.0 * gmpl * (byl * byl + bzl * bzl))) * + 0.5 / rol); + const double cfr = std::sqrt((gpbr + std::sqrt((gmpr - 2.0 * pbr) * (gmpr - 2.0 * pbr) + + 4.0 * gmpr * (byr * byr + bzr * bzr))) * + 0.5 / ror); + + const double sl = std::min(vxl, vxr) - std::max(cfl, cfr); + const double sr = std::max(vxl, vxr) + std::max(cfl, cfr); + + const double fql[7] = {rxl, + rxl * vxl + ptl - bxsq, + rxl * vyl - bxs * byl, + rxl * vzl - bxs * bzl, + vxl * (eel + ptl - bxsq) - bxs * (vyl * byl + vzl * bzl), + byl * vxl - bxs * vyl, + bzl * vxl - bxs * vzl}; + const double fqr[7] = {rxr, + rxr * vxr + ptr - bxsq, + rxr * vyr - bxs * byr, + rxr * vzr - bxs * bzr, + vxr * (eer + ptr - bxsq) - bxs * (vyr * byr + vzr * bzr), + byr * vxr - bxs * vyr, + bzr * vxr - bxs * vzr}; + + const double sdl = sl - vxl; + const double sdr = sr - vxr; + const double rosdl = rol * sdl; + const double rosdr = ror * sdr; + const double temp = 1.0 / (rosdr - rosdl); + const double sm = (rosdr * vxr - rosdl * vxl - ptr + ptl) * temp; + const double sdml = sl - sm; + const double sdmr = sr - sm; + const double ptst = (rosdr * ptl - rosdl * ptr + rosdl * rosdr * (vxr - vxl)) * temp; + + const double temp_fst_l = rosdl * sdml - bxsq; + const double sign1_l = std::copysign(1.0, std::abs(temp_fst_l) - epsilon); + const double maxs1_l = std::max(0.0, sign1_l); + const double mins1_l = std::min(0.0, sign1_l); + const double itf_l = 1.0 / (temp_fst_l + mins1_l); + const double isdml = 1.0 / sdml; + + const double temp_l = bxs * (sdl - sdml) * itf_l; + const double rolst = maxs1_l * (rosdl * isdml) - mins1_l * rol; + const double vxlst = maxs1_l * sm - mins1_l * vxl; + const double rxlst = rolst * vxlst; + const double vylst = maxs1_l * (vyl - byl * temp_l) - mins1_l * vyl; + const double rylst = rolst * vylst; + const double vzlst = maxs1_l * (vzl - bzl * temp_l) - mins1_l * vzl; + const double rzlst = rolst * vzlst; + const double temp_l_b = (rosdl * sdl - bxsq) * itf_l; + const double bylst = maxs1_l * (byl * temp_l_b) - mins1_l * byl; + const double bzlst = maxs1_l * (bzl * temp_l_b) - mins1_l * bzl; + const double vdbstl = vxlst * bxs + vylst * bylst + vzlst * bzlst; + const double eelst = maxs1_l * ((sdl * eel - ptl * vxl + ptst * sm + + bxs * (vxl * bxs + vyl * byl + vzl * bzl - vdbstl)) * + isdml) - + mins1_l * eel; + + const double temp_fst_r = rosdr * sdmr - bxsq; + const double sign1_r = std::copysign(1.0, std::abs(temp_fst_r) - epsilon); + const double maxs1_r = std::max(0.0, sign1_r); + const double mins1_r = std::min(0.0, sign1_r); + const double itf_r = 1.0 / (temp_fst_r + mins1_r); + const double isdmr = 1.0 / sdmr; + + const double temp_r = bxs * (sdr - sdmr) * itf_r; + const double rorst = maxs1_r * (rosdr * isdmr) - mins1_r * ror; + const double vxrst = maxs1_r * sm - mins1_r * vxr; + const double rxrst = rorst * vxrst; + const double vyrst = maxs1_r * (vyr - byr * temp_r) - mins1_r * vyr; + const double ryrst = rorst * vyrst; + const double vzrst = maxs1_r * (vzr - bzr * temp_r) - mins1_r * vzr; + const double rzrst = rorst * vzrst; + const double temp_r_b = (rosdr * sdr - bxsq) * itf_r; + const double byrst = maxs1_r * (byr * temp_r_b) - mins1_r * byr; + const double bzrst = maxs1_r * (bzr * temp_r_b) - mins1_r * bzr; + const double vdbstr = vxrst * bxs + vyrst * byrst + vzrst * bzrst; + const double eerst = maxs1_r * ((sdr * eer - ptr * vxr + ptst * sm + + bxs * (vxr * bxs + vyr * byr + vzr * bzr - vdbstr)) * + isdmr) - + mins1_r * eer; + + const double sqrtrol = std::sqrt(rolst); + const double sqrtror = std::sqrt(rorst); + const double abbx = std::abs(bxs); + const double slst = sm - abbx / sqrtrol; + const double srst = sm + abbx / sqrtror; + const double signbx = std::copysign(1.0, bxs); + const double sign1_b = std::copysign(1.0, abbx - epsilon); + const double maxs1_b = std::max(0.0, sign1_b); + const double mins1_b = -std::min(0.0, sign1_b); + const double invsumro = maxs1_b / (sqrtrol + sqrtror); + + const double roldst = rolst; + const double rordst = rorst; + const double rxldst = rxlst; + const double rxrdst = rxrst; + + const double vy_shared = + invsumro * (sqrtrol * vylst + sqrtror * vyrst + signbx * (byrst - bylst)); + const double ryldst = rylst * mins1_b + roldst * vy_shared; + const double ryrdst = ryrst * mins1_b + rordst * vy_shared; + + const double vz_shared = + invsumro * (sqrtrol * vzlst + sqrtror * vzrst + signbx * (bzrst - bzlst)); + const double rzldst = rzlst * mins1_b + roldst * vz_shared; + const double rzrdst = rzrst * mins1_b + rordst * vz_shared; + + const double by_shared = + invsumro * (sqrtrol * byrst + sqrtror * bylst + signbx * sqrtrol * sqrtror * (vyrst - vylst)); + const double byldst = bylst * mins1_b + by_shared; + const double byrdst = byrst * mins1_b + by_shared; + + const double bz_shared = + invsumro * (sqrtrol * bzrst + sqrtror * bzlst + signbx * sqrtrol * sqrtror * (vzrst - vzlst)); + const double bzldst = bzlst * mins1_b + bz_shared; + const double bzrdst = bzrst * mins1_b + bz_shared; + + const double vyldst = vylst * mins1_b + vy_shared; + const double vyrdst = vyrst * mins1_b + vy_shared; + const double vzldst = vzlst * mins1_b + vz_shared; + const double vzrdst = vzrst * mins1_b + vz_shared; + const double temp_dst = sm * bxs + vyldst * byldst + vzldst * bzldst; + const double eeldst = eelst - sqrtrol * signbx * (vdbstl - temp_dst) * maxs1_b; + const double eerdst = eerst + sqrtror * signbx * (vdbstr - temp_dst) * maxs1_b; + + const double sign1 = std::copysign(1.0, sm); + const double maxs1 = std::max(0.0, sign1); + const double mins1 = -std::min(0.0, sign1); + const double msl = std::min(sl, 0.0); + const double mslst = std::min(slst, 0.0); + const double msrst = std::max(srst, 0.0); + const double msr = std::max(sr, 0.0); + const double temp_flux_l = mslst - msl; + const double temp_flux_r = msrst - msr; + + flux[0] = (fql[0] - msl * rol - rolst * temp_flux_l + roldst * mslst) * maxs1 + + (fqr[0] - msr * ror - rorst * temp_flux_r + rordst * msrst) * mins1; + flux[1] = (fql[1] - msl * rxl - rxlst * temp_flux_l + rxldst * mslst) * maxs1 + + (fqr[1] - msr * rxr - rxrst * temp_flux_r + rxrdst * msrst) * mins1; + flux[2] = (fql[2] - msl * ryl - rylst * temp_flux_l + ryldst * mslst) * maxs1 + + (fqr[2] - msr * ryr - ryrst * temp_flux_r + ryrdst * msrst) * mins1; + flux[3] = (fql[3] - msl * rzl - rzlst * temp_flux_l + rzldst * mslst) * maxs1 + + (fqr[3] - msr * rzr - rzrst * temp_flux_r + rzrdst * msrst) * mins1; + flux[4] = (fql[4] - msl * eel - eelst * temp_flux_l + eeldst * mslst) * maxs1 + + (fqr[4] - msr * eer - eerst * temp_flux_r + eerdst * msrst) * mins1; + flux[5] = (fql[5] - msl * byl - bylst * temp_flux_l + byldst * mslst) * maxs1 + + (fqr[5] - msr * byr - byrst * temp_flux_r + byrdst * msrst) * mins1; + flux[6] = (fql[6] - msl * bzl - bzlst * temp_flux_l + bzldst * mslst) * maxs1 + + (fqr[6] - msr * bzr - bzrst * temp_flux_r + bzrdst * msrst) * mins1; +} diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/src/hlld.hpp b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/src/hlld.hpp new file mode 100644 index 0000000..ae80ebd --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/src/hlld.hpp @@ -0,0 +1,4 @@ +#pragma once + +void hlld_flux_from_primitive(const double* left, const double* right, double bx, double gamma, + double* flux); diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/src/main.cpp b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/src/main.cpp new file mode 100644 index 0000000..b6ea583 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/src/main.cpp @@ -0,0 +1,89 @@ +#include "mhd1d.hpp" + +#include +#include +#include +#include + +constexpr int Nx = 100; +constexpr double Gamma = 2.0; +constexpr double Bx = 0.75; +constexpr mhd1d::StateVector LeftPrimitive{ + 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, +}; +constexpr mhd1d::StateVector RightPrimitive{ + 0.125, 0.0, 0.0, 0.0, 0.1, -1.0, 0.0, +}; + +int parse_nx(int argc, char** argv) +{ + if (argc <= 1) { + return Nx; + } + + char* end = nullptr; + const long parsed = std::strtol(argv[1], &end, 10); + if (end == argv[1] || *end != '\0' || parsed <= 0) { + throw std::runtime_error("usage: solver [nx]"); + } + return static_cast(parsed); +} + +mhd1d::SolverWorkspace initialize(int nx, double gamma, double bx, + const mhd1d::StateVector& left_state, + const mhd1d::StateVector& right_state) +{ + mhd1d::SolverWorkspace workspace(nx, gamma, bx); + + for (int ix = workspace.Lbx; ix <= workspace.Ubx; ++ix) { + const mhd1d::StateVector& state = (workspace.x(ix) < 0.5) ? left_state : right_state; + for (int component = 0; component < mhd1d::N_Component; ++component) { + workspace.up(ix, component) = state[component]; + workspace.uc(ix, component) = 0.0; + } + } + + for (int ix = 0; ix < workspace.Lbx; ++ix) { + for (int component = 0; component < mhd1d::N_Component; ++component) { + workspace.up(ix, component) = workspace.up(workspace.Lbx, component); + workspace.uc(ix, component) = workspace.uc(workspace.Lbx, component); + } + } + for (int ix = workspace.Ubx + 1; ix < workspace.Nx + 2 * mhd1d::N_margin; ++ix) { + for (int component = 0; component < mhd1d::N_Component; ++component) { + workspace.up(ix, component) = workspace.up(workspace.Ubx, component); + workspace.uc(ix, component) = workspace.uc(workspace.Ubx, component); + } + } + + (void)gamma; + (void)bx; + + return workspace; +} + +void write_csv(const mhd1d::SolverWorkspace& workspace, std::ostream& os) +{ + os << "x,rho,u,v,w,p,by,bz\n"; + os << std::setprecision(17); + for (int ix = workspace.Lbx; ix <= workspace.Ubx; ++ix) { + os << workspace.x(ix) << ',' << workspace.up(ix, 0) << ',' << workspace.up(ix, 1) << ',' + << workspace.up(ix, 2) << ',' << workspace.up(ix, 3) << ',' << workspace.up(ix, 4) << ',' + << workspace.up(ix, 5) << ',' << workspace.up(ix, 6) << '\n'; + } +} + +int main(int argc, char** argv) +{ + const int nx = parse_nx(argc, argv); + const double delt = 5.0e-4; + const double tmax = 0.1; + + auto workspace = initialize(nx, Gamma, Bx, LeftPrimitive, RightPrimitive); + + mhd1d::evolve_ssp_rk3(workspace, delt, tmax); + + write_csv(workspace, std::cout); + + return 0; +} diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/src/mhd1d.cpp b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/src/mhd1d.cpp new file mode 100644 index 0000000..7e34980 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/src/mhd1d.cpp @@ -0,0 +1,14 @@ +#include "mhd1d.hpp" + +namespace mhd1d +{ + +void evolve_ssp_rk3(SolverWorkspace& workspace, double dt, double t_final) +{ + (void)workspace; + (void)dt; + (void)t_final; + // TODO(student): implement the complete 1D MHD solver time evolution. +} + +} // namespace mhd1d diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/src/mhd1d.hpp b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/src/mhd1d.hpp new file mode 100644 index 0000000..ab97869 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/src/mhd1d.hpp @@ -0,0 +1,84 @@ +#pragma once + +#include +#include + +#include + +namespace mhd1d +{ + +namespace stdex = std::experimental; + +constexpr int N_Component = 7; +constexpr int N_margin = 1; + +using StateVector = std::array; +using ArrayView1D = stdex::mdspan, stdex::layout_right>; +using ArrayView2D = stdex::mdspan, stdex::layout_right>; + +struct SolverWorkspace { + explicit SolverWorkspace(int nx, double gamma, double bx) + : Nx(nx), Lbx(N_margin), Ubx(N_margin + nx - 1), dx(1.0 / static_cast(nx)), + gamma(gamma), bx(bx), storage(Nx + 2 * N_margin, N_Component) + { + init_views(Nx + 2 * N_margin, N_Component); + + for (int ix = Lbx; ix <= Ubx; ++ix) { + x(ix) = (static_cast(ix - Lbx) + 0.5) * dx; + } + } + + int Nx; + int Lbx; + int Ubx; + double dx; + double gamma; + double bx; + + ArrayView1D x; + ArrayView2D uc; + ArrayView2D up; + ArrayView2D up_l; + ArrayView2D up_r; + ArrayView2D rhs; + ArrayView2D prev; + ArrayView2D flux; + +private: + void init_views(int n_grid, int n_component) + { + x = ArrayView1D(storage.x.data(), n_grid); + uc = ArrayView2D(storage.uc.data(), n_grid, n_component); + up = ArrayView2D(storage.up.data(), n_grid, n_component); + up_l = ArrayView2D(storage.up_l.data(), n_grid, n_component); + up_r = ArrayView2D(storage.up_r.data(), n_grid, n_component); + rhs = ArrayView2D(storage.rhs.data(), n_grid, n_component); + prev = ArrayView2D(storage.prev.data(), n_grid, n_component); + flux = ArrayView2D(storage.flux.data(), n_grid, n_component); + } + + struct Storage { + explicit Storage(int n_grid, int n_component) + : x(n_grid), uc(n_grid * n_component), up(n_grid * n_component), up_l(n_grid * n_component), + up_r(n_grid * n_component), rhs(n_grid * n_component), prev(n_grid * n_component), + flux(n_grid * n_component) + { + } + + std::vector x; + std::vector uc; + std::vector up; + std::vector up_l; + std::vector up_r; + std::vector rhs; + std::vector prev; + std::vector flux; + }; + + Storage storage; +}; + +void evolve_ssp_rk3(SolverWorkspace& workspace, double dt, double t_final); + +} // namespace mhd1d diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/tests/cpp/test_public.cpp b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/tests/cpp/test_public.cpp new file mode 100644 index 0000000..c4eca2d --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/tests/cpp/test_public.cpp @@ -0,0 +1,27 @@ +#include + +#include + +#include "mhd1d.hpp" + +TEST_CASE("set_boundary duplicates edge states on both sides", "[mhd1d][boundary]") +{ + std::vector padded_buffer(4 * mhd1d::N_Component, 0.0); + const mhd1d::ArrayView2D padded(padded_buffer.data(), 4, mhd1d::N_Component); + + padded(1, 0) = 1.2; + padded(2, 0) = 1.4; + + const int lbx = 1; + const int ubx = 2; + + for (int ix = 0; ix < lbx; ++ix) { + padded(ix, 0) = padded(lbx, 0); + } + for (int ix = ubx + 1; ix < 4; ++ix) { + padded(ix, 0) = padded(ubx, 0); + } + + REQUIRE(padded(0, 0) == padded(1, 0)); + REQUIRE(padded(3, 0) == padded(2, 0)); +} diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/tests/data/brio_wu_golden.csv b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/tests/data/brio_wu_golden.csv new file mode 100644 index 0000000..e72dfa5 --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/tests/data/brio_wu_golden.csv @@ -0,0 +1,101 @@ +x,rho,u,v,w,p,by,bz +0.0050000000000000001,1,0,0,0,1,1,0 +0.014999999999999999,1,0,0,0,1,1,0 +0.025000000000000001,1,0,0,0,1,1,0 +0.035000000000000003,1,0,0,0,1,1,0 +0.044999999999999998,1,0,0,0,1,1,0 +0.055,1,0,0,0,1,1,0 +0.065000000000000002,1,0,0,0,1,1,0 +0.074999999999999997,1,0,0,0,1,1,0 +0.085000000000000006,1,0,0,0,1,1,0 +0.095000000000000001,1,0,0,0,1,1,0 +0.105,1,0,0,0,1,1,0 +0.115,1,0,0,0,1,1,0 +0.125,1,0,0,0,1,1,0 +0.13500000000000001,1,0,0,0,1,1,0 +0.14499999999999999,1,0,0,0,1,1,0 +0.155,1,0,0,0,1,1,0 +0.16500000000000001,1,0,0,0,1,1,0 +0.17500000000000002,1,0,0,0,1,1,0 +0.185,1,0,0,0,1,1,0 +0.19500000000000001,1,0,0,0,1,1,0 +0.20500000000000002,1,0,0,0,1,1,0 +0.215,1,0,0,0,1,1,0 +0.22500000000000001,1,0,0,0,1,1,0 +0.23500000000000001,1,0,0,0,1,1,0 +0.245,1,0,0,0,1,1,0 +0.255,1,0,0,0,1,1,0 +0.26500000000000001,1,0,0,0,1,1,0 +0.27500000000000002,1,0,0,0,1,1,0 +0.28500000000000003,1,0,0,0,1,1,0 +0.29499999999999998,1,0,0,0,1,1,0 +0.30499999999999999,1,0,0,0,1,1,0 +0.315,0.99258917532833379,0.013274302361789324,-0.0037458540886650027,0,0.98532404108866567,0.99104740522973966,0 +0.32500000000000001,0.96954607581582897,0.054883618137207428,-0.015827325460063591,0,0.94023568077652442,0.96299689161606516,0 +0.33500000000000002,0.94025803324835733,0.10865479486043322,-0.031944255536031786,0,0.88435499782767446,0.92711462956015256,0 +0.34500000000000003,0.90897792466167582,0.16698841420781432,-0.050131763210425707,0,0.82652179164341721,0.88849866375884556,0 +0.35499999999999998,0.87725610844274526,0.2271603117432259,-0.069719685021130948,0,0.76985377322754589,0.84898878620884088,0 +0.36499999999999999,0.84566618167244145,0.28816698962982518,-0.090519447417695451,0,0.71541656913426399,0.80923410080538904,0 +0.375,0.81450435463148285,0.3494865276909434,-0.11251682956314066,0,0.66367321125402712,0.76950238387022263,0 +0.38500000000000001,0.78404538979850258,0.41062539085171551,-0.13575856770700617,0,0.61497905337973746,0.72997249890053162,0 +0.39500000000000002,0.75467120186953685,0.47083530429296916,-0.1602094195276916,0,0.56978778527926832,0.69094510148101218,0 +0.40500000000000003,0.72701668590610768,0.52870556766657628,-0.18539026277804579,0,0.52883750835390897,0.65319266964541056,0 +0.41500000000000004,0.70216500224646816,0.58153016354527853,-0.20973136326536138,0,0.4933637549672012,0.61876152226558601,0 +0.42499999999999999,0.68193441338380167,0.62487275671749021,-0.22845986767252549,0,0.46540195161446823,0.59219206428336624,0 +0.435,0.6666986977176832,0.65196598708089948,-0.23211489711409145,0,0.44490074049787121,0.58021922926273972,0 +0.44500000000000001,0.66015529724292976,0.66607074009479628,-0.22555655390938342,0,0.43615912199888263,0.58524191570556205,0 +0.45500000000000002,0.65997980757445474,0.66324409170331222,-0.23280516118974198,0,0.43727412310940939,0.5796363680769816,0 +0.46500000000000002,0.73349815599883794,0.60086667962898554,-0.62171855754180494,0,0.57886068825314341,0.27652712488086967,0 +0.47500000000000003,0.79237811897791921,0.46454032083596353,-1.2161018009267417,0,0.6842784144671038,-0.24404258805909654,0 +0.48499999999999999,0.74259318372203176,0.53084767864673321,-1.4743018340823315,0,0.60002741951352012,-0.44224666294204562,0 +0.495,0.69493377959694547,0.61399418172955245,-1.5431753009247675,0,0.54413704626033854,-0.54049642839751277,0 +0.505,0.70278259276020427,0.61662067481286442,-1.5872354257997463,0,0.52068648102692328,-0.56052646550215834,0 +0.51500000000000001,0.70390914156072559,0.6077114699355689,-1.6001701751263477,0,0.51193399003676154,-0.54226823182770345,0 +0.52500000000000002,0.69922181544266515,0.59340751947871018,-1.6046948629200928,0,0.51300004963251122,-0.52185059484429897,0 +0.53500000000000003,0.67807490745420074,0.5878535845789149,-1.6006935764888095,0,0.51466016361553968,-0.51621274881535362,0 +0.54500000000000004,0.60556902444692728,0.59045915738825405,-1.5906721688577199,0,0.51204702934936586,-0.52148853682254903,0 +0.55500000000000005,0.48266830107336006,0.59697028797374452,-1.5761776779942758,0,0.51057551463380291,-0.53191252428398161,0 +0.56500000000000006,0.34834934855591537,0.59188322457049136,-1.5687669989374082,0,0.5151520944223198,-0.54463835756014178,0 +0.57500000000000007,0.2451691037246034,0.59463166677984525,-1.5635053912378623,0,0.51994523862074438,-0.55151343157376009,0 +0.58499999999999996,0.22308154337733685,0.61421260394352284,-1.5558407025582697,0,0.51450769544894648,-0.54648231691723681,0 +0.59499999999999997,0.22390587217315483,0.62861601814674595,-1.555379908924208,0,0.51042675178345809,-0.53931383334019445,0 +0.60499999999999998,0.22786331744185459,0.61304302077924422,-1.5697800797404926,0,0.51789637516013132,-0.53999599169525736,0 +0.61499999999999999,0.23452030041149688,0.58777367268577241,-1.5968680437122895,0,0.53659755807779264,-0.54285121456661267,0 +0.625,0.23506241740122699,0.58441088978544375,-1.6180990627429224,0,0.5312595858066933,-0.53847776600605912,0 +0.63500000000000001,0.22912802575710367,0.64096361665071178,-1.5587196384023227,0,0.50180683386498415,-0.51954980419936259,0 +0.64500000000000002,0.20820170172948924,0.4429088168703938,-1.3138217298639516,0,0.4107172773448764,-0.63242114973177121,0 +0.65500000000000003,0.14280420150766387,0.0013572736674349979,-0.58334822550752841,0,0.15933600494306066,-0.82699909098420499,0 +0.66500000000000004,0.11735885521106922,-0.23309434559311201,-0.17605497312958984,0,0.088246122408452865,-0.90091689844612777,0 +0.67500000000000004,0.11691966169225833,-0.24239401825294279,-0.16901850205441424,0,0.087525697429624683,-0.90138999879178838,0 +0.68500000000000005,0.1168975018076187,-0.24275168390313129,-0.16913431059427403,0,0.087491282208618681,-0.90130727955920587,0 +0.69500000000000006,0.11688490837927806,-0.24293963466430563,-0.16922798396131322,0,0.087471166714507165,-0.90122308503037618,0 +0.70499999999999996,0.11687882431088358,-0.24305091000018803,-0.16930677036965813,0,0.087461000889423768,-0.90113549166198792,0 +0.71499999999999997,0.11688210335016401,-0.24310898990635241,-0.16941137635009459,0,0.087464485048653229,-0.90109713084582599,0 +0.72499999999999998,0.11688746427801196,-0.24311790246317952,-0.16948241337481523,0,0.087471346584835463,-0.90112657201926949,0 +0.73499999999999999,0.11689293842702393,-0.24301542095697384,-0.16941123056591925,0,0.087478382198893812,-0.90117181152414561,0 +0.745,0.11689754429437521,-0.24279548243457205,-0.16922004702154958,0,0.087484264982216398,-0.90123329716500089,0 +0.755,0.11690472407462463,-0.24244042822845885,-0.16894496953161006,0,0.087493985877884928,-0.90135933427866255,0 +0.76500000000000001,0.1169351752430936,-0.24164401100336819,-0.16834345193351358,0,0.087538755474644847,-0.90173628521210369,0 +0.77500000000000002,0.11702346553875453,-0.2389118539454739,-0.16634253632348067,0,0.087670236260091849,-0.90283181009609326,0 +0.78500000000000003,0.11723705803609173,-0.23241448265557926,-0.16159143199373074,0,0.087990348375741601,-0.90548092874079178,0 +0.79500000000000004,0.1176285175883393,-0.22051415125476836,-0.15292012220738538,0,0.088578608675684678,-0.91032952865801275,0 +0.80500000000000005,0.11822301685274909,-0.20247335890203855,-0.13985941063243096,0,0.089475764221054743,-0.91767747139414524,0 +0.81500000000000006,0.11901085894402198,-0.178638590244622,-0.12276084795550267,0,0.090670936816770853,-0.92738054886244792,0 +0.82500000000000007,0.11995507930331456,-0.15017685276699991,-0.10257309790892337,0,0.092113203419944889,-0.93896119897869035,0 +0.83499999999999996,0.12100582881114735,-0.1186354504616307,-0.080489249938489674,0,0.093731854039529328,-0.95178772370322251,0 +0.84499999999999997,0.12210948952666369,-0.085657286840511535,-0.057715619723010918,0,0.095446790184988584,-0.96519228251210643,0 +0.85499999999999998,0.12320528139333707,-0.053056324701219029,-0.035509818552657238,0,0.097164687932375315,-0.97843939905855704,0 +0.86499999999999999,0.12419939842673788,-0.023611385320102929,-0.015706138420103915,0,0.098733750673405729,-0.99040292502414518,0 +0.875,0.1248831018288558,-0.0034412091825772586,-0.0022747475485175887,0,0.099815318398622899,-0.99860261559100016,0 +0.88500000000000001,0.12500000000700623,2.0693358136986429e-10,1.3690028369419877e-10,0,0.10000000001121101,-1.0000000000838631,0 +0.89500000000000002,0.12500000000690034,2.0295860176552916e-10,1.3426844820417816e-10,0,0.10000000001104148,-1.0000000000825946,0 +0.90500000000000003,0.12500000000616657,1.8175890421477852e-10,1.2024374828573813e-10,0,0.10000000000986675,-1.0000000000738092,0 +0.91500000000000004,0.12500000000447511,1.3188042879502353e-10,8.7246950401911659e-11,0,0.10000000000716036,-1.0000000000535656,0 +0.92500000000000004,0.1250000000023313,6.8702813807084164e-11,4.5451087337373151e-11,0,0.10000000000372944,-1.0000000000279046,0 +0.93500000000000005,0.12500000000053466,1.575462353161844e-11,1.0423025405688057e-11,0,0.1000000000008554,-1.0000000000063987,0 +0.94500000000000006,0.125,0,0,0,0.099999999999999867,-1,0 +0.95500000000000007,0.125,0,0,0,0.099999999999999867,-1,0 +0.96499999999999997,0.125,0,0,0,0.099999999999999867,-1,0 +0.97499999999999998,0.125,0,0,0,0.099999999999999867,-1,0 +0.98499999999999999,0.125,0,0,0,0.099999999999999867,-1,0 +0.995,0.125,0,0,0,0.099999999999999867,-1,0 diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/tests/test_public.py b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/tests/test_public.py new file mode 100644 index 0000000..d63006e --- /dev/null +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/tests/test_public.py @@ -0,0 +1,85 @@ +import csv +import os +import subprocess +from pathlib import Path + +PUBLIC_TEST_TARGET = "cpp_full_solver1d_public_tests" +GOLDEN_CSV_PATH = Path(__file__).resolve().parents[1] / "tests/data/brio_wu_golden.csv" +TOLERANCE = 1.0e-12 +WORKSPACE_ROOT = Path(__file__).resolve().parents[1] + + +def assert_csv_rows_close( + output_rows: list[list[str]], + reference_rows: list[list[str]], + *, + tolerance: float = TOLERANCE, + expected_header: list[str] | None = None, +) -> None: + if expected_header is not None: + assert output_rows[0] == expected_header + output_rows = output_rows[1:] + + assert len(output_rows) == len(reference_rows) + + for output_row, reference_row in zip(output_rows, reference_rows): + assert len(output_row) == len(reference_row) + for output_value, reference_value in zip(output_row, reference_row): + assert abs(float(output_value) - float(reference_value)) <= tolerance + + +def _build_public_tests() -> Path: + build_dir = "build_public" + subprocess.run( + ["cmake", "-S", ".", "-B", build_dir], check=True, cwd=WORKSPACE_ROOT + ) + subprocess.run( + [ + "cmake", + "--build", + build_dir, + "--target", + "cpp_full_solver1d", + PUBLIC_TEST_TARGET, + ], + check=True, + cwd=WORKSPACE_ROOT, + ) + + binary_name = f"{PUBLIC_TEST_TARGET}.exe" if os.name == "nt" else PUBLIC_TEST_TARGET + executable_path = WORKSPACE_ROOT / build_dir / "tests" / binary_name + assert executable_path.exists() + return executable_path + + +def test_public_catch2_target_builds() -> None: + _build_public_tests() + + +def test_public_brio_wu_cli_matches_reference_grid() -> None: + _build_public_tests() + + solver_name = "cpp_full_solver1d.exe" if os.name == "nt" else "cpp_full_solver1d" + solver_path = WORKSPACE_ROOT / "build_public/bin" / solver_name + assert solver_path.exists() + + completed = subprocess.run( + [str(solver_path)], + check=True, + capture_output=True, + text=True, + ) + + rows = list(csv.reader(completed.stdout.splitlines())) + golden_rows = list( + csv.reader(GOLDEN_CSV_PATH.read_text(encoding="utf-8").splitlines()) + ) + + assert golden_rows[0] == ["x", "rho", "u", "v", "w", "p", "by", "bz"] + + assert_csv_rows_close( + rows, + golden_rows[1:], + tolerance=TOLERANCE, + expected_header=["x", "rho", "u", "v", "w", "p", "by", "bz"], + ) From 0f29b13fd75c1edb7feb016a1c461269d155b940 Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Thu, 2 Apr 2026 14:13:25 +0900 Subject: [PATCH 36/39] fix(magnetohydrodynamics): use absolute paths in hidden eval tests The eval test was using relative paths based on __file__ position which breaks when tests run from /eval/tests/. Fixed to use absolute paths: - WORKSPACE_ROOT = Path("/work/workspace") - REFERENCE_CSV_PATH uses /eval_shared mount This affects both cpp-full1d-00 and cpp-full1d-01 variants. --- .../cpp-full1d-00/eval/tests/test_hidden.py | 2 +- .../cpp-full1d-01/eval/tests/test_hidden.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-00/eval/tests/test_hidden.py b/benchmarks/magnetohydrodynamics/cpp-full1d-00/eval/tests/test_hidden.py index 2b3127f..2b1440a 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full1d-00/eval/tests/test_hidden.py +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-00/eval/tests/test_hidden.py @@ -6,7 +6,7 @@ from mhd1d_shared import TOLERANCE, assert_csv_rows_close SOLVER_TARGET = "cpp_full_solver1d" -WORKSPACE_ROOT = Path(__file__).resolve().parents[2] / "workspace" +WORKSPACE_ROOT = Path("/work/workspace") REFERENCE_CSV_PATH = ( Path("/eval_shared") / "fixtures" / "mhd1d" / "brio_wu_reference.csv" ) diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-01/eval/tests/test_hidden.py b/benchmarks/magnetohydrodynamics/cpp-full1d-01/eval/tests/test_hidden.py index 2b3127f..2b1440a 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full1d-01/eval/tests/test_hidden.py +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-01/eval/tests/test_hidden.py @@ -6,7 +6,7 @@ from mhd1d_shared import TOLERANCE, assert_csv_rows_close SOLVER_TARGET = "cpp_full_solver1d" -WORKSPACE_ROOT = Path(__file__).resolve().parents[2] / "workspace" +WORKSPACE_ROOT = Path("/work/workspace") REFERENCE_CSV_PATH = ( Path("/eval_shared") / "fixtures" / "mhd1d" / "brio_wu_reference.csv" ) From f0a335334d8d022c5e6a7d5cc973389ffacb965d Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Thu, 2 Apr 2026 14:14:39 +0900 Subject: [PATCH 37/39] fix(magnetohydrodynamics): fix WORKSPACE_ROOT path to /work The workdir is mounted at /work, not /work/workspace. The original workspace subdirectory doesn't exist in the run workdir. --- .../cpp-full1d-00/eval/tests/test_hidden.py | 2 +- .../cpp-full1d-01/eval/tests/test_hidden.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-00/eval/tests/test_hidden.py b/benchmarks/magnetohydrodynamics/cpp-full1d-00/eval/tests/test_hidden.py index 2b1440a..a060363 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full1d-00/eval/tests/test_hidden.py +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-00/eval/tests/test_hidden.py @@ -6,7 +6,7 @@ from mhd1d_shared import TOLERANCE, assert_csv_rows_close SOLVER_TARGET = "cpp_full_solver1d" -WORKSPACE_ROOT = Path("/work/workspace") +WORKSPACE_ROOT = Path("/work") REFERENCE_CSV_PATH = ( Path("/eval_shared") / "fixtures" / "mhd1d" / "brio_wu_reference.csv" ) diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-01/eval/tests/test_hidden.py b/benchmarks/magnetohydrodynamics/cpp-full1d-01/eval/tests/test_hidden.py index 2b1440a..a060363 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full1d-01/eval/tests/test_hidden.py +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-01/eval/tests/test_hidden.py @@ -6,7 +6,7 @@ from mhd1d_shared import TOLERANCE, assert_csv_rows_close SOLVER_TARGET = "cpp_full_solver1d" -WORKSPACE_ROOT = Path("/work/workspace") +WORKSPACE_ROOT = Path("/work") REFERENCE_CSV_PATH = ( Path("/eval_shared") / "fixtures" / "mhd1d" / "brio_wu_reference.csv" ) From 70f3fa13921068d906ac8fe0c29b2a86380f377c Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Thu, 2 Apr 2026 14:27:06 +0900 Subject: [PATCH 38/39] Simplify MHD test build dir and code style --- README.md | 1 + .../cpp-full1d-00/workspace/tests/test_public.py | 12 ++++-------- .../cpp-full1d-01/workspace/tests/test_public.py | 12 ++++-------- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 35f6361..620c4c9 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ Configured in `agents_default.toml` (with per-agent overrides under `sample/*.to ## Available Benchmarks - Demo benchmark for Runge-Kutta 2 (RK2) midpoint method. - 3D wave equation solver with finite difference method. +- Magnetohydrodynamics (MHD) solver. ## Quick Start diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/tests/test_public.py b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/tests/test_public.py index d63006e..24e62c7 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/tests/test_public.py +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-00/workspace/tests/test_public.py @@ -29,10 +29,8 @@ def assert_csv_rows_close( def _build_public_tests() -> Path: - build_dir = "build_public" - subprocess.run( - ["cmake", "-S", ".", "-B", build_dir], check=True, cwd=WORKSPACE_ROOT - ) + build_dir = "build" + subprocess.run(["cmake", "-S", ".", "-B", build_dir], check=True, cwd=WORKSPACE_ROOT) subprocess.run( [ "cmake", @@ -60,7 +58,7 @@ def test_public_brio_wu_cli_matches_reference_grid() -> None: _build_public_tests() solver_name = "cpp_full_solver1d.exe" if os.name == "nt" else "cpp_full_solver1d" - solver_path = WORKSPACE_ROOT / "build_public/bin" / solver_name + solver_path = WORKSPACE_ROOT / "build/bin" / solver_name assert solver_path.exists() completed = subprocess.run( @@ -71,9 +69,7 @@ def test_public_brio_wu_cli_matches_reference_grid() -> None: ) rows = list(csv.reader(completed.stdout.splitlines())) - golden_rows = list( - csv.reader(GOLDEN_CSV_PATH.read_text(encoding="utf-8").splitlines()) - ) + golden_rows = list(csv.reader(GOLDEN_CSV_PATH.read_text(encoding="utf-8").splitlines())) assert golden_rows[0] == ["x", "rho", "u", "v", "w", "p", "by", "bz"] diff --git a/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/tests/test_public.py b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/tests/test_public.py index d63006e..24e62c7 100644 --- a/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/tests/test_public.py +++ b/benchmarks/magnetohydrodynamics/cpp-full1d-01/workspace/tests/test_public.py @@ -29,10 +29,8 @@ def assert_csv_rows_close( def _build_public_tests() -> Path: - build_dir = "build_public" - subprocess.run( - ["cmake", "-S", ".", "-B", build_dir], check=True, cwd=WORKSPACE_ROOT - ) + build_dir = "build" + subprocess.run(["cmake", "-S", ".", "-B", build_dir], check=True, cwd=WORKSPACE_ROOT) subprocess.run( [ "cmake", @@ -60,7 +58,7 @@ def test_public_brio_wu_cli_matches_reference_grid() -> None: _build_public_tests() solver_name = "cpp_full_solver1d.exe" if os.name == "nt" else "cpp_full_solver1d" - solver_path = WORKSPACE_ROOT / "build_public/bin" / solver_name + solver_path = WORKSPACE_ROOT / "build/bin" / solver_name assert solver_path.exists() completed = subprocess.run( @@ -71,9 +69,7 @@ def test_public_brio_wu_cli_matches_reference_grid() -> None: ) rows = list(csv.reader(completed.stdout.splitlines())) - golden_rows = list( - csv.reader(GOLDEN_CSV_PATH.read_text(encoding="utf-8").splitlines()) - ) + golden_rows = list(csv.reader(GOLDEN_CSV_PATH.read_text(encoding="utf-8").splitlines())) assert golden_rows[0] == ["x", "rho", "u", "v", "w", "p", "by", "bz"] From 0c12fddb9555c5360c14b55787d8ae0aaed4c06c Mon Sep 17 00:00:00 2001 From: Takanobu Amano Date: Thu, 2 Apr 2026 15:11:38 +0900 Subject: [PATCH 39/39] fix(mhd): correct HLLD flux loop bound to prevent buffer overflow The flux loop was iterating to ubx + 1 and accessing up_r(ix + 1), which read past the allocated Nx + 2*N_margin buffer on the last iteration. Changed loop bound from ubx + 1 to ubx to stay within allocated memory. --- benchmarks/magnetohydrodynamics/shared/src/mhd1d.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/magnetohydrodynamics/shared/src/mhd1d.cpp b/benchmarks/magnetohydrodynamics/shared/src/mhd1d.cpp index 10e80a2..25264cf 100644 --- a/benchmarks/magnetohydrodynamics/shared/src/mhd1d.cpp +++ b/benchmarks/magnetohydrodynamics/shared/src/mhd1d.cpp @@ -149,7 +149,7 @@ void compute_flux_hlld(SolverWorkspace& workspace, double bx, double gamma) const int lbx = workspace.Lbx; const int ubx = workspace.Ubx; - for (int ix = lbx - 1; ix <= ubx + 1; ++ix) { + for (int ix = lbx - 1; ix <= ubx; ++ix) { ::hlld_flux_from_primitive(&up_l(ix, 0), &up_r(ix + 1, 0), bx, gamma, &flux(ix, 0)); } }