214 lines
5.3 KiB
C++
214 lines
5.3 KiB
C++
#include "lor.hpp"
|
|
|
|
|
|
const Array<int> &GetDofMap(FiniteElementSpace &fes, int i)
|
|
{
|
|
const FiniteElement *fe = fes.GetFE(i);
|
|
auto tfe = dynamic_cast<const TensorBasisElement*>(fe);
|
|
MFEM_ASSERT(tfe != NULL, "");
|
|
return tfe->GetDofMap();
|
|
}
|
|
|
|
Array<int> ComputeVectorFE_LORPermutation(
|
|
FiniteElementSpace &fes_ho,
|
|
FiniteElementSpace &fes_lor,
|
|
FiniteElement::MapType type)
|
|
{
|
|
// Given an index `i` of a LOR dof, `perm[i]` is the index of the
|
|
// corresponding HO dof.
|
|
Array<int> perm(fes_lor.GetVSize());
|
|
Array<int> vdof_ho, vdof_lor;
|
|
|
|
Mesh &mesh_lor = *fes_lor.GetMesh();
|
|
int dim = mesh_lor.Dimension();
|
|
const CoarseFineTransformations &cf_tr = mesh_lor.GetRefinementTransforms();
|
|
for (int ilor=0; ilor<mesh_lor.GetNE(); ++ilor)
|
|
{
|
|
int iho = cf_tr.embeddings[ilor].parent;
|
|
int lor_index = cf_tr.embeddings[ilor].matrix;
|
|
|
|
int p = fes_ho.GetOrder(iho);
|
|
int p1 = p+1;
|
|
int ndof_per_dim = (dim == 2) ? p*p1 :
|
|
type == FiniteElement::H_CURL ? p*p1*p1 : p*p*p1;
|
|
|
|
fes_ho.GetElementVDofs(iho, vdof_ho);
|
|
fes_lor.GetElementVDofs(ilor, vdof_lor);
|
|
|
|
const Array<int> &dofmap_ho = GetDofMap(fes_ho, iho);
|
|
const Array<int> &dofmap_lor = GetDofMap(fes_lor, ilor);
|
|
|
|
int off_x = lor_index % p;
|
|
int off_y = (lor_index / p) % p;
|
|
int off_z = (lor_index / p) / p;
|
|
|
|
auto absdof = [](int i) { return i < 0 ? -1-i : i; };
|
|
|
|
auto set_perm = [&](int off_lor, int off_ho, int n1, int n2)
|
|
{
|
|
for (int i1=0; i1<2; ++i1)
|
|
{
|
|
int m = (dim == 2 || type == FiniteElement::H_DIV) ? 1 : 2;
|
|
for (int i2=0; i2<m; ++i2)
|
|
{
|
|
int i;
|
|
i = dofmap_lor[off_lor + i1 + i2*2];
|
|
int s1 = i < 0 ? -1 : 1;
|
|
int idof_lor = vdof_lor[absdof(i)];
|
|
i = dofmap_ho[off_ho + i1*n1 + i2*n2];
|
|
int s2 = i < 0 ? -1 : 1;
|
|
int idof_ho = vdof_ho[absdof(i)];
|
|
int s3 = idof_lor < 0 ? -1 : 1;
|
|
int s4 = idof_ho < 0 ? -1 : 1;
|
|
int s = s1*s2*s3*s4;
|
|
i = absdof(idof_ho);
|
|
perm[absdof(idof_lor)] = s < 0 ? -1-absdof(i) : absdof(i);
|
|
}
|
|
}
|
|
};
|
|
|
|
int offset;
|
|
|
|
if (type == FiniteElement::H_CURL)
|
|
{
|
|
// x
|
|
offset = off_x + off_y*p + off_z*p*p1;
|
|
set_perm(0, offset, p, p*p1);
|
|
// y
|
|
offset = ndof_per_dim + off_x + off_y*(p1) + off_z*p1*p;
|
|
set_perm(dim == 2 ? 2 : 4, offset, 1, p*p1);
|
|
// z
|
|
if (dim == 3)
|
|
{
|
|
offset = 2*ndof_per_dim + off_x + off_y*p1 + off_z*p1*p1;
|
|
set_perm(8, offset, 1, p+1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// x
|
|
offset = off_x + off_y*p1 + off_z*p*p1;
|
|
set_perm(0, offset, 1, 0);
|
|
// y
|
|
offset = ndof_per_dim + off_x + off_y*p + off_z*p1*p;
|
|
set_perm(2, offset, p, 0);
|
|
// z
|
|
if (dim == 3)
|
|
{
|
|
offset = 2*ndof_per_dim + off_x + off_y*p + off_z*p*p;
|
|
set_perm(4, offset, p*p, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
return perm;
|
|
}
|
|
|
|
|
|
RealLORSolver::RealLORSolver(HypreParMatrix & A, const Array<int> p_, bool exact, Solver * prec)
|
|
: Solver(A.Height()), p(p_)
|
|
{
|
|
if (exact)
|
|
{
|
|
solv = new MUMPSSolver;
|
|
dynamic_cast<MUMPSSolver*>(solv)->SetOperator(A);
|
|
}
|
|
else
|
|
{
|
|
solv = prec;
|
|
}
|
|
int n = A.Height();
|
|
n2 = p.Size();
|
|
n1 = n - n2;
|
|
perm.SetSize(n);
|
|
for (int i = 0; i<n1; i++) { perm[i] = i; }
|
|
for (int i = 0; i<n2; i++) { perm[i+n1] = p[i]; }
|
|
}
|
|
|
|
void RealLORSolver::Mult(const Vector &b, Vector &x) const
|
|
{
|
|
Vector bp(b.Size());
|
|
Vector xp(x.Size());
|
|
|
|
for (int i=0; i<n1; ++i)
|
|
{
|
|
bp[i] = b[i];
|
|
}
|
|
|
|
for (int i=n1; i<n1+n2; ++i)
|
|
{
|
|
int m = perm[i] < 0 ? n1-1-perm[i] : n1+perm[i];
|
|
bp[i] = perm[i] < 0 ? -b[m] : b[m];
|
|
}
|
|
|
|
solv->Mult(bp, xp);
|
|
|
|
for (int i=0; i<n1; ++i)
|
|
{
|
|
x[i] = xp[i];
|
|
}
|
|
for (int i=n1; i<x.Size(); ++i)
|
|
{
|
|
int pi = perm[i];
|
|
int s = pi < 0 ? -1 : 1;
|
|
int n = pi < 0 ? n1-1-pi : n1 + pi;
|
|
x[n] = s*xp[i];
|
|
}
|
|
}
|
|
|
|
ComplexLORSolver::ComplexLORSolver(HypreParMatrix & A, const Array<int> p_, bool exact, Solver * prec)
|
|
: Solver(A.Height()), p(p_)
|
|
{
|
|
if (exact)
|
|
{
|
|
solv = new MUMPSSolver;
|
|
dynamic_cast<MUMPSSolver*>(solv)->SetOperator(A);
|
|
}
|
|
else
|
|
{
|
|
solv = prec;
|
|
}
|
|
int n = A.Height()/2;
|
|
n2 = p.Size();
|
|
n1 = n - n2;
|
|
perm.SetSize(n);
|
|
for (int i = 0; i<n1; i++) { perm[i] = i; }
|
|
for (int i = 0; i<n2; i++) { perm[i+n1] = p[i]; }
|
|
}
|
|
|
|
void ComplexLORSolver::Mult(const Vector &b, Vector &x) const
|
|
{
|
|
Vector bp(b.Size());
|
|
Vector xp(x.Size());
|
|
|
|
for (int i=0; i<n1; ++i)
|
|
{
|
|
bp[i] = b[i];
|
|
bp[n1+n2+i] = b[n1+n2+i];
|
|
}
|
|
|
|
for (int i=n1; i<n1+n2; ++i)
|
|
{
|
|
int m = perm[i] < 0 ? n1-1-perm[i] : n1+perm[i];
|
|
bp[i] = perm[i] < 0 ? -b[m] : b[m];
|
|
bp[n1+n2+i] = perm[i] < 0 ? -b[n1+n2+m] : b[n1+n2+m];
|
|
}
|
|
|
|
solv->Mult(bp, xp);
|
|
|
|
for (int i=0; i<n1; ++i)
|
|
{
|
|
x[i] = xp[i];
|
|
x[n1+n2+i] = xp[n1+n2+i];
|
|
}
|
|
|
|
for (int i=n1; i<n1+n2; ++i)
|
|
{
|
|
int pi = perm[i];
|
|
int s = pi < 0 ? -1 : 1;
|
|
int n = pi < 0 ? n1-1-pi : n1 + pi;
|
|
x[n] = s*xp[i];
|
|
x[n+n1+n2] = s*xp[i+n1+n2];
|
|
}
|
|
|
|
} |