66 #include "../../general/forall.hpp" 71 constexpr
int DIM = 2;
73 constexpr
double PI = M_PI;
74 constexpr
double NRM = 1.e-4;
75 constexpr
double EPS = 1.e-14;
77 constexpr
double NL_DMAX = std::numeric_limits<double>::max();
102 bool by_vdim =
false;
103 bool snapshot =
false;
104 bool vis_mesh =
false;
107 double amr_threshold = 0.6;
108 const char *keys =
"gAm";
109 const char *device_config =
"cpu";
110 const char *mesh_file =
"../../data/mobius-strip.mesh";
114 class Surface:
public Mesh 126 Surface(Opt &opt,
const char *file):
Mesh(file, true), opt(opt) { }
129 Surface(Opt &opt,
bool):
Mesh(), opt(opt) { }
133 :
Mesh(
Mesh::MakeCartesian2D(opt.nx, opt.ny,
QUAD, true)), opt(opt) { }
136 Surface(Opt &opt,
int nv,
int ne,
int nbe):
150 if (opt.amr) { EnsureNCMesh(); }
151 mesh =
new Mesh(*
this,
true);
153 BoundaryConditions();
165 ByVDim(*
this, opt).Solve();
169 ByNodes(*
this, opt).Solve();
171 if (opt.vis && opt.snapshot)
174 Visualize(glvis, opt, mesh, mesh->
GetNodes());
181 if (opt.vis) { glvis.
close(); }
182 delete mesh;
delete fec;
delete fes;
185 virtual void Prefix()
190 virtual void Transform() {
if (opt.Tptr) {
Mesh::Transform(opt.Tptr); } }
192 virtual void Postfix()
197 virtual void Refine()
199 for (
int l = 0; l < opt.refine; l++)
208 for (
int i = 0; i < nodes.
Size(); i++)
210 if (std::abs(nodes(i)) <
EPS)
217 void SnapNodesToUnitSphere()
223 for (
int d = 0; d <
SDIM; d++)
228 for (
int d = 0; d <
SDIM; d++)
235 virtual void BoundaryConditions()
237 if (bdr_attributes.Size())
248 Opt &opt,
const Mesh *mesh,
249 const int w,
const int h,
253 if (opt.vis_mesh) { glvis <<
"mesh\n" << *mesh; }
254 else { glvis <<
"solution\n" << *mesh << solution; }
256 glvis <<
"window_size " << w <<
" " << h <<
"\n";
257 glvis <<
"keys " << opt.keys <<
"\n";
259 if (opt.wait) { glvis <<
"pause\n"; }
265 const Opt &opt,
const Mesh *mesh,
269 if (opt.vis_mesh) { glvis <<
"mesh\n" << *mesh; }
270 else { glvis <<
"solution\n" << *mesh << solution; }
271 if (opt.wait) { glvis <<
"pause\n"; }
272 if (opt.snapshot && opt.keys) { glvis <<
"keys " << opt.keys <<
"\n"; }
279 const char *mesh_file =
"surface.mesh";
280 const char *sol_file =
"sol.gf";
283 mfem::out <<
"Printing " << mesh_file <<
", " << sol_file << std::endl;
286 std::ofstream mesh_ofs(mesh_file);
287 mesh_ofs.precision(8);
288 mesh->
Print(mesh_ofs);
291 std::ofstream sol_ofs(sol_file);
292 sol_ofs.precision(8);
309 const int print_iter = -1, max_num_iter = 2000;
310 const double RTOLERANCE =
EPS, ATOLERANCE =
EPS*
EPS;
312 Solver(Surface &S, Opt &opt): opt(opt), S(S), cg(),
313 a(S.fes), x(S.fes), x0(S.fes),
b(S.fes), one(1.0)
325 constexpr
bool converged =
true;
327 for (
int i=0; i < opt.niters; ++i)
329 if (opt.amr) { Amr(); }
330 if (opt.vis) { Surface::Visualize(S.glvis, opt, S.mesh); }
331 if (!opt.id) {
mfem::out <<
"Iteration " << i <<
": "; }
332 S.mesh->NodesUpdated();
335 if (Step() == converged) {
break; }
337 if (opt.print) {
Surface::Print(opt, S.mesh, S.mesh->GetNodes()); }
340 virtual bool Step() = 0;
343 bool Converged(
const double rnorm) {
return rnorm <
NRM; }
349 a.FormLinearSystem(S.bc, x,
b, A, X, B);
354 a.RecoverFEMSolution(X,
b, x);
355 const bool by_vdim = opt.by_vdim;
356 GridFunction *nodes = by_vdim ? &x0 : S.fes->GetMesh()->GetNodes();
360 if (!opt.id) {
mfem::out <<
"rnorm = " << rnorm << std::endl; }
361 const double lambda = opt.lambda;
364 MFEM_VERIFY(!opt.radial,
"'VDim solver can't use radial option!");
365 return Converged(rnorm);
373 for (
int i = 0; i <
delta.Size()/
SDIM; i++)
376 const int ndof = S.fes->GetNDofs();
377 for (
int d = 0; d <
SDIM; d++)
379 ni(d) = (*nodes)(d*ndof + i);
380 di(d) =
delta(d*ndof + i);
383 const double ndotd = (ni*di) / (ni*ni);
386 for (
int d = 0; d <
SDIM; d++) {
delta(d*ndof + i) = di(d); }
391 add(lambda, *nodes, (1.0-lambda), x, x);
392 return Converged(rnorm);
397 MFEM_VERIFY(opt.amr_threshold >= 0.0 && opt.amr_threshold <= 1.0,
"");
398 Mesh *smesh = S.mesh;
400 const int NE = smesh->
GetNE();
402 for (
int e = 0; e < NE; e++)
411 for (
int q = 0; q < NQ; q++)
418 const double w = Jadjt.
Weight();
419 minW = std::fmin(minW, w);
420 maxW = std::fmax(maxW, w);
422 if (std::fabs(maxW) != 0.0)
424 const double rho = minW / maxW;
425 MFEM_VERIFY(rho <= 1.0,
"");
439 S.BoundaryConditions();
445 class ByNodes:
public Solver 448 ByNodes(Surface &S, Opt &opt):
Solver(S, opt)
453 x = *S.fes->GetMesh()->GetNodes();
454 bool converge = ParAXeqB();
456 return converge ? true :
false;
461 class ByVDim:
public Solver 466 auto d_Xi = Xi.
Read();
467 auto d_nodes = S.fes->GetMesh()->GetNodes()->Write();
468 const int ndof = S.fes->GetNDofs();
471 d_nodes[c*ndof + i] = d_Xi[i];
477 auto d_Xi = Xi.
Write();
478 const int ndof = S.fes->GetNDofs();
479 auto d_nodes = S.fes->GetMesh()->GetNodes()->Read();
482 d_Xi[i] = d_nodes[c*ndof + i];
486 ByVDim(Surface &S, Opt &opt):
Solver(S, opt)
491 bool cvg[
SDIM] {
false};
492 for (
int c=0; c <
SDIM; ++c)
499 const bool converged = cvg[0] && cvg[1] && cvg[2];
500 return converged ? true :
false;
506 struct MeshFromFile:
public Surface
508 MeshFromFile(Opt &opt): Surface(opt, opt.mesh_file) { }
512 struct Catenoid:
public Surface
514 Catenoid(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
520 for (
int i = 0; i < v2v.Size(); i++) { v2v[i] = i; }
522 for (
int j = 0; j <= opt.ny; j++)
524 const int v_old = opt.nx + j * (opt.nx + 1);
525 const int v_new = j * (opt.nx + 1);
529 for (
int i = 0; i < GetNE(); i++)
534 for (
int j = 0; j < nv; j++)
540 for (
int i = 0; i < GetNBE(); i++)
542 Element *el = GetBdrElement(i);
545 for (
int j = 0; j < nv; j++)
550 RemoveUnusedVertices();
551 RemoveInternalBoundaries();
558 const double u = 2.0*
PI*x[0];
559 const double v =
PI*(x[1]-0.5)/3.;
567 struct Helicoid:
public Surface
569 Helicoid(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
575 const double u = 2.0*
PI*x[0];
576 const double v = 2.0*
PI*(2.0*x[1]-1.0)/3.0;
584 struct Enneper:
public Surface
586 Enneper(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
592 const double u = 4.0*(x[0]-0.5);
593 const double v = 4.0*(x[1]-0.5);
594 p[0] = +
u -
u*
u*
u/3.0 +
u*v*v;
595 p[1] = -v -
u*
u*v + v*v*v/3.0;
601 struct Hold:
public Surface
603 Hold(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
609 for (
int i = 0; i < v2v.Size(); i++) { v2v[i] = i; }
611 for (
int j = 0; j <= opt.ny; j++)
613 const int v_old = opt.nx + j * (opt.nx + 1);
614 const int v_new = j * (opt.nx + 1);
618 for (
int i = 0; i < GetNE(); i++)
623 for (
int j = 0; j < nv; j++)
629 for (
int i = 0; i < GetNBE(); i++)
631 Element *el = GetBdrElement(i);
634 for (
int j = 0; j < nv; j++)
639 RemoveUnusedVertices();
640 RemoveInternalBoundaries();
647 const double u = 2.0*
PI*x[0];
648 const double v = x[1];
649 p[0] = cos(
u)*(1.0 + 0.3*sin(3.*
u +
PI*v));
650 p[1] = sin(
u)*(1.0 + 0.3*sin(3.*
u +
PI*v));
658 #define I cdouble(0.0, 1.0) 664 double delta = std::numeric_limits<double>::max();
670 const cdouble j = pow(-1,n)*pow(q,n*(n+1.0))*sin((2.0*n+1.0)*
u);
674 return 2.0*pow(q,0.25)*J;
679 const cdouble j = pow(q,n*(n+1))*cos((2.0*n+1.0)*
u);
683 return 2.0*pow(q,0.25)*J;
687 const cdouble j = pow(q,n*n)*cos(2.0*n*
u);
695 const cdouble j =pow(-1,n)*pow(q,n*n)*cos(2.0*n*
u);
710 const cdouble q = exp(I*M_PI*tau);
711 const cdouble e1 = M_PI*M_PI/(12.0*w1*w1)*
714 const cdouble u = M_PI*z / (2.0*w1);
723 double delta = std::numeric_limits<double>::max();
726 const double alpha = 2.0*n+1.0;
728 const cdouble j = pow(-1,n)*pow(q,n*(n+1.0))*Dcosine;
732 return 2.0*pow(q,0.25)*J;
739 double delta = std::numeric_limits<double>::max();
743 if (abs(q2n) <
EPS) { q2n = 0.0; }
744 const cdouble j = q2n/(1.0-q2n)*sin(2.0*n*
u);
748 return 1.0/tan(
u) + 4.0*J;
757 const cdouble q = exp(I*M_PI*tau);
758 const cdouble n1 = -M_PI*M_PI/(12.0*w1) *
761 const cdouble u = M_PI*z / (2.0*w1);
766 static double ALPHA[4] {0.0};
767 struct Costa:
public Surface
769 Costa(Opt &opt): Surface((opt.Tptr = Parametrization, opt), false) { }
774 const int nx = opt.nx, ny = opt.ny;
775 MFEM_VERIFY(nx>2 && ny>2,
"");
776 const int nXhalf = (nx%2)==0 ? 4 : 2;
777 const int nYhalf = (ny%2)==0 ? 4 : 2;
778 const int nxh = nXhalf + nYhalf;
779 const int NVert = (nx+1) * (ny+1);
780 const int NElem = nx*ny - 4 - nxh;
781 const int NBdrElem = 0;
782 InitMesh(
DIM,
SDIM, NVert, NElem, NBdrElem);
784 for (
int j = 0; j <= ny; j++)
786 const double cy = ((double) j / ny) ;
787 for (
int i = 0; i <= nx; i++)
789 const double cx = ((double) i / nx);
790 const double coords[
SDIM] = {cx, cy, 0.0};
795 for (
int j = 0; j < ny; j++)
797 for (
int i = 0; i < nx; i++)
799 if (i == 0 && j == 0) {
continue; }
800 if (i+1 == nx && j == 0) {
continue; }
801 if (i == 0 && j+1 == ny) {
continue; }
802 if (i+1 == nx && j+1 == ny) {
continue; }
803 if ((j == 0 || j+1 == ny) && (abs(nx-(i<<1)-1)<=1)) {
continue; }
804 if ((i == 0 || i+1 == nx) && (abs(ny-(j<<1)-1)<=1)) {
continue; }
805 const int i0 = i + j*(nx+1);
806 const int i1 = i+1 + j*(nx+1);
807 const int i2 = i+1 + (j+1)*(nx+1);
808 const int i3 = i + (j+1)*(nx+1);
809 const int ind[4] = {i0, i1, i2, i3};
813 RemoveUnusedVertices();
814 FinalizeQuadMesh(
false, 0,
true);
821 const double tau = ALPHA[3];
828 const bool y_top = x[1] > 0.5;
829 const bool x_top = x[0] > 0.5;
832 if (y_top) { v = 1.0 - x[1]; }
833 if (x_top) {
u = 1.0 - x[0]; }
841 p[0] = real(
PI*(
u+
PI/(4.*e1))- zw +
PI/(2.*e1)*(dw));
842 p[1] = real(
PI*(v+
PI/(4.*e1))-I*zw-
PI*I/(2.*e1)*(dw));
843 p[2] = sqrt(
PI/2.)*log(abs((pw-e1)/(pw+e1)));
844 if (y_top) {
p[1] *= -1.0; }
845 if (x_top) {
p[0] *= -1.0; }
846 const bool nan = std::isnan(
p[0]) || std::isnan(
p[1]) || std::isnan(
p[2]);
847 MFEM_VERIFY(!nan,
"nan");
848 ALPHA[0] = std::fmax(
p[0], ALPHA[0]);
849 ALPHA[1] = std::fmax(
p[1], ALPHA[1]);
850 ALPHA[2] = std::fmax(
p[2], ALPHA[2]);
856 MFEM_VERIFY(ALPHA[0] > 0.0,
"");
857 MFEM_VERIFY(ALPHA[1] > 0.0,
"");
858 MFEM_VERIFY(ALPHA[2] > 0.0,
"");
860 const double phi = (1.0 + sqrt(5.0)) / 2.0;
863 for (
int d = 0; d <
SDIM; d++)
865 const double alpha = d==2 ? phi : 1.0;
867 nodes(vdof) /=
alpha * ALPHA[d];
874 struct Shell:
public Surface
876 Shell(Opt &opt): Surface((opt.niters = 1, opt.Tptr = Parametrization, opt)) { }
882 const double u = 2.0*
PI*x[0];
883 const double v = 21.0*x[1]-15.0;
884 p[0] = +1.0*pow(1.16,v)*cos(v)*(1.0+cos(
u));
885 p[1] = -1.0*pow(1.16,v)*sin(v)*(1.0+cos(
u));
886 p[2] = -2.0*pow(1.16,v)*(1.0+sin(
u));
891 struct Scherk:
public Surface
896 const double alpha = 0.49;
898 const double u =
alpha*
PI*(2.0*x[0]-1.0);
899 const double v =
alpha*
PI*(2.0*x[1]-1.0);
902 p[2] = log(cos(v)/cos(
u));
905 Scherk(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
909 struct FullPeach:
public Surface
911 static constexpr
int NV = 8;
912 static constexpr
int NE = 6;
915 Surface((opt.niters =
std::min(4, opt.niters), opt), NV, NE, 0) { }
919 const double quad_v[NV][
SDIM] =
921 {-1, -1, -1}, {+1, -1, -1}, {+1, +1, -1}, {-1, +1, -1},
922 {-1, -1, +1}, {+1, -1, +1}, {+1, +1, +1}, {-1, +1, +1}
924 const int quad_e[NE][4] =
926 {3, 2, 1, 0}, {0, 1, 5, 4}, {1, 2, 6, 5},
927 {2, 3, 7, 6}, {3, 0, 4, 7}, {4, 5, 6, 7}
930 for (
int j = 0; j < NV; j++) { AddVertex(quad_v[j]); }
931 for (
int j = 0; j < NE; j++) { AddQuad(quad_e[j], j+1); }
933 FinalizeQuadMesh(
false, 0,
true);
934 FinalizeTopology(
false);
939 void Snap() { SnapNodesToUnitSphere(); }
941 void BoundaryConditions()
951 for (
int e = 0; e < fes->
GetNE(); e++)
958 for (
int dof = 0; dof < dofs.
Size(); dof++)
962 const int k = dofs[dof];
963 MFEM_ASSERT(k >= 0,
"");
964 PointMat.
Mult(one, X);
965 const bool halfX = std::fabs(X[0]) <
EPS && X[1] <= 0.0;
966 const bool halfY = std::fabs(X[2]) <
EPS && X[1] >= 0.0;
967 const bool is_on_bc = halfX || halfY;
968 for (
int c = 0; c <
SDIM; c++)
969 { ess_vdofs[fes->
DofToVDof(k, c)] = is_on_bc; }
987 struct QuarterPeach:
public Surface
989 QuarterPeach(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
994 const double x = 2.0*X[0]-1.0;
995 const double y = X[1];
996 const double r = sqrt(x*x + y*y);
997 const double t = (x==0.0) ?
PI/2.0 :
998 (y==0.0 && x>0.0) ? 0. :
999 (y==0.0 && x<0.0) ?
PI : acos(x/r);
1000 const double sqrtx = sqrt(1.0 + x*x);
1001 const double sqrty = sqrt(1.0 + y*y);
1002 const bool yaxis =
PI/4.0<
t &&
t < 3.0*
PI/4.0;
1003 const double R = yaxis?sqrtx:sqrty;
1004 const double gamma = r/R;
1005 p[0] = gamma * cos(
t);
1006 p[1] = gamma * sin(
t);
1012 for (
int i = 0; i < GetNBE(); i++)
1014 Element *el = GetBdrElement(i);
1015 const int fn = GetBdrElementEdgeIndex(i);
1016 MFEM_VERIFY(!FaceIsTrueInterior(fn),
"");
1018 GetFaceVertices(fn, vertices);
1021 double R[2], X[2][
SDIM];
1022 for (
int v = 0; v < 2; v++)
1025 const int iv = vertices[v];
1026 for (
int d = 0; d <
SDIM; d++)
1029 const double x = X[v][d] = nval[iv];
1030 if (d < 2) { R[v] += x*x; }
1033 if (std::fabs(X[0][1])<=
EPS && std::fabs(X[1][1])<=
EPS &&
1034 (R[0]>0.1 || R[1]>0.1))
1042 struct SlottedSphere:
public Surface
1044 SlottedSphere(Opt &opt): Surface((opt.niters = 4, opt), 64, 40, 0) { }
1048 constexpr
double delta = 0.15;
1049 constexpr
int NV1D = 4;
1050 constexpr
int NV = NV1D*NV1D*NV1D;
1051 constexpr
int NEPF = (NV1D-1)*(NV1D-1);
1052 constexpr
int NE = NEPF*6;
1053 const double V1D[NV1D] = {-1.0, -
delta,
delta, 1.0};
1055 for (
int iv=0; iv<NV; ++iv)
1058 int iy = (iv / NV1D) % NV1D;
1059 int iz = (iv / NV1D) / NV1D;
1061 QV[iv][0] = V1D[ix];
1062 QV[iv][1] = V1D[iy];
1063 QV[iv][2] = V1D[iz];
1066 for (
int ix=0; ix<NV1D-1; ++ix)
1068 for (
int iy=0; iy<NV1D-1; ++iy)
1070 int el_offset = ix + iy*(NV1D-1);
1072 QE[0*NEPF + el_offset][0] = NV1D*ix + NV1D*NV1D*iy;
1073 QE[0*NEPF + el_offset][1] = NV1D*(ix+1) + NV1D*NV1D*iy;
1074 QE[0*NEPF + el_offset][2] = NV1D*(ix+1) + NV1D*NV1D*(iy+1);
1075 QE[0*NEPF + el_offset][3] = NV1D*ix + NV1D*NV1D*(iy+1);
1078 QE[1*NEPF + el_offset][3] = x_off + NV1D*ix + NV1D*NV1D*iy;
1079 QE[1*NEPF + el_offset][2] = x_off + NV1D*(ix+1) + NV1D*NV1D*iy;
1080 QE[1*NEPF + el_offset][1] = x_off + NV1D*(ix+1) + NV1D*NV1D*(iy+1);
1081 QE[1*NEPF + el_offset][0] = x_off + NV1D*ix + NV1D*NV1D*(iy+1);
1083 QE[2*NEPF + el_offset][0] = NV1D*NV1D*iy + ix;
1084 QE[2*NEPF + el_offset][1] = NV1D*NV1D*iy + ix + 1;
1085 QE[2*NEPF + el_offset][2] = NV1D*NV1D*(iy+1) + ix + 1;
1086 QE[2*NEPF + el_offset][3] = NV1D*NV1D*(iy+1) + ix;
1088 int y_off = NV1D*(NV1D-1);
1089 QE[3*NEPF + el_offset][0] = y_off + NV1D*NV1D*iy + ix;
1090 QE[3*NEPF + el_offset][1] = y_off + NV1D*NV1D*iy + ix + 1;
1091 QE[3*NEPF + el_offset][2] = y_off + NV1D*NV1D*(iy+1) + ix + 1;
1092 QE[3*NEPF + el_offset][3] = y_off + NV1D*NV1D*(iy+1) + ix;
1094 QE[4*NEPF + el_offset][0] = NV1D*iy + ix;
1095 QE[4*NEPF + el_offset][1] = NV1D*iy + ix + 1;
1096 QE[4*NEPF + el_offset][2] = NV1D*(iy+1) + ix + 1;
1097 QE[4*NEPF + el_offset][3] = NV1D*(iy+1) + ix;
1099 int z_off = NV1D*NV1D*(NV1D-1);
1100 QE[5*NEPF + el_offset][0] = z_off + NV1D*iy + ix;
1101 QE[5*NEPF + el_offset][1] = z_off + NV1D*iy + ix + 1;
1102 QE[5*NEPF + el_offset][2] = z_off + NV1D*(iy+1) + ix + 1;
1103 QE[5*NEPF + el_offset][3] = z_off + NV1D*(iy+1) + ix;
1107 QE[0*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1108 QE[0*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1110 QE[1*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1111 QE[1*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1113 QE[3*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1114 QE[3*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1116 QE[5*NEPF + 0 + 1*(NV1D-1)][0] = -1;
1117 QE[5*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1118 QE[5*NEPF + 2 + 1*(NV1D-1)][0] = -1;
1120 QE[4*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1121 QE[4*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1122 QE[4*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1124 QE[2*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1125 QE[2*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1126 for (
int j = 0; j < NV; j++) { AddVertex(QV[j]); }
1127 for (
int j = 0; j < NE; j++)
1129 if (QE[j][0] < 0) {
continue; }
1130 AddQuad(QE[j], j+1);
1132 RemoveUnusedVertices();
1133 FinalizeQuadMesh(
false, 0,
true);
1138 void Snap() { SnapNodesToUnitSphere(); }
1141 static int Problem0(Opt &opt)
1144 Surface *S =
nullptr;
1145 switch (opt.surface)
1147 case 0: S =
new MeshFromFile(opt);
break;
1148 case 1: S =
new Catenoid(opt);
break;
1149 case 2: S =
new Helicoid(opt);
break;
1150 case 3: S =
new Enneper(opt);
break;
1151 case 4: S =
new Hold(opt);
break;
1152 case 5: S =
new Costa(opt);
break;
1153 case 6: S =
new Shell(opt);
break;
1154 case 7: S =
new Scherk(opt);
break;
1155 case 8: S =
new FullPeach(opt);
break;
1156 case 9: S =
new QuarterPeach(opt);
break;
1157 case 10: S =
new SlottedSphere(opt);
break;
1158 default: MFEM_ABORT(
"Unknown surface (surface <= 10)!");
1168 static double u0(
const Vector &x) {
return sin(3.0 *
PI * (x[1] + x[0])); }
1172 static double qf(
const int order,
const int ker,
Mesh &m,
1179 const int NE(m.
GetNE());
1187 MFEM_VERIFY(ND == D1D*D1D,
"");
1188 MFEM_VERIFY(NQ == Q1D*Q1D,
"");
1190 Vector Eu(ND*NE), grad_u(
DIM*NQ*NE), sum(NE*NQ), one(NE*NQ);
1195 qi->Derivatives(Eu, grad_u);
1200 auto grdU =
Reshape(grad_u.Read(),
DIM, Q1D, Q1D, NE);
1201 auto S =
Reshape(sum.Write(), Q1D, Q1D, NE);
1205 MFEM_FOREACH_THREAD(qy,y,Q1D)
1207 MFEM_FOREACH_THREAD(qx,x,Q1D)
1209 const double w = W(qx, qy);
1210 const double J11 = J(qx, qy, 0, 0, e);
1211 const double J12 = J(qx, qy, 1, 0, e);
1212 const double J21 = J(qx, qy, 0, 1, e);
1213 const double J22 = J(qx, qy, 1, 1, e);
1214 const double det = detJ(qx, qy, e);
1215 const double area = w * det;
1216 const double gu0 = grdU(0, qx, qy, e);
1217 const double gu1 = grdU(1, qx, qy, e);
1218 const double tgu0 = (J22*gu0 - J12*gu1)/det;
1219 const double tgu1 = (J11*gu1 - J21*gu0)/det;
1220 const double ngu = tgu0*tgu0 + tgu1*tgu1;
1221 const double s = (ker ==
AREA) ? sqrt(1.0 + ngu) :
1222 (ker ==
NORM) ? ngu : 0.0;
1223 S(qx, qy, e) = area *
s;
1231 static int Problem1(Opt &opt)
1233 const int order = opt.order;
1248 u.ProjectCoefficient(u0_fc);
1251 if (opt.vis) { Surface::Visualize(glvis, opt, &mesh,
GLVIZ_W,
GLVIZ_H, &
u); }
1260 for (
int i = 0; i < opt.niters; i++)
1266 const double q_uold = qf(order,
AREA, mesh, fes, uold);
1267 MFEM_VERIFY(std::fabs(q_uold) >
EPS,
"");
1271 a.FormLinearSystem(ess_tdof_list,
u,
b, A, X, B);
1274 a.RecoverFEMSolution(X,
b,
u);
1276 const double norm = sqrt(std::fabs(qf(order,
NORM, mesh, fes, eps)));
1277 const double area = qf(order,
AREA, mesh, fes,
u);
1280 mfem::out <<
"Iteration " << i <<
", norm: " << norm
1281 <<
", area: " << area << std::endl;
1283 if (opt.vis) { Surface::Visualize(glvis, opt, &mesh, &
u); }
1285 if (norm <
NRM) {
break; }
1293 opt.sz = opt.id = 0;
1296 args.
AddOption(&opt.pb,
"-p",
"--problem",
"Problem to solve.");
1297 args.
AddOption(&opt.mesh_file,
"-m",
"--mesh",
"Mesh file to use.");
1298 args.
AddOption(&opt.wait,
"-w",
"--wait",
"-no-w",
"--no-wait",
1299 "Enable or disable a GLVis pause.");
1300 args.
AddOption(&opt.radial,
"-rad",
"--radial",
"-no-rad",
"--no-radial",
1301 "Enable or disable radial constraints in solver.");
1302 args.
AddOption(&opt.nx,
"-x",
"--num-elements-x",
1303 "Number of elements in x-direction.");
1304 args.
AddOption(&opt.ny,
"-y",
"--num-elements-y",
1305 "Number of elements in y-direction.");
1306 args.
AddOption(&opt.order,
"-o",
"--order",
"Finite element order.");
1307 args.
AddOption(&opt.refine,
"-r",
"--ref-levels",
"Refinement");
1308 args.
AddOption(&opt.niters,
"-n",
"--niter-max",
"Max number of iterations");
1309 args.
AddOption(&opt.surface,
"-s",
"--surface",
"Choice of the surface.");
1310 args.
AddOption(&opt.pa,
"-pa",
"--partial-assembly",
"-no-pa",
1311 "--no-partial-assembly",
"Enable Partial Assembly.");
1312 args.
AddOption(&opt.tau,
"-t",
"--tau",
"Costa scale factor.");
1313 args.
AddOption(&opt.lambda,
"-l",
"--lambda",
"Lambda step toward solution.");
1314 args.
AddOption(&opt.amr,
"-a",
"--amr",
"-no-a",
"--no-amr",
"Enable AMR.");
1315 args.
AddOption(&opt.amr_threshold,
"-at",
"--amr-threshold",
"AMR threshold.");
1316 args.
AddOption(&opt.device_config,
"-d",
"--device",
1317 "Device configuration string, see Device::Configure().");
1318 args.
AddOption(&opt.keys,
"-k",
"--keys",
"GLVis configuration keys.");
1319 args.
AddOption(&opt.vis,
"-vis",
"--visualization",
"-no-vis",
1320 "--no-visualization",
"Enable or disable visualization.");
1321 args.
AddOption(&opt.vis_mesh,
"-vm",
"--vis-mesh",
"-no-vm",
1322 "--no-vis-mesh",
"Enable or disable mesh visualization.");
1323 args.
AddOption(&opt.by_vdim,
"-c",
"--solve-byvdim",
1324 "-no-c",
"--solve-bynodes",
1325 "Enable or disable the 'ByVdim' solver");
1326 args.
AddOption(&opt.print,
"-print",
"--print",
"-no-print",
"--no-print",
1327 "Enable or disable result output (files in mfem format).");
1328 args.
AddOption(&opt.snapshot,
"-ss",
"--snapshot",
"-no-ss",
"--no-snapshot",
1329 "Enable or disable GLVis snapshot.");
1332 MFEM_VERIFY(opt.lambda >= 0.0 && opt.lambda <= 1.0,
"");
1336 Device device(opt.device_config);
1337 if (!opt.id) { device.
Print(); }
1339 if (opt.pb == 0) { Problem0(opt); }
1341 if (opt.pb == 1) { Problem1(opt); }
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
T * HostReadWrite()
Shortcut for mfem::ReadWrite(a.GetMemory(), a.Size(), false).
Conjugate gradient method.
int GetNPoints() const
Returns the number of the points in the integration rule.
Class for an integration rule - an Array of IntegrationPoint.
Class for grid function - Vector with associated FE space.
cdouble LogEllipticTheta1Prime(const cdouble u, const cdouble q)
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
void forall_2D(int N, int X, int Y, lambda &&body)
A coefficient that is constant across space and time.
const GeometricFactors * GetGeometricFactors(const IntegrationRule &ir, const int flags, MemoryType d_mt=MemoryType::DEFAULT)
Return the mesh geometric factors corresponding to the given integration rule.
virtual void GetVertices(Array< int > &v) const =0
Returns element's vertices.
void PrintOptions(std::ostream &out) const
Print the options.
Geometry::Type GetElementBaseGeometry(int i) const
cdouble WeierstrassZeta(const cdouble z, const cdouble w1=0.5, const cdouble w3=0.5 *I)
virtual const double * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
void PrintUsage(std::ostream &out) const
Print the usage message.
Pointer to an Operator of a specified type.
std::complex< double > cdouble
void CalcAdjugate(const DenseMatrix &a, DenseMatrix &adja)
virtual void Mult(const Vector &b, Vector &x) const
Operator application: y=A(x).
int Size() const
Returns the size of the vector.
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Data type dense matrix using column-major storage.
void Transform(void(*f)(const Vector &, Vector &))
int GetNDofs() const
Returns number of degrees of freedom. This is the number of Local Degrees of Freedom.
virtual const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
virtual void GetEssentialTrueDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_tdof_list, int component=-1)
Get a list of essential true dofs, ess_tdof_list, corresponding to the boundary attributes marked in ...
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
void Print(std::ostream &out=mfem::out)
Print the configuration of the MFEM virtual device object.
const Element * GetElement(int i) const
Return pointer to the i'th element object.
bool Good() const
Return true if the command line options were parsed successfully.
constexpr Element::Type QUAD
Structure for storing mesh geometric factors: coordinates, Jacobians, and determinants of the Jacobia...
void add(const Vector &v1, const Vector &v2, Vector &v)
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
static void MarkerToList(const Array< int > &marker, Array< int > &list)
Convert a Boolean marker array to a list containing all marked indices.
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
int close()
Close the socketstream.
Data type for Gauss-Seidel smoother of sparse matrix.
const ElementRestrictionOperator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
int main(int argc, char *argv[])
Vector J
Jacobians of the element transformations at all quadrature points.
const Array< double > & GetWeights() const
Return the quadrature weights in a contiguous array.
double DistanceTo(const double *p) const
Compute the Euclidean distance to another vector.
virtual void SetPrintLevel(int print_lvl)
Legacy method to set the level of verbosity of the solver output.
Geometry::Type GetGeometryType() const
void Parse()
Parse the command-line options. Note that this function expects all the options provided through the ...
cdouble WeierstrassP(const cdouble z, const cdouble w1=0.5, const cdouble w3=0.5 *I)
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Vector detJ
Determinants of the Jacobians at all quadrature points.
virtual double * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
A class that performs interpolation from an E-vector to quadrature point values and/or derivatives (Q...
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
virtual const SparseMatrix * GetRestrictionMatrix() const
The returned SparseMatrix is owned by the FiniteElementSpace.
int GetOrder() const
Returns the order of the integration rule.
void SetMaxIter(int max_it)
virtual void SetCurvature(int order, bool discont=false, int space_dim=-1, int ordering=1)
Set the curvature of the mesh nodes using the given polynomial degree.
Type
Constants for the classes derived from Element.
cdouble EllipticTheta(const int a, const cdouble u, const cdouble q)
FiniteElementSpace * FESpace()
void Mult(const double *x, double *y) const
Matrix vector multiplication.
int GetNE() const
Returns number of elements in the mesh.
void GetNodalValues(int i, Array< double > &nval, int vdim=1) const
Returns the values in the vertices of i'th element for dimension vdim.
virtual int GetTrueVSize() const
Return the number of vector true (conforming) dofs.
void SetAbsTol(double atol)
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
double p(const Vector &x, double t)
void SetRelTol(double rtol)
void Transpose()
(*this) = (*this)^t
void forall(int N, lambda &&body)
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
void subtract(const Vector &x, const Vector &y, Vector &z)
void AddOption(bool *var, const char *enable_short_name, const char *enable_long_name, const char *disable_short_name, const char *disable_long_name, const char *description, bool required=false)
Add a boolean option and set 'var' to receive the value. Enable/disable tags are used to set the bool...
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
static Mesh MakeCartesian2D(int nx, int ny, Element::Type type, bool generate_edges=false, double sx=1.0, double sy=1.0, bool sfc_ordering=true)
int GetDof() const
Returns the number of degrees of freedom in the finite element.
virtual DofTransformation * GetElementDofs(int elem, Array< int > &dofs) const
Returns indices of degrees of freedom of element 'elem'. The returned indices are offsets into an ldo...
virtual void Update()
Transform by the Space UpdateMatrix (e.g., on Mesh change).
void BooleanMult(const Array< int > &x, Array< int > &y) const
y = A * x, treating all entries as booleans (zero=false, nonzero=true).
int GetNE() const
Returns number of elements.
const QuadratureInterpolator * GetQuadratureInterpolator(const IntegrationRule &ir) const
Return a QuadratureInterpolator that interpolates E-vectors to quadrature point values and/or derivat...
void GetElementTransformation(int i, IsoparametricTransformation *ElTr)
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Lexicographic ordering for tensor-product FiniteElements.
virtual int GetNVertices() const =0
void SetAttribute(const int attr)
Set element's attribute.
double Norml2() const
Returns the l2 norm of the vector.
int open(const char hostname[], int port)
Open the socket stream on 'port' at 'hostname'.
int Size() const
Return the logical size of the array.
void MakeRef(T *, int)
Make this Array a reference to a pointer.
virtual void SetOperator(const Operator &op)
Also calls SetOperator for the preconditioner if there is one.
A general function coefficient.
int DofToVDof(int dof, int vd, int ndofs=-1) const
Compute a single vdof corresponding to the index dof and the vector index vd.
virtual void Print(std::ostream &os=mfem::out) const
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
Arbitrary order H1-conforming (continuous) finite elements.
void GetNodes(Vector &node_coord) const
double u(const Vector &xvec)
cdouble EllipticTheta1Prime(const int k, const cdouble u, const cdouble q)
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
The MFEM Device class abstracts hardware devices such as GPUs, as well as programming models such as ...
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims... dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
const IntegrationRule & GetNodes() const
Get a const reference to the nodes of the element.
void GeneralRefinement(const Array< Refinement > &refinements, int nonconforming=-1, int nc_limit=0)
Abstract data type element.
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
virtual double * HostReadWrite()
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), false).
VDIM x NQPT x NE (values) / VDIM x DIM x NQPT x NE (grads)