Manicore
Library to implement schemes on n-dimensionnal manifolds.
maxwell.hpp
Go to the documentation of this file.
1 #ifndef MAXWELL_HPP_INCLUDED
2 #define MAXWELL_HPP_INCLUDED
3 
4 #include <Eigen/Sparse>
5 #include <string_view>
6 
7 #include "ddr_spaces.hpp"
8 #include "parallel_for.hpp"
9 #include <atomic>
10 
11 #include <unsupported/Eigen/src/IterativeSolvers/Scaling.h>
12 
21 namespace Manicore {
24 
26 
30  public:
32  typedef Eigen::SparseMatrix<double> SystemMatrixType;
34  typedef Eigen::SparseLU<SystemMatrixType,Eigen::COLAMDOrdering<int> > SolverType;
36  static constexpr std::string_view SolverName = "SparseLU";
37 
38  MaxwellProblem(const Mesh<2> &mesh ,
39  int degree ,
40  double timestep ,
41  bool use_threads = true ,
42  std::array<int,2> const* dqr = nullptr ,
43  std::ostream &output = std::cout );
44 
46 #ifdef THREEFIELDS
47  size_t dimensionH() const {return 1;}
48 #else
49  size_t dimensionH() const {return 0;}
50 #endif
52 #ifdef THREEFIELDS
53  size_t dimensionG() const {return _ddrcore.dofspace(0).dimensionMesh();}
54 #else
55  size_t dimensionG() const {return 0;}
56 #endif
58  size_t dimensionE() const {return _ddrcore.dofspace(1).dimensionMesh();}
60  size_t dimensionB() const {return _ddrcore.dofspace(2).dimensionMesh();}
62  size_t dimensionSystem() const {return dimensionH() + dimensionG() + dimensionE() + dimensionB();}
63 
65  DDR_Spaces<2> const & ddrcore() const {return _ddrcore;}
67  double timeStep() const {return _dt;}
68 
70  void assembleRHS(Eigen::Ref<const Eigen::VectorXd> const & rho ,
71  Eigen::Ref<const Eigen::VectorXd> const & J ,
72  Eigen::Ref<const Eigen::VectorXd> const & EOld ,
73  Eigen::Ref<const Eigen::VectorXd> const & BOld );
74 
76  void compute();
78  bool validateSolution(Eigen::Ref<const Eigen::VectorXd> const &u) const;
80  Eigen::VectorXd solve();
82  Eigen::VectorXd solve(const Eigen::VectorXd &rhs);
83 
85 
88  template<typename Derived>
89  double norm(Eigen::MatrixBase<Derived> const &E ,
90  size_t k ) const;
92 
95  template<typename Derived>
96  double normd(Eigen::MatrixBase<Derived> const &E ,
97  size_t k ) const;
98 
99  private:
100  void assembleLocalContribution(Eigen::Ref<const Eigen::MatrixXd> const & A, size_t iT, size_t kL, size_t kR, std::forward_list<Eigen::Triplet<double>> * triplets) const;
101  void assembleLocalContributionH(Eigen::Ref<const Eigen::MatrixXd> const & A, size_t iT, size_t k, std::forward_list<Eigen::Triplet<double>> * triplets) const;
102  void assembleLocalContribution(Eigen::Ref<const Eigen::VectorXd> const & R, size_t iT, size_t k);
103  // Assemble the system and initialize the masses matrices
104  void assembleSystem();
105 
106  private:
107  DDR_Spaces<2> _ddrcore;
108  double _dt;
109  bool _use_threads;
110  std::ostream & _output;
111  SystemMatrixType _system;
112  Eigen::VectorXd _rhs;
113  SolverType _solver;
114  Eigen::VectorXd _interpOne; // Interpolate of the 0-form 1
115  std::vector<Eigen::MatrixXd> _ALoc00; // Mass matrices
116  std::vector<Eigen::MatrixXd> _ALoc11; // Mass matrices
117  std::vector<Eigen::MatrixXd> _ALoc22; // Mass matrices
118  Eigen::VectorXd _scalingL, _scalingR; // Scaling to enhance the condition number
119  };
120 
122  struct MaxwellVector {
123  MaxwellVector(MaxwellProblem const & maxwell )
124  : u(maxwell.dimensionSystem()), sizeG(maxwell.dimensionG()), sizeE(maxwell.dimensionE()), sizeB(maxwell.dimensionB()),
125  offsetG(maxwell.dimensionH()), offsetE(offsetG + sizeG), offsetB(offsetE + sizeE) {}
128  u = other.u;
129  return *this;
130  }
132  MaxwellVector& operator =(const Eigen::VectorXd& other) {
133  u = other;
134  return *this;
135  }
137  Eigen::VectorBlock<Eigen::VectorXd> h()
138  {
139  return u.head(offsetG);
140  }
142  Eigen::VectorBlock<Eigen::VectorXd> G()
143  {
144  return u.segment(offsetG,sizeG);
145  }
147  Eigen::VectorBlock<Eigen::VectorXd> E()
148  {
149  return u.segment(offsetE,sizeE);
150  }
152  Eigen::VectorBlock<Eigen::VectorXd> B()
153  {
154  return u.segment(offsetB,sizeB);
155  }
156  Eigen::VectorXd u;
159  };
161 
162  MaxwellProblem::MaxwellProblem(const Mesh<2> &mesh,int degree, double dt, bool use_threads, std::array<int,2> const *dqr, std::ostream &output)
163  : _ddrcore(mesh,degree,use_threads,dqr, output), _dt(dt), _use_threads(use_threads), _output(output), _rhs(dimensionSystem())
164  {
165  auto oneFunc = [](size_t , const Eigen::Vector<double,2> &)->Eigen::Vector<double,1> {
166  return Eigen::Vector<double,1>{1.};
167  };
168  _interpOne = _ddrcore.template interpolate<0>(oneFunc,dqr);
169  assembleSystem();
170  }
171 
173  void MaxwellProblem::assembleLocalContribution(Eigen::Ref<const Eigen::MatrixXd> const & A, size_t iT, size_t kL, size_t kR,
174  std::forward_list<Eigen::Triplet<double>> * triplets) const
175  {
176  size_t gOffsetL = dimensionH(), gOffsetR = dimensionH();
177  // Initialise the global offsets
178  switch(kL) {
179  case 2:
180  gOffsetL += dimensionE();
181  case 1:
182  gOffsetL += dimensionG();
183  default:
184  ;
185  }
186  switch(kR) {
187  case 2:
188  gOffsetR += dimensionE();
189  case 1:
190  gOffsetR += dimensionG();
191  default:
192  ;
193  }
194  for (size_t iDL = 0; iDL <= 2; ++iDL) { // Iterate dimensions on the left
195  const size_t nbLDofsL = _ddrcore.dofspace(kL).numLocalDofs(iDL);
196  if (nbLDofsL == 0) continue;
197  std::vector<size_t> const & boundariesL = _ddrcore.mesh()->get_boundary(iDL,2,iT);
198  for (size_t iDR = 0; iDR <= 2; ++iDR) { // Iterate dimensions on the right
199  const size_t nbLDofsR = _ddrcore.dofspace(kR).numLocalDofs(iDR);
200  if (nbLDofsR == 0) continue;
201  std::vector<size_t> const & boundariesR = _ddrcore.mesh()->get_boundary(iDR,2,iT);
202  for (size_t iFL = 0; iFL < boundariesL.size(); ++iFL) { // Iterate cells on the left
203  const size_t offsetL = gOffsetL + _ddrcore.dofspace(kL).globalOffset(iDL,boundariesL[iFL]);
204  const size_t lOffsetL = _ddrcore.dofspace(kL).localOffset(iDL,2,iFL,iT);
205  for (size_t iFR = 0; iFR < boundariesR.size(); ++iFR) { // Iterate cells on the right
206  const size_t offsetR = gOffsetR + _ddrcore.dofspace(kR).globalOffset(iDR,boundariesR[iFR]);
207  const size_t lOffsetR = _ddrcore.dofspace(kR).localOffset(iDR,2,iFR,iT);
208  for (size_t iRow = 0; iRow < nbLDofsL; ++iRow) { // Iterate local dofs
209  for (size_t iCol = 0; iCol < nbLDofsR; ++iCol) { // Iterate local dofs
210  triplets->emplace_front(offsetL + iRow,offsetR + iCol,A(lOffsetL + iRow,lOffsetR + iCol));
211  } // iCol
212  } // iRow
213  } // iFR
214  } // iFL
215  } // iDR
216  } // iDL
217  };
218 
219  void MaxwellProblem::assembleLocalContributionH(Eigen::Ref<const Eigen::MatrixXd> const & A, size_t iT, size_t k, std::forward_list<Eigen::Triplet<double>> * triplets) const
220  {
221  assert(A.cols() == 1 && "Expected only 1 harmonic form");
222  size_t gOffset = dimensionH();
223  // Initialise the global offsets
224  switch(k) {
225  case 2:
226  gOffset += dimensionE();
227  case 1:
228  gOffset += dimensionG();
229  default:
230  ;
231  }
232  for (size_t iD = 0; iD <= 2; ++iD) { // Iterate dimensions on the left
233  const size_t nbLDofs = _ddrcore.dofspace(k).numLocalDofs(iD);
234  if (nbLDofs == 0) continue;
235  std::vector<size_t> const & boundaries = _ddrcore.mesh()->get_boundary(iD,2,iT);
236  for (size_t iF = 0; iF < boundaries.size(); ++iF) { // Iterate cells on the left
237  const size_t offset = gOffset + _ddrcore.dofspace(k).globalOffset(iD,boundaries[iF]);
238  const size_t lOffset = _ddrcore.dofspace(k).localOffset(iD,2,iF,iT);
239  for (size_t iRow = 0; iRow < nbLDofs; ++iRow) { // Iterate local dofs
240  triplets->emplace_front(offset+iRow,0,A(lOffset+iRow,0));
241  triplets->emplace_front(0,offset+iRow,A(lOffset+iRow,0));
242  } // iRow
243  } // iF
244  } // iD
245  };
246 
247  void MaxwellProblem::assembleLocalContribution(Eigen::Ref<const Eigen::VectorXd> const & R, size_t iT, size_t k)
248  {
249  size_t gOffset = dimensionH();
250  // Initialise the global offsets
251  switch(k) {
252  case 2:
253  gOffset += dimensionE();
254  case 1:
255  gOffset += dimensionG();
256  default:
257  ;
258  }
259  for (size_t iD = 0; iD <= 2; ++iD) { // Iterate dimensions on the left
260  const size_t nbLDofs = _ddrcore.dofspace(k).numLocalDofs(iD);
261  if (nbLDofs == 0) continue;
262  std::vector<size_t> const & boundaries = _ddrcore.mesh()->get_boundary(iD,2,iT);
263  for (size_t iF = 0; iF < boundaries.size(); ++iF) { // Iterate cells on the left
264  const size_t offset = gOffset + _ddrcore.dofspace(k).globalOffset(iD,boundaries[iF]);
265  const size_t lOffset = _ddrcore.dofspace(k).localOffset(iD,2,iF,iT);
266  for (size_t iRow = 0; iRow < nbLDofs; ++iRow) { // Iterate local dofs
267  std::atomic_ref<double> atomicRHS(_rhs[offset+iRow]); // Prevent race condition when using several thread
268  atomicRHS.fetch_add(R(lOffset+iRow),std::memory_order_relaxed); // Only requires the atomicity of the addition
269  } // iRow
270  } // iF
271  } // iD
272  };
273 
274  void MaxwellProblem::assembleSystem()
275  {
276  const size_t nb_cell = _ddrcore.mesh()->n_cells(2);
277 #ifdef THREEFIELDS
278  std::vector<Eigen::MatrixXd> ALoc0h(nb_cell);
279  std::vector<Eigen::MatrixXd> ALoc01(nb_cell);
280 #endif
281  std::vector<Eigen::MatrixXd> ALoc12(nb_cell);
282 #ifdef THREEFIELDS
283  _ALoc00.resize(nb_cell);
284 #endif
285  _ALoc11.resize(nb_cell);
286  _ALoc22.resize(nb_cell);
287  std::function<void(size_t start, size_t end)> assemble_local = [&](size_t start, size_t end)->void {
288  for (size_t iT = start; iT < end; iT++) {
289 #ifdef THREEFIELDS
290  Eigen::MatrixXd loc00 = _ddrcore.computeL2Product(0,iT);
291 #endif
292  Eigen::MatrixXd loc11 = _ddrcore.computeL2Product(1,iT);
293  Eigen::MatrixXd loc22 = _ddrcore.computeL2Product(2,iT);
294 #ifdef THREEFIELDS
295  Eigen::MatrixXd loc0h = loc00*_ddrcore.dofspace(0).restrict(2,iT,_interpOne);
296  Eigen::MatrixXd loc01 = _ddrcore.compose_diff(0,2,iT).transpose()*loc11;
297 #endif
298  Eigen::MatrixXd loc12 = _ddrcore.compose_diff(1,2,iT).transpose()*loc22;
299 #ifdef THREEFIELDS
300  ALoc0h[iT] = loc0h;
301  ALoc01[iT] = loc01;
302 #endif
303  ALoc12[iT] = loc12;
304 #ifdef THREEFIELDS
305  _ALoc00[iT] = loc00;
306 #endif
307  _ALoc11[iT] = loc11;
308  _ALoc22[iT] = loc22;
309  }
310  };
311  _output<< "[MaxwellProblem] Assembling local contributions..."<<std::flush;
312  parallel_for(nb_cell,assemble_local,_use_threads);
313  _output<<"\r[MaxwellProblem] Assembled local contributions "<<std::endl;
314 
315  auto batch_local_assembly = [&](size_t start, size_t end, std::forward_list<Eigen::Triplet<double>> * triplets)->void {
316  for (size_t iT = start; iT < end; iT++) {
317 #ifdef THREEFIELDS
318  assembleLocalContributionH(ALoc0h[iT],iT,0,triplets);
319  assembleLocalContribution(ALoc01[iT],iT,0,1,triplets); // Constraint <E,dv0>
320  assembleLocalContribution(ALoc01[iT].transpose(),iT,1,0,triplets); // Constraint <dA,v1>
321 #endif
322  assembleLocalContribution(0.5*_dt*ALoc12[iT],iT,1,2,triplets); // <dE,v2>
323  assembleLocalContribution(0.5*_dt*ALoc12[iT].transpose(),iT,2,1,triplets); // <B,dv1>
324  assembleLocalContribution(-1.*_ALoc11[iT],iT,1,1,triplets); // -<E,v1>
325  assembleLocalContribution(_ALoc22[iT],iT,2,2,triplets); // <B,v2>
326  }
327  };
328  _output<< "[MaxwellProblem] Assembling global system from local contributions..."<<std::flush;
329  _system = parallel_assembly(nb_cell,std::make_pair(dimensionSystem(),dimensionSystem()),
330  batch_local_assembly,_use_threads);
331  _output<<"\r[MaxwellProblem] Assembled global system from local contributions "<<std::endl;
332  };
333 
334  void MaxwellProblem::assembleRHS(Eigen::Ref<const Eigen::VectorXd> const & rho, Eigen::Ref<const Eigen::VectorXd> const & J,Eigen::Ref<const Eigen::VectorXd> const & EOld, Eigen::Ref<const Eigen::VectorXd> const & BOld)
335  {
336  auto batch_local_assembly = [&](size_t start,size_t end)->void {
337  for (size_t iT = start; iT < end; ++iT) {
338  Eigen::VectorXd loc;
339 #ifdef THREEFIELDS
340  // 0 forms
341  assert(rho.size() == dimensionG() && "Incorrect size of rho");
342  loc = -_ALoc00[iT]*_ddrcore.dofspace(0).restrict(2,iT,rho);
343  assembleLocalContribution(loc,iT,0);
344 #endif
345  // 1 forms
346  assert(J.size() == dimensionE() && "Incorrect size of J");
347  assert(EOld.size() == dimensionE() && "Incorrect size of EOld");
348  loc = _ALoc11[iT]*_ddrcore.dofspace(1).restrict(2,iT,_dt*J - EOld);
349  loc -= 0.5*_dt*_ddrcore.compose_diff(1,2,iT).transpose()*_ALoc22[iT]*_ddrcore.dofspace(2).restrict(2,iT,BOld);
350  assembleLocalContribution(loc,iT,1);
351  // 2 forms
352  assert(BOld.size() == dimensionB() && "Incorrect size of BOld");
353  loc = _ALoc22[iT]*_ddrcore.dofspace(2).restrict(2,iT,BOld);
354  loc -= 0.5*_dt*_ALoc22[iT]*_ddrcore.compose_diff(1,2,iT)*_ddrcore.dofspace(1).restrict(2,iT,EOld);
355  assembleLocalContribution(loc,iT,2);
356  }
357  };
358  _output<< "[MaxwellProblem] Assembling RHS..."<<std::flush;
359  _rhs.setZero();
360  parallel_for(_ddrcore.mesh()->n_cells(2),batch_local_assembly,_use_threads);
361  _output<<"\r[MaxwellProblem] Assembled RHS "<<std::endl;
362  };
363 
364  bool MaxwellProblem::validateSolution(Eigen::Ref<const Eigen::VectorXd> const &u) const
365  {
366  double const err = (_system*u - _rhs).norm()/_rhs.norm();
367  if (err > 1e-5) {
368  std::cerr<<"[MaxwellProblem] The relative error on the solution is "<<err<<". This could indicate that the solver silently failed"<<std::endl;
369  return false;
370  }
371  return true;
372  }
374  _output << "[MaxwellProblem] Setting solver "<<SolverName<<" with "<<dimensionSystem()<<" degrees of freedom"<<std::endl;
375  SystemMatrixType systemScaled = _system;
376  Eigen::IterScaling<SystemMatrixType> iterScaling;
377  iterScaling.computeRef(systemScaled);
378  _scalingL = iterScaling.LeftScaling();
379  _scalingR = iterScaling.RightScaling();
380  _solver.compute(systemScaled);
381  if (_solver.info() != Eigen::Success) {
382  std::cerr << "[MaxwellProblem] Failed to factorize the system" << std::endl;
383  throw std::runtime_error("Factorization failed");
384  }
385  }
386  Eigen::VectorXd MaxwellProblem::solve() {
387  Eigen::VectorXd scaledRhs = _rhs.cwiseProduct(_scalingR);
388  Eigen::VectorXd u = _solver.solve(scaledRhs);
389  u = u.cwiseProduct(_scalingL);
390  if (_solver.info() != Eigen::Success) {
391  std::cerr << "[MaxwellProblem] Failed to solve the system" << std::endl;
392  throw std::runtime_error("Solver failed");
393  }
394  validateSolution(u);
395  return u;
396  }
397 
398  Eigen::VectorXd MaxwellProblem::solve(const Eigen::VectorXd &rhs) {
399  Eigen::VectorXd scaledRhs = rhs.cwiseProduct(_scalingR);
400  Eigen::VectorXd u = _solver.solve(scaledRhs);
401  u = u.cwiseProduct(_scalingL);
402  if (_solver.info() != Eigen::Success) {
403  std::cerr << "[MaxwellProblem] Failed to solve the system" << std::endl;
404  throw std::runtime_error("Solver failed");
405  }
406  validateSolution(u);
407  return u;
408  }
409 
410  template<typename Derived>
411  double MaxwellProblem::norm(Eigen::MatrixBase<Derived> const &E, size_t k) const
412  {
413  assert(E.size() == _ddrcore.dofspace(k).dimensionMesh() && "Mismatched dimension, wrong form degree?");
414  const size_t nb_cell = _ddrcore.mesh()->n_cells(2);
415  std::vector<double> accErr(nb_cell);
416  std::function<void(size_t start, size_t end)> compute_local = [&](size_t start, size_t end)->void {
417  for (size_t iT = start; iT < end; ++iT){
418  Eigen::VectorXd locE = _ddrcore.dofspace(k).restrict(2,iT,E);
419  Eigen::MatrixXd matL2;
420  switch(k) {
421 #ifdef THREEFIELDS
422  case 0:
423  matL2 = _ALoc00[iT];
424  break;
425 #endif
426  case 1:
427  matL2 = _ALoc11[iT];
428  break;
429  case 2:
430  matL2 = _ALoc22[iT];
431  break;
432  default:
433  ;
434  }
435  accErr[iT] = locE.dot(matL2*locE);
436  }
437  };
438  parallel_for(nb_cell,compute_local,_use_threads);
439  double acc = 0;
440  for (double err : accErr) {
441  acc += err;
442  }
443  return std::sqrt(acc);
444  }
445 
446  template<typename Derived>
447  double MaxwellProblem::normd(Eigen::MatrixBase<Derived> const &E,size_t k) const
448  {
449  if (k == 2) return 0.;
450  assert(E.size() == _ddrcore.dofspace(k).dimensionMesh() && "Mismatched dimension, wrong form degree?");
451  const size_t nb_cell = _ddrcore.mesh()->n_cells(2);
452  std::vector<double> accErr(nb_cell);
453  std::function<void(size_t start, size_t end)> compute_local = [&](size_t start, size_t end)->void {
454  for (size_t iT = start; iT < end; ++iT){
455  Eigen::VectorXd locE = _ddrcore.compose_diff(k,2,iT)*_ddrcore.dofspace(k).restrict(2,iT,E);
456  Eigen::MatrixXd matL2;
457  switch(k) {
458 #ifdef THREEFIELDS
459  case 0:
460  matL2 = _ALoc11[iT];
461  break;
462 #endif
463  case 1:
464  matL2 = _ALoc22[iT];
465  break;
466  default:
467  ;
468  }
469  accErr[iT] = locE.dot(matL2*locE);
470  }
471  };
472  parallel_for(nb_cell,compute_local,_use_threads);
473  double acc = 0;
474  for (double err : accErr) {
475  acc += err;
476  }
477  return std::sqrt(acc);
478  }
479 
480 }; // Namespace
481 #endif
482 
Eigen::MatrixXd computeL2Product(size_t k, size_t i_cell) const
Compute the local product (including the cell boundary)
Definition: ddr_spaces.cpp:272
const Mesh< dimension > * mesh() const
Return the Mesh associated with the class.
Definition: ddr_spaces.hpp:72
DOFSpace< dimension > const & dofspace(size_t k) const
Return DOFSpace associated to k forms.
Definition: ddr_spaces.hpp:68
Eigen::MatrixXd compose_diff(size_t k, size_t d, size_t i_cell) const
Compute the projected differential operator.
Definition: ddr_spaces.cpp:248
2 dimensional Maxwell equation on a manifold without boundary
Definition: maxwell.hpp:29
void compute()
Setup the solver.
Definition: maxwell.hpp:373
double normd(Eigen::MatrixBase< Derived > const &E, size_t k) const
Compute the discrete norm of the differential of a -form.
Definition: maxwell.hpp:447
static constexpr std::string_view SolverName
Name of the solver.
Definition: maxwell.hpp:36
size_t dimensionG() const
Return the number of unknowns attached to the space of 0 forms.
Definition: maxwell.hpp:55
Eigen::VectorXd solve()
Solve the system and return the solution.
Definition: maxwell.hpp:386
void assembleRHS(Eigen::Ref< const Eigen::VectorXd > const &rho, Eigen::Ref< const Eigen::VectorXd > const &J, Eigen::Ref< const Eigen::VectorXd > const &EOld, Eigen::Ref< const Eigen::VectorXd > const &BOld)
Assemble the Right-Hand side from the given interpolates.
Definition: maxwell.hpp:334
size_t dimensionH() const
Return the number of unknowns attached to the space of harmonic 0 forms.
Definition: maxwell.hpp:49
Eigen::SparseLU< SystemMatrixType, Eigen::COLAMDOrdering< int > > SolverType
Type used to store the solver.
Definition: maxwell.hpp:34
Eigen::SparseMatrix< double > SystemMatrixType
Type used to store the system.
Definition: maxwell.hpp:32
size_t dimensionE() const
Return the number of unknowns attached to the space of 1 forms.
Definition: maxwell.hpp:58
size_t dimensionB() const
Return the number of unknowns attached to the space of 2 forms.
Definition: maxwell.hpp:60
size_t dimensionSystem() const
Return the total number of unknowns.
Definition: maxwell.hpp:62
double timeStep() const
Return the time-step.
Definition: maxwell.hpp:67
double norm(Eigen::MatrixBase< Derived > const &E, size_t k) const
Compute the discrete norm of a -form.
Definition: maxwell.hpp:411
DDR_Spaces< 2 > const & ddrcore() const
Return the associated DDR_Spaces.
Definition: maxwell.hpp:65
bool validateSolution(Eigen::Ref< const Eigen::VectorXd > const &u) const
Check if the vector u if a solution up to a given relative accuracy.
Definition: maxwell.hpp:364
MaxwellProblem(const Mesh< 2 > &mesh, int degree, double timestep, bool use_threads=true, std::array< int, 2 > const *dqr=nullptr, std::ostream &output=std::cout)
Definition: maxwell.hpp:162
Main data structure for the mesh.
Definition: mesh.hpp:54
Discrete operators for DDR-PEC.
Definition: maxwell.hpp:21
static void parallel_for(unsigned nb_elements, std::function< void(size_t start, size_t end)> functor, bool use_threads=true)
Generic function to execute threaded processes.
Definition: parallel_for.hpp:42
Eigen::SparseMatrix< double > parallel_assembly(size_t nb_elements, std::pair< size_t, size_t > systemSize, FType localAssembly, bool use_threads=true)
Function to assemble a global sparse matrix from a procedure that compute local contributions.
Definition: parallel_for.hpp:74
Helper to parallelize operations using pthreads.
Construct a convenient wrapper around a vector of global unknowns to manipulate individual components...
Definition: maxwell.hpp:122
int offsetG
Definition: maxwell.hpp:158
Eigen::VectorBlock< Eigen::VectorXd > E()
Return the electric part.
Definition: maxwell.hpp:147
MaxwellVector & operator=(const MaxwellVector &other)
Copy another MaxwellVector.
Definition: maxwell.hpp:127
int offsetE
Definition: maxwell.hpp:158
int sizeE
Definition: maxwell.hpp:157
Eigen::VectorXd u
Definition: maxwell.hpp:156
int sizeB
Definition: maxwell.hpp:157
int sizeG
Definition: maxwell.hpp:157
Eigen::VectorBlock< Eigen::VectorXd > B()
Return the magnetic part.
Definition: maxwell.hpp:152
Eigen::VectorBlock< Eigen::VectorXd > h()
Return the harmonic part.
Definition: maxwell.hpp:137
int offsetB
Definition: maxwell.hpp:158
MaxwellVector(MaxwellProblem const &maxwell)
Definition: maxwell.hpp:123
Eigen::VectorBlock< Eigen::VectorXd > G()
Return the ghost part.
Definition: maxwell.hpp:142