Files
mfem/fem/complex_fem.cpp
T
2020-03-09 19:30:02 -07:00

1125 lines
33 KiB
C++

// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "complex_fem.hpp"
using namespace std;
namespace mfem
{
ComplexGridFunction::ComplexGridFunction(FiniteElementSpace *fes)
: Vector(2*(fes->GetVSize()))
{
gfr = new GridFunction(fes, data);
gfi = new GridFunction(fes, &data[fes->GetVSize()]);
}
void
ComplexGridFunction::Update()
{
FiniteElementSpace * fes = gfr->FESpace();
int vsize = fes->GetVSize();
const Operator *T = fes->GetUpdateOperator();
if (T)
{
// Update the individual GridFunction objects. This will allocate new data
// arrays for each GridFunction.
gfr->Update();
gfi->Update();
// Our data array now contains old data as well as being the wrong size so
// reallocate it.
this->SetSize(2 * vsize);
// Create temporary vectors which point to the new data array
Vector gf_r(data, vsize);
Vector gf_i((data) ? &data[vsize] : data, vsize);
// Copy the updated GridFunctions into the new data array
gf_r = *gfr;
gf_i = *gfi;
// Replace the individual data arrays with pointers into the new data
// array
gfr->NewDataAndSize(data, vsize);
gfi->NewDataAndSize((data) ? &data[vsize] : data, vsize);
}
else
{
// The existing data will not be transferred to the new GridFunctions so
// delete it a allocate a new array
this->SetSize(2 * vsize);
// Point the individual GridFunctions to the new data array
gfr->NewDataAndSize(data, vsize);
gfi->NewDataAndSize((data) ? &data[vsize] : data, vsize);
// These updates will only set the proper 'sequence' value within the
// individual GridFunction objects because their sizes are already correct
gfr->Update();
gfi->Update();
}
}
void
ComplexGridFunction::ProjectCoefficient(Coefficient &real_coeff,
Coefficient &imag_coeff)
{
gfr->ProjectCoefficient(real_coeff);
gfi->ProjectCoefficient(imag_coeff);
}
void
ComplexGridFunction::ProjectCoefficient(VectorCoefficient &real_vcoeff,
VectorCoefficient &imag_vcoeff)
{
gfr->ProjectCoefficient(real_vcoeff);
gfi->ProjectCoefficient(imag_vcoeff);
}
void
ComplexGridFunction::ProjectBdrCoefficient(Coefficient &real_coeff,
Coefficient &imag_coeff,
Array<int> &attr)
{
gfr->ProjectBdrCoefficient(real_coeff, attr);
gfi->ProjectBdrCoefficient(imag_coeff, attr);
}
void
ComplexGridFunction::ProjectBdrCoefficientNormal(VectorCoefficient &real_vcoeff,
VectorCoefficient &imag_vcoeff,
Array<int> &attr)
{
gfr->ProjectBdrCoefficientNormal(real_vcoeff, attr);
gfi->ProjectBdrCoefficientNormal(imag_vcoeff, attr);
}
void
ComplexGridFunction::ProjectBdrCoefficientTangent(VectorCoefficient
&real_vcoeff,
VectorCoefficient
&imag_vcoeff,
Array<int> &attr)
{
gfr->ProjectBdrCoefficientTangent(real_vcoeff, attr);
gfi->ProjectBdrCoefficientTangent(imag_vcoeff, attr);
}
ComplexLinearForm::ComplexLinearForm(FiniteElementSpace *f,
ComplexOperator::Convention convention)
: Vector(2*(f->GetVSize())),
conv(convention)
{
lfr = new LinearForm(f, data);
lfi = new LinearForm(f, &data[f->GetVSize()]);
}
ComplexLinearForm::ComplexLinearForm(FiniteElementSpace *fes,
LinearForm *lf_r, LinearForm *lf_i,
ComplexOperator::Convention convention)
: Vector(2*(fes->GetVSize())),
conv(convention)
{
lfr = new LinearForm(fes, lf_r); lfr->SetData(data);
lfi = new LinearForm(fes, lf_i); lfi->SetData(&data[fes->GetVSize()]);
}
ComplexLinearForm::~ComplexLinearForm()
{
delete lfr;
delete lfi;
}
void
ComplexLinearForm::AddDomainIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag)
{
if ( lfi_real ) { lfr->AddDomainIntegrator(lfi_real); }
if ( lfi_imag ) { lfi->AddDomainIntegrator(lfi_imag); }
}
void
ComplexLinearForm::AddBoundaryIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag)
{
if ( lfi_real ) { lfr->AddBoundaryIntegrator(lfi_real); }
if ( lfi_imag ) { lfi->AddBoundaryIntegrator(lfi_imag); }
}
void
ComplexLinearForm::AddBoundaryIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag,
Array<int> &bdr_attr_marker)
{
if ( lfi_real ) { lfr->AddBoundaryIntegrator(lfi_real, bdr_attr_marker); }
if ( lfi_imag ) { lfi->AddBoundaryIntegrator(lfi_imag, bdr_attr_marker); }
}
void
ComplexLinearForm::AddBdrFaceIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag)
{
if ( lfi_real ) { lfr->AddBdrFaceIntegrator(lfi_real); }
if ( lfi_imag ) { lfi->AddBdrFaceIntegrator(lfi_imag); }
}
void
ComplexLinearForm::AddBdrFaceIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag,
Array<int> &bdr_attr_marker)
{
if ( lfi_real ) { lfr->AddBdrFaceIntegrator(lfi_real, bdr_attr_marker); }
if ( lfi_imag ) { lfi->AddBdrFaceIntegrator(lfi_imag, bdr_attr_marker); }
}
void
ComplexLinearForm::Update()
{
FiniteElementSpace *fes = lfr->FESpace();
this->Update(fes);
}
void
ComplexLinearForm::Update(FiniteElementSpace *fes)
{
int vsize = fes->GetVSize();
SetSize(2 * vsize);
Vector vlfr(data, vsize);
Vector vlfi((data) ? &data[vsize] : data, vsize);
lfr->Update(fes, vlfr, 0);
lfi->Update(fes, vlfi, 0);
}
void
ComplexLinearForm::Assemble()
{
lfr->Assemble();
lfi->Assemble();
if (conv == ComplexOperator::BLOCK_SYMMETRIC)
{
*lfi *= -1.0;
}
}
complex<double>
ComplexLinearForm::operator()(const ComplexGridFunction &gf) const
{
double s = (conv == ComplexOperator::HERMITIAN)?1.0:-1.0;
return complex<double>((*lfr)(gf.real()) - s * (*lfi)(gf.imag()),
(*lfr)(gf.imag()) + s * (*lfi)(gf.real()));
}
bool SesquilinearForm::RealInteg()
{
int nint = blfr->GetFBFI()->Size() + blfr->GetDBFI()->Size() +
blfr->GetBBFI()->Size() + blfr->GetBFBFI()->Size();
return (nint != 0);
}
bool SesquilinearForm::ImagInteg()
{
int nint = blfi->GetFBFI()->Size() + blfi->GetDBFI()->Size() +
blfi->GetBBFI()->Size() + blfi->GetBFBFI()->Size();
return (nint != 0);
}
SesquilinearForm::SesquilinearForm(FiniteElementSpace *f,
ComplexOperator::Convention convention)
: conv(convention),
blfr(new BilinearForm(f)),
blfi(new BilinearForm(f))
{}
SesquilinearForm::SesquilinearForm(FiniteElementSpace *f,
BilinearForm *bfr, BilinearForm *bfi,
ComplexOperator::Convention convention)
: conv(convention),
blfr(new BilinearForm(f,bfr)),
blfi(new BilinearForm(f,bfi))
{}
void SesquilinearForm::SetDiagonalPolicy(mfem::Matrix::DiagonalPolicy dpolicy)
{
diag_policy = dpolicy;
}
SesquilinearForm::~SesquilinearForm()
{
delete blfr;
delete blfi;
}
void SesquilinearForm::AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag)
{
if (bfi_real) { blfr->AddDomainIntegrator(bfi_real); }
if (bfi_imag) { blfi->AddDomainIntegrator(bfi_imag); }
}
void
SesquilinearForm::AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag)
{
if (bfi_real) { blfr->AddBoundaryIntegrator(bfi_real); }
if (bfi_imag) { blfi->AddBoundaryIntegrator(bfi_imag); }
}
void
SesquilinearForm::AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag,
Array<int> & bdr_marker)
{
if (bfi_real) { blfr->AddBoundaryIntegrator(bfi_real, bdr_marker); }
if (bfi_imag) { blfi->AddBoundaryIntegrator(bfi_imag, bdr_marker); }
}
void
SesquilinearForm::AddInteriorFaceIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag)
{
if (bfi_real) { blfr->AddInteriorFaceIntegrator(bfi_real); }
if (bfi_imag) { blfi->AddInteriorFaceIntegrator(bfi_imag); }
}
void SesquilinearForm::AddBdrFaceIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag)
{
if (bfi_real) { blfr->AddBdrFaceIntegrator(bfi_real); }
if (bfi_imag) { blfi->AddBdrFaceIntegrator(bfi_imag); }
}
void SesquilinearForm::AddBdrFaceIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag,
Array<int> &bdr_marker)
{
if (bfi_real) { blfr->AddBdrFaceIntegrator(bfi_real, bdr_marker); }
if (bfi_imag) { blfi->AddBdrFaceIntegrator(bfi_imag, bdr_marker); }
}
void
SesquilinearForm::Assemble(int skip_zeros)
{
blfr->Assemble(skip_zeros);
blfi->Assemble(skip_zeros);
}
void
SesquilinearForm::Finalize(int skip_zeros)
{
blfr->Finalize(skip_zeros);
blfi->Finalize(skip_zeros);
}
ComplexSparseMatrix *
SesquilinearForm::AssembleComplexSparseMatrix()
{
return new ComplexSparseMatrix(&blfr->SpMat(),
&blfi->SpMat(),
false, false, conv);
}
void
SesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
Vector &x, Vector &b,
OperatorHandle &A,
Vector &X, Vector &B,
int ci)
{
FiniteElementSpace * fes = blfr->FESpace();
int vsize = fes->GetVSize();
// Allocate temporary vectors
Vector b_0(vsize); b_0 = 0.0;
// Extract the real and imaginary parts of the input vectors
MFEM_ASSERT(x.Size() == 2 * vsize, "Input GridFunction of incorrect size!");
Vector x_r(x.GetData(), vsize);
Vector x_i(&(x.GetData())[vsize], vsize);
MFEM_ASSERT(b.Size() == 2 * vsize, "Input LinearForm of incorrect size!");
Vector b_r(b.GetData(), vsize);
Vector b_i(&(b.GetData())[vsize], vsize);
if (conv == ComplexOperator::BLOCK_SYMMETRIC) { b_i *= -1.0; }
int tvsize = fes->GetTrueVSize();
SparseMatrix * A_r = nullptr;
SparseMatrix * A_i = nullptr;
X.SetSize(2 * tvsize);
B.SetSize(2 * tvsize);
Vector X_0(tvsize), B_0(tvsize);
Vector X_r(X.GetData(),tvsize);
Vector X_i(&(X.GetData())[tvsize], tvsize);
Vector B_r(B.GetData(), tvsize);
Vector B_i(&(B.GetData())[tvsize], tvsize);
if (RealInteg())
{
A_r = new SparseMatrix;
blfr->SetDiagonalPolicy(diag_policy);
b_0 = b_r;
blfr->FormLinearSystem(ess_tdof_list, x_r, b_0, *A_r, X_0, B_0, ci);
X_r = X_0; B_r = B_0;
b_0 = b_i;
blfr->FormLinearSystem(ess_tdof_list, x_i, b_0, *A_r, X_0, B_0, ci);
X_i = X_0; B_i = B_0;
if (ImagInteg())
{
A_i = new SparseMatrix;
blfi->SetDiagonalPolicy(mfem::Matrix::DiagonalPolicy::DIAG_ZERO);
b_0 = 0.0;
blfi->FormLinearSystem(ess_tdof_list, x_i, b_0, *A_i, X_0, B_0, false);
B_r -= B_0;
b_0 = 0.0;
blfi->FormLinearSystem(ess_tdof_list, x_r, b_0, *A_i, X_0, B_0, false);
B_i += B_0;
}
}
else if (ImagInteg())
{
A_i = new SparseMatrix;
blfi->SetDiagonalPolicy(diag_policy);
b_0 = b_i;
blfi->FormLinearSystem(ess_tdof_list, x_r, b_0, *A_i, X_0, B_0, ci);
X_r = X_0; B_i = B_0;
b_0 = b_r; b_0 *= -1.0;
blfi->FormLinearSystem(ess_tdof_list, x_i, b_0, *A_i, X_0, B_0, ci);
X_i = X_0; B_r = B_0; B_r *= -1.0;
}
else
{
MFEM_ABORT("Real and Imaginary part of the Sesquilinear form are empty");
}
if (conv == ComplexOperator::BLOCK_SYMMETRIC)
{
B_i *= -1.0;
b_i *= -1.0;
}
// A = A_r + i A_i
A.Clear();
ComplexSparseMatrix * A_sp;
A_sp = new ComplexSparseMatrix(A_r, A_i, true, true, conv);
A.Reset<ComplexSparseMatrix>(A_sp, true);
}
void
SesquilinearForm::FormSystemMatrix(const Array<int> &ess_tdof_list,
OperatorHandle &A)
{
SparseMatrix * A_r = nullptr;
SparseMatrix * A_i = nullptr;
if (RealInteg())
{
A_r = new SparseMatrix;
blfr->SetDiagonalPolicy(diag_policy);
blfr->FormSystemMatrix(ess_tdof_list, *A_r);
}
if (ImagInteg())
{
A_i = new SparseMatrix;
blfr->SetDiagonalPolicy(diag_policy);
blfi->FormSystemMatrix(ess_tdof_list, *A_i);
}
if (!RealInteg() && !ImagInteg())
{
MFEM_ABORT("Both Real and Imaginary part of the Sesquilinear form are empty");
}
// A = A_r + i A_i
A.Clear();
ComplexSparseMatrix * A_sp =
new ComplexSparseMatrix(A_r, A_i, true, true, conv);
A.Reset<ComplexSparseMatrix>(A_sp, true);
}
void
SesquilinearForm::RecoverFEMSolution(const Vector &X, const Vector &b,
Vector &x)
{
FiniteElementSpace * fes = blfr->FESpace();
const SparseMatrix *P = fes->GetConformingProlongation();
int vsize = fes->GetVSize();
int tvsize = X.Size() / 2;
Vector X_r(X.GetData(), tvsize);
Vector X_i(&(X.GetData())[tvsize], tvsize);
Vector x_r(x.GetData(), vsize);
Vector x_i(&(x.GetData())[vsize], vsize);
if (!P)
{
x = X;
}
else
{
// Apply conforming prolongation
P->Mult(X_r, x_r);
P->Mult(X_i, x_i);
}
}
void
SesquilinearForm::Update(FiniteElementSpace *nfes)
{
if ( blfr ) { blfr->Update(nfes); }
if ( blfi ) { blfi->Update(nfes); }
}
#ifdef MFEM_USE_MPI
ParComplexGridFunction::ParComplexGridFunction(ParFiniteElementSpace *pfes)
: Vector(2*(pfes->GetVSize()))
{
pgfr = new ParGridFunction(pfes, data);
pgfi = new ParGridFunction(pfes, (data) ? &data[pfes->GetVSize()]:data);
}
void
ParComplexGridFunction::Update()
{
ParFiniteElementSpace * pfes = pgfr->ParFESpace();
int vsize = pfes->GetVSize();
const Operator *T = pfes->GetUpdateOperator();
if (T)
{
// Update the individual GridFunction objects. This will allocate new data
// arrays for each GridFunction.
pgfr->Update();
pgfi->Update();
// Our data array now contains old data as well as being the wrong size so
// reallocate it.
this->SetSize(2 * vsize);
// Create temporary vectors which point to the new data array
Vector gf_r(data, vsize);
Vector gf_i((data) ? &data[vsize] : data, vsize);
// Copy the updated GridFunctions into the new data array
gf_r = *pgfr;
gf_i = *pgfi;
// Replace the individual data arrays with pointers into the new data
// array
pgfr->NewDataAndSize(data, vsize);
pgfi->NewDataAndSize((data) ? &data[vsize] : data, vsize);
}
else
{
// The existing data will not be transferred to the new GridFunctions so
// delete it a allocate a new array
this->SetSize(2 * vsize);
// Point the individual GridFunctions to the new data array
pgfr->NewDataAndSize(data, vsize);
pgfi->NewDataAndSize((data) ? &data[vsize] : data, vsize);
// These updates will only set the proper 'sequence' value within the
// individual GridFunction objects because their sizes are already correct
pgfr->Update();
pgfi->Update();
}
}
void
ParComplexGridFunction::ProjectCoefficient(Coefficient &real_coeff,
Coefficient &imag_coeff)
{
pgfr->ProjectCoefficient(real_coeff);
pgfi->ProjectCoefficient(imag_coeff);
}
void
ParComplexGridFunction::ProjectCoefficient(VectorCoefficient &real_vcoeff,
VectorCoefficient &imag_vcoeff)
{
pgfr->ProjectCoefficient(real_vcoeff);
pgfi->ProjectCoefficient(imag_vcoeff);
}
void
ParComplexGridFunction::ProjectBdrCoefficient(Coefficient &real_coeff,
Coefficient &imag_coeff,
Array<int> &attr)
{
pgfr->ProjectBdrCoefficient(real_coeff, attr);
pgfi->ProjectBdrCoefficient(imag_coeff, attr);
}
void
ParComplexGridFunction::ProjectBdrCoefficientNormal(VectorCoefficient
&real_vcoeff,
VectorCoefficient
&imag_vcoeff,
Array<int> &attr)
{
pgfr->ProjectBdrCoefficientNormal(real_vcoeff, attr);
pgfi->ProjectBdrCoefficientNormal(imag_vcoeff, attr);
}
void
ParComplexGridFunction::ProjectBdrCoefficientTangent(VectorCoefficient
&real_vcoeff,
VectorCoefficient
&imag_vcoeff,
Array<int> &attr)
{
pgfr->ProjectBdrCoefficientTangent(real_vcoeff, attr);
pgfi->ProjectBdrCoefficientTangent(imag_vcoeff, attr);
}
void
ParComplexGridFunction::Distribute(const Vector *tv)
{
ParFiniteElementSpace * pfes = pgfr->ParFESpace();
HYPRE_Int size = pfes->GetTrueVSize();
double * tvd = tv->GetData();
Vector tvr(tvd, size);
Vector tvi((tvd) ? &tvd[size] : tvd, size);
pgfr->Distribute(tvr);
pgfi->Distribute(tvi);
}
void
ParComplexGridFunction::ParallelProject(Vector &tv) const
{
ParFiniteElementSpace * pfes = pgfr->ParFESpace();
HYPRE_Int size = pfes->GetTrueVSize();
double * tvd = tv.GetData();
Vector tvr(tvd, size);
Vector tvi((tvd) ? &tvd[size] : tvd, size);
pgfr->ParallelProject(tvr);
pgfi->ParallelProject(tvi);
}
ParComplexLinearForm::ParComplexLinearForm(ParFiniteElementSpace *pfes,
ComplexOperator::Convention
convention)
: Vector(2*(pfes->GetVSize())),
conv(convention)
{
plfr = new ParLinearForm(pfes, data);
plfi = new ParLinearForm(pfes, (data) ? &data[pfes->GetVSize()]:data);
HYPRE_Int * tdof_offsets_fes = pfes->GetTrueDofOffsets();
int n = (HYPRE_AssumedPartitionCheck()) ? 2 : pfes->GetNRanks();
tdof_offsets = new HYPRE_Int[n+1];
for (int i=0; i<=n; i++)
{
tdof_offsets[i] = 2 * tdof_offsets_fes[i];
}
}
ParComplexLinearForm::ParComplexLinearForm(ParFiniteElementSpace *pfes,
ParLinearForm *plf_r, ParLinearForm *plf_i,
ComplexOperator::Convention
convention)
: Vector(2*(pfes->GetVSize())),
conv(convention)
{
plfr = new ParLinearForm(pfes, plf_r);
plfr->SetData(data);
plfi = new ParLinearForm(pfes, plf_i);
plfi->SetData((data) ? &data[pfes->GetVSize()]:data);
HYPRE_Int * tdof_offsets_fes = pfes->GetTrueDofOffsets();
int n = (HYPRE_AssumedPartitionCheck()) ? 2 : pfes->GetNRanks();
tdof_offsets = new HYPRE_Int[n+1];
for (int i=0; i<=n; i++)
{
tdof_offsets[i] = 2 * tdof_offsets_fes[i];
}
}
ParComplexLinearForm::~ParComplexLinearForm()
{
delete plfr;
delete plfi;
delete [] tdof_offsets;
}
void
ParComplexLinearForm::AddDomainIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag)
{
if ( lfi_real ) { plfr->AddDomainIntegrator(lfi_real); }
if ( lfi_imag ) { plfi->AddDomainIntegrator(lfi_imag); }
}
void
ParComplexLinearForm::AddBoundaryIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag)
{
if ( lfi_real ) { plfr->AddBoundaryIntegrator(lfi_real); }
if ( lfi_imag ) { plfi->AddBoundaryIntegrator(lfi_imag); }
}
void
ParComplexLinearForm::AddBoundaryIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag,
Array<int> &bdr_attr_marker)
{
if ( lfi_real ) { plfr->AddBoundaryIntegrator(lfi_real, bdr_attr_marker); }
if ( lfi_imag ) { plfi->AddBoundaryIntegrator(lfi_imag, bdr_attr_marker); }
}
void
ParComplexLinearForm::AddBdrFaceIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag)
{
if ( lfi_real ) { plfr->AddBdrFaceIntegrator(lfi_real); }
if ( lfi_imag ) { plfi->AddBdrFaceIntegrator(lfi_imag); }
}
void
ParComplexLinearForm::AddBdrFaceIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag,
Array<int> &bdr_attr_marker)
{
if ( lfi_real ) { plfr->AddBdrFaceIntegrator(lfi_real, bdr_attr_marker); }
if ( lfi_imag ) { plfi->AddBdrFaceIntegrator(lfi_imag, bdr_attr_marker); }
}
void
ParComplexLinearForm::Update(ParFiniteElementSpace *pf)
{
ParFiniteElementSpace *pfes = (pf!=NULL)?pf:plfr->ParFESpace();
int vsize = pfes->GetVSize();
SetSize(2 * vsize);
Vector vplfr(data, vsize);
Vector vplfi((data) ? &data[vsize] : data, vsize);
plfr->Update(pfes, vplfr, 0);
plfi->Update(pfes, vplfi, 0);
}
void
ParComplexLinearForm::Assemble()
{
plfr->Assemble();
plfi->Assemble();
if (conv == ComplexOperator::BLOCK_SYMMETRIC)
{
*plfi *= -1.0;
}
}
void
ParComplexLinearForm::ParallelAssemble(Vector &tv)
{
HYPRE_Int size = plfr->ParFESpace()->GetTrueVSize();
double * tvd = tv.GetData();
Vector tvr(tvd, size);
Vector tvi((tvd) ? &tvd[size] : tvd, size);
plfr->ParallelAssemble(tvr);
plfi->ParallelAssemble(tvi);
}
HypreParVector *
ParComplexLinearForm::ParallelAssemble()
{
const ParFiniteElementSpace * pfes = plfr->ParFESpace();
HypreParVector * tv = new HypreParVector(pfes->GetComm(),
2*(pfes->GlobalTrueVSize()),
tdof_offsets);
HYPRE_Int size = pfes->GetTrueVSize();
double * tvd = tv->GetData();
Vector tvr(tvd, size);
Vector tvi((tvd) ? &tvd[size] : tvd, size);
plfr->ParallelAssemble(tvr);
plfi->ParallelAssemble(tvi);
return tv;
}
complex<double>
ParComplexLinearForm::operator()(const ParComplexGridFunction &gf) const
{
double s = (conv == ComplexOperator::HERMITIAN)?1.0:-1.0;
return complex<double>((*plfr)(gf.real()) - s * (*plfi)(gf.imag()),
(*plfr)(gf.imag()) + s * (*plfi)(gf.real()));
}
bool ParSesquilinearForm::RealInteg()
{
int nint = pblfr->GetFBFI()->Size() + pblfr->GetDBFI()->Size() +
pblfr->GetBBFI()->Size() + pblfr->GetBFBFI()->Size();
return (nint != 0);
}
bool ParSesquilinearForm::ImagInteg()
{
int nint = pblfi->GetFBFI()->Size() + pblfi->GetDBFI()->Size() +
pblfi->GetBBFI()->Size() + pblfi->GetBFBFI()->Size();
return (nint != 0);
}
ParSesquilinearForm::ParSesquilinearForm(ParFiniteElementSpace *pf,
ComplexOperator::Convention
convention)
: conv(convention),
pblfr(new ParBilinearForm(pf)),
pblfi(new ParBilinearForm(pf))
{}
ParSesquilinearForm::ParSesquilinearForm(ParFiniteElementSpace *pf,
ParBilinearForm *pbfr, ParBilinearForm *pbfi,
ComplexOperator::Convention convention)
: conv(convention),
pblfr(new ParBilinearForm(pf,pbfr)),
pblfi(new ParBilinearForm(pf,pbfi))
{}
ParSesquilinearForm::~ParSesquilinearForm()
{
delete pblfr;
delete pblfi;
}
void ParSesquilinearForm::AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag)
{
if (bfi_real) { pblfr->AddDomainIntegrator(bfi_real); }
if (bfi_imag) { pblfi->AddDomainIntegrator(bfi_imag); }
}
void
ParSesquilinearForm::AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag)
{
if (bfi_real) { pblfr->AddBoundaryIntegrator(bfi_real); }
if (bfi_imag) { pblfi->AddBoundaryIntegrator(bfi_imag); }
}
void
ParSesquilinearForm::AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag,
Array<int> & bdr_marker)
{
if (bfi_real) { pblfr->AddBoundaryIntegrator(bfi_real, bdr_marker); }
if (bfi_imag) { pblfi->AddBoundaryIntegrator(bfi_imag, bdr_marker); }
}
void
ParSesquilinearForm::AddInteriorFaceIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag)
{
if (bfi_real) { pblfr->AddInteriorFaceIntegrator(bfi_real); }
if (bfi_imag) { pblfi->AddInteriorFaceIntegrator(bfi_imag); }
}
void
ParSesquilinearForm::AddBdrFaceIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag)
{
if (bfi_real) { pblfr->AddBdrFaceIntegrator(bfi_real); }
if (bfi_imag) { pblfi->AddBdrFaceIntegrator(bfi_imag); }
}
void
ParSesquilinearForm::AddBdrFaceIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag,
Array<int> &bdr_marker)
{
if (bfi_real) { pblfr->AddBdrFaceIntegrator(bfi_real, bdr_marker); }
if (bfi_imag) { pblfi->AddBdrFaceIntegrator(bfi_imag, bdr_marker); }
}
void
ParSesquilinearForm::Assemble(int skip_zeros)
{
pblfr->Assemble(skip_zeros);
pblfi->Assemble(skip_zeros);
}
void
ParSesquilinearForm::Finalize(int skip_zeros)
{
pblfr->Finalize(skip_zeros);
pblfi->Finalize(skip_zeros);
}
ComplexHypreParMatrix *
ParSesquilinearForm::ParallelAssemble()
{
return new ComplexHypreParMatrix(pblfr->ParallelAssemble(),
pblfi->ParallelAssemble(),
true, true, conv);
}
void
ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
Vector &x, Vector &b,
OperatorHandle &A,
Vector &X, Vector &B,
int ci)
{
ParFiniteElementSpace * pfes = pblfr->ParFESpace();
int vsize = pfes->GetVSize();
// Allocate temporary vectors
Vector b_0(vsize); b_0 = 0.0;
// Extract the real and imaginary parts of the input vectors
Vector x_r(x.GetData(), vsize);
Vector x_i(&(x.GetData())[vsize], vsize);
MFEM_ASSERT(b.Size() == 2 * vsize, "Input LinearForm of incorrect size!");
Vector b_r(b.GetData(), vsize);
Vector b_i(&(b.GetData())[vsize], vsize);
if (conv == ComplexOperator::BLOCK_SYMMETRIC) { b_i *= -1.0; }
int tvsize = pfes->GetTrueVSize();
OperatorHandle A_r, A_i;
X.SetSize(2 * tvsize);
B.SetSize(2 * tvsize);
Vector X_0(tvsize), B_0(tvsize);
Vector X_r(X.GetData(),tvsize);
Vector X_i(&(X.GetData())[tvsize], tvsize);
Vector B_r(B.GetData(), tvsize);
Vector B_i(&(B.GetData())[tvsize], tvsize);
if (RealInteg())
{
b_0 = b_r;
pblfr->FormLinearSystem(ess_tdof_list, x_r, b_0, A_r, X_0, B_0, ci);
X_r = X_0; B_r = B_0;
b_0 = b_i;
pblfr->FormLinearSystem(ess_tdof_list, x_i, b_0, A_r, X_0, B_0, ci);
X_i = X_0; B_i = B_0;
if (ImagInteg())
{
b_0 = 0.0;
pblfi->FormLinearSystem(ess_tdof_list, x_i, b_0, A_i, X_0, B_0, false);
B_r -= B_0;
b_0 = 0.0;
pblfi->FormLinearSystem(ess_tdof_list, x_r, b_0, A_i, X_0, B_0, false);
B_i += B_0;
}
}
else if (ImagInteg())
{
b_0 = b_i;
pblfi->FormLinearSystem(ess_tdof_list, x_r, b_0, A_i, X_0, B_0, ci);
X_r = X_0; B_i = B_0;
b_0 = b_r; b_0 *= -1.0;
pblfi->FormLinearSystem(ess_tdof_list, x_i, b_0, A_i, X_0, B_0, ci);
X_i = X_0; B_r = B_0; B_r *= -1.0;
}
else
{
MFEM_ABORT("Real and Imaginary part of the Sesquilinear form are empty");
}
// Modify RHS and offdiagonal blocks (Imaginary parts of the matrix) to
// conform with standard essential BC treatment i.e. zero out rows and
// columns and place ones on the diagonal.
if (RealInteg() && ImagInteg())
{
if ( A_i.Type() == Operator::Hypre_ParCSR )
{
HypreParMatrix * Ah; A_i.Get(Ah);
int n = ess_tdof_list.Size();
hypre_ParCSRMatrix * Aih =
(hypre_ParCSRMatrix *)const_cast<HypreParMatrix&>(*Ah);
for (int k=0; k<n; k++)
{
int j=ess_tdof_list[k];
Aih->diag->data[Aih->diag->i[j]] = 0.0;
B_r(j) = X_r(j);
B_i(j) = X_i(j);
}
}
}
if (conv == ComplexOperator::BLOCK_SYMMETRIC)
{
B_i *= -1.0;
b_i *= -1.0;
}
// A = A_r + i A_i
A.Clear();
if ( A_r.Type() == Operator::Hypre_ParCSR ||
A_i.Type() == Operator::Hypre_ParCSR )
{
ComplexHypreParMatrix * A_hyp =
new ComplexHypreParMatrix(A_r.As<HypreParMatrix>(),
A_i.As<HypreParMatrix>(),
A_r.OwnsOperator(),
A_i.OwnsOperator(),
conv);
A.Reset<ComplexHypreParMatrix>(A_hyp, true);
}
else
{
ComplexOperator * A_op =
new ComplexOperator(A_r.As<Operator>(),
A_i.As<Operator>(),
A_r.OwnsOperator(),
A_i.OwnsOperator(),
conv);
A.Reset<ComplexOperator>(A_op, true);
}
}
void
ParSesquilinearForm::FormSystemMatrix(const Array<int> &ess_tdof_list,
OperatorHandle &A)
{
OperatorHandle A_r, A_i;
if (RealInteg())
{
pblfr->FormSystemMatrix(ess_tdof_list, A_r);
}
if (ImagInteg())
{
pblfi->FormSystemMatrix(ess_tdof_list, A_i);
}
if (!RealInteg() && !ImagInteg())
{
MFEM_ABORT("Both Real and Imaginary part of the Sesquilinear form are empty");
}
// Modify offdiagonal blocks (Imaginary parts of the matrix) to conform with
// standard essential BC treatment i.e. zero out rows and columns and place
// ones on the diagonal.
if (RealInteg() && ImagInteg())
{
if ( A_i.Type() == Operator::Hypre_ParCSR )
{
int n = ess_tdof_list.Size();
int j;
HypreParMatrix * Ah; A_i.Get(Ah);
hypre_ParCSRMatrix * Aih =
(hypre_ParCSRMatrix *)const_cast<HypreParMatrix&>(*Ah);
for (int k=0; k<n; k++)
{
j=ess_tdof_list[k];
Aih->diag->data[Aih->diag->i[j]] = 0.0;
}
}
}
// A = A_r + i A_i
A.Clear();
if ( A_r.Type() == Operator::Hypre_ParCSR ||
A_i.Type() == Operator::Hypre_ParCSR )
{
ComplexHypreParMatrix * A_hyp =
new ComplexHypreParMatrix(A_r.As<HypreParMatrix>(),
A_i.As<HypreParMatrix>(),
A_r.OwnsOperator(),
A_i.OwnsOperator(),
conv);
A.Reset<ComplexHypreParMatrix>(A_hyp, true);
}
else
{
ComplexOperator * A_op =
new ComplexOperator(A_r.As<Operator>(),
A_i.As<Operator>(),
A_r.OwnsOperator(),
A_i.OwnsOperator(),
conv);
A.Reset<ComplexOperator>(A_op, true);
}
}
void
ParSesquilinearForm::RecoverFEMSolution(const Vector &X, const Vector &b,
Vector &x)
{
ParFiniteElementSpace * pfes = pblfr->ParFESpace();
const Operator &P = *pfes->GetProlongationMatrix();
int vsize = pfes->GetVSize();
int tvsize = X.Size() / 2;
Vector X_r(X.GetData(), tvsize);
Vector X_i(&(X.GetData())[tvsize], tvsize);
Vector x_r(x.GetData(), vsize);
Vector x_i(&(x.GetData())[vsize], vsize);
// Apply conforming prolongation
P.Mult(X_r, x_r);
P.Mult(X_i, x_i);
}
void
ParSesquilinearForm::Update(FiniteElementSpace *nfes)
{
if ( pblfr ) { pblfr->Update(nfes); }
if ( pblfi ) { pblfi->Update(nfes); }
}
#endif // MFEM_USE_MPI
}