HArD::Core2D
Hybrid Arbitrary Degree::Core 2D - Library to implement 2D schemes with edge and cell polynomials as unknowns
Loading...
Searching...
No Matches
HMM_StefanPME_transient.hpp
Go to the documentation of this file.
1// Implementation of the HMM in 2D for the transient Stefan and PME models
2//
3// { d_t u - div(K \grad(zeta(u))) = f, inside Omega
4// { K \grad(zeta(u)) . nTF = g, on GammaN
5// { u = g, on GammaD
6// { u(0) = u_ini
7//
8// At the moment, only pure Neumann or pure Dirichlet
9//
10// Author: Jerome Droniou (jerome.droniou@monash.edu)
11//
12
13#ifndef _HMM_STEFANPME_TRANSIENT_HPP
14#define _HMM_STEFANPME_TRANSIENT_HPP
15
16#include <functional>
17#include <utility>
18#include <iostream>
19
20#include <boost/timer/timer.hpp>
21
22// Matrices and linear solvers
23#include <Eigen/Sparse>
24#include <Eigen/Dense>
25//#include "Eigen/MA41.cpp"
26
27#include "mesh.hpp"
28#include "hybridcore.hpp"
29#include "quad2d.hpp"
33
39namespace HArDCore2D {
40
45// ----------------------------------------------------------------------------
46// Class definition
47// ----------------------------------------------------------------------------
48/* The HMM_StefanPME_Transient class provides an implementation of the HMM method for the transient Stefan and PME problems.
49*
50*/
52
54
55// Types
56public:
57 using solution_function_type = std::function<double(const double&, const VectorRd&)>;
58 using source_function_type = std::function<double(const double&, const VectorRd&, const Cell*)>;
59 using grad_function_type = std::function<VectorRd(const double&, const VectorRd&, const Cell*)>;
60 using tensor_function_type = std::function<Eigen::Matrix2d(const double, const double, const Cell*)>;
61
64 HybridCore &hmm,
68 solution_function_type exact_solution,
69 grad_function_type grad_exact_solution,
71 double weight,
72 std::string solver_type,
73 std::ostream & output = std::cout
74 );
75
78 const double tps,
79 const double dt,
80 const UVector& Xn
81 );
82
84 Eigen::VectorXd apply_nonlinearity(const Eigen::VectorXd& Y, const std::string type) const;
85 UVector apply_nonlinearity(const UVector& Y, const std::string type) const;
86
88 double L2_MassLumped(const UVector& Xh) const;
89
91 double Lp_MassLumped(const UVector& Xh, double p) const;
92
94 double EnergyNorm(const UVector& Xh) const;
95
97 inline double get_assembly_time() const {
98 return double(_assembly_time) * pow(10, -9);
99 }
101 inline double get_solving_time() const {
102 return double(_solving_time) * pow(10, -9);
103 }
105 inline double get_itime(size_t idx) const {
106 return double(_itime[idx]) * pow(10, -9);
107 }
109 inline double get_solving_error() const {
110 return _solving_error;
111 }
113 inline size_t get_nb_newton() const {
114 return m_nb_newton;
115 }
117 inline Eigen::MatrixXd get_MassT(size_t iT) const {
118 return MassT[iT];
119 }
120
121
122private:
124 Eigen::MatrixXd diffusion_operator(const size_t iT) const;
125
127 Eigen::VectorXd load_operator(const double tps, const size_t iT) const;
128
131 Eigen::VectorXd residual_scheme(const double dt, const UVector& Xh) const;
132
133 const HybridCore& hmm;
134 const tensor_function_type kappa;
135 const source_function_type source;
136 const BoundaryConditions m_BC;
137 const solution_function_type exact_solution;
138 const grad_function_type grad_exact_solution;
140 const double _weight;
141 const std::string solver_type;
142 std::ostream & m_output;
143
144 // To store local diffusion, mass and source terms
145 std::vector<Eigen::MatrixXd> DiffT;
146 std::vector<Eigen::MatrixXd> MassT;
147 std::vector<Eigen::VectorXd> RightHandSideT;
148
149 // Computation statistics
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);
154 size_t m_nb_newton;
155
156};
157
159 : hmm(hmm),
160 kappa(kappa),
161 source(source),
162 m_BC(BC),
163 exact_solution(exact_solution),
164 grad_exact_solution(grad_exact_solution),
165 zeta(zeta),
166 _weight(weight),
167 solver_type(solver_type),
168 m_output(output) {
169
170 //---- Compute diffusion and mass matrix (do not change during time stepping or Newton) ------//
171 const Mesh* mesh = hmm.get_mesh();
172 DiffT.resize(mesh->n_cells());
173 MassT.resize(mesh->n_cells());
174 // Source is pre-allocated but not computed as it changes with each time iteration
175 RightHandSideT.resize(mesh->n_cells());
176 for (size_t iT = 0; iT < mesh->n_cells(); iT++) {
177 size_t n_edgesT = mesh->cell(iT)->n_edges();
178 size_t n_local_dofs = 1 + n_edgesT;
179 double measT = mesh->cell(iT)->measure();
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);
184 }
185}
186
187// PERFORM ONE TIME ITERATION
188UVector HMM_StefanPME_Transient::iterate(const double tps, const double dt, const UVector& Xn) {
189
190 boost::timer::cpu_timer timer;
191 boost::timer::cpu_timer timerint;
192 const auto mesh = hmm.get_mesh();
193 size_t n_edges_dofs = mesh->n_edges();
194 size_t n_cell_dofs = mesh->n_cells();
195
196 //----- COMPUTE SOURCE: load + previous time -----//
197 for (size_t iT = 0; iT < mesh->n_cells(); iT++) {
198 RightHandSideT[iT] = dt * load_operator(tps, iT) + MassT[iT]*Xn.restr(iT);
199 }
200
201 //----- PARAMETERS FOR NEWTON ------------//
202 constexpr double tol = 1e-8;
203 constexpr size_t maxiter = 400;
204 // relaxation parameter
205 double relax = 1;
206 size_t iter = 0;
207 UVector Xhprev = Xn;
208 UVector Xh = UVector(Eigen::VectorXd::Zero(n_cell_dofs + n_edges_dofs), *hmm.get_mesh(), 0, 0);
209
210 // Vector of Dirichlet BC, either on u (if weight>0) or zeta(u) (if weight=0)
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();
217 for (QuadratureNode quadrule : quadF){
218 if (_weight == 0){
219 DirBC(n_cell_dofs + iF) += quadrule.w * zeta(exact_solution(tps, quadrule.vector()), "fct");
220 }else{
221 DirBC(n_cell_dofs + iF) += quadrule.w * exact_solution(tps, quadrule.vector());
222 }
223 }
224 // Take average
225 DirBC(n_cell_dofs + iF) /= mesh->b_edge(ibF)->measure();
226 }
227 }
228 // Adjust initial iteration of Newton to match these BCs
229 Xhprev.asVectorXd().tail(mesh->n_b_edges()) = DirBC.tail(mesh->n_b_edges());
230
231
232 // ---- NEWTON ITERATONS ------ //
233 Eigen::VectorXd RES = residual_scheme(dt, Xhprev); // Scheme is F(X)=C, then RES = C - F(u_prev)
234 std::vector<double> residual(maxiter, 1.0);
235 residual[iter] = RES.norm();
236
237 while ( (iter < maxiter) && (residual[iter] > tol) ){
238 iter++;
239
240 // System matrix and initialisation of RHS (only on the edge dofs)
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);
244
245 // Static condensation: matrix and source to recover cell unknowns
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);
249
250 // Assemble local contributions
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();
254
255 // Local static condensation of element unknowns
256 Eigen::VectorXd XTprev = Xhprev.restr(iT);
257 Eigen::VectorXd ZetaprimeXTprev = apply_nonlinearity(XTprev, "der");
258 Eigen::MatrixXd MatZetaprimeXTprev = Eigen::MatrixXd::Zero(1+n_edgesT, 1+n_edgesT);
259
260 for (size_t i = 0; i < 1 + n_edgesT; i++){
261 MatZetaprimeXTprev(i, i) = ZetaprimeXTprev(i);
262 }
263
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);
270
271 Eigen::PartialPivLU<Eigen::MatrixXd> invATT;
272 invATT.compute(ATT);
273
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);
277
278 // Local matrix and right-hand side on the face unknowns
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; // only additional RHS coming from static condensation, beyond RES
283
284 // Assemble static condensation operator
285 ScRHS.segment(iT, 1) = invATT_RES_cell;
286
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));
293 }
294 }
295
296 // GLOBAL MATRIX and RHS on the edge unknowns, using the matrices MatF obtained after static condensation
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));
302 }
303 GlobRHS(iGlobal) += bF(i);
304 }
305 }
306
307
308 // Assemble the global linear system (without BC), and matrix to recover statically-condensed cell dofs
309 GlobMat.setFromTriplets(std::begin(triplets_GlobMat), std::end(triplets_GlobMat));
310 ScMat.setFromTriplets(std::begin(triplets_ScMat), std::end(triplets_ScMat));
311
312 // Dirichlet boundary conditions are trivial. Newton requires to solve
313 // F'(X^k) (X^{k+1} - X^k) = B - F(X^k)
314 // Both X^k and X^{k+1} have fixed Dirichlet values on boundary edges, so the system we solve
315 // is Dirichlet homogeneous, and we just select the non-dirichlet edges (first ones in the list)
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);
318//std::cout << "Number non-zero terms in matrix: " << A.nonZeros() << "\n";
319 Eigen::VectorXd B = GlobRHS.head(n_edge_unknowns);
320
321 // Solve condensed system and recover cell unknowns. dX = X^{k+1}-X^k//
322 Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > solver;
323 solver.compute(A);
324 Eigen::VectorXd dX_edge_unknowns = solver.solve(B);
325
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);
329
330 // Recover the fixed boundary values and cell unknowns (from static condensation and Newton).
331 // We start by putting the Dirichlet BC at the end.
332 Xh.asVectorXd() = DirBC;
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);
334
335 // Compute new residual. We might not accept new Xh but start over reducing relax. Otherwise, accept Xh and increase relax
336 // to a max of 1
337 Eigen::VectorXd RES_temp = residual_scheme(dt, Xh);
338 double residual_temp = RES_temp.norm();
339
340 if (iter > 1 && residual_temp > 10*residual[iter-1]){
341 // We don't update the residual and Xh, but we will do another iteration with relax reduced
342 relax = relax/2.0;
343 iter--;
344 } else {
345 // Increase relax
346 relax = std::min(1.0, 1.2*relax);
347 // Store Xh in Xhprev, compute new residual
348 Xhprev.asVectorXd() = Xh.asVectorXd();
349 RES = RES_temp;
350 residual[iter] = residual_temp;
351 }
352
353 m_output << " ...Iteration: " << iter << "; residual = " << residual[iter] << "; relax = "<< relax << "\n";
354
355 } //-------- END NEWTON ITERATIONS -----------//
356 m_nb_newton = iter;
357
358 return Xh;
359}
360
361//****************************************
362// apply nonlinearity zeta to a vector
363//****************************************
364
365Eigen::VectorXd HMM_StefanPME_Transient::apply_nonlinearity(const Eigen::VectorXd& Y, const std::string type) const {
366 // Type="fct", "nlin" or "der" as per the nonlinear function zeta
367 // The function applied to each coefficient of Y depends on its nature. If it's a coefficient appearing in
368 // the mass-lumping (which depends on _weight), the unknown represents u and we apply the full nonlinear function zeta.
369 // Otherwise, the unknown is zeta(u) itself and the function we apply is the identity s->s (with nlin/der: s-> 1)
370 //
371
372 Eigen::VectorXd ZetaY;
373 // Initialisation depends on "type". We initialise as if the nonlinearity was the identity, we'll change the
374 // appropriate coefficients afterwards
375 if (type == "fct"){
376 ZetaY = Y;
377 }else if (type == "der" || type == "nlin"){
378 ZetaY = Eigen::VectorXd::Ones(Y.size());
379 }else{
380 m_output << "type unknown in apply_nonlinearity: " << type << "\n";
381 exit(EXIT_FAILURE);
382 }
383
384 const Mesh* mesh = hmm.get_mesh();
385 // We check if Y is a local vector or a global one, this determines the number of cell and edge unknowns
386 size_t n_cell_dofs = 0;
387 if (size_t(Y.size()) == mesh->n_cells() + mesh->n_edges()){
388 n_cell_dofs = mesh->n_cells();
389 }else{
390 n_cell_dofs = 1;
391 }
392 size_t n_edges_dofs = Y.size() - n_cell_dofs;
393
394 // The type of nonlinearity we apply on each coefficient depends on _weight
395 if (_weight == 0){
396 for (size_t i = 0; i < n_cell_dofs; i++){
397 ZetaY(i) = zeta(Y(i), type);
398 }
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);
402 }
403 }else{
404 for (size_t i = 0; i < n_cell_dofs + n_edges_dofs; i++){
405 ZetaY(i) = zeta(Y(i), type);
406 }
407 }
408
409 return ZetaY;
410}
411
412// Overloaded version: apply to the values of UVector, don't change the other parameters
413UVector HMM_StefanPME_Transient::apply_nonlinearity(const UVector& Y, const std::string type) const {
414
415 UVector ZetaY = Y;
416 ZetaY.asVectorXd() = apply_nonlinearity(Y.asVectorXd(), type);
417 return ZetaY;
418}
419
420
421//********************************
422// local diffusion matrix
423//********************************
424
425Eigen::MatrixXd HMM_StefanPME_Transient::diffusion_operator(const size_t iT) const {
426
427 const auto mesh = hmm.get_mesh();
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();
432
433 size_t local_dofs = 1 + n_edgesT;
434 Eigen::MatrixXd StiffT = Eigen::MatrixXd::Zero(local_dofs, local_dofs);
435
436 // Diffusion in the cell.
437 Eigen::Vector2d xT = T->center_mass();
438 Eigen::Matrix2d kappaT = kappa(xT.x(), xT.y(), T);
439
440 // Matrix of \nabla_K
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);
446 }
447 nablaK /= mT;
448
449 // Contribution per diamond
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();
455 // Distance center to edge and measure of diamond
456 double dTE = (xE-xT).dot(nTE);
457 double mTE = mE * dTE / dim;
458
459 // stabilisation (without scaling or normal: u_E-u_K-nablaK u . (xE-xK))
460 Eigen::MatrixXd stabE = Eigen::MatrixXd::Zero(1, local_dofs);
461 stabE(0) = -1.0;
462 stabE(1+iE) = 1.0;
463 stabE -= (xE-xT).transpose() * nablaK;
464
465 // Complete gradient with stabilisation
466 Eigen::MatrixXd GRAD = nablaK + (pow(dim, 0.5)/dTE) * nTE * stabE;
467
468 // Contribution to stiffness
469 StiffT += mTE * GRAD.transpose() * kappaT * GRAD;
470 }
471
472 return StiffT;
473}
474
475
476//********************************
477// local load term
478//********************************
479
480Eigen::VectorXd HMM_StefanPME_Transient::load_operator(const double tps, const size_t iT) const {
481
482 const auto mesh = hmm.get_mesh();
483 Cell* T = mesh->cell(iT);
484 size_t n_edgesT = T->n_edges();
485 size_t local_dofs = 1 + n_edgesT;
486
487 // Beware, MassT[iT] must have been created
488 if (MassT.size() < iT || size_t(MassT[iT].rows()) != local_dofs){
489 m_output << "Called load_operator without creating MassT[iT]\n";
490 exit(EXIT_FAILURE);
491 }
492 Eigen::VectorXd fvec = Eigen::VectorXd::Zero(1 + n_edgesT);
493 for (size_t i = 0; i < local_dofs; i++){
494 VectorRd node;
495 if (i == 0){
496 node = T->center_mass();
497 }else{
498 node = T->edge(i-1)->center_mass();
499 }
500 fvec(i) = source(tps, node, T);
501 }
502 // Contribution of source to loading term
503 Eigen::VectorXd load = MassT[iT] * fvec;
504
505 // Adding Neumann boundary conditions
506 // The boundary conditions coming from Neumann edges are computed based on the piecewise constant
507 // discrete trace: if g is the value of the outer flux,
508 // \int g v -> \int g Tv
509 // where (Tv)_e = average of v on e, for e Neumann edge.
510 // Only edge-based basis functions therefore have a contribution, which will simply be \int_e g.
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);
518 std::function<double(VectorRd)> Kgrad_n = [&](VectorRd p){
519 return zeta(exact_solution(tps, p), "der") * nTF.dot(kappa(p.x(),p.y(),T) * grad_exact_solution(tps, p, T));
520 };
521 for (QuadratureNode qr : quadF){
522 load(DimPoly<Cell>(1) + ilF) += qr.w * Kgrad_n(qr.vector());
523 }
524 }
525 }
526 }
527 }
528
529 return load;
530}
531
532//****************************
533// Residual non-linear scheme
534//****************************
535
536Eigen::VectorXd HMM_StefanPME_Transient::residual_scheme(const double dt, const UVector& Xh) const{
537
538 const Mesh* mesh = hmm.get_mesh();
539 Eigen::VectorXd RES = Eigen::VectorXd::Zero(mesh->n_cells() + mesh->n_edges());
540
541 // Compute the residual: C - (dt * DIFF * ZetaXh + MASS * Xh), where DIFF is the diffusion matrix, MASS is the mass matrix and C is the source term
542 size_t n_cell_dofs = mesh->n_cells();
543 for (size_t iT = 0; iT < mesh->n_cells(); iT++){
544 Cell* T = mesh->cell(iT);
545 size_t n_edgesT = T->n_edges();
546 // Local unknown in the cell, and zeta of these unknowns
547 Eigen::VectorXd XT = Xh.restr(iT);
548 Eigen::VectorXd ZetaXT = apply_nonlinearity(XT, "fct");
549
550 Eigen::VectorXd REST = RightHandSideT[iT] - (dt * DiffT[iT] * ZetaXT + MassT[iT] * XT);
551 RES(iT) += REST(0);
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);
555 }
556 }
557
558 // No residual on Dirichlet edges (do not correspond to equations of the system)
559 RES.tail(m_BC.n_dir_edges()) = Eigen::VectorXd::Zero(m_BC.n_dir_edges());
560
561 return RES;
562}
563
564//*******************************************************
565// Norms: L2 mass lumped, Energy (pure diffusion)
566//*******************************************************
567
569 const Mesh* mesh = hmm.get_mesh();
570 double value = 0.0;
571
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;
575 }
576
577 return sqrt(value);
578}
579
580
581double HMM_StefanPME_Transient::Lp_MassLumped(const UVector& Xh, const double p) const {
582 const Mesh* mesh = hmm.get_mesh();
583 double value = 0.0;
584
585 for (size_t iT = 0; iT < mesh-> n_cells(); iT++) {
586 Eigen::VectorXd XTF = Xh.restr(iT);
587 // Coefficient-wise power p
588 Eigen::VectorXd XTF_powerp = (XTF.array().abs()).pow(p);
589 // Sum local contributions; this assumes that MassT is diagonal
590 value += (MassT[iT] * XTF_powerp.matrix() ).sum();
591 }
592
593 return std::pow(value, 1.0/p);
594}
595
597 const Mesh* mesh = hmm.get_mesh();
598 double value = 0.0;
599
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;
603 }
604
605 return sqrt(value);
606}
607
608
610} // end of namespace HArDCore2D
611
612#endif //_HMM_STEFANPME_TRANSIENT_HPP
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
Definition Mesh2D.hpp:26
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
A
Definition mmread.m:102
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