13#ifndef _HMM_STEFANPME_TRANSIENT_HPP
14#define _HMM_STEFANPME_TRANSIENT_HPP
20#include <boost/timer/timer.hpp>
23#include <Eigen/Sparse>
72 std::string solver_type,
73 std::ostream & output = std::cout
84 Eigen::VectorXd
apply_nonlinearity(
const Eigen::VectorXd& Y,
const std::string type)
const;
98 return double(_assembly_time) * pow(10, -9);
102 return double(_solving_time) * pow(10, -9);
106 return double(_itime[idx]) * pow(10, -9);
110 return _solving_error;
124 Eigen::MatrixXd diffusion_operator(
const size_t iT)
const;
127 Eigen::VectorXd load_operator(
const double tps,
const size_t iT)
const;
131 Eigen::VectorXd residual_scheme(
const double dt,
const UVector& Xh)
const;
140 const double _weight;
141 const std::string solver_type;
142 std::ostream & m_output;
145 std::vector<Eigen::MatrixXd> DiffT;
146 std::vector<Eigen::MatrixXd> MassT;
147 std::vector<Eigen::VectorXd> RightHandSideT;
150 size_t _assembly_time;
151 size_t _solving_time;
152 double _solving_error;
153 mutable std::vector<size_t> _itime = std::vector<size_t>(10, 0);
163 exact_solution(exact_solution),
164 grad_exact_solution(grad_exact_solution),
167 solver_type(solver_type),
175 RightHandSideT.resize(mesh->
n_cells());
176 for (
size_t iT = 0; iT < mesh->
n_cells(); iT++) {
178 size_t n_local_dofs = 1 + n_edgesT;
180 DiffT[iT] = diffusion_operator(iT);
181 MassT[iT] = Eigen::MatrixXd::Zero(n_local_dofs, n_local_dofs);
182 MassT[iT](0,0) = (1-_weight) * measT;
183 MassT[iT].bottomRightCorner(n_edgesT, n_edgesT) = _weight * (measT / n_edgesT) * Eigen::MatrixXd::Identity(n_edgesT, n_edgesT);
190 boost::timer::cpu_timer timer;
191 boost::timer::cpu_timer timerint;
193 size_t n_edges_dofs = mesh->
n_edges();
194 size_t n_cell_dofs = mesh->n_cells();
197 for (
size_t iT = 0; iT < mesh->n_cells(); iT++) {
198 RightHandSideT[iT] = dt * load_operator(tps, iT) + MassT[iT]*Xn.
restr(iT);
202 constexpr double tol = 1e-8;
203 constexpr size_t maxiter = 400;
211 Eigen::VectorXd DirBC = Eigen::VectorXd::Zero(n_cell_dofs + n_edges_dofs);
212 for (
size_t ibF = 0; ibF < mesh->n_b_edges(); ibF++){
213 Edge* edge = mesh->b_edge(ibF);
214 if (m_BC.
type(*edge)==
"dir"){
215 size_t iF = edge->global_index();
219 DirBC(n_cell_dofs + iF) += quadrule.w * zeta(exact_solution(tps, quadrule.vector()),
"fct");
221 DirBC(n_cell_dofs + iF) += quadrule.w * exact_solution(tps, quadrule.vector());
225 DirBC(n_cell_dofs + iF) /= mesh->b_edge(ibF)->measure();
229 Xhprev.
asVectorXd().tail(mesh->n_b_edges()) = DirBC.tail(mesh->n_b_edges());
233 Eigen::VectorXd RES = residual_scheme(dt, Xhprev);
234 std::vector<double> residual(maxiter, 1.0);
235 residual[iter] = RES.norm();
237 while ( (iter < maxiter) && (residual[iter] > tol) ){
241 Eigen::SparseMatrix<double> GlobMat(n_edges_dofs, n_edges_dofs);
242 std::vector<Eigen::Triplet<double>> triplets_GlobMat;
243 Eigen::VectorXd GlobRHS = RES.tail(n_edges_dofs);
246 Eigen::SparseMatrix<double> ScMat(n_cell_dofs, n_edges_dofs);
247 std::vector<Eigen::Triplet<double>> triplets_ScMat;
248 Eigen::VectorXd ScRHS = Eigen::VectorXd::Zero(n_cell_dofs);
251 for (
size_t iT = 0; iT < mesh->n_cells(); iT++) {
252 Cell* cell = mesh->cell(iT);
253 size_t n_edgesT = cell->n_edges();
256 Eigen::VectorXd XTprev = Xhprev.
restr(iT);
258 Eigen::MatrixXd MatZetaprimeXTprev = Eigen::MatrixXd::Zero(1+n_edgesT, 1+n_edgesT);
260 for (
size_t i = 0;
i < 1 + n_edgesT;
i++){
261 MatZetaprimeXTprev(
i,
i) = ZetaprimeXTprev(
i);
265 Eigen::MatrixXd MatT = dt * DiffT[iT] * MatZetaprimeXTprev + MassT[iT];
266 Eigen::MatrixXd ATT = MatT.topLeftCorner(1, 1);
267 Eigen::MatrixXd ATF = MatT.topRightCorner(1, n_edgesT);
268 Eigen::MatrixXd AFT = MatT.bottomLeftCorner(n_edgesT, 1);
269 Eigen::MatrixXd AFF = MatT.bottomRightCorner(n_edgesT, n_edgesT);
271 Eigen::PartialPivLU<Eigen::MatrixXd> invATT;
274 Eigen::MatrixXd invATT_ATF = invATT.solve(ATF);
275 Eigen::VectorXd RES_cell = RES.segment(iT, 1);
276 Eigen::VectorXd invATT_RES_cell = invATT.solve(RES_cell);
279 Eigen::MatrixXd MatF = Eigen::MatrixXd::Zero(n_edgesT, n_edgesT);
280 Eigen::VectorXd bF = Eigen::VectorXd::Zero(n_edgesT);
281 MatF = AFF - AFT * invATT_ATF;
282 bF = - AFT * invATT_RES_cell;
285 ScRHS.segment(iT, 1) = invATT_RES_cell;
288 for (
size_t i = 0;
i < 1;
i++){
289 size_t iGlobal = iT +
i;
290 for (
size_t j = 0;
j < n_edgesT;
j++){
291 size_t jGlobal = cell->edge(
j)->global_index();
292 triplets_ScMat.emplace_back(iGlobal, jGlobal, invATT_ATF(
i,
j));
297 for (
size_t i = 0;
i < n_edgesT;
i++){
298 size_t iGlobal = cell->edge(
i)->global_index();
299 for (
size_t j = 0;
j < n_edgesT;
j++){
300 size_t jGlobal = cell->edge(
j)->global_index();
301 triplets_GlobMat.emplace_back(iGlobal, jGlobal, MatF(
i,
j));
303 GlobRHS(iGlobal) += bF(
i);
309 GlobMat.setFromTriplets(std::begin(triplets_GlobMat), std::end(triplets_GlobMat));
310 ScMat.setFromTriplets(std::begin(triplets_ScMat), std::end(triplets_ScMat));
316 size_t n_edge_unknowns = mesh->n_edges() - m_BC.
n_dir_edges();
317 Eigen::SparseMatrix<double>
A = GlobMat.topLeftCorner(n_edge_unknowns, n_edge_unknowns);
319 Eigen::VectorXd B = GlobRHS.head(n_edge_unknowns);
322 Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > solver;
324 Eigen::VectorXd dX_edge_unknowns = solver.solve(B);
326 Eigen::VectorXd dX = Eigen::VectorXd::Zero(n_cell_dofs + n_edges_dofs);
327 dX.segment(n_cell_dofs, n_edge_unknowns) = dX_edge_unknowns;
328 dX.head(n_cell_dofs) = ScRHS - ScMat * dX.tail(n_edges_dofs);
333 Xh.
asVectorXd().head(n_cell_dofs + n_edge_unknowns) = relax*dX.head(n_cell_dofs + n_edge_unknowns) + Xhprev.
asVectorXd().head(n_cell_dofs + n_edge_unknowns);
337 Eigen::VectorXd RES_temp = residual_scheme(dt, Xh);
338 double residual_temp = RES_temp.norm();
340 if (iter > 1 && residual_temp > 10*residual[iter-1]){
346 relax = std::min(1.0, 1.2*relax);
350 residual[iter] = residual_temp;
353 m_output <<
" ...Iteration: " << iter <<
"; residual = " << residual[iter] <<
"; relax = "<< relax <<
"\n";
372 Eigen::VectorXd ZetaY;
377 }
else if (type ==
"der" || type ==
"nlin"){
378 ZetaY = Eigen::VectorXd::Ones(Y.size());
380 m_output <<
"type unknown in apply_nonlinearity: " << type <<
"\n";
386 size_t n_cell_dofs = 0;
392 size_t n_edges_dofs = Y.size() - n_cell_dofs;
396 for (
size_t i = 0;
i < n_cell_dofs;
i++){
397 ZetaY(
i) = zeta(Y(
i), type);
399 }
else if (_weight == 1){
400 for (
size_t i = n_cell_dofs;
i < n_cell_dofs + n_edges_dofs;
i++){
401 ZetaY(
i) = zeta(Y(
i), type);
404 for (
size_t i = 0;
i < n_cell_dofs + n_edges_dofs;
i++){
405 ZetaY(
i) = zeta(Y(
i), type);
425Eigen::MatrixXd HMM_StefanPME_Transient::diffusion_operator(
const size_t iT)
const {
428 size_t dim = mesh->
dim();
429 Cell*
T = mesh->cell(iT);
430 double mT =
T->measure();
431 const size_t n_edgesT =
T->n_edges();
433 size_t local_dofs = 1 + n_edgesT;
434 Eigen::MatrixXd StiffT = Eigen::MatrixXd::Zero(local_dofs, local_dofs);
437 Eigen::Vector2d xT =
T->center_mass();
438 Eigen::Matrix2d kappaT = kappa(xT.x(), xT.y(),
T);
441 Eigen::MatrixXd nablaK = Eigen::MatrixXd::Zero(dim, local_dofs);
442 for (
size_t iE=0; iE < n_edgesT; iE++){
443 Edge* E =
T->edge(iE);
444 double mE = E->measure();
445 nablaK.block(0, iE+1, dim, 1) = mE *
T->edge_normal(iE);
450 for (
size_t iE=0; iE < n_edgesT; iE++){
451 Edge* E =
T->edge(iE);
452 Eigen::Vector2d xE = E->center_mass();
453 Eigen::Vector2d nTE =
T->edge_normal(iE);
454 double mE = E->measure();
456 double dTE = (xE-xT).dot(nTE);
457 double mTE = mE * dTE / dim;
460 Eigen::MatrixXd stabE = Eigen::MatrixXd::Zero(1, local_dofs);
463 stabE -= (xE-xT).transpose() * nablaK;
466 Eigen::MatrixXd GRAD = nablaK + (pow(dim, 0.5)/dTE) * nTE * stabE;
469 StiffT += mTE * GRAD.transpose() * kappaT * GRAD;
480Eigen::VectorXd HMM_StefanPME_Transient::load_operator(
const double tps,
const size_t iT)
const {
483 Cell*
T = mesh->cell(iT);
484 size_t n_edgesT =
T->n_edges();
485 size_t local_dofs = 1 + n_edgesT;
488 if (MassT.size() < iT ||
size_t(MassT[iT].rows()) != local_dofs){
489 m_output <<
"Called load_operator without creating MassT[iT]\n";
492 Eigen::VectorXd fvec = Eigen::VectorXd::Zero(1 + n_edgesT);
493 for (
size_t i = 0;
i < local_dofs;
i++){
496 node =
T->center_mass();
498 node =
T->edge(
i-1)->center_mass();
500 fvec(
i) = source(tps, node,
T);
503 Eigen::VectorXd load = MassT[iT] * fvec;
511 if (
T->is_boundary()){
512 for (
size_t ilF = 0; ilF <
T->n_edges(); ilF++) {
513 Edge* edge =
T->edge(ilF);
514 if (m_BC.
type(*edge)==
"neu"){
515 if (edge->is_boundary()){
516 const auto& nTF =
T->edge_normal(ilF);
519 return zeta(exact_solution(tps, p),
"der") * nTF.dot(kappa(p.x(),p.y(),
T) * grad_exact_solution(tps, p,
T));
536Eigen::VectorXd HMM_StefanPME_Transient::residual_scheme(
const double dt,
const UVector& Xh)
const{
539 Eigen::VectorXd RES = Eigen::VectorXd::Zero(mesh->
n_cells() + mesh->
n_edges());
542 size_t n_cell_dofs = mesh->
n_cells();
543 for (
size_t iT = 0; iT < mesh->
n_cells(); iT++){
547 Eigen::VectorXd XT = Xh.
restr(iT);
550 Eigen::VectorXd REST = RightHandSideT[iT] - (dt * DiffT[iT] * ZetaXT + MassT[iT] * XT);
552 for (
size_t ilE = 0; ilE < n_edgesT; ilE++){
553 size_t iE =
T->edge(ilE)->global_index();
554 RES(n_cell_dofs + iE) += REST(1+ilE);
572 for (
size_t iT = 0; iT < mesh-> n_cells(); iT++) {
573 Eigen::VectorXd XTF = Xh.
restr(iT);
574 value += XTF.transpose() * MassT[iT] * XTF;
585 for (
size_t iT = 0; iT < mesh-> n_cells(); iT++) {
586 Eigen::VectorXd XTF = Xh.
restr(iT);
588 Eigen::VectorXd XTF_powerp = (XTF.array().abs()).pow(p);
590 value += (MassT[iT] * XTF_powerp.matrix() ).sum();
593 return std::pow(value, 1.0/p);
600 for (
size_t iT = 0; iT < mesh-> n_cells(); iT++) {
601 Eigen::VectorXd XTF = Xh.
restr(iT);
602 value += XTF.transpose() * DiffT[iT] * XTF;
The BoundaryConditions class provides definition of boundary conditions.
Definition BoundaryConditions.hpp:45
const std::string type(const Edge &edge) const
Test the boundary condition of an edge.
Definition BoundaryConditions.cpp:41
const size_t n_dir_edges() const
Returns the number of Dirichlet edges.
Definition BoundaryConditions.hpp:70
The vector Xh manipulated in the resolution has mixed components, corresponding either to the unknown...
Definition HMM_StefanPME_transient.hpp:53
Definition hybridcore.hpp:179
Definition hybridcore.hpp:82
std::function< double(double, std::string)> nonlinearity_function_type
type for nonlinear function
Definition TestCaseNonLinearity.hpp:48
Compute max and min eigenvalues of all matrices for i
Definition compute_eigs.m:5
Eigen::Vector2d VectorRd
Definition basis.hpp:55
std::function< VectorRd(const double &, const VectorRd &, const Cell *)> grad_function_type
type for gradient
Definition HMM_StefanPME_transient.hpp:59
std::function< double(const double &, const VectorRd &)> solution_function_type
type for solution
Definition HMM_StefanPME_transient.hpp:57
Eigen::MatrixXd get_MassT(size_t iT) const
Mass matrix in cell iT.
Definition HMM_StefanPME_transient.hpp:117
std::function< double(const double &, const VectorRd &, const Cell *)> source_function_type
type for source
Definition HMM_StefanPME_transient.hpp:58
HMM_StefanPME_Transient(HybridCore &hmm, tensor_function_type kappa, source_function_type source, BoundaryConditions BC, solution_function_type exact_solution, grad_function_type grad_exact_solution, TestCaseNonLinearity::nonlinearity_function_type zeta, double weight, std::string solver_type, std::ostream &output=std::cout)
Constructor of the class.
Definition HMM_StefanPME_transient.hpp:158
double get_assembly_time() const
cpu time to assemble the scheme
Definition HMM_StefanPME_transient.hpp:97
double get_solving_error() const
residual after solving the scheme
Definition HMM_StefanPME_transient.hpp:109
double get_itime(size_t idx) const
various intermediate assembly times
Definition HMM_StefanPME_transient.hpp:105
UVector iterate(const double tps, const double dt, const UVector &Xn)
Execute one time iteration.
Definition HMM_StefanPME_transient.hpp:188
double get_solving_time() const
cpu time to solve the scheme
Definition HMM_StefanPME_transient.hpp:101
std::function< Eigen::Matrix2d(const double, const double, const Cell *)> tensor_function_type
type for diffusion tensor (does not depend on time)
Definition HMM_StefanPME_transient.hpp:60
double EnergyNorm(const UVector &Xh) const
Discrete energy norm (associated to the diffusion operator)
Definition HMM_StefanPME_transient.hpp:596
double Lp_MassLumped(const UVector &Xh, double p) const
Mass-lumped Lp norm of a function given by a vector.
Definition HMM_StefanPME_transient.hpp:581
double L2_MassLumped(const UVector &Xh) const
Mass-lumped L2 norm of a function given by a vector.
Definition HMM_StefanPME_transient.hpp:568
size_t get_nb_newton() const
number of Newton iterations
Definition HMM_StefanPME_transient.hpp:113
Eigen::VectorXd apply_nonlinearity(const Eigen::VectorXd &Y, const std::string type) const
Compute non-linearity on vector (depends if weight=0, weight=1 or weight\in (0,1) )
Definition HMM_StefanPME_transient.hpp:365
Eigen::VectorXd restr(size_t iT) const
Extract the restriction of the unknowns corresponding to cell iT and its edges.
Definition hybridcore.cpp:29
const size_t DimPoly< Cell >(const int m)
Compute the size of the basis of 2-variate polynomials up to degree m.
Definition hybridcore.hpp:63
Eigen::VectorXd & asVectorXd() const
Return the values as an Eigen vector.
Definition hybridcore.hpp:92
const Mesh * get_mesh() const
Returns a pointer to the mesh.
Definition hybridcore.hpp:201
double measure() const
Return the Lebesgue measure of the Polytope.
Definition Polytope2D.hpp:76
Polytope< DIMENSION > Cell
Definition Polytope2D.hpp:151
std::size_t dim() const
dimension of the mesh
Definition Mesh2D.hpp:58
Cell * cell(std::size_t index) const
get a constant pointer to a cell using its global index
Definition Mesh2D.hpp:178
size_t n_edges() const
Return the number of edges of the Polytope.
Definition Polytope2D.hpp:88
Polytope< 1 > Edge
A Face is a Polytope with object_dim = DIMENSION - 1.
Definition Polytope2D.hpp:147
std::size_t n_cells() const
number of cells in the mesh.
Definition Mesh2D.hpp:63
std::size_t n_edges() const
number of edges in the mesh.
Definition Mesh2D.hpp:61
std::vector< QuadratureNode > QuadratureRule
Definition quadraturerule.hpp:55
QuadratureRule generate_quadrature_rule(const Cell &T, const int doe, const bool force_split)
Generate quadrature rule on mesh element.
Definition quadraturerule.cpp:10
if(strcmp(field, 'real')) % real valued entries T
Definition mmread.m:93
for j
Definition mmread.m:174
Definition ddr-klplate.hpp:27
Description of one node and one weight from a quadrature rule.
Definition quadraturerule.hpp:41