Files
mfem/tests/unit/fem/test_surf_blf.cpp
T

220 lines
5.6 KiB
C++

// Copyright (c) 2010-2025, 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 "mfem.hpp"
#include "catch.hpp"
using namespace mfem;
namespace surf_blf
{
Mesh * GetCylMesh(int type);
void trans_skew_cyl(const Vector &x, Vector &r);
void sigmaFunc(const Vector &x, DenseMatrix &s);
double uExact(const Vector &x)
{
return (0.25 * (2.0 + x[0]) - x[2]) * (x[2] + 0.25 * (2.0 + x[0]));
}
TEST_CASE("Embedded Surface Diffusion",
"[DiffusionIntegrator]")
{
for (int type = (int) Element::TRIANGLE;
type <= (int) Element::QUADRILATERAL;
type++)
{
int order = 3;
Mesh *mesh = GetCylMesh(type);
int dim = mesh->Dimension();
mesh->SetCurvature(3);
mesh->Transform(trans_skew_cyl);
H1_FECollection fec(order, dim);
FiniteElementSpace fespace(mesh, &fec);
Array<int> ess_tdof_list;
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
LinearForm b(&fespace);
ConstantCoefficient one(1.0);
b.AddDomainIntegrator(new DomainLFIntegrator(one));
b.Assemble();
GridFunction x(&fespace);
x = 0.0;
BilinearForm a(&fespace);
MatrixFunctionCoefficient sigma(3, sigmaFunc);
a.AddDomainIntegrator(new DiffusionIntegrator(sigma));
a.Assemble();
OperatorPtr A;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
GSSmoother M((SparseMatrix&)(*A));
PCG(*A, M, B, X, 0, 200, 1e-12, 0.0);
a.RecoverFEMSolution(X, b, x);
FunctionCoefficient uCoef(uExact);
double err = x.ComputeL2Error(uCoef);
REQUIRE(err < 1.5e-3);
delete mesh;
}
}
Mesh * GetCylMesh(int type)
{
Mesh * mesh = NULL;
if (type == (int) Element::TRIANGLE)
{
mesh = new Mesh(2, 12, 16, 8, 3);
mesh->AddVertex(-1.0, -1.0, 0.0);
mesh->AddVertex( 1.0, -1.0, 0.0);
mesh->AddVertex( 1.0, 1.0, 0.0);
mesh->AddVertex(-1.0, 1.0, 0.0);
mesh->AddVertex(-1.0, -1.0, 1.0);
mesh->AddVertex( 1.0, -1.0, 1.0);
mesh->AddVertex( 1.0, 1.0, 1.0);
mesh->AddVertex(-1.0, 1.0, 1.0);
mesh->AddVertex( 0.0, -1.0, 0.5);
mesh->AddVertex( 1.0, 0.0, 0.5);
mesh->AddVertex( 0.0, 1.0, 0.5);
mesh->AddVertex(-1.0, 0.0, 0.5);
mesh->AddTriangle(0, 1, 8);
mesh->AddTriangle(1, 5, 8);
mesh->AddTriangle(5, 4, 8);
mesh->AddTriangle(4, 0, 8);
mesh->AddTriangle(1, 2, 9);
mesh->AddTriangle(2, 6, 9);
mesh->AddTriangle(6, 5, 9);
mesh->AddTriangle(5, 1, 9);
mesh->AddTriangle(2, 3, 10);
mesh->AddTriangle(3, 7, 10);
mesh->AddTriangle(7, 6, 10);
mesh->AddTriangle(6, 2, 10);
mesh->AddTriangle(3, 0, 11);
mesh->AddTriangle(0, 4, 11);
mesh->AddTriangle(4, 7, 11);
mesh->AddTriangle(7, 3, 11);
mesh->AddBdrSegment(0, 1, 1);
mesh->AddBdrSegment(1, 2, 1);
mesh->AddBdrSegment(2, 3, 1);
mesh->AddBdrSegment(3, 0, 1);
mesh->AddBdrSegment(5, 4, 2);
mesh->AddBdrSegment(6, 5, 2);
mesh->AddBdrSegment(7, 6, 2);
mesh->AddBdrSegment(4, 7, 2);
}
else if (type == (int) Element::QUADRILATERAL)
{
mesh = new Mesh(2, 8, 4, 8, 3);
mesh->AddVertex(-1.0, -1.0, 0.0);
mesh->AddVertex( 1.0, -1.0, 0.0);
mesh->AddVertex( 1.0, 1.0, 0.0);
mesh->AddVertex(-1.0, 1.0, 0.0);
mesh->AddVertex(-1.0, -1.0, 1.0);
mesh->AddVertex( 1.0, -1.0, 1.0);
mesh->AddVertex( 1.0, 1.0, 1.0);
mesh->AddVertex(-1.0, 1.0, 1.0);
mesh->AddQuad(0, 1, 5, 4);
mesh->AddQuad(1, 2, 6, 5);
mesh->AddQuad(2, 3, 7, 6);
mesh->AddQuad(3, 0, 4, 7);
mesh->AddBdrSegment(0, 1, 1);
mesh->AddBdrSegment(1, 2, 1);
mesh->AddBdrSegment(2, 3, 1);
mesh->AddBdrSegment(3, 0, 1);
mesh->AddBdrSegment(5, 4, 2);
mesh->AddBdrSegment(6, 5, 2);
mesh->AddBdrSegment(7, 6, 2);
mesh->AddBdrSegment(4, 7, 2);
}
else
{
MFEM_ABORT("Unrecognized mesh type " << type << "!");
}
mesh->FinalizeTopology();
return mesh;
}
void trans_skew_cyl(const Vector &x, Vector &r)
{
r.SetSize(3);
double tol = 1e-6;
double theta = 0.0;
if (fabs(x[1] + 1.0) < tol)
{
theta = 0.25 * M_PI * (x[0] - 2.0);
}
else if (fabs(x[0] - 1.0) < tol)
{
theta = 0.25 * M_PI * x[1];
}
else if (fabs(x[1] - 1.0) < tol)
{
theta = 0.25 * M_PI * (2.0 - x[0]);
}
else if (fabs(x[0] + 1.0) < tol)
{
theta = 0.25 * M_PI * (4.0 - x[1]);
}
else
{
mfem::out << "side not recognized "
<< x[0] << " " << x[1] << " " << x[2] << std::endl;
}
r[0] = cos(theta);
r[1] = sin(theta);
r[2] = 0.25 * (2.0 * x[2] - 1.0) * (r[0] + 2.0);
}
void sigmaFunc(const Vector &x, DenseMatrix &s)
{
s.SetSize(3);
double a = 17.0 - 2.0 * x[0] * (1.0 + x[0]);
s(0,0) = 0.5 + x[0] * x[0] * (8.0 / a - 0.5);
s(0,1) = x[0] * x[1] * (8.0 / a - 0.5);
s(0,2) = 0.0;
s(1,0) = s(0,1);
s(1,1) = 0.5 * x[0] * x[0] + 8.0 * x[1] * x[1] / a;
s(1,2) = 0.0;
s(2,0) = 0.0;
s(2,1) = 0.0;
s(2,2) = a / 32.0;
}
} // namespace surf_blf