Skip to content

Commit 8e2263e

Browse files
Add minIter to the NewtonRaphson settings (#327)
1 parent 9b4bbef commit 8e2263e

File tree

8 files changed

+128
-78
lines changed

8 files changed

+128
-78
lines changed

ikarus/finiteelements/mechanics/materials/vanishingstress.hh

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <ikarus/finiteelements/mechanics/materials/interface.hh>
1515
#include <ikarus/solver/nonlinearsolver/newtonraphson.hh>
1616
#include <ikarus/solver/nonlinearsolver/nonlinearsolverfactory.hh>
17+
#include <ikarus/utils/concepts.hh>
1718
#include <ikarus/utils/nonlinearoperator.hh>
1819

1920
namespace Ikarus {
@@ -37,6 +38,7 @@ struct VanishingStress : public Material<VanishingStress<stressIndexPair, MI>>
3738
countDiagonalIndices(fixedPairs); ///< Number of fixed diagonal indices.
3839
static constexpr auto freeStrains = freeVoigtIndices.size(); ///< Number of free strains.
3940
using ScalarType = typename Underlying::ScalarType; ///< Scalar type.
41+
static constexpr bool isAutoDiff = Concepts::AutodiffScalar<ScalarType>;
4042

4143
static constexpr auto strainTag = Underlying::strainTag; ///< Strain tag.
4244
static constexpr auto stressTag = Underlying::stressTag; ///< Stress tag.
@@ -185,10 +187,13 @@ private:
185187
E(indexPair[0], indexPair[1]) += ecomps(ri++);
186188
}
187189
};
190+
191+
int minIter = isAutoDiff ? 1 : 0;
188192
// THE CTAD is broken for designated initializers in clang 16, when we drop support this can be simplified
189193
NewtonRaphsonConfig<decltype(linearSolver), decltype(updateFunction)> nrs{
190-
.parameters = {.tol = tol_, .maxIter = 100},
191-
.linearSolver = linearSolver, .updateFunction = updateFunction
194+
.parameters = {.tol = tol_, .maxIter = 100, .minIter = minIter},
195+
.linearSolver = linearSolver,
196+
.updateFunction = updateFunction
192197
};
193198

194199
auto nr = createNonlinearSolver(std::move(nrs), nonOp);

ikarus/solver/nonlinearsolver/newtonraphson.hh

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ struct NRSettings
2525
{
2626
double tol{1e-8};
2727
int maxIter{20};
28+
int minIter{0};
2829
};
2930

3031
/**
@@ -131,7 +132,12 @@ public:
131132
* \brief Set up the solver with the given settings.
132133
* \param settings Newton-Raphson settings.
133134
*/
134-
void setup(const Settings& settings) { settings_ = settings; }
135+
void setup(const Settings& settings) {
136+
if (settings.minIter > settings.maxIter)
137+
DUNE_THROW(Dune::InvalidStateException,
138+
"Minimum number of iterations cannot be greater than maximum number of iterations");
139+
settings_ = settings;
140+
}
135141

