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;
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 125 Surface(Opt &opt,
const char *file):
Mesh(file, true), opt(opt) { }
128 Surface(Opt &opt,
bool):
Mesh(), opt(opt) { }
132 :
Mesh(
Mesh::MakeCartesian2D(opt.nx, opt.ny,
QUAD, true)), opt(opt) { }
135 Surface(Opt &opt,
int nv,
int ne,
int nbe):
149 if (opt.amr) { EnsureNCMesh(); }
150 mesh =
new ParMesh(MPI_COMM_WORLD, *
this);
152 BoundaryConditions();
164 ByVDim(*
this, opt).Solve();
168 ByNodes(*
this, opt).Solve();
170 if (opt.vis && opt.snapshot)
173 Visualize(glvis, opt, mesh, mesh->
GetNodes());
180 if (opt.vis) { glvis.
close(); }
181 delete mesh;
delete fec;
delete fes;
184 virtual void Prefix()
189 virtual void Transform() {
if (opt.Tptr) {
Mesh::Transform(opt.Tptr); } }
191 virtual void Postfix()
196 virtual void Refine()
198 for (
int l = 0; l < opt.refine; l++)
207 for (
int i = 0; i < nodes.
Size(); i++)
209 if (std::abs(nodes(i)) <
EPS)
216 void SnapNodesToUnitSphere()
222 for (
int d = 0; d <
SDIM; d++)
227 for (
int d = 0; d <
SDIM; d++)
234 virtual void BoundaryConditions()
236 if (bdr_attributes.Size())
247 Opt &opt,
const Mesh *mesh,
248 const int w,
const int h,
252 glvis <<
"parallel " << opt.sz <<
" " << opt.id <<
"\n";
253 glvis <<
"solution\n" << *mesh << solution;
255 glvis <<
"window_size " << w <<
" " << h <<
"\n";
256 glvis <<
"keys " << opt.keys <<
"\n";
258 if (opt.wait) { glvis <<
"pause\n"; }
264 const Opt &opt,
const Mesh *mesh,
267 glvis <<
"parallel " << opt.sz <<
" " << opt.id <<
"\n";
269 glvis <<
"solution\n" << *mesh << solution;
270 if (opt.wait) { glvis <<
"pause\n"; }
271 if (opt.snapshot && opt.keys) { glvis <<
"keys " << opt.keys <<
"\n"; }
278 const char *mesh_file =
"surface.mesh";
279 const char *sol_file =
"sol.gf";
282 mfem::out <<
"Printing " << mesh_file <<
", " << sol_file << std::endl;
285 std::ostringstream mesh_name;
286 mesh_name << mesh_file <<
"." << std::setfill(
'0') << std::setw(6) << opt.id;
287 std::ofstream mesh_ofs(mesh_name.str().c_str());
288 mesh_ofs.precision(8);
289 mesh->
Print(mesh_ofs);
292 std::ostringstream sol_name;
293 sol_name << sol_file <<
"." << std::setfill(
'0') << std::setw(6) << opt.id;
294 std::ofstream sol_ofs(sol_name.str().c_str());
295 sol_ofs.precision(8);
312 const int print_iter = -1, max_num_iter = 2000;
313 const double RTOLERANCE =
EPS, ATOLERANCE =
EPS*
EPS;
315 Solver(Surface &S, Opt &opt): opt(opt), S(S), cg(MPI_COMM_WORLD),
316 a(S.fes), x(S.fes), x0(S.fes),
b(S.fes), one(1.0)
328 constexpr
bool converged =
true;
330 for (
int i=0; i < opt.niters; ++i)
332 if (opt.amr) { Amr(); }
333 if (opt.vis) { Surface::Visualize(S.glvis, opt, S.mesh); }
334 if (!opt.id) {
mfem::out <<
"Iteration " << i <<
": "; }
335 S.mesh->NodesUpdated();
338 if (Step() == converged) {
break; }
340 if (opt.print) {
Surface::Print(opt, S.mesh, S.mesh->GetNodes()); }
343 virtual bool Step() = 0;
346 bool Converged(
const double rnorm) {
return rnorm <
NRM; }
352 a.FormLinearSystem(S.bc, x,
b, A, X, B);
357 a.RecoverFEMSolution(X,
b, x);
358 const bool by_vdim = opt.by_vdim;
359 GridFunction *nodes = by_vdim ? &x0 : S.fes->GetMesh()->GetNodes();
364 MPI_Allreduce(&rnorm, &glob_norm, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
366 if (!opt.id) {
mfem::out <<
"rnorm = " << rnorm << std::endl; }
367 const double lambda = opt.lambda;
370 MFEM_VERIFY(!opt.radial,
"'VDim solver can't use radial option!");
371 return Converged(rnorm);
379 for (
int i = 0; i <
delta.Size()/
SDIM; i++)
382 const int ndof = S.fes->GetNDofs();
383 for (
int d = 0; d <
SDIM; d++)
385 ni(d) = (*nodes)(d*ndof + i);
386 di(d) =
delta(d*ndof + i);
389 const double ndotd = (ni*di) / (ni*ni);
392 for (
int d = 0; d <
SDIM; d++) {
delta(d*ndof + i) = di(d); }
397 add(lambda, *nodes, (1.0-lambda), x, x);
398 return Converged(rnorm);
403 MFEM_VERIFY(opt.amr_threshold >= 0.0 && opt.amr_threshold <= 1.0,
"");
404 Mesh *smesh = S.mesh;
406 const int NE = smesh->
GetNE();
408 for (
int e = 0; e < NE; e++)
418 for (
int q = 0; q < NQ; q++)
425 const double w = Jadjt.
Weight();
426 minW = std::fmin(minW, w);
427 maxW = std::fmax(maxW, w);
429 if (std::fabs(maxW) != 0.0)
431 const double rho = minW / maxW;
432 MFEM_VERIFY(rho <= 1.0,
"");
446 S.BoundaryConditions();
452 class ByNodes:
public Solver 455 ByNodes(Surface &S, Opt &opt):
Solver(S, opt)
460 x = *S.fes->GetMesh()->GetNodes();
461 bool converge = ParAXeqB();
463 return converge ? true :
false;
468 class ByVDim:
public Solver 473 auto d_Xi = Xi.
Read();
474 auto d_nodes = S.fes->GetMesh()->GetNodes()->Write();
475 const int ndof = S.fes->GetNDofs();
478 d_nodes[c*ndof + i] = d_Xi[i];
484 auto d_Xi = Xi.
Write();
485 const int ndof = S.fes->GetNDofs();
486 auto d_nodes = S.fes->GetMesh()->GetNodes()->Read();
489 d_Xi[i] = d_nodes[c*ndof + i];
493 ByVDim(Surface &S, Opt &opt):
Solver(S, opt)
498 bool cvg[
SDIM] {
false};
499 for (
int c=0; c <
SDIM; ++c)
506 const bool converged = cvg[0] && cvg[1] && cvg[2];
507 return converged ? true :
false;
513 struct MeshFromFile:
public Surface
515 MeshFromFile(Opt &opt): Surface(opt, opt.mesh_file) { }
519 struct Catenoid:
public Surface
521 Catenoid(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
527 for (
int i = 0; i < v2v.Size(); i++) { v2v[i] = i; }
529 for (
int j = 0; j <= opt.ny; j++)
531 const int v_old = opt.nx + j * (opt.nx + 1);
532 const int v_new = j * (opt.nx + 1);
536 for (
int i = 0; i < GetNE(); i++)
541 for (
int j = 0; j < nv; j++)
547 for (
int i = 0; i < GetNBE(); i++)
549 Element *el = GetBdrElement(i);
552 for (
int j = 0; j < nv; j++)
557 RemoveUnusedVertices();
558 RemoveInternalBoundaries();
565 const double u = 2.0*
PI*x[0];
566 const double v =
PI*(x[1]-0.5)/3.;
574 struct Helicoid:
public Surface
576 Helicoid(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
582 const double u = 2.0*
PI*x[0];
583 const double v = 2.0*
PI*(2.0*x[1]-1.0)/3.0;
591 struct Enneper:
public Surface
593 Enneper(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
599 const double u = 4.0*(x[0]-0.5);
600 const double v = 4.0*(x[1]-0.5);
601 p[0] = +
u -
u*
u*
u/3.0 +
u*v*v;
602 p[1] = -v -
u*
u*v + v*v*v/3.0;
608 struct Hold:
public Surface
610 Hold(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
616 for (
int i = 0; i < v2v.Size(); i++) { v2v[i] = i; }
618 for (
int j = 0; j <= opt.ny; j++)
620 const int v_old = opt.nx + j * (opt.nx + 1);
621 const int v_new = j * (opt.nx + 1);
625 for (
int i = 0; i < GetNE(); i++)
630 for (
int j = 0; j < nv; j++)
636 for (
int i = 0; i < GetNBE(); i++)
638 Element *el = GetBdrElement(i);
641 for (
int j = 0; j < nv; j++)
646 RemoveUnusedVertices();
647 RemoveInternalBoundaries();
654 const double u = 2.0*
PI*x[0];
655 const double v = x[1];
656 p[0] = cos(
u)*(1.0 + 0.3*sin(3.*
u +
PI*v));
657 p[1] = sin(
u)*(1.0 + 0.3*sin(3.*
u +
PI*v));
665 #define I cdouble(0.0, 1.0) 671 double delta = std::numeric_limits<double>::max();
677 const cdouble j = pow(-1,n)*pow(q,n*(n+1.0))*sin((2.0*n+1.0)*
u);
681 return 2.0*pow(q,0.25)*J;
686 const cdouble j = pow(q,n*(n+1))*cos((2.0*n+1.0)*
u);
690 return 2.0*pow(q,0.25)*J;
694 const cdouble j = pow(q,n*n)*cos(2.0*n*
u);
702 const cdouble j =pow(-1,n)*pow(q,n*n)*cos(2.0*n*
u);
717 const cdouble q = exp(I*M_PI*tau);
718 const cdouble e1 = M_PI*M_PI/(12.0*w1*w1)*
721 const cdouble u = M_PI*z / (2.0*w1);
730 double delta = std::numeric_limits<double>::max();
733 const double alpha = 2.0*n+1.0;
735 const cdouble j = pow(-1,n)*pow(q,n*(n+1.0))*Dcosine;
739 return 2.0*pow(q,0.25)*J;
746 double delta = std::numeric_limits<double>::max();
750 if (abs(q2n) <
EPS) { q2n = 0.0; }
751 const cdouble j = q2n/(1.0-q2n)*sin(2.0*n*
u);
755 return 1.0/tan(
u) + 4.0*J;
764 const cdouble q = exp(I*M_PI*tau);
765 const cdouble n1 = -M_PI*M_PI/(12.0*w1) *
768 const cdouble u = M_PI*z / (2.0*w1);
773 static double ALPHA[4] {0.0};
774 struct Costa:
public Surface
776 Costa(Opt &opt): Surface((opt.Tptr = Parametrization, opt), false) { }
781 const int nx = opt.nx, ny = opt.ny;
782 MFEM_VERIFY(nx>2 && ny>2,
"");
783 const int nXhalf = (nx%2)==0 ? 4 : 2;
784 const int nYhalf = (ny%2)==0 ? 4 : 2;
785 const int nxh = nXhalf + nYhalf;
786 const int NVert = (nx+1) * (ny+1);
787 const int NElem = nx*ny - 4 - nxh;
788 const int NBdrElem = 0;
789 InitMesh(
DIM,
SDIM, NVert, NElem, NBdrElem);
791 for (
int j = 0; j <= ny; j++)
793 const double cy = ((double) j / ny) ;
794 for (
int i = 0; i <= nx; i++)
796 const double cx = ((double) i / nx);
797 const double coords[
SDIM] = {cx, cy, 0.0};
802 for (
int j = 0; j < ny; j++)
804 for (
int i = 0; i < nx; i++)
806 if (i == 0 && j == 0) {
continue; }
807 if (i+1 == nx && j == 0) {
continue; }
808 if (i == 0 && j+1 == ny) {
continue; }
809 if (i+1 == nx && j+1 == ny) {
continue; }
810 if ((j == 0 || j+1 == ny) && (abs(nx-(i<<1)-1)<=1)) {
continue; }
811 if ((i == 0 || i+1 == nx) && (abs(ny-(j<<1)-1)<=1)) {
continue; }
812 const int i0 = i + j*(nx+1);
813 const int i1 = i+1 + j*(nx+1);
814 const int i2 = i+1 + (j+1)*(nx+1);
815 const int i3 = i + (j+1)*(nx+1);
816 const int ind[4] = {i0, i1, i2, i3};
820 RemoveUnusedVertices();
821 FinalizeQuadMesh(
false, 0,
true);
828 const double tau = ALPHA[3];
835 const bool y_top = x[1] > 0.5;
836 const bool x_top = x[0] > 0.5;
839 if (y_top) { v = 1.0 - x[1]; }
840 if (x_top) {
u = 1.0 - x[0]; }
848 p[0] = real(
PI*(
u+
PI/(4.*e1))- zw +
PI/(2.*e1)*(dw));
849 p[1] = real(
PI*(v+
PI/(4.*e1))-I*zw-
PI*I/(2.*e1)*(dw));
850 p[2] = sqrt(
PI/2.)*log(abs((pw-e1)/(pw+e1)));
851 if (y_top) {
p[1] *= -1.0; }
852 if (x_top) {
p[0] *= -1.0; }
853 const bool nan = std::isnan(
p[0]) || std::isnan(
p[1]) || std::isnan(
p[2]);
854 MFEM_VERIFY(!nan,
"nan");
855 ALPHA[0] = std::fmax(
p[0], ALPHA[0]);
856 ALPHA[1] = std::fmax(
p[1], ALPHA[1]);
857 ALPHA[2] = std::fmax(
p[2], ALPHA[2]);
863 MFEM_VERIFY(ALPHA[0] > 0.0,
"");
864 MFEM_VERIFY(ALPHA[1] > 0.0,
"");
865 MFEM_VERIFY(ALPHA[2] > 0.0,
"");
867 const double phi = (1.0 + sqrt(5.0)) / 2.0;
870 for (
int d = 0; d <
SDIM; d++)
872 const double alpha = d==2 ? phi : 1.0;
874 nodes(vdof) /=
alpha * ALPHA[d];
881 struct Shell:
public Surface
883 Shell(Opt &opt): Surface((opt.niters = 1, opt.Tptr = Parametrization, opt)) { }
889 const double u = 2.0*
PI*x[0];
890 const double v = 21.0*x[1]-15.0;
891 p[0] = +1.0*pow(1.16,v)*cos(v)*(1.0+cos(
u));
892 p[1] = -1.0*pow(1.16,v)*sin(v)*(1.0+cos(
u));
893 p[2] = -2.0*pow(1.16,v)*(1.0+sin(
u));
898 struct Scherk:
public Surface
903 const double alpha = 0.49;
905 const double u =
alpha*
PI*(2.0*x[0]-1.0);
906 const double v =
alpha*
PI*(2.0*x[1]-1.0);
909 p[2] = log(cos(v)/cos(
u));
912 Scherk(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
916 struct FullPeach:
public Surface
918 static constexpr
int NV = 8;
919 static constexpr
int NE = 6;
922 Surface((opt.niters =
std::min(4, opt.niters), opt), NV, NE, 0) { }
926 const double quad_v[NV][
SDIM] =
928 {-1, -1, -1}, {+1, -1, -1}, {+1, +1, -1}, {-1, +1, -1},
929 {-1, -1, +1}, {+1, -1, +1}, {+1, +1, +1}, {-1, +1, +1}
931 const int quad_e[NE][4] =
933 {3, 2, 1, 0}, {0, 1, 5, 4}, {1, 2, 6, 5},
934 {2, 3, 7, 6}, {3, 0, 4, 7}, {4, 5, 6, 7}
937 for (
int j = 0; j < NV; j++) { AddVertex(quad_v[j]); }
938 for (
int j = 0; j < NE; j++) { AddQuad(quad_e[j], j+1); }
940 FinalizeQuadMesh(
false, 0,
true);
941 FinalizeTopology(
false);
946 void Snap() { SnapNodesToUnitSphere(); }
948 void BoundaryConditions()
958 for (
int e = 0; e < fes->
GetNE(); e++)
965 for (
int dof = 0; dof < dofs.
Size(); dof++)
969 const int k = dofs[dof];
970 MFEM_ASSERT(k >= 0,
"");
971 PointMat.
Mult(one, X);
972 const bool halfX = std::fabs(X[0]) <
EPS && X[1] <= 0.0;
973 const bool halfY = std::fabs(X[2]) <
EPS && X[1] >= 0.0;
974 const bool is_on_bc = halfX || halfY;
975 for (
int c = 0; c <
SDIM; c++)
976 { ess_vdofs[fes->
DofToVDof(k, c)] = is_on_bc; }
994 struct QuarterPeach:
public Surface
996 QuarterPeach(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
1001 const double x = 2.0*X[0]-1.0;
1002 const double y = X[1];
1003 const double r = sqrt(x*x + y*y);
1004 const double t = (x==0.0) ?
PI/2.0 :
1005 (y==0.0 && x>0.0) ? 0. :
1006 (y==0.0 && x<0.0) ?
PI : acos(x/r);
1007 const double sqrtx = sqrt(1.0 + x*x);
1008 const double sqrty = sqrt(1.0 + y*y);
1009 const bool yaxis =
PI/4.0<
t &&
t < 3.0*
PI/4.0;
1010 const double R = yaxis?sqrtx:sqrty;
1011 const double gamma = r/R;
1012 p[0] = gamma * cos(
t);
1013 p[1] = gamma * sin(
t);
1019 for (
int i = 0; i < GetNBE(); i++)
1021 Element *el = GetBdrElement(i);
1022 const int fn = GetBdrElementEdgeIndex(i);
1023 MFEM_VERIFY(!FaceIsTrueInterior(fn),
"");
1025 GetFaceVertices(fn, vertices);
1028 double R[2], X[2][
SDIM];
1029 for (
int v = 0; v < 2; v++)
1032 const int iv = vertices[v];
1033 for (
int d = 0; d <
SDIM; d++)
1036 const double x = X[v][d] = nval[iv];
1037 if (d < 2) { R[v] += x*x; }
1040 if (std::fabs(X[0][1])<=
EPS && std::fabs(X[1][1])<=
EPS &&
1041 (R[0]>0.1 || R[1]>0.1))
1049 struct SlottedSphere:
public Surface
1051 SlottedSphere(Opt &opt): Surface((opt.niters = 4, opt), 64, 40, 0) { }
1055 constexpr
double delta = 0.15;
1056 constexpr
int NV1D = 4;
1057 constexpr
int NV = NV1D*NV1D*NV1D;
1058 constexpr
int NEPF = (NV1D-1)*(NV1D-1);
1059 constexpr
int NE = NEPF*6;
1060 const double V1D[NV1D] = {-1.0, -
delta,
delta, 1.0};
1062 for (
int iv=0; iv<NV; ++iv)
1065 int iy = (iv / NV1D) % NV1D;
1066 int iz = (iv / NV1D) / NV1D;
1068 QV[iv][0] = V1D[ix];
1069 QV[iv][1] = V1D[iy];
1070 QV[iv][2] = V1D[iz];
1073 for (
int ix=0; ix<NV1D-1; ++ix)
1075 for (
int iy=0; iy<NV1D-1; ++iy)
1077 int el_offset = ix + iy*(NV1D-1);
1079 QE[0*NEPF + el_offset][0] = NV1D*ix + NV1D*NV1D*iy;
1080 QE[0*NEPF + el_offset][1] = NV1D*(ix+1) + NV1D*NV1D*iy;
1081 QE[0*NEPF + el_offset][2] = NV1D*(ix+1) + NV1D*NV1D*(iy+1);
1082 QE[0*NEPF + el_offset][3] = NV1D*ix + NV1D*NV1D*(iy+1);
1085 QE[1*NEPF + el_offset][3] = x_off + NV1D*ix + NV1D*NV1D*iy;
1086 QE[1*NEPF + el_offset][2] = x_off + NV1D*(ix+1) + NV1D*NV1D*iy;
1087 QE[1*NEPF + el_offset][1] = x_off + NV1D*(ix+1) + NV1D*NV1D*(iy+1);
1088 QE[1*NEPF + el_offset][0] = x_off + NV1D*ix + NV1D*NV1D*(iy+1);
1090 QE[2*NEPF + el_offset][0] = NV1D*NV1D*iy + ix;
1091 QE[2*NEPF + el_offset][1] = NV1D*NV1D*iy + ix + 1;
1092 QE[2*NEPF + el_offset][2] = NV1D*NV1D*(iy+1) + ix + 1;
1093 QE[2*NEPF + el_offset][3] = NV1D*NV1D*(iy+1) + ix;
1095 int y_off = NV1D*(NV1D-1);
1096 QE[3*NEPF + el_offset][0] = y_off + NV1D*NV1D*iy + ix;
1097 QE[3*NEPF + el_offset][1] = y_off + NV1D*NV1D*iy + ix + 1;
1098 QE[3*NEPF + el_offset][2] = y_off + NV1D*NV1D*(iy+1) + ix + 1;
1099 QE[3*NEPF + el_offset][3] = y_off + NV1D*NV1D*(iy+1) + ix;
1101 QE[4*NEPF + el_offset][0] = NV1D*iy + ix;
1102 QE[4*NEPF + el_offset][1] = NV1D*iy + ix + 1;
1103 QE[4*NEPF + el_offset][2] = NV1D*(iy+1) + ix + 1;
1104 QE[4*NEPF + el_offset][3] = NV1D*(iy+1) + ix;
1106 int z_off = NV1D*NV1D*(NV1D-1);
1107 QE[5*NEPF + el_offset][0] = z_off + NV1D*iy + ix;
1108 QE[5*NEPF + el_offset][1] = z_off + NV1D*iy + ix + 1;
1109 QE[5*NEPF + el_offset][2] = z_off + NV1D*(iy+1) + ix + 1;
1110 QE[5*NEPF + el_offset][3] = z_off + NV1D*(iy+1) + ix;
1114 QE[0*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1115 QE[0*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1117 QE[1*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1118 QE[1*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1120 QE[3*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1121 QE[3*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1123 QE[5*NEPF + 0 + 1*(NV1D-1)][0] = -1;
1124 QE[5*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1125 QE[5*NEPF + 2 + 1*(NV1D-1)][0] = -1;
1127 QE[4*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1128 QE[4*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1129 QE[4*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1131 QE[2*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1132 QE[2*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1133 for (
int j = 0; j < NV; j++) { AddVertex(QV[j]); }
1134 for (
int j = 0; j < NE; j++)
1136 if (QE[j][0] < 0) {
continue; }
1137 AddQuad(QE[j], j+1);
1139 RemoveUnusedVertices();
1140 FinalizeQuadMesh(
false, 0,
true);
1145 void Snap() { SnapNodesToUnitSphere(); }
1148 static int Problem0(Opt &opt)
1151 Surface *S =
nullptr;
1152 switch (opt.surface)
1154 case 0: S =
new MeshFromFile(opt);
break;
1155 case 1: S =
new Catenoid(opt);
break;
1156 case 2: S =
new Helicoid(opt);
break;
1157 case 3: S =
new Enneper(opt);
break;
1158 case 4: S =
new Hold(opt);
break;
1159 case 5: S =
new Costa(opt);
break;
1160 case 6: S =
new Shell(opt);
break;
1161 case 7: S =
new Scherk(opt);
break;
1162 case 8: S =
new FullPeach(opt);
break;
1163 case 9: S =
new QuarterPeach(opt);
break;
1164 case 10: S =
new SlottedSphere(opt);
break;
1165 default: MFEM_ABORT(
"Unknown surface (surface <= 10)!");
1175 static double u0(
const Vector &x) {
return sin(3.0 *
PI * (x[1] + x[0])); }
1179 static double qf(
const int order,
const int ker,
Mesh &m,
1186 const int NE(m.
GetNE());
1194 MFEM_VERIFY(ND == D1D*D1D,
"");
1195 MFEM_VERIFY(NQ == Q1D*Q1D,
"");
1197 Vector Eu(ND*NE), grad_u(
DIM*NQ*NE), sum(NE*NQ), one(NE*NQ);
1202 qi->Derivatives(Eu, grad_u);
1207 auto grdU =
Reshape(grad_u.Read(),
DIM, Q1D, Q1D, NE);
1208 auto S =
Reshape(sum.Write(), Q1D, Q1D, NE);
1212 MFEM_FOREACH_THREAD(qy,y,Q1D)
1214 MFEM_FOREACH_THREAD(qx,x,Q1D)
1216 const double w = W(qx, qy);
1217 const double J11 = J(qx, qy, 0, 0, e);
1218 const double J12 = J(qx, qy, 1, 0, e);
1219 const double J21 = J(qx, qy, 0, 1, e);
1220 const double J22 = J(qx, qy, 1, 1, e);
1221 const double det = detJ(qx, qy, e);
1222 const double area = w * det;
1223 const double gu0 = grdU(0, qx, qy, e);
1224 const double gu1 = grdU(1, qx, qy, e);
1225 const double tgu0 = (J22*gu0 - J12*gu1)/det;
1226 const double tgu1 = (J11*gu1 - J21*gu0)/det;
1227 const double ngu = tgu0*tgu0 + tgu1*tgu1;
1228 const double s = (ker ==
AREA) ? sqrt(1.0 + ngu) :
1229 (ker ==
NORM) ? ngu : 0.0;
1230 S(qx, qy, e) = area *
s;
1238 static int Problem1(Opt &opt)
1240 const int order = opt.order;
1244 ParMesh mesh(MPI_COMM_WORLD, smesh);
1256 u.ProjectCoefficient(u0_fc);
1259 if (opt.vis) { Surface::Visualize(glvis, opt, &mesh,
GLVIZ_W,
GLVIZ_H, &
u); }
1268 for (
int i = 0; i < opt.niters; i++)
1274 const double q_uold = qf(order,
AREA, mesh, fes, uold);
1275 MFEM_VERIFY(std::fabs(q_uold) >
EPS,
"");
1279 a.FormLinearSystem(ess_tdof_list,
u,
b, A, X, B);
1282 a.RecoverFEMSolution(X,
b,
u);
1284 const double norm = sqrt(std::fabs(qf(order,
NORM, mesh, fes, eps)));
1285 const double area = qf(order,
AREA, mesh, fes,
u);
1288 mfem::out <<
"Iteration " << i <<
", norm: " << norm
1289 <<
", area: " << area << std::endl;
1291 if (opt.vis) { Surface::Visualize(glvis, opt, &mesh, &
u); }
1293 if (norm <
NRM) {
break; }
1308 args.
AddOption(&opt.pb,
"-p",
"--problem",
"Problem to solve.");
1309 args.
AddOption(&opt.mesh_file,
"-m",
"--mesh",
"Mesh file to use.");
1310 args.
AddOption(&opt.wait,
"-w",
"--wait",
"-no-w",
"--no-wait",
1311 "Enable or disable a GLVis pause.");
1312 args.
AddOption(&opt.radial,
"-rad",
"--radial",
"-no-rad",
"--no-radial",
1313 "Enable or disable radial constraints in solver.");
1314 args.
AddOption(&opt.nx,
"-x",
"--num-elements-x",
1315 "Number of elements in x-direction.");
1316 args.
AddOption(&opt.ny,
"-y",
"--num-elements-y",
1317 "Number of elements in y-direction.");
1318 args.
AddOption(&opt.order,
"-o",
"--order",
"Finite element order.");
1319 args.
AddOption(&opt.refine,
"-r",
"--ref-levels",
"Refinement");
1320 args.
AddOption(&opt.niters,
"-n",
"--niter-max",
"Max number of iterations");
1321 args.
AddOption(&opt.surface,
"-s",
"--surface",
"Choice of the surface.");
1322 args.
AddOption(&opt.pa,
"-pa",
"--partial-assembly",
"-no-pa",
1323 "--no-partial-assembly",
"Enable Partial Assembly.");
1324 args.
AddOption(&opt.tau,
"-t",
"--tau",
"Costa scale factor.");
1325 args.
AddOption(&opt.lambda,
"-l",
"--lambda",
"Lambda step toward solution.");
1326 args.
AddOption(&opt.amr,
"-a",
"--amr",
"-no-a",
"--no-amr",
"Enable AMR.");
1327 args.
AddOption(&opt.amr_threshold,
"-at",
"--amr-threshold",
"AMR threshold.");
1328 args.
AddOption(&opt.device_config,
"-d",
"--device",
1329 "Device configuration string, see Device::Configure().");
1330 args.
AddOption(&opt.keys,
"-k",
"--keys",
"GLVis configuration keys.");
1331 args.
AddOption(&opt.vis,
"-vis",
"--visualization",
"-no-vis",
1332 "--no-visualization",
"Enable or disable visualization.");
1333 args.
AddOption(&opt.by_vdim,
"-c",
"--solve-byvdim",
1334 "-no-c",
"--solve-bynodes",
1335 "Enable or disable the 'ByVdim' solver");
1336 args.
AddOption(&opt.print,
"-print",
"--print",
"-no-print",
"--no-print",
1337 "Enable or disable result output (files in mfem format).");
1338 args.
AddOption(&opt.snapshot,
"-ss",
"--snapshot",
"-no-ss",
"--no-snapshot",
1339 "Enable or disable GLVis snapshot.");
1342 MFEM_VERIFY(opt.lambda >= 0.0 && opt.lambda <= 1.0,
"");
1346 Device device(opt.device_config);
1347 if (!opt.id) { device.
Print(); }
1349 if (opt.pb == 0) { Problem0(opt); }
1351 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).
static void Init()
Initialize hypre by calling HYPRE_Init() and set default options. After calling Hypre::Init(), hypre will be finalized automatically at program exit.
virtual void GetEssentialTrueDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_tdof_list, int component=-1)
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.
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
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)
constexpr Element::Type QUAD
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.
cdouble LogEllipticTheta1Prime(const cdouble u, const cdouble q)
bool Good() const
Return true if the command line options were parsed successfully.
Abstract parallel finite element space.
Structure for storing mesh geometric factors: coordinates, Jacobians, and determinants of the Jacobia...
static int WorldSize()
Return the size of MPI_COMM_WORLD.
virtual const SparseMatrix * GetRestrictionMatrix() const
Get the R matrix which restricts a local dof vector to true dof vector.
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.
const ElementRestrictionOperator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
The BoomerAMG solver in hypre.
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
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 ...
int Append(const T &el)
Append element 'el' to array, resize if necessary.
virtual void Update()
Transform by the Space UpdateMatrix (e.g., on Mesh change).
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 *)
int GetOrder() const
Returns the order of the integration rule.
int main(int argc, char *argv[])
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.
static void Init()
Singleton creation with Mpi::Init();.
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 DofTransformation * GetElementDofs(int i, Array< int > &dofs) const
Returns indexes of degrees of freedom in array dofs for i'th element.
cdouble WeierstrassP(const cdouble z, const cdouble w1=0.5, const cdouble w3=0.5 *I)
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
virtual const FiniteElement * GetFE(int i) const
void forall(int N, lambda &&body)
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
cdouble EllipticTheta(const int a, const cdouble u, const cdouble q)
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.
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.
virtual int GetTrueVSize() const
Return the number of local vector true dofs.
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'.
static int WorldRank()
Return the MPI rank in MPI_COMM_WORLD.
int Size() const
Return the logical size of the array.
cdouble EllipticTheta1Prime(const int k, const cdouble u, const cdouble q)
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
void Print(std::ostream &out=mfem::out) const override
double u(const Vector &xvec)
Class for parallel grid function.
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)
Class for parallel meshes.
Abstract data type element.
cdouble WeierstrassZeta(const cdouble z, const cdouble w1=0.5, const cdouble w3=0.5 *I)
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)