HArD::Core2D
Hybrid Arbitrary Degree::Core 2D - Library to implement 2D schemes with edge and cell polynomials as unknowns
Loading...
Searching...
No Matches
LEPNC_StefanPME_transient.hpp
Go to the documentation of this file.
1// Implementation of the NC Poly scheme 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 _LEPNC_STEFANPME_TRANSIENT_HPP
14#define _LEPNC_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 "lepnccore.hpp"
29#include "quad2d.hpp"
33
38namespace HArDCore2D {
39
44// ----------------------------------------------------------------------------
45// Class definition
46// ----------------------------------------------------------------------------
47/* The LEPNC_StefanPME_Transient class provides an implementation of the LEPNC method for the transient Stefan and PME problems.
48
49* If using this code in a scientific publication, please cite the reference for the LEPNC:
50*
51* Non-conforming finite elements on polytopal mesh,
52* J. Droniou, R. Eymard, T. Gallouët and R. Herbin
53* url:
54*
55*/
57
59
61
62// Types
63public:
64 using solution_function_type = std::function<double(const double&, const VectorRd&)>;
65 using source_function_type = std::function<double(const double&, const VectorRd&, const Cell*)>;
66 using grad_function_type = std::function<VectorRd(const double&, const VectorRd&, const Cell*)>;
67 using tensor_function_type = std::function<Eigen::Matrix2d(const double, const double, const Cell*)>;
68
71 LEPNCCore &nc,
73 size_t deg_kappa,
76 solution_function_type exact_solution,
77 grad_function_type grad_exact_solution,
79 double weight,
80 std::string solver_type,
81 std::ostream & output = std::cout
82 );
83
85 Eigen::VectorXd iterate(
86 const double tps,
87 const double dt,
88 const Eigen::VectorXd Xn
89 );
90
92 Eigen::VectorXd apply_nonlinearity(const Eigen::VectorXd& Y, const std::string type) const;
93
95 double L2_MassLumped(const Eigen::VectorXd Xh) const;
96
98 double Lp_MassLumped(const Eigen::VectorXd Xh, double p) const;
99
101 double EnergyNorm(const Eigen::VectorXd Xh) const;
102
104 inline double get_assembly_time() const {
105 return double(_assembly_time) * pow(10, -9);
106 }
108 inline double get_solving_time() const {
109 return double(_solving_time) * pow(10, -9);
110 }
112 inline double get_itime(size_t idx) const {
113 return double(_itime[idx]) * pow(10, -9);
114 }
116 inline double get_solving_error() const {
117 return _solving_error;
118 }
120 inline size_t get_nb_newton() const {
121 return m_nb_newton;
122 }
124 inline Eigen::MatrixXd get_MassT(size_t iT) const {
125 return MassT[iT];
126 }
127
128
129private:
131 Eigen::MatrixXd diffusion_operator(const size_t iT) const;
132
134 Eigen::VectorXd load_operator_ml(const double tps, const size_t iT) const;
135
138 Eigen::VectorXd residual_scheme(const double dt, const Eigen::VectorXd& Xh) const;
139
140 const LEPNCCore& nc;
141 const tensor_function_type kappa;
142 size_t _deg_kappa;
143 const source_function_type source;
144 const BoundaryConditions m_BC;
145 const solution_function_type exact_solution;
146 const grad_function_type grad_exact_solution;
148 const double _weight;
149 const std::string solver_type;
150 std::ostream & m_output;
151
152 // To store local diffusion, mass and source terms
153 std::vector<Eigen::MatrixXd> DiffT;
154 std::vector<Eigen::MatrixXd> MassT;
155 std::vector<Eigen::VectorXd> RightHandSideT;
156
157 // Computation statistics
158 size_t _assembly_time;
159 size_t _solving_time;
160 double _solving_error;
161 mutable std::vector<size_t> _itime = std::vector<size_t>(10, 0);
162 size_t m_nb_newton;
163
164};
165
166LEPNC_StefanPME_Transient::LEPNC_StefanPME_Transient(LEPNCCore &nc, tensor_function_type kappa, size_t deg_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)
167 : nc(nc),
168 kappa(kappa),
169 _deg_kappa(deg_kappa),
170 source(source),
171 m_BC(BC),
172 exact_solution(exact_solution),
173 grad_exact_solution(grad_exact_solution),
174 zeta(zeta),
175 _weight(weight),
176 solver_type(solver_type),
177 m_output(output) {
178
179 m_output << "[LEPNC_StefanPME_Transient] Initializing" << std::endl;
180 //---- Compute diffusion and mass matrix (do not change during time stepping or Newton) ------//
181 const Mesh* mesh = nc.get_mesh();
182 DiffT.resize(mesh->n_cells());
183 MassT.resize(mesh->n_cells());
184 // Source is pre-allocated but not computed as it changes with each time iteration
185 RightHandSideT.resize(mesh->n_cells());
186 for (size_t iT = 0; iT < mesh->n_cells(); iT++) {
187 size_t n_edgesT = mesh->cell(iT)->n_edges();
188 size_t n_local_dofs = DimPoly<Cell>(1) + n_edgesT;
189 double measT = mesh->cell(iT)->measure();
190 DiffT[iT] = diffusion_operator(iT);
191 MassT[iT] = Eigen::MatrixXd::Zero(n_local_dofs, n_local_dofs);
192 MassT[iT].topLeftCorner(DimPoly<Cell>(1), DimPoly<Cell>(1)) = (1-_weight) * (measT / DimPoly<Cell>(1)) * Eigen::MatrixXd::Identity(DimPoly<Cell>(1), DimPoly<Cell>(1));
193 MassT[iT].bottomRightCorner(n_edgesT, n_edgesT) = _weight * (measT / n_edgesT) * Eigen::MatrixXd::Identity(n_edgesT, n_edgesT);
194 }
195}
196
197// PERFORM ONE TIME ITERATION
198Eigen::VectorXd LEPNC_StefanPME_Transient::iterate(const double tps, const double dt, const Eigen::VectorXd Xn) {
199
200 boost::timer::cpu_timer timer;
201 boost::timer::cpu_timer timerint;
202 const auto mesh = nc.get_mesh();
203 size_t n_edges_dofs = mesh->n_edges();
204 size_t n_cell_dofs = mesh->n_cells() * DimPoly<Cell>(1);
205
206 //----- COMPUTE SOURCE: load + previous time -----//
207 for (size_t iT = 0; iT < mesh->n_cells(); iT++) {
208 RightHandSideT[iT] = dt * load_operator_ml(tps, iT) + MassT[iT]*nc.nc_restr(Xn, iT);
209 }
210
211 //----- PARAMETERS FOR NEWTON ------------//
212 constexpr double tol = 1e-8;
213 constexpr size_t maxiter = 400;
214 // relaxation parameter
215 double relax = 1;
216 size_t iter = 0;
217 Eigen::VectorXd Xhprev = Eigen::VectorXd::Zero(n_cell_dofs + n_edges_dofs);
218 Eigen::VectorXd Xh = Eigen::VectorXd::Zero(n_cell_dofs + n_edges_dofs);
219
220 // Vector of Dirichlet BC, either on u (if weight>0) or zeta(u) (if weight=0)
221 Eigen::VectorXd DirBC = Eigen::VectorXd::Zero(n_cell_dofs + n_edges_dofs);
222 for (size_t ibF = 0; ibF < mesh->n_b_edges(); ibF++){
223 Edge* edge = mesh->b_edge(ibF);
224 if (m_BC.type(*edge)=="dir"){
225 size_t iF = edge->global_index();
227 for (QuadratureNode quadrule : quadF){
228 if (_weight == 0){
229 DirBC(n_cell_dofs + iF) += quadrule.w * zeta(exact_solution(tps, quadrule.vector()), "fct");
230 }else{
231 DirBC(n_cell_dofs + iF) += quadrule.w * exact_solution(tps, quadrule.vector());
232 }
233 }
234 // Take average
235 DirBC(n_cell_dofs + iF) /= mesh->b_edge(ibF)->measure();
236 }
237 }
238 Xhprev = DirBC;
239
240
241 // ---- NEWTON ITERATONS ------ //
242 Eigen::VectorXd RES = residual_scheme(dt, Xhprev); // Scheme is F(X)=C, then RES = C - F(u_prev)
243 std::vector<double> residual(maxiter, 1.0);
244 residual[iter] = RES.norm();
245
246 while ( (iter < maxiter) && (residual[iter] > tol) ){
247 iter++;
248
249 // System matrix and initialisation of RHS (only on the edge dofs)
250 Eigen::SparseMatrix<double> GlobMat(n_edges_dofs, n_edges_dofs);
251 std::vector<Eigen::Triplet<double>> triplets_GlobMat;
252 Eigen::VectorXd GlobRHS = RES.tail(n_edges_dofs);
253
254 // Static condensation: matrix and source to recover cell unknowns
255 Eigen::SparseMatrix<double> ScMat(n_cell_dofs, n_edges_dofs);
256 std::vector<Eigen::Triplet<double>> triplets_ScMat;
257 Eigen::VectorXd ScRHS = Eigen::VectorXd::Zero(n_cell_dofs);
258
259 // Assemble local contributions
260 for (size_t iT = 0; iT < mesh->n_cells(); iT++) {
261 Cell* cell = mesh->cell(iT);
262 size_t n_edgesT = cell->n_edges();
263
264 // Local static condensation of element unknowns
265 Eigen::VectorXd XTprev = nc.nc_restr(Xhprev, iT);
266 Eigen::VectorXd ZetaprimeXTprev = apply_nonlinearity(XTprev, "der");
267 Eigen::MatrixXd MatZetaprimeXTprev = Eigen::MatrixXd::Zero(DimPoly<Cell>(1)+n_edgesT, DimPoly<Cell>(1)+n_edgesT);
268 for (size_t i = 0; i < DimPoly<Cell>(1) + n_edgesT; i++){
269 MatZetaprimeXTprev(i, i) = ZetaprimeXTprev(i);
270 }
271 Eigen::MatrixXd MatT = dt * DiffT[iT] * MatZetaprimeXTprev + MassT[iT];
272 Eigen::MatrixXd ATT = MatT.topLeftCorner(DimPoly<Cell>(1), DimPoly<Cell>(1));
273 Eigen::MatrixXd ATF = MatT.topRightCorner(DimPoly<Cell>(1), n_edgesT);
274 Eigen::MatrixXd AFT = MatT.bottomLeftCorner(n_edgesT, DimPoly<Cell>(1));
275 Eigen::MatrixXd AFF = MatT.bottomRightCorner(n_edgesT, n_edgesT);
276
277 Eigen::PartialPivLU<Eigen::MatrixXd> invATT;
278 invATT.compute(ATT);
279
280 Eigen::MatrixXd invATT_ATF = invATT.solve(ATF);
281 Eigen::VectorXd RES_cell = RES.segment(iT * DimPoly<Cell>(1), DimPoly<Cell>(1));
282 Eigen::VectorXd invATT_RES_cell = invATT.solve(RES_cell);
283
284 // Local matrix and right-hand side on the face unknowns
285 Eigen::MatrixXd MatF = Eigen::MatrixXd::Zero(n_edgesT, n_edgesT);
286 Eigen::VectorXd bF = Eigen::VectorXd::Zero(n_edgesT);
287 MatF = AFF - AFT * invATT_ATF;
288 bF = - AFT * invATT_RES_cell; // only additional RHS coming from static condensation, beyond RES
289
290 // Assemble static condensation operator
291 ScRHS.segment(iT * DimPoly<Cell>(1), DimPoly<Cell>(1)) = invATT_RES_cell;
292 for (size_t i = 0; i < DimPoly<Cell>(1); i++){
293 size_t iGlobal = iT * DimPoly<Cell>(1) + i;
294 for (size_t j = 0; j < n_edgesT; j++){
295 size_t jGlobal = cell->edge(j)->global_index();
296 triplets_ScMat.emplace_back(iGlobal, jGlobal, invATT_ATF(i, j));
297 }
298 }
299
300 // GLOBAL MATRIX and RHS on the edge unknowns, using the matrices MatF obtained after static condensation
301 for (size_t i = 0; i < n_edgesT; i++){
302 size_t iGlobal = cell->edge(i)->global_index();
303 for (size_t j = 0; j < n_edgesT; j++){
304 size_t jGlobal = cell->edge(j)->global_index();
305 triplets_GlobMat.emplace_back(iGlobal, jGlobal, MatF(i, j));
306 }
307 GlobRHS(iGlobal) += bF(i);
308 }
309 }
310
311 // Assemble the global linear system (without BC), and matrix to recover statically-condensed cell dofs
312 GlobMat.setFromTriplets(std::begin(triplets_GlobMat), std::end(triplets_GlobMat));
313 ScMat.setFromTriplets(std::begin(triplets_ScMat), std::end(triplets_ScMat));
314
315 // Dirichlet boundary conditions are trivial. Newton requires to solve
316 // F'(X^k) (X^{k+1} - X^k) = B - F(X^k)
317 // Both X^k and X^{k+1} have fixed Dirichlet values on boundary edges, so the system we solve
318 // is Dirichlet homogeneous, and we just select the non-dirichlet edges (first ones in the list)
319 size_t n_edge_unknowns = mesh->n_edges() - m_BC.n_dir_edges();
320 Eigen::SparseMatrix<double> A = GlobMat.topLeftCorner(n_edge_unknowns, n_edge_unknowns);
321 Eigen::VectorXd B = GlobRHS.head(n_edge_unknowns);
322
323 // Solve condensed system and recover cell unknowns. dX = X^{k+1}-X^k//
324 Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > solver;
325 solver.compute(A);
326 Eigen::VectorXd dX_edge_unknowns = solver.solve(B);
327
328 Eigen::VectorXd dX = Eigen::VectorXd::Zero(n_cell_dofs + n_edges_dofs);
329 dX.segment(n_cell_dofs, n_edge_unknowns) = dX_edge_unknowns;
330 dX.head(n_cell_dofs) = ScRHS - ScMat * dX.tail(n_edges_dofs);
331
332 // Recover the fixed boundary values and cell unknowns (from static condensation and Newton).
333 // We start by putting the Dirichlet BC at the end.
334 Xh = DirBC;
335 Xh.head(n_cell_dofs + n_edge_unknowns) = relax*dX.head(n_cell_dofs + n_edge_unknowns) + Xhprev.head(n_cell_dofs + n_edge_unknowns);
336
337 // Compute new residual. We might not accept new Xh but start over reducing relax. Otherwise, accept Xh and increase relax
338 // to a max of 1
339 Eigen::VectorXd RES_temp = residual_scheme(dt, Xh);
340 double residual_temp = RES_temp.norm();
341 if (iter > 1 && residual_temp > 10*residual[iter-1]){
342 // We don't update the residual and Xh, but we will do another iteration with relax reduced
343 relax = relax/2.0;
344 iter--;
345 } else {
346 // Increase relax
347 relax = std::min(1.0, 1.2*relax);
348 // Store Xh in Xhprev, compute new residual
349 Xhprev = Xh;
350 RES = RES_temp;
351 residual[iter] = residual_temp;
352 }
353
354 m_output << " ...Iteration: " << iter << "; residual = " << residual[iter] << "; relax = "<< relax << "\n";
355
356 } //-------- END NEWTON ITERATIONS -----------//
357 m_nb_newton = iter;
358
359 return Xh;
360}
361
362//****************************************
363// apply nonlinearity zeta to a vector
364//****************************************
365
366Eigen::VectorXd LEPNC_StefanPME_Transient::apply_nonlinearity(const Eigen::VectorXd& Y, const std::string type) const {
367 // Type="fct", "nlin" or "der" as per the nonlinear function zeta
368 // The function applied to each coefficient of Y depends on its nature. If it's a coefficient appearing in
369 // the mass-lumping (which depends on _weight), the unknown represents u and we apply the full nonlinear function zeta.
370 // Otherwise, the unknown is zeta(u) itself and the function we apply is the identity s->s (with nlin/der: s-> 1)
371 //
372
373 Eigen::VectorXd ZetaY;
374 // Initialisation depends on "type". We initialise as if the nonlinearity was the identity, we'll change the
375 // appropriate coefficients afterwards
376 if (type == "fct"){
377 ZetaY = Y;
378 }else if (type == "der" || type == "nlin"){
379 ZetaY = Eigen::VectorXd::Ones(Y.size());
380 }else{
381 m_output << "type unknown in apply_nonlinearity: " << type << "\n";
382 exit(EXIT_FAILURE);
383 }
384
385 const Mesh* mesh = nc.get_mesh();
386 // We check if Y is a local vector or a global one, this determines the number of cell and edge unknowns
387 size_t n_cell_dofs = 0;
388 if (size_t(Y.size()) == DimPoly<Cell>(1)*mesh->n_cells() + mesh->n_edges()){
389 n_cell_dofs = DimPoly<Cell>(1)*mesh->n_cells();
390 }else{
391 n_cell_dofs = DimPoly<Cell>(1);
392 }
393 size_t n_edges_dofs = Y.size() - n_cell_dofs;
394
395 // The type of nonlinearity we apply on each coefficient depends on _weight
396 if (_weight == 0){
397 for (size_t i = 0; i < n_cell_dofs; i++){
398 ZetaY(i) = zeta(Y(i), type);
399 }
400 }else if (_weight == 1){
401 for (size_t i = n_cell_dofs; i < n_cell_dofs + n_edges_dofs; i++){
402 ZetaY(i) = zeta(Y(i), type);
403 }
404 }else{
405 for (size_t i = 0; i < n_cell_dofs + n_edges_dofs; i++){
406 ZetaY(i) = zeta(Y(i), type);
407 }
408 }
409
410
411 return ZetaY;
412}
413
414
415//********************************
416// local diffusion matrix
417//********************************
418
419Eigen::MatrixXd LEPNC_StefanPME_Transient::diffusion_operator(const size_t iT) const {
420
421 const auto mesh = nc.get_mesh();
422 Cell* cell = mesh->cell(iT);
423 const size_t n_edgesT = cell->n_edges();
424
425 // Total number of degrees of freedom local to this cell
426 size_t local_dofs = n_edgesT + DimPoly<Cell>(1);
427
428 // Diffusion in the cell.
429 std::function<Eigen::Matrix2d(double,double)> kappaT = [&](double x, double y){
430 return kappa(x, y, cell);
431 };
432
433 // Compute cell quadrature nodes and values of cell basis functions and gradients at these nodes
434 size_t doe = 2 + _deg_kappa;
435 QuadratureRule quadT = generate_quadrature_rule(*cell, doe, true);
436 std::vector<Eigen::ArrayXXd> Dnc_phiT_quadT = nc.grad_nc_basis_quad(iT, quadT);
437 // Diffusion tensor at the quadrature nodes
438 std::vector<Eigen::Matrix2d> kappaT_quadT(quadT.size());
439 std::transform(quadT.begin(), quadT.end(), kappaT_quadT.begin(),
440 [&kappaT](QuadratureNode qr) -> Eigen::MatrixXd { return kappaT(qr.x, qr.y); });
441
442 return nc.gram_matrix(Dnc_phiT_quadT, Dnc_phiT_quadT, local_dofs, local_dofs, quadT, true, kappaT_quadT);
443}
444
445
446//********************************
447// local load term
448//********************************
449
450Eigen::VectorXd LEPNC_StefanPME_Transient::load_operator_ml(const double tps, const size_t iT) const {
451 // Load for the cell DOFs (first indices) and face DOFs (last indices)
452 const auto mesh = nc.get_mesh();
453 Cell* cell = mesh->cell(iT);
454 size_t n_edgesT = cell->n_edges();
455 size_t local_dofs = DimPoly<Cell>(1) + n_edgesT;
456
457 // Beware, MassT[iT] must have been created
458 if (MassT.size() < iT || size_t(MassT[iT].rows()) != local_dofs){
459 m_output << "Called load_operator_ml without creating MassT[iT]\n";
460 exit(EXIT_FAILURE);
461 }
462 Eigen::VectorXd fvec = Eigen::VectorXd::Zero(DimPoly<Cell>(1) + n_edgesT);
463 for (size_t i = 0; i < local_dofs; i++){
464 VectorRd node;
465 if (i < DimPoly<Cell>(1)){
466 node = nc.ml_node(iT, i);
467 }else{
468 node = cell->edge(i-DimPoly<Cell>(1))->center_mass();
469 }
470 fvec(i) = source(tps, node, cell);
471 }
472 // Contribution of source to loading term
473 Eigen::VectorXd load = MassT[iT] * fvec;
474
475 // Adding Neumann boundary conditions
476 // The boundary conditions coming from Neumann edges are computed based on the piecewise constant
477 // discrete trace: if g is the value of the outer flux,
478 // \int g v -> \int g Tv
479 // where (Tv)_e = average of v on e, for e Neumann edge.
480 // Only edge-based basis functions therefore have a contribution, which will simply be \int_e g.
481 if (cell->is_boundary()){
482 for (size_t ilF = 0; ilF < cell->n_edges(); ilF++) {
483 Edge* edge = cell->edge(ilF);
484 if (m_BC.type(*edge)=="neu"){
485 if (edge->is_boundary()){
486 const auto& nTF = cell->edge_normal(ilF);
488 std::function<double(VectorRd)> Kgrad_n = [&](VectorRd p){
489 return zeta(exact_solution(tps, p), "der") * nTF.dot(kappa(p.x(),p.y(),cell) * grad_exact_solution(tps, p,cell));
490 };
491 for (QuadratureNode qr : quadF){
492 load(DimPoly<Cell>(1) + ilF) += qr.w * Kgrad_n(qr.vector());
493 }
494 }
495 }
496 }
497 }
498
499 return load;
500}
501
502//****************************
503// Residual non-linear scheme
504//****************************
505
506Eigen::VectorXd LEPNC_StefanPME_Transient::residual_scheme(const double dt, const Eigen::VectorXd& Xh) const{
507
508 const Mesh* mesh = nc.get_mesh();
509 Eigen::VectorXd RES = Eigen::VectorXd::Zero(mesh->n_cells() * DimPoly<Cell>(1) + mesh->n_edges());
510
511 // 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
512 size_t n_cell_dofs = mesh->n_cells() * DimPoly<Cell>(1);
513 for (size_t iT = 0; iT < mesh->n_cells(); iT++){
514 Cell* cell = mesh->cell(iT);
515 size_t n_edgesT = cell->n_edges();
516 // Local unknown in the cell, and zeta of these unknowns
517 Eigen::VectorXd XT = nc.nc_restr(Xh, iT);
518 Eigen::VectorXd ZetaXT = apply_nonlinearity(XT, "fct");
519
520 Eigen::VectorXd REST = RightHandSideT[iT] - (dt * DiffT[iT] * ZetaXT + MassT[iT] * XT);
521 RES.segment(iT*DimPoly<Cell>(1), DimPoly<Cell>(1)) += REST.head(DimPoly<Cell>(1));
522 for (size_t ilE = 0; ilE < n_edgesT; ilE++){
523 size_t iE = cell->edge(ilE)->global_index();
524 RES(n_cell_dofs + iE) += REST(DimPoly<Cell>(1)+ilE);
525 }
526 }
527
528 // No residual on Dirichlet edges (do not correspond to equations of the system)
529 RES.tail(m_BC.n_dir_edges()) = Eigen::VectorXd::Zero(m_BC.n_dir_edges());
530
531 return RES;
532}
533
534//*******************************************************
535// Norms: L2 mass lumped, Energy (pure diffusion)
536//*******************************************************
537
538double LEPNC_StefanPME_Transient::L2_MassLumped(const Eigen::VectorXd Xh) const {
539 const Mesh* mesh = nc.get_mesh();
540 double value = 0.0;
541
542 for (size_t iT = 0; iT < mesh-> n_cells(); iT++) {
543 Eigen::VectorXd XTF = nc.nc_restr(Xh, iT);
544 value += XTF.transpose() * MassT[iT] * XTF;
545 }
546
547 return sqrt(value);
548}
549
550
551double LEPNC_StefanPME_Transient::Lp_MassLumped(const Eigen::VectorXd Xh, const double p) const {
552 const Mesh* mesh = nc.get_mesh();
553 double value = 0.0;
554
555 for (size_t iT = 0; iT < mesh-> n_cells(); iT++) {
556 Eigen::VectorXd XTF = nc.nc_restr(Xh, iT);
557 // Coefficient-wise power p
558 Eigen::VectorXd XTF_powerp = (XTF.array().abs()).pow(p);
559 // Sum local contributions; this assumes that MassT is diagonal
560 value += (MassT[iT] * XTF_powerp.matrix() ).sum();
561 }
562
563 return std::pow(value, 1.0/p);
564}
565
566double LEPNC_StefanPME_Transient::EnergyNorm(const Eigen::VectorXd Xh) const {
567 const Mesh* mesh = nc.get_mesh();
568 double value = 0.0;
569
570 for (size_t iT = 0; iT < mesh-> n_cells(); iT++) {
571 Eigen::VectorXd XTF = nc.nc_restr(Xh, iT);
572 value += XTF.transpose() * DiffT[iT] * XTF;
573 }
574
575 return sqrt(value);
576}
577
578
579
581} // end of namespace HArDCore2D
582
583#endif //_LEPNC_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
Definition lepnccore.hpp:33
LEPNC scheme for diffusion equation .
Definition LEPNC_StefanPME_transient.hpp:60
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
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
const Mesh * get_mesh() const
Returns a pointer to the mesh.
Definition hybridcore.hpp:201
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 LEPNC_StefanPME_transient.hpp:366
Eigen::MatrixXd get_MassT(size_t iT) const
Mass matrix in cell iT.
Definition LEPNC_StefanPME_transient.hpp:124
Eigen::MatrixXd gram_matrix(const std::vector< Eigen::ArrayXd > &f_quad, const std::vector< Eigen::ArrayXd > &g_quad, const size_t &nrows, const size_t &ncols, const QuadratureRule &quad, const bool &sym, std::vector< double > L2weight={}) const
Definition lepnccore.hpp:517
LEPNC_StefanPME_Transient(LEPNCCore &nc, tensor_function_type kappa, size_t deg_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 LEPNC_StefanPME_transient.hpp:166
Eigen::VectorXd iterate(const double tps, const double dt, const Eigen::VectorXd Xn)
Execute one time iteration.
Definition LEPNC_StefanPME_transient.hpp:198
Eigen::VectorXd nc_restr(const Eigen::VectorXd &Xh, size_t iT) const
Extract from a global vector Xh of unknowns the non-conforming unknowns corresponding to cell iT.
Definition lepnccore.hpp:678
double L2_MassLumped(const Eigen::VectorXd Xh) const
Mass-lumped L2 norm of a function given by a vector.
Definition LEPNC_StefanPME_transient.hpp:538
const std::vector< Eigen::ArrayXXd > grad_nc_basis_quad(const size_t iT, const QuadratureRule quad) const
Compute at the quadrature nodes, where are the cell basis functions.
Definition lepnccore.hpp:471
size_t get_nb_newton() const
number of Newton iterations
Definition LEPNC_StefanPME_transient.hpp:120
std::function< VectorRd(const double &, const VectorRd &, const Cell *)> grad_function_type
type for gradient
Definition LEPNC_StefanPME_transient.hpp:66
double EnergyNorm(const Eigen::VectorXd Xh) const
Discrete energy norm (associated to the diffusion operator)
Definition LEPNC_StefanPME_transient.hpp:566
std::function< Eigen::Matrix2d(const double, const double, const Cell *)> tensor_function_type
type for diffusion tensor (does not depend on time)
Definition LEPNC_StefanPME_transient.hpp:67
double get_solving_time() const
cpu time to solve the scheme
Definition LEPNC_StefanPME_transient.hpp:108
double get_itime(size_t idx) const
various intermediate assembly times
Definition LEPNC_StefanPME_transient.hpp:112
double Lp_MassLumped(const Eigen::VectorXd Xh, double p) const
Mass-lumped Lp norm of a function given by a vector.
Definition LEPNC_StefanPME_transient.hpp:551
double get_solving_error() const
residual after solving the scheme
Definition LEPNC_StefanPME_transient.hpp:116
const VectorRd ml_node(size_t iT, size_t i) const
Return the i'th nodal point in cell iT (for mass lumping)
Definition lepnccore.hpp:422
std::function< double(const double &, const VectorRd &, const Cell *)> source_function_type
type for source
Definition LEPNC_StefanPME_transient.hpp:65
double get_assembly_time() const
cpu time to assemble the scheme
Definition LEPNC_StefanPME_transient.hpp:104
std::function< double(const double &, const VectorRd &)> solution_function_type
type for solution
Definition LEPNC_StefanPME_transient.hpp:64
double measure() const
Return the Lebesgue measure of the Polytope.
Definition Polytope2D.hpp:76
Polytope< DIMENSION > Cell
Definition Polytope2D.hpp:151
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
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