136142
#ifndef DOXYGEN
137143
struct NoPredictor
@@ -164,7 +170,7 @@ public:
164170
int iter{0};
165171
if constexpr (isLinearSolver)
166172
linearSolver_.analyzePattern(Ax);
167-
while (rNorm > settings_.tol && iter < settings_.maxIter) {
173+
while ((rNorm > settings_.tol && iter < settings_.maxIter) or iter < settings_.minIter) {
168174
this->notify(NonLinearSolverMessages::ITERATION_STARTED);
169175
if constexpr (isLinearSolver) {
170176
linearSolver_.factorize(Ax);

ikarus/utils/concepts.hh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include <Eigen/Dense>
2020
#include <Eigen/Sparse>
2121

22+
#include <autodiff/forward/dual/dual.hpp>
23+
2224
#include "ikarus/assembler/dirichletbcenforcement.hh"
2325
#include "ikarus/finiteelements/mechanics/materials/tags.hh"
2426
#include <ikarus/utils/traits.hh>
@@ -584,5 +586,26 @@ namespace Concepts {
584586
{ g.grid() };
585587
};
586588

589+
namespace Impl {
590+
template <typename T>
591+
struct is_dual : std::false_type
592+
{
593+
};
594+
595+
// Specialization for Dual<T, U>: this will be true for Dual types
596+
template <typename T, typename U>
597+
struct is_dual<autodiff::detail::Dual<T, U>> : std::true_type
598+
{
599+
};
600+
} // namespace Impl
601+
602+
/**
603+
\concept AutodiffScalar
604+
\brief Concept to check if the underlying scalar type is a dual type.
605+
\tparam T The scalar type to be checked if it is a dual type.
606+
*/
607+
template <typename T>
608+
concept AutodiffScalar = Impl::is_dual<T>::value;
609+
587610
} // namespace Concepts
588611
} // namespace Ikarus

tests/src/checkfebyautodiff.hh

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
// SPDX-License-Identifier: LGPL-3.0-or-later
33

44
#pragma once
5+
6+
#include "testhelpers.hh"
7+
58
#include <dune/common/float_cmp.hh>
69
#include <dune/common/test/testsuite.hh>
710

@@ -11,19 +14,17 @@
1114
#include <ikarus/finiteelements/fefactory.hh>
1215
#include <ikarus/utils/basis.hh>
1316

14-
template <typename GridView, typename PreBasis, typename Skills, typename AffordanceColl>
15-
auto checkFESByAutoDiff(const GridView& gridView, const PreBasis& pb, Skills&& skills, AffordanceColl affordance) {
16-
auto basis = Ikarus::makeBasis(gridView, pb);
17-
Eigen::VectorXd d;
18-
d.setRandom(basis.flat().dimension());
17+
template <typename GridView, typename BasisHandler, typename Skills, typename AffordanceColl, typename VectorType>
18+
auto checkFESByAutoDiffImpl(const GridView& gridView, const BasisHandler& basis, Skills&& skills,
19+
AffordanceColl affordance, VectorType& d, const std::string& messageIfFailed = "") {
1920
double lambda = 7.3;
20-
21-
auto fe = Ikarus::makeFE(basis, std::forward<Skills>(skills));
22-
using FE = decltype(fe);
21+
auto fe = Ikarus::makeFE(basis, std::forward<Skills>(skills));
22+
using FE = decltype(fe);
2323

2424
auto req = typename FE::Requirement();
2525
req.insertGlobalSolution(d).insertParameter(lambda);
26-
Dune::TestSuite t("Check calculateScalarImpl() and calculateVectorImpl() by Automatic Differentiation");
26+
Dune::TestSuite t("Check calculateScalarImpl() and calculateVectorImpl() by Automatic Differentiation" +
27+
messageIfFailed);
2728
for (auto element : elements(gridView)) {
2829
auto localView = basis.flat().localView();
2930
localView.bind(element);
@@ -51,7 +52,7 @@ auto checkFESByAutoDiff(const GridView& gridView, const PreBasis& pb, Skills&& s
5152
calculateVector(fe, req, affordance.vectorAffordance(), R);
5253
calculateVector(feAutoDiff, req, affordance.vectorAffordance(), RAutoDiff);
5354

54-
t.check(K.isApprox(KAutoDiff, tol),
55+
t.check(isApproxSame(K, KAutoDiff, tol),
5556
"Mismatch between the stiffness matrices obtained from explicit implementation and the one based on "
5657
"automatic differentiation for " +
5758
feClassName)
@@ -60,7 +61,7 @@ auto checkFESByAutoDiff(const GridView& gridView, const PreBasis& pb, Skills&& s
6061
<< KAutoDiff << "\nThe difference is\n"
6162
<< (K - KAutoDiff);
6263

63-
t.check(R.isApprox(RAutoDiff, tol),
64+
t.check(isApproxSame(R, RAutoDiff, tol),
6465
"Mismatch between the residual vectors obtained from explicit implementation and the one based on "
6566
"automatic differentiation for " +
6667
feClassName)
@@ -76,3 +77,16 @@ auto checkFESByAutoDiff(const GridView& gridView, const PreBasis& pb, Skills&& s
7677

7778
return t;
7879
}
80+
81+
template <typename GridView, typename PreBasis, typename Skills, typename AffordanceColl>
82+
auto checkFESByAutoDiff(const GridView& gridView, const PreBasis& pb, Skills&& skills, AffordanceColl affordance,
83+
const std::string& testName = "") {
84+
Dune::TestSuite t("AutoDiff Test" + testName);
85+
auto basis = Ikarus::makeBasis(gridView, pb);
86+
Eigen::VectorXd d;
87+
d.setZero(basis.flat().dimension());
88+
t.subTest(checkFESByAutoDiffImpl(gridView, basis, skills, affordance, d, " Zero Displacements"));
89+
d.setRandom(basis.flat().dimension());
90+
t.subTest(checkFESByAutoDiffImpl(gridView, basis, skills, affordance, d, " Non-zero Displacements"));
91+
return t;
92+
}

tests/src/testnonlinearelasticity.hh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <config.h>
55

6+
#include "checkfebyautodiff.hh"
67
#include "resultcollection.hh"
78
#include "testcommon.hh"
89

@@ -287,3 +288,34 @@ auto SingleElementTest(const Material& mat) {
287288
}
288289
return t;
289290
}
291+
292+
template <int gridDim, typename MAT, typename TestSuiteType>
293+
void autoDiffTest(TestSuiteType& t, const MAT& mat, const std::string& testName = "") {
294+
using namespace Ikarus;
295+
using namespace Dune::Functions::BasisFactory;
296+
auto vL = []<typename VectorType>([[maybe_unused]] const VectorType& globalCoord, auto& lamb) {
297+
Eigen::Vector<typename VectorType::field_type, VectorType::dimension> fExt;
298+
fExt.setZero();
299+
fExt[1] = 2 * lamb;
300+
return fExt;
301+
};
302+
303+
auto nBL = []<typename VectorType>([[maybe_unused]] const VectorType& globalCoord, auto& lamb) {
304+
Eigen::Vector<typename VectorType::field_type, VectorType::dimension> fExt;
305+
fExt.setZero();
306+
fExt[0] = lamb / 40;
307+
return fExt;
308+
};
309+
310+
auto grid = createUGGridFromCorners<gridDim>(CornerDistortionFlag::randomlyDistorted);
311+
auto gridView = grid->leafGridView();
312+
313+
/// We artificially apply a Neumann load on the complete boundary
314+
Dune::BitSetVector<1> neumannVertices(gridView.size(gridDim), true);
315+
BoundaryPatch neumannBoundary(gridView, neumannVertices);
316+
317+
t.subTest(checkFESByAutoDiff(
318+
gridView, power<gridDim>(lagrange<1>()),
319+
skills(Ikarus::nonLinearElastic(mat), volumeLoad<gridDim>(vL), neumannBoundaryLoad(&neumannBoundary, nBL)),
320+
Ikarus::AffordanceCollections::elastoStatics, testName));
321+
}

tests/src/testnonlinearelasticityneohooke.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,26 @@
1111
using Dune::TestSuite;
1212

1313
int main(int argc, char** argv) {
14+
using namespace Ikarus;
1415
Ikarus::init(argc, argv);
15-
TestSuite t;
16+
TestSuite t("NonLinearElastic + NeoHooke Test");
1617

17-
auto matParameter = Ikarus::toLamesFirstParameterAndShearModulus({.emodul = 1000, .nu = 0.3});
18+
auto matParameter1 = toLamesFirstParameterAndShearModulus({.emodul = 1000, .nu = 0.3});
19+
auto matParameter2 = toLamesFirstParameterAndShearModulus({.emodul = 1000, .nu = 0.0});
1820

19-
Ikarus::NeoHooke matNH(matParameter);
21+
NeoHooke matNH1(matParameter1);
22+
NeoHooke matNH2(matParameter2);
2023

21-
t.subTest(NonLinearElasticityLoadControlNRandTR<Grids::Alu>(matNH));
22-
t.subTest(NonLinearElasticityLoadControlNRandTR<Grids::Yasp>(matNH));
23-
t.subTest(NonLinearElasticityLoadControlNRandTR<Grids::IgaSurfaceIn2D>(matNH));
24+
auto planeStressMat1 = planeStress(matNH1, 1e-8);
25+
auto planeStressMat2 = planeStress(matNH2, 1e-8);
26+
27+
t.subTest(NonLinearElasticityLoadControlNRandTR<Grids::Alu>(matNH1));
28+
t.subTest(NonLinearElasticityLoadControlNRandTR<Grids::Yasp>(matNH1));
29+
t.subTest(NonLinearElasticityLoadControlNRandTR<Grids::IgaSurfaceIn2D>(matNH1));
30+
31+
autoDiffTest<2>(t, planeStressMat1, " nu != 0");
32+
autoDiffTest<2>(t, planeStressMat2, " nu = 0");
33+
autoDiffTest<3>(t, matNH1, " nu != 0");
34+
autoDiffTest<3>(t, matNH2, " nu = 0");
2435
return t.exit();
2536
}

tests/src/testnonlinearelasticitysvk.cpp

Lines changed: 14 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
#include <config.h>
55

6-
#include "checkfebyautodiff.hh"
76
#include "testcommon.hh"
87
#include "testnonlinearelasticity.hh"
98

@@ -13,74 +12,32 @@ using Dune::TestSuite;
1312

1413
int main(int argc, char** argv) {
1514
using namespace Ikarus;
16-
using namespace Dune::Functions::BasisFactory;
1715
Ikarus::init(argc, argv);
18-
TestSuite t;
16+
TestSuite t("NonLinearElastic + StVenantKirchhoff Test");
1917

2018
auto matParameter1 = toLamesFirstParameterAndShearModulus({.emodul = 1000, .nu = 0.3});
2119
auto matParameter2 = toLamesFirstParameterAndShearModulus({.emodul = 1000, .nu = 0.0});
2220

2321
StVenantKirchhoff matSVK1(matParameter1);
2422
StVenantKirchhoff matSVK2(matParameter2);
25-
auto planeStressMat = planeStress(matSVK2, 1e-8);
26-
auto planeStrainMat = planeStrain(matSVK1);
23+
auto planeStressMat1 = planeStress(matSVK1, 1e-8);
24+
auto planeStressMat2 = planeStress(matSVK2, 1e-8);
25+
auto planeStrainMat = planeStrain(matSVK1);
2726

2827
t.subTest(NonLinearElasticityLoadControlNRandTR<Grids::Alu>(matSVK1));
2928
t.subTest(NonLinearElasticityLoadControlNRandTR<Grids::Yasp>(matSVK1));
3029
t.subTest(NonLinearElasticityLoadControlNRandTR<Grids::IgaSurfaceIn2D>(matSVK1));
31-
t.subTest(GreenLagrangeStrainTest<2>(planeStressMat));
30+
t.subTest(GreenLagrangeStrainTest<2>(planeStressMat1));
31+
t.subTest(GreenLagrangeStrainTest<2>(planeStressMat2));
3232
t.subTest(GreenLagrangeStrainTest<2>(planeStrainMat));
33-
t.subTest(GreenLagrangeStrainTest<3>(matSVK2));
34-
t.subTest(SingleElementTest(planeStressMat));
35-
36-
auto vL = []<typename VectorType>([[maybe_unused]] const VectorType& globalCoord, auto& lamb) {
37-
Eigen::Vector<typename VectorType::field_type, VectorType::dimension> fExt;
38-
fExt.setZero();
39-
fExt[1] = 2 * lamb;
40-
return fExt;
41-
};
42-
43-
auto nBL = []<typename VectorType>([[maybe_unused]] const VectorType& globalCoord, auto& lamb) {
44-
Eigen::Vector<typename VectorType::field_type, VectorType::dimension> fExt;
45-
fExt.setZero();
46-
fExt[0] = lamb / 40;
47-
return fExt;
48-
};
49-
50-
{
51-
auto grid = createUGGridFromCorners<2>(CornerDistortionFlag::randomlyDistorted);
52-
auto gridView = grid->leafGridView();
53-
/// We artificially apply a Neumann load on the complete boundary
54-
Dune::BitSetVector<1> neumannVertices(gridView.size(2), true);
55-
BoundaryPatch neumannBoundary(gridView, neumannVertices);
56-
t.subTest(checkFESByAutoDiff(
57-
gridView, power<2>(lagrange<1>()),
58-
skills(Ikarus::nonLinearElastic(planeStressMat), volumeLoad<2>(vL), neumannBoundaryLoad(&neumannBoundary, nBL)),
59-
Ikarus::AffordanceCollections::elastoStatics));
60-
}
61-
{
62-
auto grid = createUGGridFromCorners<2>(CornerDistortionFlag::randomlyDistorted);
63-
auto gridView = grid->leafGridView();
64-
/// We artificially apply a Neumann load on the complete boundary
65-
Dune::BitSetVector<1> neumannVertices(gridView.size(2), true);
66-
BoundaryPatch neumannBoundary(gridView, neumannVertices);
67-
t.subTest(checkFESByAutoDiff(
68-
gridView, power<2>(lagrange<1>()),
69-
skills(Ikarus::nonLinearElastic(planeStrainMat), volumeLoad<2>(vL), neumannBoundaryLoad(&neumannBoundary, nBL)),
70-
Ikarus::AffordanceCollections::elastoStatics));
71-
}
72-
73-
{
74-
auto grid = createUGGridFromCorners<3>(CornerDistortionFlag::randomlyDistorted);
75-
auto gridView = grid->leafGridView();
76-
/// We artificially apply a Neumann load on the complete boundary
77-
Dune::BitSetVector<1> neumannVertices(gridView.size(3), true);
78-
BoundaryPatch neumannBoundary(gridView, neumannVertices);
79-
t.subTest(checkFESByAutoDiff(
80-
gridView, power<3>(lagrange<1>()),
81-
skills(Ikarus::nonLinearElastic(matSVK1), volumeLoad<3>(vL), neumannBoundaryLoad(&neumannBoundary, nBL)),
82-
Ikarus::AffordanceCollections::elastoStatics));
83-
}
33+
t.subTest(GreenLagrangeStrainTest<3>(matSVK1));
34+
t.subTest(SingleElementTest(planeStressMat2));
35+
36+
autoDiffTest<2>(t, planeStressMat1, " nu != 0");
37+
autoDiffTest<2>(t, planeStressMat2, " nu = 0");
38+
autoDiffTest<2>(t, planeStrainMat, " nu != 0");
39+
autoDiffTest<3>(t, matSVK1, " nu != 0");
40+
autoDiffTest<3>(t, matSVK2, " nu = 0");
8441

8542
return t.exit();
8643
}

tests/src/testnonlinearoperator.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ template <typename SolutionType, typename SolutionTypeExpected, typename NewtonR
2323
auto checkNewtonRaphson(NewtonRaphson& nr, SolutionType& x, double tolerance, int maxIter, int iterExpected,
2424
const SolutionTypeExpected& xExpected, const auto& x_Predictor) {
2525
TestSuite t("checkNewtonRaphson");
26+
t.checkThrow<Dune::InvalidStateException>([&]() { nr.setup({tolerance, maxIter, maxIter + 1}); },
27+
"NewtonRaphson setup should fail if minIter > maxIter");
2628
nr.setup({tolerance, maxIter});
2729
const auto solverInfo = nr.solve(x_Predictor);
2830

0 commit comments

Comments
 (0)