diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000000000000000000000000000000000..442ac76345bc8676ac9ff97ebddd226b829c9542 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "externals/fmt"] + path = externals/fmt + url = https://github.com/fmtlib/fmt.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cb8e11196d5fe19bd37d25d880c4a789b00c143..96780b564c01ae7e5eaf11d4036a83cc8ad94ee1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ add_subdirectory("test") add_subdirectory("examples" EXCLUDE_FROM_ALL) add_subdirectory("doc") add_subdirectory("cmake/modules") +add_subdirectory("externals" EXCLUDE_FROM_ALL) target_include_directories(amdis PUBLIC $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/src>) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ab96c269b68d746d67d4b4eda919c38d785fd312..d799f6d14ed1e55fc0079930b91b678d0c568e21 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -6,7 +6,7 @@ foreach(project ${projects2d}) add_executable(${project}.2d ${project}.cc) add_dune_alberta_flags(GRIDDIM 2 WORLDDIM 2 ${project}.2d) target_link_dune_default_libraries(${project}.2d) - target_link_libraries(${project}.2d "amdis") + target_link_libraries(${project}.2d amdis fmt) target_compile_definitions(${project}.2d PRIVATE AMDIS_DIM=2 AMDIS_DOW=2) add_dependencies(examples ${project}.2d) endforeach() @@ -17,7 +17,7 @@ foreach(project ${projects3d}) add_executable(${project}.3d ${project}.cc) add_dune_alberta_flags(GRIDDIM 3 WORLDDIM 3 ${project}.3d) target_link_dune_default_libraries(${project}.3d) - target_link_libraries(${project}.3d "amdis") + target_link_libraries(${project}.3d amdis fmt) target_compile_definitions(${project}.3d PRIVATE AMDIS_DIM=3 AMDIS_DOW=3) add_dependencies(examples ${project}.3d) endforeach() \ No newline at end of file diff --git a/examples/ellipt.cc b/examples/ellipt.cc index 6baf47bfb8cbba1adf2a4ffc10a5cb46f742a29f..0414e633a00c14d0c0ee320d7728b90583257d3e 100644 --- a/examples/ellipt.cc +++ b/examples/ellipt.cc @@ -3,55 +3,95 @@ #include <iostream> +#include <fmt/core.h> + #include <amdis/AMDiS.hpp> #include <amdis/ProblemStat.hpp> #include <amdis/Operators.hpp> #include <amdis/common/Literals.hpp> +#include <amdis/gridfunctions/Integrate.hpp> using namespace AMDiS; +using namespace Dune::Indices; // 1 component with polynomial degree 1 -//using Grid = Dune::AlbertaGrid<AMDIS_DIM, AMDIS_DOW>; -using ElliptParam = YaspGridBasis<AMDIS_DIM, 1>; -using ElliptProblem = ProblemStat<ElliptParam>; +using Param = YaspGridBasis<AMDIS_DIM, 1>; +using ElliptProblem = ProblemStat<Param>; int main(int argc, char** argv) { AMDiS::init(argc, argv); - using namespace Dune::Indices; + int numLevels = AMDIS_DIM == 2 ? 8 : 5; + if (argc > 2) + numLevels = std::atoi(argv[2]); + + auto f = [](auto const& x) { + double r2 = dot(x,x); + double ux = std::exp(-10.0 * r2); + return -(400.0 * r2 - 20.0 * x.size()) * ux; + }; + auto g = [](auto const& x){ return std::exp(-10.0 * dot(x,x)); }; + auto grad_g = [](auto const& x) -> FieldMatrix<double,1,AMDIS_DIM> { + return {-20.0 * std::exp(-10.0 * dot(x,x)) * x}; + }; ElliptProblem prob("ellipt"); prob.initialize(INIT_ALL); - AdaptInfo adaptInfo("adapt"); - auto opL = makeOperator(tag::gradtest_gradtrial{}, 1.0); prob.addMatrixOperator(opL, _0, _0); - auto opForce = makeOperator(tag::test{}, [](auto const& x) { return -1.0; }, 0); + auto opForce = makeOperator(tag::test{}, f, 6); prob.addVectorOperator(opForce, _0); - auto opForce2 = makeOperator(tag::test{}, [](auto const& x) { return -2.0; }, 0); - prob.addVectorOperator(BoundaryType{0}, opForce2, _0); - // set boundary condition - auto predicate = [](auto const& x){ return x[0] < 1.e-8 || x[1] < 1.e-8; }; // define boundary - auto dbcValues = [](auto const& x){ return 0.0; }; // set value - prob.addDirichletBC(predicate, _0, _0, dbcValues); + auto boundary = [](auto const& x){ return x[0] < 1.e-8 || x[1] < 1.e-8 || x[0] > 1.0-1.e-8 || x[1] > 1.0-1.e-8; }; + prob.addDirichletBC(boundary, _0, _0, g); + + AdaptInfo adaptInfo("adapt"); - prob.buildAfterCoarsen(adaptInfo, Flag(0)); + std::vector<double> errL2; errL2.reserve(numLevels); + std::vector<double> errH1; errH1.reserve(numLevels); + std::vector<double> widths; widths.reserve(numLevels); + for (int i = 0; i < numLevels; ++i) { + prob.getGrid()->globalRefine(1); + auto gridView = prob.getGlobalBasis()->gridView(); + + double h = 0; + for (auto const& e : edges(gridView)) + h = std::max(h, e.geometry().volume()); + widths.push_back(h); + + prob.buildAfterCoarsen(adaptInfo, Flag(0)); + prob.solve(adaptInfo); + + double errorL2 = integrate(sqr(g - prob.getSolution(_0)), gridView, 6); + errL2.push_back(std::sqrt(errorL2)); + double errorH1 = errorL2 + integrate(unary_dot(grad_g - gradientAtQP(prob.getSolution(_0))), gridView, 6); + errH1.push_back(std::sqrt(errorH1)); + +#if WRITE_FILES + Dune::VTKWriter<typename ElliptProblem::GridView> vtkWriter(prob.getGlobalBasis()->gridView()); + vtkWriter.addVertexData(prob.getSolution(_0), Dune::VTK::FieldInfo("u", Dune::VTK::FieldInfo::Type::scalar, 1)); + vtkWriter.write("u_" + std::to_string(i)); +#endif + } - // write matrix to file - if (Parameters::get<int>("elliptMesh->global refinements").value_or(0) < 5) { - mtl::io::matrix_market_ostream out("matrix.mtx"); - out << prob.getSystemMatrix()->getMatrix(); + std::cout << "\n"; + fmt::print("{:5} | {:12} | {:12} | {:12} | {:12} | {:12}\n", + "level", "h", "|u - u*|_L2","|u - u*|_H1","eoc_L2","eoc_H1"); + fmt::print("{0:->7}{0:->15}{0:->15}{0:->15}{0:->15}{1:->14}","+","\n"); - std::cout << prob.getSystemMatrix()->getMatrix() << '\n'; + std::vector<double> eocL2(numLevels, 0.0), eocH1(numLevels, 0.0); + for (int i = 1; i < numLevels; ++i) { + eocL2[i] = std::log(errL2[i]/errL2[i-1]) / std::log(widths[i]/widths[i-1]); + eocH1[i] = std::log(errH1[i]/errH1[i-1]) / std::log(widths[i]/widths[i-1]); } - prob.solve(adaptInfo); - prob.writeFiles(adaptInfo, true); + for (int i = 0; i < numLevels; ++i) + fmt::print("{:<5} | {:<12} | {:<12} | {:<12} | {:<12} | {:<12}\n", + i+1, widths[i], errL2[i], errH1[i], eocL2[i], eocH1[i]); AMDiS::finalize(); return 0; diff --git a/examples/init/ellipt.dat.2d b/examples/init/ellipt.dat.2d index 37ba6ea98163b277213cc64c1a5afe3c1f823610..f12565729e95e06f7902cf81744b29450c3445e1 100644 --- a/examples/init/ellipt.dat.2d +++ b/examples/init/ellipt.dat.2d @@ -1,13 +1,10 @@ -dimension of world: 2 - -elliptMesh->macro file name: ./macro/macro.stand.2d -elliptMesh->global refinements: 5 +elliptMesh->global refinements: 0 ellipt->mesh: elliptMesh -ellipt->solver->name: cg +ellipt->solver->name: bicgstab ellipt->solver->max iteration: 1000 -ellipt->solver->tolerance: 1.e-8 +ellipt->solver->relative tolerance: 1.e-8 ellipt->solver->info: 10 ellipt->solver->left precon: diag ellipt->solver->right precon: no diff --git a/examples/init/ellipt.dat.3d b/examples/init/ellipt.dat.3d new file mode 100644 index 0000000000000000000000000000000000000000..c05c023447ac2718894383a4d5df234cfbe4dade --- /dev/null +++ b/examples/init/ellipt.dat.3d @@ -0,0 +1,14 @@ +elliptMesh->global refinements: 0 + +ellipt->mesh: elliptMesh + +ellipt->solver->name: bicgstab +ellipt->solver->max iteration: 1000 +ellipt->solver->relative tolerance: 1.e-8 +ellipt->solver->info: 10 +ellipt->solver->left precon: diag +ellipt->solver->right precon: no + +ellipt->output[0]->filename: ellipt.3d +ellipt->output[0]->name: u +ellipt->output[0]->output directory: ./output diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..763f19e11d62943509a44746ba6c70ad04bd390e --- /dev/null +++ b/externals/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(fmt) \ No newline at end of file diff --git a/externals/fmt b/externals/fmt new file mode 160000 index 0000000000000000000000000000000000000000..c6d9730ddbfaa5dbefd5d2b48ef047ad362157f4 --- /dev/null +++ b/externals/fmt @@ -0,0 +1 @@ +Subproject commit c6d9730ddbfaa5dbefd5d2b48ef047ad362157f4 diff --git a/src/amdis/DirichletBC.hpp b/src/amdis/DirichletBC.hpp index 1729ec65a3f51a56f52450b108d924f236730ad5..d456189e62747eff3bad6265f70af886c41c4e73 100644 --- a/src/amdis/DirichletBC.hpp +++ b/src/amdis/DirichletBC.hpp @@ -80,6 +80,7 @@ namespace AMDiS // subtract columns of dirichlet nodes from rhs // for (auto const& triplet : columns) // rhs[triplet.row] -= triplet.value * solution[triplet.col]; + initialized_ = false; } protected: diff --git a/src/amdis/GridFunctionOperator.hpp b/src/amdis/GridFunctionOperator.hpp index 70a12642d81e1fd311b8957c6833bf0e751378f2..318506fa12473ce9c561258b8a9f781d4cbb2975 100644 --- a/src/amdis/GridFunctionOperator.hpp +++ b/src/amdis/GridFunctionOperator.hpp @@ -61,24 +61,9 @@ namespace AMDiS **/ GridFunctionOperatorBase(GridFunction const& gridFct, int termOrder) : gridFct_(gridFct) - , localFct_(localFunction(gridFct_)) , termOrder_(termOrder) {} - // Copy constructor - GridFunctionOperatorBase(GridFunctionOperatorBase const& that) - : gridFct_(that.gridFct_) - , localFct_(localFunction(gridFct_)) // recreate localFct_ on new gridFct_ - , termOrder_(that.termOrder_) - {} - - // Move constructor - GridFunctionOperatorBase(GridFunctionOperatorBase&& that) - : gridFct_(std::move(that.gridFct_)) - , localFct_(localFunction(gridFct_)) // recreate localFct_ on new gridFct_ - , termOrder_(std::move(that.termOrder_)) - {} - /// \brief Binds operator to `element` and `geometry`. /** * Binding an operator to the currently visited element in grid traversal. @@ -91,21 +76,24 @@ namespace AMDiS void bind_impl(Element const& element, Geometry const& geometry) { assert( bool(quadFactory_) ); - localFct_.bind(element); - quadFactory_->bind(localFct_); + localFct_.emplace(localFunction(gridFct_)); + localFct_->bind(element); + quadFactory_->bind(localFct_.value()); } /// Unbinds operator from element. void unbind_impl() { - localFct_.unbind(); + localFct_->unbind(); + localFct_.reset(); } /// Create a quadrature factory from a PreQuadratureFactory, e.g. class derived from \ref QuadratureFactory template <class PreQuadFactory> void setQuadFactory(PreQuadFactory const& pre) { - quadFactory_ = makeQuadratureFactoryPtr<typename Geometry::ctype, LocalContext::mydimension, LocalFunction>(pre); + using ctype = typename Geometry::ctype; + quadFactory_.emplace(makeQuadratureFactory<ctype, LocalContext::mydimension, LocalFunction>(pre)); } protected: @@ -113,7 +101,7 @@ namespace AMDiS auto coefficient(LocalCoordinate const& local) const { assert( this->bound_ ); - return localFct_(local); + return (*localFct_)(local); } /// Create a quadrature rule using the \ref QuadratureFactory by calculating the @@ -131,10 +119,10 @@ namespace AMDiS GridFunction gridFct_; /// localFunction associated with gridFunction. Mus be updated whenever gridFunction changes. - LocalFunction localFct_; + Dune::Std::optional<LocalFunction> localFct_; /// Assign each element type a quadrature rule - std::shared_ptr<QuadFactory> quadFactory_ = std::make_shared<QuadFactory>(); + Dune::Std::optional<QuadFactory> quadFactory_; /// the derivative order of this operator (in {0, 1, 2}) int termOrder_ = 0; diff --git a/src/amdis/common/Math.hpp b/src/amdis/common/Math.hpp index f3a7f3b3ae6718fede5558194ab59cc22e422559..555d1585c0cbb0cb97bd83e727f7afa681845834 100644 --- a/src/amdis/common/Math.hpp +++ b/src/amdis/common/Math.hpp @@ -118,7 +118,7 @@ namespace AMDiS } template <class T> - constexpr T threshold = T(1.e-16); //Math::sqr(std::numeric_limits<T>::epsilon()); + constexpr T threshold = T(1.e-18L); //Math::sqr(std::numeric_limits<T>::epsilon()); /// Calculates factorial of i diff --git a/src/amdis/linear_algebra/LinearSolverInterface.hpp b/src/amdis/linear_algebra/LinearSolverInterface.hpp index f308e1d2c5200cae184a45a85348cfb2e00c7254..5d1534f9f522db80170bdd3ee36bea85d25d56cd 100644 --- a/src/amdis/linear_algebra/LinearSolverInterface.hpp +++ b/src/amdis/linear_algebra/LinearSolverInterface.hpp @@ -45,6 +45,7 @@ namespace AMDiS void solve(Matrix const& A, VectorX& x, VectorB const& b, SolverInfo& solverInfo) { + assert( num_cols(A) == size(x) && num_rows(A) == size(b) ); solveImpl(A, x, b, solverInfo); } diff --git a/src/amdis/linear_algebra/mtl/DOFMatrix.hpp b/src/amdis/linear_algebra/mtl/DOFMatrix.hpp index efadcc319d8618f27bb854331f083a08bbbe4730..dba705f9dba0809107058fb1ea8e3e12dd71ccb3 100644 --- a/src/amdis/linear_algebra/mtl/DOFMatrix.hpp +++ b/src/amdis/linear_algebra/mtl/DOFMatrix.hpp @@ -146,7 +146,9 @@ namespace AMDiS test_exit(!insertionMode && !inserter, "Matrix already in insertion mode!"); calculateSlotSize(); - matrix->change_dim(rowFeSpace.size(), colFeSpace.size()); + matrix->change_dim(rowFeSpace.dimension(), colFeSpace.dimension()); + test_exit(num_rows(*matrix) == rowFeSpace.dimension() && num_cols(*matrix) == colFeSpace.dimension(), + "Wrong dimensions in matrix"); if (prepareForInsertion) { set_to_zero(*matrix); inserter = new Inserter(*matrix, slot_size); @@ -281,7 +283,7 @@ namespace AMDiS private: /// The minimal number of nonzeros per row - static constexpr int MIN_NNZ_PER_ROW = 20; + static constexpr int MIN_NNZ_PER_ROW = 50; /// The finite element space / basis of the row RowFeSpace const& rowFeSpace; @@ -302,7 +304,7 @@ namespace AMDiS bool insertionMode = false; /// The size of the slots used to insert values per row - int slot_size = 20; + int slot_size = MIN_NNZ_PER_ROW; // friend class declarations template <class, class> friend class SystemMatrix; diff --git a/src/amdis/linear_algebra/mtl/DOFVector.hpp b/src/amdis/linear_algebra/mtl/DOFVector.hpp index b66d6ab5cf2c7bb71f46f6c601d24dc1e1c56e3c..6cfb293aac137b7c371a73642be289c0f64e54cb 100644 --- a/src/amdis/linear_algebra/mtl/DOFVector.hpp +++ b/src/amdis/linear_algebra/mtl/DOFVector.hpp @@ -45,7 +45,6 @@ namespace AMDiS , vector(ClonablePtr<BaseVector>::make()) { compress(); - *vector = ValueType(0); } /// Constructor. Takes reference to existing BaseVector @@ -89,8 +88,10 @@ namespace AMDiS /// Resize the \ref vector to the size of the \ref feSpace. void compress() { - if (num_rows(*vector) != getSize()) + if (num_rows(*vector) != getSize()) { resize(getSize()); + *vector = ValueType(0); + } } template <class SizeInfo>