diff --git a/test/experimental/timestepping/CMakeLists.txt b/test/experimental/timestepping/CMakeLists.txt index ea918317f3cfd30b56d49fd6b1907223d04722b9..d4da32cf5e4f17cdfbca62f86f9c5ac40b798cd2 100644 --- a/test/experimental/timestepping/CMakeLists.txt +++ b/test/experimental/timestepping/CMakeLists.txt @@ -2,3 +2,4 @@ # SPDX-License-Identifier: GPL-3.0-or-later dumux_add_test(SOURCES test_timestepmethods.cc LABELS unit timestepping experimental) +dumux_add_test(SOURCES test_newmarkbeta.cc LABELS unit timestepping experimental) diff --git a/test/experimental/timestepping/test_newmarkbeta.cc b/test/experimental/timestepping/test_newmarkbeta.cc new file mode 100644 index 0000000000000000000000000000000000000000..ebbf49d71d418594c671d03bb9ac667cf41eb81f --- /dev/null +++ b/test/experimental/timestepping/test_newmarkbeta.cc @@ -0,0 +1,86 @@ +// +// SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder +// SPDX-License-Identifier: GPL-3.0-or-later +// +#include <config.h> + +#include <iostream> +#include <vector> + +#include <dune/istl/bvector.hh> +#include <dune/common/exceptions.hh> + +#include <dumux/common/parameters.hh> +#include <dumux/common/initialize.hh> +#include <dumux/nonlinear/findscalarroot.hh> +#include <dumux/io/gnuplotinterface.hh> + +#include <dumux/experimental/timestepping/newmarkbeta.hh> + +int main(int argc, char* argv[]) +{ + using namespace Dumux; + + // maybe initialize MPI and/or multithreading backend + Dumux::initialize(argc, argv); + + // integrate d^2x/dt^2 = -x with Newmark-beta scheme + Experimental::NewmarkBeta<double, Dune::BlockVector<double>> newmark; + Dune::BlockVector<double> x(1); x = -1.0; + Dune::BlockVector<double> v(1); v = 0.0; + Dune::BlockVector<double> a(1); a = 1.0; + newmark.initialize(x, v, a); + + const double dt = 0.1; + const double tEnd = 16*M_PI; + const int nSteps = tEnd/dt; + + const bool showPlot = getParam<bool>("Plot", false); + Dumux::GnuplotInterface<double> plotter(showPlot); + std::vector<double> tValues, xValues, xExact, vValues, vExact, aValues, aExact; + tValues.reserve(nSteps); + xValues.reserve(nSteps); xExact.reserve(nSteps); + vValues.reserve(nSteps); vExact.reserve(nSteps); + aValues.reserve(nSteps); aExact.reserve(nSteps); + + for (int i = 0; i < nSteps; ++i) + { + const double t = dt*i; + + // mimic a nonlinear solver by finding the root of the residual (d^2x/dt^2 + x = 0) + const auto residual = [&](const auto x){ return newmark.acceleration(0, dt, x) + x; }; + const auto xNew = findScalarRootNewton(x[0], residual); + + x[0] = xNew; + // update with the new position + // after the update we have the current position, velocity and acceleration + newmark.update(dt, x); + + tValues.push_back(t); + xValues.push_back(newmark.position(0)); + xExact.push_back(-std::cos(t)); + vValues.push_back(newmark.velocity(0)); + vExact.push_back(std::sin(t)); + aValues.push_back(newmark.acceleration(0)); + aExact.push_back(std::cos(t)); + + if (i % 50 == 0) + { + plotter.resetPlot(); + plotter.addDataSetToPlot(tValues, xValues, "x.dat", "w l"); + plotter.addDataSetToPlot(tValues, xExact, "xe.dat", "w l"); + plotter.addDataSetToPlot(tValues, vValues, "v.dat", "w l"); + plotter.addDataSetToPlot(tValues, vExact, "ve.dat", "w l"); + plotter.addDataSetToPlot(tValues, aValues, "a.dat", "w l"); + plotter.addDataSetToPlot(tValues, aExact, "ae.dat", "w l"); + plotter.plot("result"); + } + } + + // compare the final position with the exact solution + const double error = std::abs(x[0] + std::cos(tEnd)); + if (error > 0.006) + DUNE_THROW(Dune::Exception, "Integration error too large: " << error); + + return 0; +}