MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
complex_fem.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12#include "complex_fem.hpp"
13#include "../general/forall.hpp"
14#include "../general/text.hpp"
15
16using namespace std;
17
18namespace mfem
19{
20
22 : Vector(2*(f->GetVSize())), fes(f), fec_owned(NULL)
23{
24 UseDevice(true);
25 this->Vector::operator=(0.0);
26
27 gfr = new GridFunction();
28 gfr->MakeRef(fes, *this, 0);
29
30 gfi = new GridFunction();
31 gfi->MakeRef(fes, *this, fes->GetVSize());
32
34}
35
37 : Vector(), fes(NULL), fec_owned(NULL)
38{
39 string buff;
40
41 // Grid functions are stored on the device
42 UseDevice(true);
43
44 input >> std::ws;
45 getline(input, buff); // 'ComplexGridFunction'
46 filter_dos(buff);
47 if (buff != "ComplexGridFunction")
48 {
49 MFEM_ABORT("unrecognized file header: " << buff);
50 }
51
53 fec_owned = fes->Load(m, input);
54
55 skip_comment_lines(input, '#');
56 istream::int_type next_char = input.peek();
57 if (next_char == 'N') // First letter of "NURBS_patches"
58 {
59 getline(input, buff);
60 filter_dos(buff);
61 if (buff == "NURBS_patches")
62 {
63 MFEM_ABORT("NURBS not yet supported with ComplexGridFunction objects");
64 }
65 else
66 {
67 MFEM_ABORT("unknown section: " << buff);
68 }
69 }
70 else
71 {
72 Vector::Load(input, 2*fes->GetVSize());
73
74 // if the mesh is a legacy (v1.1) NC mesh, it has old vertex ordering
75 if (fes->Nonconforming() &&
77 {
78 // LegacyNCReorder();
79 MFEM_ABORT("LegacyNCReorder not supported for "
80 "ComplexGridFunction objects");
81 }
82 }
83
84 gfr = new GridFunction();
85 gfr->MakeRef(fes, *this, 0);
86
87 gfi = new GridFunction();
88 gfi->MakeRef(fes, *this, fes->GetVSize());
89
91}
92
94{
95 delete gfr; delete gfi;
96
97 if (fec_owned)
98 {
99 delete fes;
100 delete fec_owned;
101 fec_owned = NULL;
102 }
103}
104
105void
107{
108 if (fes->GetSequence() == fes_sequence)
109 {
110 return; // space and grid function are in sync, no-op
111 }
113
114 const int vsize = fes->GetVSize();
115
116 const Operator *T = fes->GetUpdateOperator();
117 if (T)
118 {
119 // Update the individual GridFunction objects. This will allocate new data
120 // arrays for each GridFunction.
121 gfr->Update();
122 gfi->Update();
123
124 // Our data array now contains old data as well as being the wrong size so
125 // reallocate it.
126 UseDevice(true);
127 this->SetSize(2 * vsize);
128 this->Vector::operator=(0.0);
129
130 // Create temporary vectors which point to the new data array
131 Vector gf_r; gf_r.MakeRef(*this, 0, vsize);
132 Vector gf_i; gf_i.MakeRef(*this, vsize, vsize);
133
134 // Copy the updated GridFunctions into the new data array
135 gf_r = *gfr;
136 gf_i = *gfi;
137 gf_r.SyncAliasMemory(*this);
138 gf_i.SyncAliasMemory(*this);
139
140 // Replace the individual data arrays with pointers into the new data
141 // array
142 gfr->MakeRef(*this, 0, vsize);
143 gfi->MakeRef(*this, vsize, vsize);
144 }
145 else
146 {
147 // The existing data will not be transferred to the new GridFunctions so
148 // delete it and allocate a new array
149 UseDevice(true);
150 this->SetSize(2 * vsize);
151 this->Vector::operator=(0.0);
152
153 // Point the individual GridFunctions to the new data array
154 gfr->MakeRef(*this, 0, vsize);
155 gfi->MakeRef(*this, vsize, vsize);
156
157 // These updates will only set the proper 'sequence' value within the
158 // individual GridFunction objects because their sizes are already correct
159 gfr->Update();
160 gfi->Update();
161 }
162}
163
165{
166 const FiniteElement *fe = fes->GetTypicalFE();
167 if (!fe || fe->GetRangeType() == FiniteElement::SCALAR)
168 {
169 return fes->GetVDim();
170 }
171 return fes->GetVDim()*std::max(fes->GetMesh()->SpaceDimension(),
172 fe->GetRangeDim());
173}
174
175void
177 Coefficient &imag_coeff)
178{
179 gfr->SyncMemory(*this);
180 gfi->SyncMemory(*this);
181 gfr->ProjectCoefficient(real_coeff);
182 gfi->ProjectCoefficient(imag_coeff);
183 gfr->SyncAliasMemory(*this);
184 gfi->SyncAliasMemory(*this);
185}
186
187void
189 VectorCoefficient &imag_vcoeff)
190{
191 gfr->SyncMemory(*this);
192 gfi->SyncMemory(*this);
193 gfr->ProjectCoefficient(real_vcoeff);
194 gfi->ProjectCoefficient(imag_vcoeff);
195 gfr->SyncAliasMemory(*this);
196 gfi->SyncAliasMemory(*this);
197}
198
199void
201 Coefficient &imag_coeff,
202 Array<int> &attr)
203{
204 gfr->SyncMemory(*this);
205 gfi->SyncMemory(*this);
206 gfr->ProjectBdrCoefficient(real_coeff, attr);
207 gfi->ProjectBdrCoefficient(imag_coeff, attr);
208 gfr->SyncAliasMemory(*this);
209 gfi->SyncAliasMemory(*this);
210}
211
212void
214 VectorCoefficient &imag_vcoeff,
215 Array<int> &attr)
216{
217 gfr->SyncMemory(*this);
218 gfi->SyncMemory(*this);
219 gfr->ProjectBdrCoefficientNormal(real_vcoeff, attr);
220 gfi->ProjectBdrCoefficientNormal(imag_vcoeff, attr);
221 gfr->SyncAliasMemory(*this);
222 gfi->SyncAliasMemory(*this);
223}
224
225void
227 &real_vcoeff,
229 &imag_vcoeff,
230 Array<int> &attr)
231{
232 gfr->SyncMemory(*this);
233 gfi->SyncMemory(*this);
234 gfr->ProjectBdrCoefficientTangent(real_vcoeff, attr);
235 gfi->ProjectBdrCoefficientTangent(imag_vcoeff, attr);
236 gfr->SyncAliasMemory(*this);
237 gfi->SyncAliasMemory(*this);
238}
239
240void ComplexGridFunction::Save(std::ostream &os) const
241{
242 os << "ComplexGridFunction\n";
243 fes->Save(os);
244 os << '\n';
246 {
247 Vector::Print(os, 1);
248 }
249 else
250 {
251 Vector::Print(os, fes->GetVDim());
252 }
253 os.flush();
254}
255
256void ComplexGridFunction::Save(const char *fname, int precision) const
257{
258 ofstream ofs(fname);
259 ofs.precision(precision);
260 Save(ofs);
261}
262
263std::ostream &operator<<(std::ostream &os, const ComplexGridFunction &sol)
264{
265 sol.Save(os);
266 return os;
267}
268
269
272 : Vector(2*(fes->GetVSize())),
273 conv(convention)
274{
275 UseDevice(true);
276 this->Vector::operator=(0.0);
277
278 lfr = new LinearForm();
279 lfr->MakeRef(fes, *this, 0);
280
281 lfi = new LinearForm();
282 lfi->MakeRef(fes, *this, fes->GetVSize());
283}
284
286 LinearForm *lf_r, LinearForm *lf_i,
288 : Vector(2*(fes->GetVSize())),
289 conv(convention)
290{
291 UseDevice(true);
292 this->Vector::operator=(0.0);
293
294 lfr = new LinearForm(fes, lf_r);
295 lfi = new LinearForm(fes, lf_i);
296
297 lfr->MakeRef(fes, *this, 0);
298 lfi->MakeRef(fes, *this, fes->GetVSize());
299}
300
302{
303 delete lfr;
304 delete lfi;
305}
306
307void
309 LinearFormIntegrator *lfi_imag)
310{
311 if ( lfi_real ) { lfr->AddDomainIntegrator(lfi_real); }
312 if ( lfi_imag ) { lfi->AddDomainIntegrator(lfi_imag); }
313}
314
315void
317 LinearFormIntegrator *lfi_imag,
318 Array<int> &elem_attr_marker)
319{
320 if ( lfi_real ) { lfr->AddDomainIntegrator(lfi_real, elem_attr_marker); }
321 if ( lfi_imag ) { lfi->AddDomainIntegrator(lfi_imag, elem_attr_marker); }
322}
323
324void
326 LinearFormIntegrator *lfi_imag)
327{
328 if ( lfi_real ) { lfr->AddBoundaryIntegrator(lfi_real); }
329 if ( lfi_imag ) { lfi->AddBoundaryIntegrator(lfi_imag); }
330}
331
332void
334 LinearFormIntegrator *lfi_imag,
335 Array<int> &bdr_attr_marker)
336{
337 if ( lfi_real ) { lfr->AddBoundaryIntegrator(lfi_real, bdr_attr_marker); }
338 if ( lfi_imag ) { lfi->AddBoundaryIntegrator(lfi_imag, bdr_attr_marker); }
339}
340
341void
343 LinearFormIntegrator *lfi_imag)
344{
345 if ( lfi_real ) { lfr->AddBdrFaceIntegrator(lfi_real); }
346 if ( lfi_imag ) { lfi->AddBdrFaceIntegrator(lfi_imag); }
347}
348
349void
351 LinearFormIntegrator *lfi_imag,
352 Array<int> &bdr_attr_marker)
353{
354 if ( lfi_real ) { lfr->AddBdrFaceIntegrator(lfi_real, bdr_attr_marker); }
355 if ( lfi_imag ) { lfi->AddBdrFaceIntegrator(lfi_imag, bdr_attr_marker); }
356}
357
358void
360{
362 this->Update(fes);
363}
364
365void
367{
368 UseDevice(true);
369 SetSize(2 * fes->GetVSize());
370 this->Vector::operator=(0.0);
371
372 lfr->MakeRef(fes, *this, 0);
373 lfi->MakeRef(fes, *this, fes->GetVSize());
374}
375
376void
378{
379 lfr->SyncMemory(*this);
380 lfi->SyncMemory(*this);
381 lfr->Assemble();
382 lfi->Assemble();
383 if (conv == ComplexOperator::BLOCK_SYMMETRIC) { *lfi *= -1.0; }
384 lfr->SyncAliasMemory(*this);
385 lfi->SyncAliasMemory(*this);
386}
387
388complex<real_t>
390{
391 real_t s = (conv == ComplexOperator::HERMITIAN) ? 1.0 : -1.0;
392 lfr->SyncMemory(*this);
393 lfi->SyncMemory(*this);
394 return complex<real_t>((*lfr)(gf.real()) - s * (*lfi)(gf.imag()),
395 (*lfr)(gf.imag()) + s * (*lfi)(gf.real()));
396}
397
398
399bool SesquilinearForm::RealInteg()
400{
401 int nint = blfr->GetFBFI()->Size() + blfr->GetDBFI()->Size() +
402 blfr->GetBBFI()->Size() + blfr->GetBFBFI()->Size();
403 return (nint != 0);
404}
405
406bool SesquilinearForm::ImagInteg()
407{
408 int nint = blfi->GetFBFI()->Size() + blfi->GetDBFI()->Size() +
409 blfi->GetBBFI()->Size() + blfi->GetBFBFI()->Size();
410 return (nint != 0);
411}
412
415 : conv(convention),
416 blfr(new BilinearForm(f)),
417 blfi(new BilinearForm(f))
418{}
419
421 BilinearForm *bfr, BilinearForm *bfi,
423 : conv(convention),
424 blfr(new BilinearForm(f,bfr)),
425 blfi(new BilinearForm(f,bfi))
426{}
427
429{
430 diag_policy = dpolicy;
431}
432
434{
435 delete blfr;
436 delete blfi;
437}
438
440 BilinearFormIntegrator *bfi_imag)
441{
442 if (bfi_real) { blfr->AddDomainIntegrator(bfi_real); }
443 if (bfi_imag) { blfi->AddDomainIntegrator(bfi_imag); }
444}
445
447 BilinearFormIntegrator *bfi_imag,
448 Array<int> & elem_marker)
449{
450 if (bfi_real) { blfr->AddDomainIntegrator(bfi_real, elem_marker); }
451 if (bfi_imag) { blfi->AddDomainIntegrator(bfi_imag, elem_marker); }
452}
453
454void
456 BilinearFormIntegrator *bfi_imag)
457{
458 if (bfi_real) { blfr->AddBoundaryIntegrator(bfi_real); }
459 if (bfi_imag) { blfi->AddBoundaryIntegrator(bfi_imag); }
460}
461
462void
464 BilinearFormIntegrator *bfi_imag,
465 Array<int> & bdr_marker)
466{
467 if (bfi_real) { blfr->AddBoundaryIntegrator(bfi_real, bdr_marker); }
468 if (bfi_imag) { blfi->AddBoundaryIntegrator(bfi_imag, bdr_marker); }
469}
470
471void
473 BilinearFormIntegrator *bfi_imag)
474{
475 if (bfi_real) { blfr->AddInteriorFaceIntegrator(bfi_real); }
476 if (bfi_imag) { blfi->AddInteriorFaceIntegrator(bfi_imag); }
477}
478
480 BilinearFormIntegrator *bfi_imag)
481{
482 if (bfi_real) { blfr->AddBdrFaceIntegrator(bfi_real); }
483 if (bfi_imag) { blfi->AddBdrFaceIntegrator(bfi_imag); }
484}
485
487 BilinearFormIntegrator *bfi_imag,
488 Array<int> &bdr_marker)
489{
490 if (bfi_real) { blfr->AddBdrFaceIntegrator(bfi_real, bdr_marker); }
491 if (bfi_imag) { blfi->AddBdrFaceIntegrator(bfi_imag, bdr_marker); }
492}
493
494void
496{
497 blfr->Assemble(skip_zeros);
498 blfi->Assemble(skip_zeros);
499}
500
501void
503{
504 blfr->Finalize(skip_zeros);
505 blfi->Finalize(skip_zeros);
506}
507
510{
511 return new ComplexSparseMatrix(&blfr->SpMat(),
512 &blfi->SpMat(),
513 false, false, conv);
514}
515
516void
518 Vector &x, Vector &b,
520 Vector &X, Vector &B,
521 int ci)
522{
523 FiniteElementSpace *fes = blfr->FESpace();
524 const int vsize = fes->GetVSize();
525
526 // Allocate temporary vector
527 Vector b_0;
528 b_0.UseDevice(true);
529 b_0.SetSize(vsize);
530 b_0 = 0.0;
531
532 // Extract the real and imaginary parts of the input vectors
533 MFEM_ASSERT(x.Size() == 2 * vsize, "Input GridFunction of incorrect size!");
534 x.Read();
535 Vector x_r; x_r.MakeRef(x, 0, vsize);
536 Vector x_i; x_i.MakeRef(x, vsize, vsize);
537
538 MFEM_ASSERT(b.Size() == 2 * vsize, "Input LinearForm of incorrect size!");
539 b.Read();
540 Vector b_r; b_r.MakeRef(b, 0, vsize);
541 Vector b_i; b_i.MakeRef(b, vsize, vsize);
542
543 if (conv == ComplexOperator::BLOCK_SYMMETRIC) { b_i *= -1.0; }
544
545 const int tvsize = fes->GetTrueVSize();
546 OperatorHandle A_r, A_i;
547
548 X.UseDevice(true);
549 X.SetSize(2 * tvsize);
550 X = 0.0;
551
552 B.UseDevice(true);
553 B.SetSize(2 * tvsize);
554 B = 0.0;
555
556 Vector X_r; X_r.MakeRef(X, 0, tvsize);
557 Vector X_i; X_i.MakeRef(X, tvsize, tvsize);
558 Vector B_r; B_r.MakeRef(B, 0, tvsize);
559 Vector B_i; B_i.MakeRef(B, tvsize, tvsize);
560
561 Vector X_0, B_0;
562
563 if (RealInteg())
564 {
565 blfr->SetDiagonalPolicy(diag_policy);
566
567 b_0 = b_r;
568 blfr->FormLinearSystem(ess_tdof_list, x_r, b_0, A_r, X_0, B_0, ci);
569 X_r = X_0; B_r = B_0;
570
571 b_0 = b_i;
572 blfr->FormLinearSystem(ess_tdof_list, x_i, b_0, A_r, X_0, B_0, ci);
573 X_i = X_0; B_i = B_0;
574
575 if (ImagInteg())
576 {
578
579 b_0 = 0.0;
580 blfi->FormLinearSystem(ess_tdof_list, x_i, b_0, A_i, X_0, B_0, false);
581 B_r -= B_0;
582
583 b_0 = 0.0;
584 blfi->FormLinearSystem(ess_tdof_list, x_r, b_0, A_i, X_0, B_0, false);
585 B_i += B_0;
586 }
587 }
588 else if (ImagInteg())
589 {
590 blfi->SetDiagonalPolicy(diag_policy);
591
592 b_0 = b_i;
593 blfi->FormLinearSystem(ess_tdof_list, x_r, b_0, A_i, X_0, B_0, ci);
594 X_r = X_0; B_i = B_0;
595
596 b_0 = b_r; b_0 *= -1.0;
597 blfi->FormLinearSystem(ess_tdof_list, x_i, b_0, A_i, X_0, B_0, ci);
598 X_i = X_0; B_r = B_0; B_r *= -1.0;
599 }
600 else
601 {
602 MFEM_ABORT("Real and Imaginary part of the Sesquilinear form are empty");
603 }
604
605 if (RealInteg() && ImagInteg())
606 {
607 // Modify RHS and off-diagonal blocks (imaginary parts of the matrix) to
608 // conform with standard essential BC treatment
609 if (A_i.Is<ConstrainedOperator>())
610 {
611 const int n = ess_tdof_list.Size();
612 auto d_B_r = B_r.Write();
613 auto d_B_i = B_i.Write();
614 auto d_X_r = X_r.Read();
615 auto d_X_i = X_i.Read();
616 auto d_idx = ess_tdof_list.Read();
617 mfem::forall(n, [=] MFEM_HOST_DEVICE (int i)
618 {
619 const int j = d_idx[i];
620 d_B_r[j] = d_X_r[j];
621 d_B_i[j] = d_X_i[j];
622 });
625 }
626 }
627
629 {
630 B_i *= -1.0;
631 b_i *= -1.0;
632 }
633
634 x_r.SyncAliasMemory(x);
635 x_i.SyncAliasMemory(x);
636 b_r.SyncAliasMemory(b);
637 b_i.SyncAliasMemory(b);
638
639 X_r.SyncAliasMemory(X);
640 X_i.SyncAliasMemory(X);
641 B_r.SyncAliasMemory(B);
642 B_i.SyncAliasMemory(B);
643
644 // A = A_r + i A_i
645 A.Clear();
646 if ( A_r.Type() == Operator::MFEM_SPARSEMAT ||
648 {
649 ComplexSparseMatrix * A_sp =
651 A_i.As<SparseMatrix>(),
652 A_r.OwnsOperator(),
653 A_i.OwnsOperator(),
654 conv);
655 A.Reset<ComplexSparseMatrix>(A_sp, true);
656 }
657 else
658 {
659 ComplexOperator * A_op =
660 new ComplexOperator(A_r.Ptr(),
661 A_i.Ptr(),
662 A_r.OwnsOperator(),
663 A_i.OwnsOperator(),
664 conv);
665 A.Reset<ComplexOperator>(A_op, true);
666 }
667 A_r.SetOperatorOwner(false);
668 A_i.SetOperatorOwner(false);
669}
670
671void
674
675{
676 OperatorHandle A_r, A_i;
677 if (RealInteg())
678 {
679 blfr->SetDiagonalPolicy(diag_policy);
680 blfr->FormSystemMatrix(ess_tdof_list, A_r);
681 }
682 if (ImagInteg())
683 {
684 blfi->SetDiagonalPolicy(RealInteg() ?
686 diag_policy);
687 blfi->FormSystemMatrix(ess_tdof_list, A_i);
688 }
689 if (!RealInteg() && !ImagInteg())
690 {
691 MFEM_ABORT("Both Real and Imaginary part of the Sesquilinear form are empty");
692 }
693
694 if (RealInteg() && ImagInteg())
695 {
696 // Modify off-diagonal blocks (imaginary parts of the matrix) to conform
697 // with standard essential BC treatment
698 if (A_i.Is<ConstrainedOperator>())
699 {
702 }
703 }
704
705 // A = A_r + i A_i
706 A.Clear();
707 if ( A_r.Type() == Operator::MFEM_SPARSEMAT ||
709 {
710 ComplexSparseMatrix * A_sp =
712 A_i.As<SparseMatrix>(),
713 A_r.OwnsOperator(),
714 A_i.OwnsOperator(),
715 conv);
716 A.Reset<ComplexSparseMatrix>(A_sp, true);
717 }
718 else
719 {
720 ComplexOperator * A_op =
721 new ComplexOperator(A_r.Ptr(),
722 A_i.Ptr(),
723 A_r.OwnsOperator(),
724 A_i.OwnsOperator(),
725 conv);
726 A.Reset<ComplexOperator>(A_op, true);
727 }
728 A_r.SetOperatorOwner(false);
729 A_i.SetOperatorOwner(false);
730}
731
732void
734 Vector &x)
735{
736 FiniteElementSpace *fes = blfr->FESpace();
737
738 const SparseMatrix *P = fes->GetConformingProlongation();
739 if (!P)
740 {
741 x = X;
742 return;
743 }
744
745 const int vsize = fes->GetVSize();
746 const int tvsize = X.Size() / 2;
747
748 X.Read();
749 Vector X_r; X_r.MakeRef(const_cast<Vector&>(X), 0, tvsize);
750 Vector X_i; X_i.MakeRef(const_cast<Vector&>(X), tvsize, tvsize);
751
752 x.Write();
753 Vector x_r; x_r.MakeRef(x, 0, vsize);
754 Vector x_i; x_i.MakeRef(x, vsize, vsize);
755
756 // Apply conforming prolongation
757 P->Mult(X_r, x_r);
758 P->Mult(X_i, x_i);
759
760 x_r.SyncAliasMemory(x);
761 x_i.SyncAliasMemory(x);
762}
763
764void
766{
767 if ( blfr ) { blfr->Update(nfes); }
768 if ( blfi ) { blfi->Update(nfes); }
769}
770
771
772#ifdef MFEM_USE_MPI
773
775 : Vector(2*(pf->GetVSize())), pfes(pf), fec_owned(NULL)
776{
777 UseDevice(true);
778 this->Vector::operator=(0.0);
779
780 pgfr = new ParGridFunction();
781 pgfr->MakeRef(pfes, *this, 0);
782
783 pgfi = new ParGridFunction();
784 pgfi->MakeRef(pfes, *this, pfes->GetVSize());
785
787}
788
790 : Vector(), pfes(NULL), fec_owned(NULL)
791{
792 string buff;
793
794 // Grid functions are stored on the device
795 UseDevice(true);
796
797 input >> std::ws;
798 getline(input, buff); // 'ParComplexGridFunction'
799 filter_dos(buff);
800 if (buff != "ParComplexGridFunction")
801 {
802 MFEM_ABORT("unrecognized file header: " << buff);
803 }
804
806 fec_owned = fes->Load(m, input);
807
809 fes->GetOrdering());
810
811 delete fes;
812
813 skip_comment_lines(input, '#');
814 istream::int_type next_char = input.peek();
815 if (next_char == 'N') // First letter of "NURBS_patches"
816 {
817 getline(input, buff);
818 filter_dos(buff);
819 if (buff == "NURBS_patches")
820 {
821 MFEM_ABORT("NURBS not yet supported with ComplexGridFunction objects");
822 }
823 else
824 {
825 MFEM_ABORT("unknown section: " << buff);
826 }
827 }
828 else
829 {
830 int vsize = pfes->GetVSize();
831 Vector::Load(input, 2*vsize);
832
833 real_t *data_ = const_cast<real_t*>(HostRead());
834 for (int i = 0; i < vsize; i++)
835 {
836 if (pfes->GetDofSign(i) < 0)
837 {
838 data_[i] = -data_[i];
839 data_[i+vsize] = -data_[i+vsize];
840 }
841 }
842
843
844 // if the mesh is a legacy (v1.1) NC mesh, it has old vertex ordering
845 if (pfes->Nonconforming() &&
847 {
848 // LegacyNCReorder();
849 MFEM_ABORT("LegacyNCReorder not supported for "
850 "ComplexGridFunction objects");
851 }
852 }
853
854 pgfr = new ParGridFunction();
855 pgfr->MakeRef(pfes, *this, 0);
856
857 pgfi = new ParGridFunction();
858 pgfi->MakeRef(pfes, *this, pfes->GetVSize());
859
861}
862
864{
865 delete pgfr; delete pgfi;
866
867 if (fec_owned)
868 {
869 delete pfes;
870 delete fec_owned;
871 fec_owned = NULL;
872 }
873}
874
875void
877{
878 if (pfes->GetSequence() == fes_sequence)
879 {
880 return; // space and grid function are in sync, no-op
881 }
883
884 const int vsize = pfes->GetVSize();
885
886 const Operator *T = pfes->GetUpdateOperator();
887 if (T)
888 {
889 // Update the individual GridFunction objects. This will allocate new data
890 // arrays for each GridFunction.
891 pgfr->Update();
892 pgfi->Update();
893
894 // Our data array now contains old data as well as being the wrong size so
895 // reallocate it.
896 UseDevice(true);
897 this->SetSize(2 * vsize);
898 this->Vector::operator=(0.0);
899
900 // Create temporary vectors which point to the new data array
901 Vector gf_r; gf_r.MakeRef(*this, 0, vsize);
902 Vector gf_i; gf_i.MakeRef(*this, vsize, vsize);
903
904 // Copy the updated GridFunctions into the new data array
905 gf_r = *pgfr; gf_r.SyncAliasMemory(*this);
906 gf_i = *pgfi; gf_i.SyncAliasMemory(*this);
907
908 // Replace the individual data arrays with pointers into the new data
909 // array
910 pgfr->MakeRef(*this, 0, vsize);
911 pgfi->MakeRef(*this, vsize, vsize);
912 }
913 else
914 {
915 // The existing data will not be transferred to the new GridFunctions so
916 // delete it and allocate a new array
917 UseDevice(true);
918 this->SetSize(2 * vsize);
919 this->Vector::operator=(0.0);
920
921 // Point the individual GridFunctions to the new data array
922 pgfr->MakeRef(*this, 0, vsize);
923 pgfi->MakeRef(*this, vsize, vsize);
924
925 // These updates will only set the proper 'sequence' value within the
926 // individual GridFunction objects because their sizes are already correct
927 pgfr->Update();
928 pgfi->Update();
929 }
930}
931
933{
934 const FiniteElement *fe = pfes->GetTypicalFE();
935 if (!fe || fe->GetRangeType() == FiniteElement::SCALAR)
936 {
937 return pfes->GetVDim();
938 }
939 return pfes->GetVDim()*std::max(pfes->GetMesh()->SpaceDimension(),
940 fe->GetRangeDim());
941}
942
943void
945 Coefficient &imag_coeff)
946{
947 pgfr->SyncMemory(*this);
948 pgfi->SyncMemory(*this);
949 pgfr->ProjectCoefficient(real_coeff);
950 pgfi->ProjectCoefficient(imag_coeff);
951 pgfr->SyncAliasMemory(*this);
952 pgfi->SyncAliasMemory(*this);
953}
954
955void
957 VectorCoefficient &imag_vcoeff)
958{
959 pgfr->SyncMemory(*this);
960 pgfi->SyncMemory(*this);
961 pgfr->ProjectCoefficient(real_vcoeff);
962 pgfi->ProjectCoefficient(imag_vcoeff);
963 pgfr->SyncAliasMemory(*this);
964 pgfi->SyncAliasMemory(*this);
965}
966
967void
969 Coefficient &imag_coeff,
970 Array<int> &attr)
971{
972 pgfr->SyncMemory(*this);
973 pgfi->SyncMemory(*this);
974 pgfr->ProjectBdrCoefficient(real_coeff, attr);
975 pgfi->ProjectBdrCoefficient(imag_coeff, attr);
976 pgfr->SyncAliasMemory(*this);
977 pgfi->SyncAliasMemory(*this);
978}
979
980void
982 &real_vcoeff,
984 &imag_vcoeff,
985 Array<int> &attr)
986{
987 pgfr->SyncMemory(*this);
988 pgfi->SyncMemory(*this);
989 pgfr->ProjectBdrCoefficientNormal(real_vcoeff, attr);
990 pgfi->ProjectBdrCoefficientNormal(imag_vcoeff, attr);
991 pgfr->SyncAliasMemory(*this);
992 pgfi->SyncAliasMemory(*this);
993}
994
995void
997 &real_vcoeff,
999 &imag_vcoeff,
1000 Array<int> &attr)
1001{
1002 pgfr->SyncMemory(*this);
1003 pgfi->SyncMemory(*this);
1004 pgfr->ProjectBdrCoefficientTangent(real_vcoeff, attr);
1005 pgfi->ProjectBdrCoefficientTangent(imag_vcoeff, attr);
1006 pgfr->SyncAliasMemory(*this);
1007 pgfi->SyncAliasMemory(*this);
1008}
1009
1010void
1012{
1013 const int tvsize = pfes->GetTrueVSize();
1014
1015 tv->Read();
1016 Vector tvr; tvr.MakeRef(const_cast<Vector&>(*tv), 0, tvsize);
1017 Vector tvi; tvi.MakeRef(const_cast<Vector&>(*tv), tvsize, tvsize);
1018
1019 pgfr->SyncMemory(*this);
1020 pgfi->SyncMemory(*this);
1021 pgfr->Distribute(tvr);
1022 pgfi->Distribute(tvi);
1023 pgfr->SyncAliasMemory(*this);
1024 pgfi->SyncAliasMemory(*this);
1025}
1026
1027void
1029{
1030 const int tvsize = pfes->GetTrueVSize();
1031
1032 tv.Write();
1033 Vector tvr; tvr.MakeRef(tv, 0, tvsize);
1034 Vector tvi; tvi.MakeRef(tv, tvsize, tvsize);
1035
1036 pgfr->SyncMemory(*this);
1037 pgfi->SyncMemory(*this);
1038 pgfr->ParallelProject(tvr);
1039 pgfi->ParallelProject(tvi);
1040 pgfr->SyncAliasMemory(*this);
1041 pgfi->SyncAliasMemory(*this);
1042
1043 tvr.SyncAliasMemory(tv);
1044 tvi.SyncAliasMemory(tv);
1045}
1046
1047void ParComplexGridFunction::Save(std::ostream &os) const
1048{
1049 os << "ParComplexGridFunction\n";
1050 pfes->Save(os);
1051 os << '\n';
1052
1053 int vsize = pfes->GetVSize();
1054 real_t *data_ = const_cast<real_t*>(HostRead());
1055 for (int i = 0; i < vsize; i++)
1056 {
1057 if (pfes->GetDofSign(i) < 0)
1058 {
1059 data_[i] = -data_[i];
1060 data_[i+vsize] = -data_[i+vsize];
1061 }
1062 }
1063
1065 {
1066 Vector::Print(os, 1);
1067 }
1068 else
1069 {
1070 Vector::Print(os, pfes->GetVDim());
1071 }
1072
1073 for (int i = 0; i < vsize; i++)
1074 {
1075 if (pfes->GetDofSign(i) < 0)
1076 {
1077 data_[i] = -data_[i];
1078 data_[i+vsize] = -data_[i+vsize];
1079 }
1080 }
1081
1082 os.flush();
1083}
1084
1085void ParComplexGridFunction::Save(const char *fname, int precision) const
1086{
1087 int rank = pfes->GetMyRank();
1088 ostringstream fname_with_suffix;
1089 fname_with_suffix << fname << "." << setfill('0') << setw(6) << rank;
1090 ofstream ofs(fname_with_suffix.str().c_str());
1091 ofs.precision(precision);
1092 Save(ofs);
1093}
1094
1095std::ostream &operator<<(std::ostream &os, const ParComplexGridFunction &sol)
1096{
1097 sol.Save(os);
1098 return os;
1099}
1100
1101
1104 convention)
1105 : Vector(2*(pfes->GetVSize())),
1106 conv(convention)
1107{
1108 UseDevice(true);
1109 this->Vector::operator=(0.0);
1110
1111 plfr = new ParLinearForm();
1112 plfr->MakeRef(pfes, *this, 0);
1113
1114 plfi = new ParLinearForm();
1115 plfi->MakeRef(pfes, *this, pfes->GetVSize());
1116
1117 HYPRE_BigInt *tdof_offsets_fes = pfes->GetTrueDofOffsets();
1118
1119 int n = (HYPRE_AssumedPartitionCheck()) ? 2 : pfes->GetNRanks();
1120 tdof_offsets = new HYPRE_BigInt[n+1];
1121
1122 for (int i = 0; i <= n; i++)
1123 {
1124 tdof_offsets[i] = 2 * tdof_offsets_fes[i];
1125 }
1126}
1127
1128
1130 ParLinearForm *plf_r,
1131 ParLinearForm *plf_i,
1133 convention)
1134 : Vector(2*(pfes->GetVSize())),
1135 conv(convention)
1136{
1137 UseDevice(true);
1138 this->Vector::operator=(0.0);
1139
1140 plfr = new ParLinearForm(pfes, plf_r);
1141 plfi = new ParLinearForm(pfes, plf_i);
1142
1143 plfr->MakeRef(pfes, *this, 0);
1144 plfi->MakeRef(pfes, *this, pfes->GetVSize());
1145
1146 HYPRE_BigInt *tdof_offsets_fes = pfes->GetTrueDofOffsets();
1147
1148 int n = (HYPRE_AssumedPartitionCheck()) ? 2 : pfes->GetNRanks();
1149 tdof_offsets = new HYPRE_BigInt[n+1];
1150
1151 for (int i = 0; i <= n; i++)
1152 {
1153 tdof_offsets[i] = 2 * tdof_offsets_fes[i];
1154 }
1155}
1156
1158{
1159 delete plfr;
1160 delete plfi;
1161 delete [] tdof_offsets;
1162}
1163
1164void
1166 LinearFormIntegrator *lfi_imag)
1167{
1168 if ( lfi_real ) { plfr->AddDomainIntegrator(lfi_real); }
1169 if ( lfi_imag ) { plfi->AddDomainIntegrator(lfi_imag); }
1170}
1171
1172void
1174 LinearFormIntegrator *lfi_imag,
1175 Array<int> &elem_attr_marker)
1176{
1177 if ( lfi_real ) { plfr->AddDomainIntegrator(lfi_real, elem_attr_marker); }
1178 if ( lfi_imag ) { plfi->AddDomainIntegrator(lfi_imag, elem_attr_marker); }
1179}
1180
1181void
1183 LinearFormIntegrator *lfi_imag)
1184{
1185 if ( lfi_real ) { plfr->AddBoundaryIntegrator(lfi_real); }
1186 if ( lfi_imag ) { plfi->AddBoundaryIntegrator(lfi_imag); }
1187}
1188
1189void
1191 LinearFormIntegrator *lfi_imag,
1192 Array<int> &bdr_attr_marker)
1193{
1194 if ( lfi_real ) { plfr->AddBoundaryIntegrator(lfi_real, bdr_attr_marker); }
1195 if ( lfi_imag ) { plfi->AddBoundaryIntegrator(lfi_imag, bdr_attr_marker); }
1196}
1197
1198void
1200 LinearFormIntegrator *lfi_imag)
1201{
1202 if ( lfi_real ) { plfr->AddBdrFaceIntegrator(lfi_real); }
1203 if ( lfi_imag ) { plfi->AddBdrFaceIntegrator(lfi_imag); }
1204}
1205
1206void
1208 LinearFormIntegrator *lfi_imag,
1209 Array<int> &bdr_attr_marker)
1210{
1211 if ( lfi_real ) { plfr->AddBdrFaceIntegrator(lfi_real, bdr_attr_marker); }
1212 if ( lfi_imag ) { plfi->AddBdrFaceIntegrator(lfi_imag, bdr_attr_marker); }
1213}
1214
1215void
1217{
1218 ParFiniteElementSpace *pfes = (pf != NULL) ? pf : plfr->ParFESpace();
1219
1220 UseDevice(true);
1221 SetSize(2 * pfes->GetVSize());
1222 this->Vector::operator=(0.0);
1223
1224 plfr->MakeRef(pfes, *this, 0);
1225 plfi->MakeRef(pfes, *this, pfes->GetVSize());
1226}
1227
1228void
1230{
1231 plfr->SyncMemory(*this);
1232 plfi->SyncMemory(*this);
1233 plfr->Assemble();
1234 plfi->Assemble();
1235 if (conv == ComplexOperator::BLOCK_SYMMETRIC) { *plfi *= -1.0; }
1236 plfr->SyncAliasMemory(*this);
1237 plfi->SyncAliasMemory(*this);
1238}
1239
1240void
1242{
1243 const int tvsize = plfr->ParFESpace()->GetTrueVSize();
1244
1245 tv.Write();
1246 Vector tvr; tvr.MakeRef(tv, 0, tvsize);
1247 Vector tvi; tvi.MakeRef(tv, tvsize, tvsize);
1248
1249 plfr->SyncMemory(*this);
1250 plfi->SyncMemory(*this);
1251 plfr->ParallelAssemble(tvr);
1252 plfi->ParallelAssemble(tvi);
1253 plfr->SyncAliasMemory(*this);
1254 plfi->SyncAliasMemory(*this);
1255
1256 tvr.SyncAliasMemory(tv);
1257 tvi.SyncAliasMemory(tv);
1258}
1259
1262{
1263 const ParFiniteElementSpace *pfes = plfr->ParFESpace();
1264 const int tvsize = pfes->GetTrueVSize();
1265
1266 HypreParVector *tv = new HypreParVector(pfes->GetComm(),
1267 2*(pfes->GlobalTrueVSize()),
1268 tdof_offsets);
1269
1270 tv->Write();
1271 Vector tvr; tvr.MakeRef(*tv, 0, tvsize);
1272 Vector tvi; tvi.MakeRef(*tv, tvsize, tvsize);
1273
1274 plfr->SyncMemory(*this);
1275 plfi->SyncMemory(*this);
1276 plfr->ParallelAssemble(tvr);
1277 plfi->ParallelAssemble(tvi);
1278 plfr->SyncAliasMemory(*this);
1279 plfi->SyncAliasMemory(*this);
1280
1281 tvr.SyncAliasMemory(*tv);
1282 tvi.SyncAliasMemory(*tv);
1283
1284 return tv;
1285}
1286
1287complex<real_t>
1289{
1290 plfr->SyncMemory(*this);
1291 plfi->SyncMemory(*this);
1292 real_t s = (conv == ComplexOperator::HERMITIAN) ? 1.0 : -1.0;
1293 return complex<real_t>((*plfr)(gf.real()) - s * (*plfi)(gf.imag()),
1294 (*plfr)(gf.imag()) + s * (*plfi)(gf.real()));
1295}
1296
1297
1298bool ParSesquilinearForm::RealInteg()
1299{
1300 int nint = pblfr->GetFBFI()->Size() + pblfr->GetDBFI()->Size() +
1301 pblfr->GetBBFI()->Size() + pblfr->GetBFBFI()->Size();
1302 return (nint != 0);
1303}
1304
1305bool ParSesquilinearForm::ImagInteg()
1306{
1307 int nint = pblfi->GetFBFI()->Size() + pblfi->GetDBFI()->Size() +
1308 pblfi->GetBBFI()->Size() + pblfi->GetBFBFI()->Size();
1309 return (nint != 0);
1310}
1311
1314 convention)
1315 : conv(convention),
1316 pblfr(new ParBilinearForm(pf)),
1317 pblfi(new ParBilinearForm(pf))
1318{}
1319
1321 ParBilinearForm *pbfr,
1322 ParBilinearForm *pbfi,
1323 ComplexOperator::Convention convention)
1324 : conv(convention),
1325 pblfr(new ParBilinearForm(pf,pbfr)),
1326 pblfi(new ParBilinearForm(pf,pbfi))
1327{}
1328
1330{
1331 delete pblfr;
1332 delete pblfi;
1333}
1334
1336 BilinearFormIntegrator *bfi_imag)
1337{
1338 if (bfi_real) { pblfr->AddDomainIntegrator(bfi_real); }
1339 if (bfi_imag) { pblfi->AddDomainIntegrator(bfi_imag); }
1340}
1341
1343 BilinearFormIntegrator *bfi_imag,
1344 Array<int> & elem_marker)
1345{
1346 if (bfi_real) { pblfr->AddDomainIntegrator(bfi_real, elem_marker); }
1347 if (bfi_imag) { pblfi->AddDomainIntegrator(bfi_imag, elem_marker); }
1348}
1349
1350void
1352 BilinearFormIntegrator *bfi_imag)
1353{
1354 if (bfi_real) { pblfr->AddBoundaryIntegrator(bfi_real); }
1355 if (bfi_imag) { pblfi->AddBoundaryIntegrator(bfi_imag); }
1356}
1357
1358void
1360 BilinearFormIntegrator *bfi_imag,
1361 Array<int> & bdr_marker)
1362{
1363 if (bfi_real) { pblfr->AddBoundaryIntegrator(bfi_real, bdr_marker); }
1364 if (bfi_imag) { pblfi->AddBoundaryIntegrator(bfi_imag, bdr_marker); }
1365}
1366
1367void
1369 BilinearFormIntegrator *bfi_imag)
1370{
1371 if (bfi_real) { pblfr->AddInteriorFaceIntegrator(bfi_real); }
1372 if (bfi_imag) { pblfi->AddInteriorFaceIntegrator(bfi_imag); }
1373}
1374
1375void
1377 BilinearFormIntegrator *bfi_imag)
1378{
1379 if (bfi_real) { pblfr->AddBdrFaceIntegrator(bfi_real); }
1380 if (bfi_imag) { pblfi->AddBdrFaceIntegrator(bfi_imag); }
1381}
1382
1383void
1385 BilinearFormIntegrator *bfi_imag,
1386 Array<int> &bdr_marker)
1387{
1388 if (bfi_real) { pblfr->AddBdrFaceIntegrator(bfi_real, bdr_marker); }
1389 if (bfi_imag) { pblfi->AddBdrFaceIntegrator(bfi_imag, bdr_marker); }
1390}
1391
1392void
1394{
1395 pblfr->Assemble(skip_zeros);
1396 pblfi->Assemble(skip_zeros);
1397}
1398
1399void
1401{
1402 pblfr->Finalize(skip_zeros);
1403 pblfi->Finalize(skip_zeros);
1404}
1405
1408{
1409 return new ComplexHypreParMatrix(pblfr->ParallelAssemble(),
1410 pblfi->ParallelAssemble(),
1411 true, true, conv);
1412}
1413
1414void
1416 Vector &x, Vector &b,
1417 OperatorHandle &A,
1418 Vector &X, Vector &B,
1419 int ci)
1420{
1421 ParFiniteElementSpace *pfes = pblfr->ParFESpace();
1422 const int vsize = pfes->GetVSize();
1423
1424 // Allocate temporary vector
1425 Vector b_0;
1426 b_0.UseDevice(true);
1427 b_0.SetSize(vsize);
1428 b_0 = 0.0;
1429
1430 // Extract the real and imaginary parts of the input vectors
1431 MFEM_ASSERT(x.Size() == 2 * vsize, "Input GridFunction of incorrect size!");
1432 x.Read();
1433 Vector x_r; x_r.MakeRef(x, 0, vsize);
1434 Vector x_i; x_i.MakeRef(x, vsize, vsize);
1435
1436 MFEM_ASSERT(b.Size() == 2 * vsize, "Input LinearForm of incorrect size!");
1437 b.Read();
1438 Vector b_r; b_r.MakeRef(b, 0, vsize);
1439 Vector b_i; b_i.MakeRef(b, vsize, vsize);
1440
1441 if (conv == ComplexOperator::BLOCK_SYMMETRIC) { b_i *= -1.0; }
1442
1443 const int tvsize = pfes->GetTrueVSize();
1444 OperatorHandle A_r, A_i;
1445
1446 X.UseDevice(true);
1447 X.SetSize(2 * tvsize);
1448 X = 0.0;
1449
1450 B.UseDevice(true);
1451 B.SetSize(2 * tvsize);
1452 B = 0.0;
1453
1454 Vector X_r; X_r.MakeRef(X, 0, tvsize);
1455 Vector X_i; X_i.MakeRef(X, tvsize, tvsize);
1456 Vector B_r; B_r.MakeRef(B, 0, tvsize);
1457 Vector B_i; B_i.MakeRef(B, tvsize, tvsize);
1458
1459 Vector X_0, B_0;
1460
1461 if (RealInteg())
1462 {
1463 b_0 = b_r;
1464 pblfr->FormLinearSystem(ess_tdof_list, x_r, b_0, A_r, X_0, B_0, ci);
1465 X_r = X_0; B_r = B_0;
1466
1467 b_0 = b_i;
1468 pblfr->FormLinearSystem(ess_tdof_list, x_i, b_0, A_r, X_0, B_0, ci);
1469 X_i = X_0; B_i = B_0;
1470
1471 if (ImagInteg())
1472 {
1473 b_0 = 0.0;
1474 pblfi->FormLinearSystem(ess_tdof_list, x_i, b_0, A_i, X_0, B_0, false);
1475 B_r -= B_0;
1476
1477 b_0 = 0.0;
1478 pblfi->FormLinearSystem(ess_tdof_list, x_r, b_0, A_i, X_0, B_0, false);
1479 B_i += B_0;
1480 }
1481 }
1482 else if (ImagInteg())
1483 {
1484 b_0 = b_i;
1485 pblfi->FormLinearSystem(ess_tdof_list, x_r, b_0, A_i, X_0, B_0, ci);
1486 X_r = X_0; B_i = B_0;
1487
1488 b_0 = b_r; b_0 *= -1.0;
1489 pblfi->FormLinearSystem(ess_tdof_list, x_i, b_0, A_i, X_0, B_0, ci);
1490 X_i = X_0; B_r = B_0; B_r *= -1.0;
1491 }
1492 else
1493 {
1494 MFEM_ABORT("Real and Imaginary part of the Sesquilinear form are empty");
1495 }
1496
1497 if (RealInteg() && ImagInteg())
1498 {
1499 // Modify RHS to conform with standard essential BC treatment
1500 const int n = ess_tdof_list.Size();
1501 auto d_B_r = B_r.Write();
1502 auto d_B_i = B_i.Write();
1503 auto d_X_r = X_r.Read();
1504 auto d_X_i = X_i.Read();
1505 auto d_idx = ess_tdof_list.Read();
1506 mfem::forall(n, [=] MFEM_HOST_DEVICE (int i)
1507 {
1508 const int j = d_idx[i];
1509 d_B_r[j] = d_X_r[j];
1510 d_B_i[j] = d_X_i[j];
1511 });
1512 // Modify off-diagonal blocks (imaginary parts of the matrix) to conform
1513 // with standard essential BC treatment
1514 if (A_i.Type() == Operator::Hypre_ParCSR)
1515 {
1516 HypreParMatrix * Ah;
1517 A_i.Get(Ah);
1518 hypre_ParCSRMatrix *Aih = *Ah;
1519 Ah->HypreReadWrite();
1520 const int *d_ess_tdof_list =
1521 ess_tdof_list.GetMemory().Read(GetHypreForallMemoryClass(), n);
1522 HYPRE_Int *d_diag_i = Aih->diag->i;
1523 real_t *d_diag_data = Aih->diag->data;
1524 mfem::hypre_forall(n, [=] MFEM_HOST_DEVICE (int k)
1525 {
1526 const int j = d_ess_tdof_list[k];
1527 d_diag_data[d_diag_i[j]] = 0.0;
1528 });
1529 }
1530 else
1531 {
1532 A_i.As<ConstrainedOperator>()->SetDiagonalPolicy
1534 }
1535 }
1536
1538 {
1539 B_i *= -1.0;
1540 b_i *= -1.0;
1541 }
1542
1543 x_r.SyncAliasMemory(x);
1544 x_i.SyncAliasMemory(x);
1545 b_r.SyncAliasMemory(b);
1546 b_i.SyncAliasMemory(b);
1547
1548 X_r.SyncAliasMemory(X);
1549 X_i.SyncAliasMemory(X);
1550 B_r.SyncAliasMemory(B);
1551 B_i.SyncAliasMemory(B);
1552
1553 // A = A_r + i A_i
1554 A.Clear();
1555 if ( A_r.Type() == Operator::Hypre_ParCSR ||
1556 A_i.Type() == Operator::Hypre_ParCSR )
1557 {
1558 ComplexHypreParMatrix * A_hyp =
1560 A_i.As<HypreParMatrix>(),
1561 A_r.OwnsOperator(),
1562 A_i.OwnsOperator(),
1563 conv);
1564 A.Reset<ComplexHypreParMatrix>(A_hyp, true);
1565 }
1566 else
1567 {
1568 ComplexOperator * A_op =
1569 new ComplexOperator(A_r.As<Operator>(),
1570 A_i.As<Operator>(),
1571 A_r.OwnsOperator(),
1572 A_i.OwnsOperator(),
1573 conv);
1574 A.Reset<ComplexOperator>(A_op, true);
1575 }
1576 A_r.SetOperatorOwner(false);
1577 A_i.SetOperatorOwner(false);
1578}
1579
1580void
1582 OperatorHandle &A)
1583{
1584 OperatorHandle A_r, A_i;
1585 if (RealInteg())
1586 {
1587 pblfr->FormSystemMatrix(ess_tdof_list, A_r);
1588 }
1589 if (ImagInteg())
1590 {
1591 pblfi->FormSystemMatrix(ess_tdof_list, A_i);
1592 }
1593 if (!RealInteg() && !ImagInteg())
1594 {
1595 MFEM_ABORT("Both Real and Imaginary part of the Sesquilinear form are empty");
1596 }
1597
1598 if (RealInteg() && ImagInteg())
1599 {
1600 // Modify off-diagonal blocks (imaginary parts of the matrix) to conform
1601 // with standard essential BC treatment
1602 if ( A_i.Type() == Operator::Hypre_ParCSR )
1603 {
1604 int n = ess_tdof_list.Size();
1605 HypreParMatrix * Ah;
1606 A_i.Get(Ah);
1607 hypre_ParCSRMatrix * Aih = *Ah;
1608 for (int k = 0; k < n; k++)
1609 {
1610 int j = ess_tdof_list[k];
1611 Aih->diag->data[Aih->diag->i[j]] = 0.0;
1612 }
1613 }
1614 else
1615 {
1616 A_i.As<ConstrainedOperator>()->SetDiagonalPolicy
1618 }
1619 }
1620
1621 // A = A_r + i A_i
1622 A.Clear();
1623 if ( A_r.Type() == Operator::Hypre_ParCSR ||
1624 A_i.Type() == Operator::Hypre_ParCSR )
1625 {
1626 ComplexHypreParMatrix * A_hyp =
1628 A_i.As<HypreParMatrix>(),
1629 A_r.OwnsOperator(),
1630 A_i.OwnsOperator(),
1631 conv);
1632 A.Reset<ComplexHypreParMatrix>(A_hyp, true);
1633 }
1634 else
1635 {
1636 ComplexOperator * A_op =
1637 new ComplexOperator(A_r.As<Operator>(),
1638 A_i.As<Operator>(),
1639 A_r.OwnsOperator(),
1640 A_i.OwnsOperator(),
1641 conv);
1642 A.Reset<ComplexOperator>(A_op, true);
1643 }
1644 A_r.SetOperatorOwner(false);
1645 A_i.SetOperatorOwner(false);
1646}
1647
1648void
1650 Vector &x)
1651{
1652 ParFiniteElementSpace *pfes = pblfr->ParFESpace();
1653
1654 const Operator &P = *pfes->GetProlongationMatrix();
1655
1656 const int vsize = pfes->GetVSize();
1657 const int tvsize = X.Size() / 2;
1658
1659 X.Read();
1660 Vector X_r; X_r.MakeRef(const_cast<Vector&>(X), 0, tvsize);
1661 Vector X_i; X_i.MakeRef(const_cast<Vector&>(X), tvsize, tvsize);
1662
1663 x.Write();
1664 Vector x_r; x_r.MakeRef(x, 0, vsize);
1665 Vector x_i; x_i.MakeRef(x, vsize, vsize);
1666
1667 // Apply conforming prolongation
1668 P.Mult(X_r, x_r);
1669 P.Mult(X_i, x_i);
1670
1671 x_r.SyncAliasMemory(x);
1672 x_i.SyncAliasMemory(x);
1673}
1674
1675void
1677{
1678 if ( pblfr ) { pblfr->Update(nfes); }
1679 if ( pblfi ) { pblfi->Update(nfes); }
1680}
1681
1682#endif // MFEM_USE_MPI
1683
1684}
Memory< T > & GetMemory()
Return a reference to the Memory object used by the Array.
Definition array.hpp:145
int Size() const
Return the logical size of the array.
Definition array.hpp:166
Memory< T > data
Pointer to data.
Definition array.hpp:51
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
Definition array.hpp:381
Abstract base class BilinearFormIntegrator.
A "square matrix" operator for the associated FE space and BLFIntegrators The sum of all the BLFInteg...
void SetDiagonalPolicy(DiagonalPolicy policy)
Sets Operator::DiagonalPolicy used upon construction of the linear system. Policies include:
void AddDomainIntegrator(BilinearFormIntegrator *bfi)
Adds new Domain Integrator. Assumes ownership of bfi.
Array< BilinearFormIntegrator * > * GetFBFI()
Access all integrators added with AddInteriorFaceIntegrator().
virtual void Update(FiniteElementSpace *nfes=NULL)
Update the FiniteElementSpace and delete all data associated with the old one.
Array< BilinearFormIntegrator * > * GetDBFI()
Access all the integrators added with AddDomainIntegrator().
void Finalize(int skip_zeros=1) override
Finalizes the matrix initialization if the AssemblyLevel is AssemblyLevel::LEGACY....
FiniteElementSpace * FESpace()
Return the FE space associated with the BilinearForm.
void AddBoundaryIntegrator(BilinearFormIntegrator *bfi)
Adds new Boundary Integrator. Assumes ownership of bfi.
void Assemble(int skip_zeros=1)
Assembles the form i.e. sums over all domain/bdr integrators.
void AddBdrFaceIntegrator(BilinearFormIntegrator *bfi)
Adds new boundary Face Integrator. Assumes ownership of bfi.
Array< BilinearFormIntegrator * > * GetBBFI()
Access all the integrators added with AddBoundaryIntegrator().
Array< BilinearFormIntegrator * > * GetBFBFI()
Access all integrators added with AddBdrFaceIntegrator().
virtual void FormLinearSystem(const Array< int > &ess_tdof_list, Vector &x, Vector &b, OperatorHandle &A, Vector &X, Vector &B, int copy_interior=0)
Form the linear system A X = B, corresponding to this bilinear form and the linear form b(....
virtual void FormSystemMatrix(const Array< int > &ess_tdof_list, OperatorHandle &A)
Form the linear system matrix A, see FormLinearSystem() for details.
const SparseMatrix & SpMat() const
Returns a const reference to the sparse matrix: .
void AddInteriorFaceIntegrator(BilinearFormIntegrator *bfi)
Adds new interior Face Integrator. Assumes ownership of bfi.
Base class Coefficients that optionally depend on space and time. These are used by the BilinearFormI...
virtual void ProjectBdrCoefficientTangent(VectorCoefficient &real_coeff, VectorCoefficient &imag_coeff, Array< int > &attr)
virtual void ProjectBdrCoefficient(Coefficient &real_coeff, Coefficient &imag_coeff, Array< int > &attr)
virtual void ProjectCoefficient(Coefficient &real_coeff, Coefficient &imag_coeff)
FiniteElementSpace * fes
FiniteElementCollection * fec_owned
Used when the grid function is read from a file. It can also be set explicitly, see MakeOwner().
virtual void ProjectBdrCoefficientNormal(VectorCoefficient &real_coeff, VectorCoefficient &imag_coeff, Array< int > &attr)
ComplexGridFunction(FiniteElementSpace *f)
Construct a ComplexGridFunction associated with the FiniteElementSpace *f.
virtual void Save(std::ostream &out) const
Save the ComplexGridFunction to an output stream.
Specialization of the ComplexOperator built from a pair of HypreParMatrices.
ComplexLinearForm(FiniteElementSpace *fes, ComplexOperator::Convention convention=ComplexOperator::HERMITIAN)
void AddBdrFaceIntegrator(LinearFormIntegrator *lfi_real, LinearFormIntegrator *lfi_imag)
Adds new Boundary Face Integrator. Assumes ownership of lfi.
void AddDomainIntegrator(LinearFormIntegrator *lfi_real, LinearFormIntegrator *lfi_imag)
Adds new Domain Integrator.
std::complex< real_t > operator()(const ComplexGridFunction &gf) const
void Assemble()
Assembles the linear form i.e. sums over all domain/bdr integrators.
void AddBoundaryIntegrator(LinearFormIntegrator *lfi_real, LinearFormIntegrator *lfi_imag)
Adds new Boundary Integrator.
Mimic the action of a complex operator using two real operators.
@ HERMITIAN
Native convention for Hermitian operators.
@ BLOCK_SYMMETRIC
Alternate convention for damping operators.
Specialization of the ComplexOperator built from a pair of Sparse Matrices.
Square Operator for imposing essential boundary conditions using only the action, Mult(),...
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:208
void Save(std::ostream &out) const
Save finite element space to output stream out.
Definition fespace.cpp:4363
virtual int GetTrueVSize() const
Return the number of vector true (conforming) dofs.
Definition fespace.hpp:829
bool Nonconforming() const
Definition fespace.hpp:655
FiniteElementCollection * Load(Mesh *m, std::istream &input)
Read a FiniteElementSpace from a stream. The returned FiniteElementCollection is owned by the caller.
Definition fespace.cpp:4484
Ordering::Type GetOrdering() const
Return the ordering method.
Definition fespace.hpp:854
const SparseMatrix * GetConformingProlongation() const
Definition fespace.cpp:1426
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:644
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition fespace.hpp:826
int GetVDim() const
Returns the vector dimension of the finite element space.
Definition fespace.hpp:819
const FiniteElement * GetTypicalFE() const
Return GetFE(0) if the local mesh is not empty; otherwise return a typical FE based on the Geometry t...
Definition fespace.cpp:3860
const Operator * GetUpdateOperator()
Get the GridFunction update operator.
Definition fespace.hpp:1468
Abstract class for all finite elements.
Definition fe_base.hpp:247
int GetRangeDim() const
Returns the vector dimension for vector-valued finite elements, which is also the dimension of the in...
Definition fe_base.hpp:328
int GetRangeType() const
Returns the FiniteElement::RangeType of the element, one of {SCALAR, VECTOR}.
Definition fe_base.hpp:354
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:32
virtual void Update()
Transform by the Space UpdateMatrix (e.g., on Mesh change).
Definition gridfunc.cpp:168
virtual void MakeRef(FiniteElementSpace *f, real_t *v)
Make the GridFunction reference external data on a new FiniteElementSpace.
Definition gridfunc.cpp:234
virtual void ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff, const Array< int > &bdr_attr)
Project the tangential components of the given VectorCoefficient on the boundary. Only boundary attri...
virtual void ProjectCoefficient(Coefficient &coeff)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
void ProjectBdrCoefficientNormal(VectorCoefficient &vcoeff, const Array< int > &bdr_attr)
void ProjectBdrCoefficient(Coefficient &coeff, const Array< int > &attr)
Project a Coefficient on the GridFunction, modifying only DOFs on the boundary associated with the bo...
Definition gridfunc.hpp:511
Wrapper for hypre's ParCSR matrix class.
Definition hypre.hpp:419
void HypreReadWrite()
Update the internal hypre_ParCSRMatrix object, A, to be in hypre memory space.
Definition hypre.hpp:945
Wrapper for hypre's parallel vector class.
Definition hypre.hpp:230
Abstract base class LinearFormIntegrator.
Definition lininteg.hpp:28
Vector with associated FE space and LinearFormIntegrators.
void AddDomainIntegrator(LinearFormIntegrator *lfi)
Adds new Domain Integrator. Assumes ownership of lfi.
FiniteElementSpace * FESpace()
Read+write access to the associated FiniteElementSpace.
virtual void MakeRef(FiniteElementSpace *f, Vector &v, int v_offset)
Make the LinearForm reference external data on a new FiniteElementSpace.
void AddBoundaryIntegrator(LinearFormIntegrator *lfi)
Adds new Boundary Integrator. Assumes ownership of lfi.
void AddBdrFaceIntegrator(LinearFormIntegrator *lfi)
Adds new Boundary Face Integrator. Assumes ownership of lfi.
void Assemble()
Assembles the linear form i.e. sums over all domain/bdr integrators.
Mesh data type.
Definition mesh.hpp:65
int SpaceDimension() const
Dimension of the physical space containing the mesh.
Definition mesh.hpp:1309
NCMesh * ncmesh
Optional nonconforming mesh extension.
Definition mesh.hpp:313
bool IsLegacyLoaded() const
I/O: Return true if the mesh was loaded from the legacy v1.1 format.
Definition ncmesh.hpp:534
Pointer to an Operator of a specified type.
Definition handle.hpp:34
OpType * As() const
Return the Operator pointer statically cast to a specified OpType. Similar to the method Get().
Definition handle.hpp:104
bool OwnsOperator() const
Return true if the OperatorHandle owns the held Operator.
Definition handle.hpp:117
void SetOperatorOwner(bool own=true)
Set the ownership flag for the held Operator.
Definition handle.hpp:120
Operator * Ptr() const
Access the underlying Operator pointer.
Definition handle.hpp:87
void Clear()
Clear the OperatorHandle, deleting the held Operator (if owned), while leaving the type id unchanged.
Definition handle.hpp:124
void Reset(OpType *A, bool own_A=true)
Reset the OperatorHandle to the given OpType pointer, A.
Definition handle.hpp:145
OpType * Is() const
Return the Operator pointer dynamically cast to a specified OpType.
Definition handle.hpp:108
Operator::Type Type() const
Get the currently set operator type id.
Definition handle.hpp:99
void Get(OpType *&A) const
Return the Operator pointer statically cast to a given OpType.
Definition handle.hpp:114
Abstract operator.
Definition operator.hpp:25
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
DiagonalPolicy
Defines operator diagonal policy upon elimination of rows and/or columns.
Definition operator.hpp:48
@ DIAG_ZERO
Set the diagonal value to zero.
Definition operator.hpp:49
@ MFEM_SPARSEMAT
ID for class SparseMatrix.
Definition operator.hpp:298
@ Hypre_ParCSR
ID for class HypreParMatrix.
Definition operator.hpp:299
Class for parallel bilinear form.
HypreParMatrix * ParallelAssemble()
Returns the matrix assembled on the true dofs, i.e. P^t A P.
void Assemble(int skip_zeros=1)
Assemble the local matrix.
void FormSystemMatrix(const Array< int > &ess_tdof_list, OperatorHandle &A) override
Form the linear system matrix A, see FormLinearSystem() for details.
void Update(FiniteElementSpace *nfes=NULL) override
Update the FiniteElementSpace and delete all data associated with the old one.
ParFiniteElementSpace * ParFESpace() const
Return the parallel FE space associated with the ParBilinearForm.
void FormLinearSystem(const Array< int > &ess_tdof_list, Vector &x, Vector &b, OperatorHandle &A, Vector &X, Vector &B, int copy_interior=0) override
Form the linear system A X = B, corresponding to this bilinear form and the linear form b(....
virtual void ProjectBdrCoefficient(Coefficient &real_coeff, Coefficient &imag_coeff, Array< int > &attr)
FiniteElementCollection * fec_owned
Used when the grid function is read from a file. It can also be set explicitly, see MakeOwner().
void ParallelProject(Vector &tv) const
Returns the vector restricted to the true dofs.
ParComplexGridFunction(ParFiniteElementSpace *pf)
Construct a ParComplexGridFunction associated with the ParFiniteElementSpace *pf.
virtual void ProjectBdrCoefficientNormal(VectorCoefficient &real_coeff, VectorCoefficient &imag_coeff, Array< int > &attr)
ParFiniteElementSpace * pfes
void Distribute(const Vector *tv)
virtual void ProjectBdrCoefficientTangent(VectorCoefficient &real_coeff, VectorCoefficient &imag_coeff, Array< int > &attr)
virtual void ProjectCoefficient(Coefficient &real_coeff, Coefficient &imag_coeff)
void Save(std::ostream &out) const
Save the local portion of the ParComplexGridFunction.
void Update(ParFiniteElementSpace *pf=NULL)
void AddBdrFaceIntegrator(LinearFormIntegrator *lfi_real, LinearFormIntegrator *lfi_imag)
Adds new Boundary Face Integrator. Assumes ownership of lfi.
std::complex< real_t > operator()(const ParComplexGridFunction &gf) const
void AddBoundaryIntegrator(LinearFormIntegrator *lfi_real, LinearFormIntegrator *lfi_imag)
Adds new Boundary Integrator.
void Assemble()
Assembles the linear form i.e. sums over all domain/bdr integrators.
HypreParVector * ParallelAssemble()
Returns the vector assembled on the true dofs, i.e. P^t v.
void AddDomainIntegrator(LinearFormIntegrator *lfi_real, LinearFormIntegrator *lfi_imag)
Adds new Domain Integrator.
ParComplexLinearForm(ParFiniteElementSpace *pf, ComplexOperator::Convention convention=ComplexOperator::HERMITIAN)
Abstract parallel finite element space.
Definition pfespace.hpp:31
MPI_Comm GetComm() const
Definition pfespace.hpp:337
HYPRE_BigInt * GetTrueDofOffsets() const
Definition pfespace.hpp:346
HYPRE_BigInt GlobalTrueVSize() const
Definition pfespace.hpp:349
int GetTrueVSize() const override
Return the number of local vector true dofs.
Definition pfespace.hpp:353
const Operator * GetProlongationMatrix() const override
Class for parallel grid function.
Definition pgridfunc.hpp:50
void ProjectBdrCoefficient(Coefficient *coeff[], VectorCoefficient *vcoeff, const Array< int > &attr)
void MakeRef(FiniteElementSpace *f, real_t *v) override
Make the ParGridFunction reference external data on a new FiniteElementSpace.
void ProjectCoefficient(Coefficient &coeff) override
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
void ParallelProject(Vector &tv) const
Returns the vector restricted to the true dofs.
void Update() override
Transform by the Space UpdateMatrix (e.g., on Mesh change).
Definition pgridfunc.cpp:85
void Distribute(const Vector *tv)
void ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff, const Array< int > &bdr_attr) override
Project the tangential components of the given VectorCoefficient on the boundary. Only boundary attri...
Class for parallel linear form.
void ParallelAssemble(Vector &tv)
Assemble the vector on the true dofs, i.e. P^t v.
void Assemble()
Assembles the ParLinearForm i.e. sums over all domain/bdr integrators.
void MakeRef(FiniteElementSpace *f, Vector &v, int v_offset) override
Make the ParLinearForm reference external data on a new FiniteElementSpace.
ParFiniteElementSpace * ParFESpace() const
Class for parallel meshes.
Definition pmesh.hpp:34
virtual void RecoverFEMSolution(const Vector &X, const Vector &b, Vector &x)
ComplexHypreParMatrix * ParallelAssemble()
Returns the matrix assembled on the true dofs, i.e. P^t A P.
ParSesquilinearForm(ParFiniteElementSpace *pf, ComplexOperator::Convention convention=ComplexOperator::HERMITIAN)
void FormSystemMatrix(const Array< int > &ess_tdof_list, OperatorHandle &A)
void FormLinearSystem(const Array< int > &ess_tdof_list, Vector &x, Vector &b, OperatorHandle &A, Vector &X, Vector &B, int copy_interior=0)
virtual void Update(FiniteElementSpace *nfes=NULL)
void AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real, BilinearFormIntegrator *bfi_imag)
Adds new Boundary Integrator.
void AddBdrFaceIntegrator(BilinearFormIntegrator *bfi_real, BilinearFormIntegrator *bfi_imag)
Adds new boundary Face Integrator. Assumes ownership of bfi.
void Finalize(int skip_zeros=1)
Finalizes the matrix initialization.
void AddDomainIntegrator(BilinearFormIntegrator *bfi_real, BilinearFormIntegrator *bfi_imag)
Adds new Domain Integrator.
void AddInteriorFaceIntegrator(BilinearFormIntegrator *bfi_real, BilinearFormIntegrator *bfi_imag)
Adds new interior Face Integrator. Assumes ownership of bfi.
void Assemble(int skip_zeros=1)
Assemble the local matrix.
ComplexSparseMatrix * AssembleComplexSparseMatrix()
Returns the matrix assembled on the true dofs, i.e. P^t A P.
void SetDiagonalPolicy(mfem::Matrix::DiagonalPolicy dpolicy)
Sets diagonal policy used upon construction of the linear system.
void Finalize(int skip_zeros=1)
Finalizes the matrix initialization.
virtual void RecoverFEMSolution(const Vector &X, const Vector &b, Vector &x)
void Assemble(int skip_zeros=1)
Assemble the local matrix.
SesquilinearForm(FiniteElementSpace *fes, ComplexOperator::Convention convention=ComplexOperator::HERMITIAN)
void FormSystemMatrix(const Array< int > &ess_tdof_list, OperatorHandle &A)
void AddDomainIntegrator(BilinearFormIntegrator *bfi_real, BilinearFormIntegrator *bfi_imag)
Adds new Domain Integrator.
void AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real, BilinearFormIntegrator *bfi_imag)
Adds new Boundary Integrator.
virtual void Update(FiniteElementSpace *nfes=NULL)
void FormLinearSystem(const Array< int > &ess_tdof_list, Vector &x, Vector &b, OperatorHandle &A, Vector &X, Vector &B, int copy_interior=0)
void AddInteriorFaceIntegrator(BilinearFormIntegrator *bfi_real, BilinearFormIntegrator *bfi_imag)
Adds new interior Face Integrator. Assumes ownership of bfi.
void AddBdrFaceIntegrator(BilinearFormIntegrator *bfi_real, BilinearFormIntegrator *bfi_imag)
Adds new boundary Face Integrator. Assumes ownership of bfi.
Data type sparse matrix.
Definition sparsemat.hpp:51
void Mult(const Vector &x, Vector &y) const override
Matrix vector multiplication.
Base class for vector Coefficients that optionally depend on time and space.
Vector data type.
Definition vector.hpp:82
virtual const real_t * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:524
virtual const real_t * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
Definition vector.hpp:520
void Print(std::ostream &out=mfem::out, int width=8) const
Prints vector to stream out.
Definition vector.cpp:870
void SyncAliasMemory(const Vector &v) const
Update the alias memory location of the vector to match v.
Definition vector.hpp:275
void SyncMemory(const Vector &v) const
Update the memory location of the vector to match v.
Definition vector.hpp:272
void Load(std::istream **in, int np, int *dim)
Reads a vector from multiple files.
Definition vector.cpp:127
virtual bool UseDevice() const
Return the device flag of the Memory object used by the Vector.
Definition vector.hpp:148
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
Definition vector.hpp:145
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:584
Vector & operator=(const real_t *v)
Copy Size() entries from v.
Definition vector.cpp:197
virtual real_t * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
Definition vector.hpp:528
void MakeRef(Vector &base, int offset, int size)
Reset the Vector to be a reference to a sub-vector of base.
Definition vector.hpp:660
HYPRE_Int HYPRE_BigInt
real_t b
Definition lissajous.cpp:42
std::ostream & operator<<(std::ostream &os, SparseMatrix const &mat)
MemoryClass GetHypreForallMemoryClass()
Definition forall.hpp:1008
void filter_dos(std::string &line)
Check for, and remove, a trailing '\r' from and std::string.
Definition text.hpp:45
void hypre_forall(int N, lambda &&body)
Definition forall.hpp:985
float real_t
Definition config.hpp:46
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
void forall(int N, lambda &&body)
Definition forall.hpp:839
void skip_comment_lines(std::istream &is, const char comment_char)
Check if the stream starts with comment_char. If so skip it.
Definition text.hpp:31