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();
476 MFEM_FORALL(i, ndof, d_nodes[c*ndof + i] = d_Xi[i]; );
481 auto d_Xi = Xi.
Write();
482 const int ndof = S.fes->GetNDofs();
483 auto d_nodes = S.fes->GetMesh()->GetNodes()->Read();
484 MFEM_FORALL(i, ndof, d_Xi[i] = d_nodes[c*ndof + i]; );
487 ByVDim(Surface &S, Opt &opt):
Solver(S, opt)
492 bool cvg[
SDIM] {
false};
493 for (
int c=0; c <
SDIM; ++c)
500 const bool converged = cvg[0] && cvg[1] && cvg[2];
501 return converged ? true :
false;
507 struct MeshFromFile:
public Surface
509 MeshFromFile(Opt &opt): Surface(opt, opt.mesh_file) { }
513 struct Catenoid:
public Surface
515 Catenoid(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
521 for (
int i = 0; i < v2v.Size(); i++) { v2v[i] = i; }
523 for (
int j = 0; j <= opt.ny; j++)
525 const int v_old = opt.nx + j * (opt.nx + 1);
526 const int v_new = j * (opt.nx + 1);
530 for (
int i = 0; i < GetNE(); i++)
535 for (
int j = 0; j < nv; j++)
541 for (
int i = 0; i < GetNBE(); i++)
543 Element *el = GetBdrElement(i);
546 for (
int j = 0; j < nv; j++)
551 RemoveUnusedVertices();
552 RemoveInternalBoundaries();
559 const double u = 2.0*
PI*x[0];
560 const double v =
PI*(x[1]-0.5)/3.;
568 struct Helicoid:
public Surface
570 Helicoid(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
576 const double u = 2.0*
PI*x[0];
577 const double v = 2.0*
PI*(2.0*x[1]-1.0)/3.0;
585 struct Enneper:
public Surface
587 Enneper(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
593 const double u = 4.0*(x[0]-0.5);
594 const double v = 4.0*(x[1]-0.5);
595 p[0] = +
u -
u*
u*
u/3.0 +
u*v*v;
596 p[1] = -v -
u*
u*v + v*v*v/3.0;
602 struct Hold:
public Surface
604 Hold(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
610 for (
int i = 0; i < v2v.Size(); i++) { v2v[i] = i; }
612 for (
int j = 0; j <= opt.ny; j++)
614 const int v_old = opt.nx + j * (opt.nx + 1);
615 const int v_new = j * (opt.nx + 1);
619 for (
int i = 0; i < GetNE(); i++)
624 for (
int j = 0; j < nv; j++)
630 for (
int i = 0; i < GetNBE(); i++)
632 Element *el = GetBdrElement(i);
635 for (
int j = 0; j < nv; j++)
640 RemoveUnusedVertices();
641 RemoveInternalBoundaries();
648 const double u = 2.0*
PI*x[0];
649 const double v = x[1];
650 p[0] = cos(
u)*(1.0 + 0.3*sin(3.*
u +
PI*v));
651 p[1] = sin(
u)*(1.0 + 0.3*sin(3.*
u +
PI*v));
659 #define I cdouble(0.0, 1.0) 665 double delta = std::numeric_limits<double>::max();
671 const cdouble j = pow(-1,n)*pow(q,n*(n+1.0))*sin((2.0*n+1.0)*
u);
675 return 2.0*pow(q,0.25)*J;
680 const cdouble j = pow(q,n*(n+1))*cos((2.0*n+1.0)*
u);
684 return 2.0*pow(q,0.25)*J;
688 const cdouble j = pow(q,n*n)*cos(2.0*n*
u);
696 const cdouble j =pow(-1,n)*pow(q,n*n)*cos(2.0*n*
u);
711 const cdouble q = exp(I*M_PI*tau);
712 const cdouble e1 = M_PI*M_PI/(12.0*w1*w1)*
715 const cdouble u = M_PI*z / (2.0*w1);
724 double delta = std::numeric_limits<double>::max();
727 const double alpha = 2.0*n+1.0;
729 const cdouble j = pow(-1,n)*pow(q,n*(n+1.0))*Dcosine;
733 return 2.0*pow(q,0.25)*J;
740 double delta = std::numeric_limits<double>::max();
744 if (abs(q2n) <
EPS) { q2n = 0.0; }
745 const cdouble j = q2n/(1.0-q2n)*sin(2.0*n*
u);
749 return 1.0/tan(
u) + 4.0*J;
758 const cdouble q = exp(I*M_PI*tau);
759 const cdouble n1 = -M_PI*M_PI/(12.0*w1) *
762 const cdouble u = M_PI*z / (2.0*w1);
767 static double ALPHA[4] {0.0};
768 struct Costa:
public Surface
770 Costa(Opt &opt): Surface((opt.Tptr = Parametrization, opt), false) { }
775 const int nx = opt.nx, ny = opt.ny;
776 MFEM_VERIFY(nx>2 && ny>2,
"");
777 const int nXhalf = (nx%2)==0 ? 4 : 2;
778 const int nYhalf = (ny%2)==0 ? 4 : 2;
779 const int nxh = nXhalf + nYhalf;
780 const int NVert = (nx+1) * (ny+1);
781 const int NElem = nx*ny - 4 - nxh;
782 const int NBdrElem = 0;
783 InitMesh(
DIM,
SDIM, NVert, NElem, NBdrElem);
785 for (
int j = 0; j <= ny; j++)
787 const double cy = ((double) j / ny) ;
788 for (
int i = 0; i <= nx; i++)
790 const double cx = ((double) i / nx);
791 const double coords[
SDIM] = {cx, cy, 0.0};
796 for (
int j = 0; j < ny; j++)
798 for (
int i = 0; i < nx; i++)
800 if (i == 0 && j == 0) {
continue; }
801 if (i+1 == nx && j == 0) {
continue; }
802 if (i == 0 && j+1 == ny) {
continue; }
803 if (i+1 == nx && j+1 == ny) {
continue; }
804 if ((j == 0 || j+1 == ny) && (abs(nx-(i<<1)-1)<=1)) {
continue; }
805 if ((i == 0 || i+1 == nx) && (abs(ny-(j<<1)-1)<=1)) {
continue; }
806 const int i0 = i + j*(nx+1);
807 const int i1 = i+1 + j*(nx+1);
808 const int i2 = i+1 + (j+1)*(nx+1);
809 const int i3 = i + (j+1)*(nx+1);
810 const int ind[4] = {i0, i1, i2, i3};
814 RemoveUnusedVertices();
815 FinalizeQuadMesh(
false, 0,
true);
822 const double tau = ALPHA[3];
829 const bool y_top = x[1] > 0.5;
830 const bool x_top = x[0] > 0.5;
833 if (y_top) { v = 1.0 - x[1]; }
834 if (x_top) {
u = 1.0 - x[0]; }
842 p[0] = real(
PI*(
u+
PI/(4.*e1))- zw +
PI/(2.*e1)*(dw));
843 p[1] = real(
PI*(v+
PI/(4.*e1))-I*zw-
PI*I/(2.*e1)*(dw));
844 p[2] = sqrt(
PI/2.)*log(abs((pw-e1)/(pw+e1)));
845 if (y_top) {
p[1] *= -1.0; }
846 if (x_top) {
p[0] *= -1.0; }
847 const bool nan = std::isnan(
p[0]) || std::isnan(
p[1]) || std::isnan(
p[2]);
848 MFEM_VERIFY(!nan,
"nan");
849 ALPHA[0] = std::fmax(
p[0], ALPHA[0]);
850 ALPHA[1] = std::fmax(
p[1], ALPHA[1]);
851 ALPHA[2] = std::fmax(
p[2], ALPHA[2]);
857 MFEM_VERIFY(ALPHA[0] > 0.0,
"");
858 MFEM_VERIFY(ALPHA[1] > 0.0,
"");
859 MFEM_VERIFY(ALPHA[2] > 0.0,
"");
861 const double phi = (1.0 + sqrt(5.0)) / 2.0;
864 for (
int d = 0; d <
SDIM; d++)
866 const double alpha = d==2 ? phi : 1.0;
868 nodes(vdof) /=
alpha * ALPHA[d];
875 struct Shell:
public Surface
877 Shell(Opt &opt): Surface((opt.niters = 1, opt.Tptr = Parametrization, opt)) { }
883 const double u = 2.0*
PI*x[0];
884 const double v = 21.0*x[1]-15.0;
885 p[0] = +1.0*pow(1.16,v)*cos(v)*(1.0+cos(
u));
886 p[1] = -1.0*pow(1.16,v)*sin(v)*(1.0+cos(
u));
887 p[2] = -2.0*pow(1.16,v)*(1.0+sin(
u));
892 struct Scherk:
public Surface
897 const double alpha = 0.49;
899 const double u =
alpha*
PI*(2.0*x[0]-1.0);
900 const double v =
alpha*
PI*(2.0*x[1]-1.0);
903 p[2] = log(cos(v)/cos(
u));
906 Scherk(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
910 struct FullPeach:
public Surface
912 static constexpr
int NV = 8;
913 static constexpr
int NE = 6;
916 Surface((opt.niters =
std::min(4, opt.niters), opt), NV, NE, 0) { }
920 const double quad_v[NV][
SDIM] =
922 {-1, -1, -1}, {+1, -1, -1}, {+1, +1, -1}, {-1, +1, -1},
923 {-1, -1, +1}, {+1, -1, +1}, {+1, +1, +1}, {-1, +1, +1}
925 const int quad_e[NE][4] =
927 {3, 2, 1, 0}, {0, 1, 5, 4}, {1, 2, 6, 5},
928 {2, 3, 7, 6}, {3, 0, 4, 7}, {4, 5, 6, 7}
931 for (
int j = 0; j < NV; j++) { AddVertex(quad_v[j]); }
932 for (
int j = 0; j < NE; j++) { AddQuad(quad_e[j], j+1); }
934 FinalizeQuadMesh(
false, 0,
true);
935 FinalizeTopology(
false);
940 void Snap() { SnapNodesToUnitSphere(); }
942 void BoundaryConditions()
952 for (
int e = 0; e < fes->
GetNE(); e++)
959 for (
int dof = 0; dof < dofs.
Size(); dof++)
963 const int k = dofs[dof];
964 MFEM_ASSERT(k >= 0,
"");
965 PointMat.
Mult(one, X);
966 const bool halfX = std::fabs(X[0]) <
EPS && X[1] <= 0.0;
967 const bool halfY = std::fabs(X[2]) <
EPS && X[1] >= 0.0;
968 const bool is_on_bc = halfX || halfY;
969 for (
int c = 0; c <
SDIM; c++)
970 { ess_vdofs[fes->
DofToVDof(k, c)] = is_on_bc; }
988 struct QuarterPeach:
public Surface
990 QuarterPeach(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
995 const double x = 2.0*X[0]-1.0;
996 const double y = X[1];
997 const double r = sqrt(x*x + y*y);
998 const double t = (x==0.0) ?
PI/2.0 :
999 (y==0.0 && x>0.0) ? 0. :
1000 (y==0.0 && x<0.0) ?
PI : acos(x/r);
1001 const double sqrtx = sqrt(1.0 + x*x);
1002 const double sqrty = sqrt(1.0 + y*y);
1003 const bool yaxis =
PI/4.0<
t &&
t < 3.0*
PI/4.0;
1004 const double R = yaxis?sqrtx:sqrty;
1005 const double gamma = r/R;
1006 p[0] = gamma * cos(
t);
1007 p[1] = gamma * sin(
t);
1013 for (
int i = 0; i < GetNBE(); i++)
1015 Element *el = GetBdrElement(i);
1016 const int fn = GetBdrElementEdgeIndex(i);
1017 MFEM_VERIFY(!FaceIsTrueInterior(fn),
"");
1019 GetFaceVertices(fn, vertices);
1022 double R[2], X[2][
SDIM];
1023 for (
int v = 0; v < 2; v++)
1026 const int iv = vertices[v];
1027 for (
int d = 0; d <
SDIM; d++)
1030 const double x = X[v][d] = nval[iv];
1031 if (d < 2) { R[v] += x*x; }
1034 if (std::fabs(X[0][1])<=
EPS && std::fabs(X[1][1])<=
EPS &&
1035 (R[0]>0.1 || R[1]>0.1))
1043 struct SlottedSphere:
public Surface
1045 SlottedSphere(Opt &opt): Surface((opt.niters = 4, opt), 64, 40, 0) { }
1049 constexpr
double delta = 0.15;
1050 constexpr
int NV1D = 4;
1051 constexpr
int NV = NV1D*NV1D*NV1D;
1052 constexpr
int NEPF = (NV1D-1)*(NV1D-1);
1053 constexpr
int NE = NEPF*6;
1054 const double V1D[NV1D] = {-1.0, -
delta,
delta, 1.0};
1056 for (
int iv=0; iv<NV; ++iv)
1059 int iy = (iv / NV1D) % NV1D;
1060 int iz = (iv / NV1D) / NV1D;
1062 QV[iv][0] = V1D[ix];
1063 QV[iv][1] = V1D[iy];
1064 QV[iv][2] = V1D[iz];
1067 for (
int ix=0; ix<NV1D-1; ++ix)
1069 for (
int iy=0; iy<NV1D-1; ++iy)
1071 int el_offset = ix + iy*(NV1D-1);
1073 QE[0*NEPF + el_offset][0] = NV1D*ix + NV1D*NV1D*iy;
1074 QE[0*NEPF + el_offset][1] = NV1D*(ix+1) + NV1D*NV1D*iy;
1075 QE[0*NEPF + el_offset][2] = NV1D*(ix+1) + NV1D*NV1D*(iy+1);
1076 QE[0*NEPF + el_offset][3] = NV1D*ix + NV1D*NV1D*(iy+1);
1079 QE[1*NEPF + el_offset][3] = x_off + NV1D*ix + NV1D*NV1D*iy;
1080 QE[1*NEPF + el_offset][2] = x_off + NV1D*(ix+1) + NV1D*NV1D*iy;
1081 QE[1*NEPF + el_offset][1] = x_off + NV1D*(ix+1) + NV1D*NV1D*(iy+1);
1082 QE[1*NEPF + el_offset][0] = x_off + NV1D*ix + NV1D*NV1D*(iy+1);
1084 QE[2*NEPF + el_offset][0] = NV1D*NV1D*iy + ix;
1085 QE[2*NEPF + el_offset][1] = NV1D*NV1D*iy + ix + 1;
1086 QE[2*NEPF + el_offset][2] = NV1D*NV1D*(iy+1) + ix + 1;
1087 QE[2*NEPF + el_offset][3] = NV1D*NV1D*(iy+1) + ix;
1089 int y_off = NV1D*(NV1D-1);
1090 QE[3*NEPF + el_offset][0] = y_off + NV1D*NV1D*iy + ix;
1091 QE[3*NEPF + el_offset][1] = y_off + NV1D*NV1D*iy + ix + 1;
1092 QE[3*NEPF + el_offset][2] = y_off + NV1D*NV1D*(iy+1) + ix + 1;
1093 QE[3*NEPF + el_offset][3] = y_off + NV1D*NV1D*(iy+1) + ix;
1095 QE[4*NEPF + el_offset][0] = NV1D*iy + ix;
1096 QE[4*NEPF + el_offset][1] = NV1D*iy + ix + 1;
1097 QE[4*NEPF + el_offset][2] = NV1D*(iy+1) + ix + 1;
1098 QE[4*NEPF + el_offset][3] = NV1D*(iy+1) + ix;
1100 int z_off = NV1D*NV1D*(NV1D-1);
1101 QE[5*NEPF + el_offset][0] = z_off + NV1D*iy + ix;
1102 QE[5*NEPF + el_offset][1] = z_off + NV1D*iy + ix + 1;
1103 QE[5*NEPF + el_offset][2] = z_off + NV1D*(iy+1) + ix + 1;
1104 QE[5*NEPF + el_offset][3] = z_off + NV1D*(iy+1) + ix;
1108 QE[0*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1109 QE[0*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1111 QE[1*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1112 QE[1*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1114 QE[3*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1115 QE[3*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1117 QE[5*NEPF + 0 + 1*(NV1D-1)][0] = -1;
1118 QE[5*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1119 QE[5*NEPF + 2 + 1*(NV1D-1)][0] = -1;
1121 QE[4*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1122 QE[4*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1123 QE[4*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1125 QE[2*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1126 QE[2*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1127 for (
int j = 0; j < NV; j++) { AddVertex(QV[j]); }
1128 for (
int j = 0; j < NE; j++)
1130 if (QE[j][0] < 0) {
continue; }
1131 AddQuad(QE[j], j+1);
1133 RemoveUnusedVertices();
1134 FinalizeQuadMesh(
false, 0,
true);
1139 void Snap() { SnapNodesToUnitSphere(); }
1142 static int Problem0(Opt &opt)
1145 Surface *S =
nullptr;
1146 switch (opt.surface)
1148 case 0: S =
new MeshFromFile(opt);
break;
1149 case 1: S =
new Catenoid(opt);
break;
1150 case 2: S =
new Helicoid(opt);
break;
1151 case 3: S =
new Enneper(opt);
break;
1152 case 4: S =
new Hold(opt);
break;
1153 case 5: S =
new Costa(opt);
break;
1154 case 6: S =
new Shell(opt);
break;
1155 case 7: S =
new Scherk(opt);
break;
1156 case 8: S =
new FullPeach(opt);
break;
1157 case 9: S =
new QuarterPeach(opt);
break;
1158 case 10: S =
new SlottedSphere(opt);
break;
1159 default: MFEM_ABORT(
"Unknown surface (surface <= 10)!");
1169 static double u0(
const Vector &x) {
return sin(3.0 *
PI * (x[1] + x[0])); }
1173 static double qf(
const int order,
const int ker,
Mesh &m,
1180 const int NE(m.
GetNE());
1188 MFEM_VERIFY(ND == D1D*D1D,
"");
1189 MFEM_VERIFY(NQ == Q1D*Q1D,
"");
1191 Vector Eu(ND*NE), grad_u(
DIM*NQ*NE), sum(NE*NQ), one(NE*NQ);
1196 qi->Derivatives(Eu, grad_u);
1201 auto grdU =
Reshape(grad_u.Read(),
DIM, Q1D, Q1D, NE);
1202 auto S =
Reshape(sum.Write(), Q1D, Q1D, NE);
1204 MFEM_FORALL_2D(e, NE, Q1D, Q1D, 1,
1206 MFEM_FOREACH_THREAD(qy,y,Q1D)
1208 MFEM_FOREACH_THREAD(qx,x,Q1D)
1210 const double w = W(qx, qy);
1211 const double J11 = J(qx, qy, 0, 0, e);
1212 const double J12 = J(qx, qy, 1, 0, e);
1213 const double J21 = J(qx, qy, 0, 1, e);
1214 const double J22 = J(qx, qy, 1, 1, e);
1215 const double det = detJ(qx, qy, e);
1216 const double area = w * det;
1217 const double gu0 = grdU(0, qx, qy, e);
1218 const double gu1 = grdU(1, qx, qy, e);
1219 const double tgu0 = (J22*gu0 - J12*gu1)/det;
1220 const double tgu1 = (J11*gu1 - J21*gu0)/det;
1221 const double ngu = tgu0*tgu0 + tgu1*tgu1;
1222 const double s = (ker ==
AREA) ? sqrt(1.0 + ngu) :
1223 (ker ==
NORM) ? ngu : 0.0;
1224 S(qx, qy, e) = area *
s;
1232 static int Problem1(Opt &opt)
1234 const int order = opt.order;
1238 ParMesh mesh(MPI_COMM_WORLD, smesh);
1250 u.ProjectCoefficient(u0_fc);
1253 if (opt.vis) { Surface::Visualize(glvis, opt, &mesh,
GLVIZ_W,
GLVIZ_H, &
u); }
1262 for (
int i = 0; i < opt.niters; i++)
1268 const double q_uold = qf(order,
AREA, mesh, fes, uold);
1269 MFEM_VERIFY(std::fabs(q_uold) >
EPS,
"");
1273 a.FormLinearSystem(ess_tdof_list,
u,
b, A, X, B);
1276 a.RecoverFEMSolution(X,
b,
u);
1278 const double norm = sqrt(std::fabs(qf(order,
NORM, mesh, fes, eps)));
1279 const double area = qf(order,
AREA, mesh, fes,
u);
1282 mfem::out <<
"Iteration " << i <<
", norm: " << norm
1283 <<
", area: " << area << std::endl;
1285 if (opt.vis) { Surface::Visualize(glvis, opt, &mesh, &
u); }
1287 if (norm <
NRM) {
break; }
1302 args.
AddOption(&opt.pb,
"-p",
"--problem",
"Problem to solve.");
1303 args.
AddOption(&opt.mesh_file,
"-m",
"--mesh",
"Mesh file to use.");
1304 args.
AddOption(&opt.wait,
"-w",
"--wait",
"-no-w",
"--no-wait",
1305 "Enable or disable a GLVis pause.");
1306 args.
AddOption(&opt.radial,
"-rad",
"--radial",
"-no-rad",
"--no-radial",
1307 "Enable or disable radial constraints in solver.");
1308 args.
AddOption(&opt.nx,
"-x",
"--num-elements-x",
1309 "Number of elements in x-direction.");
1310 args.
AddOption(&opt.ny,
"-y",
"--num-elements-y",
1311 "Number of elements in y-direction.");
1312 args.
AddOption(&opt.order,
"-o",
"--order",
"Finite element order.");
1313 args.
AddOption(&opt.refine,
"-r",
"--ref-levels",
"Refinement");
1314 args.
AddOption(&opt.niters,
"-n",
"--niter-max",
"Max number of iterations");
1315 args.
AddOption(&opt.surface,
"-s",
"--surface",
"Choice of the surface.");
1316 args.
AddOption(&opt.pa,
"-pa",
"--partial-assembly",
"-no-pa",
1317 "--no-partial-assembly",
"Enable Partial Assembly.");
1318 args.
AddOption(&opt.tau,
"-t",
"--tau",
"Costa scale factor.");
1319 args.
AddOption(&opt.lambda,
"-l",
"--lambda",
"Lambda step toward solution.");
1320 args.
AddOption(&opt.amr,
"-a",
"--amr",
"-no-a",
"--no-amr",
"Enable AMR.");
1321 args.
AddOption(&opt.amr_threshold,
"-at",
"--amr-threshold",
"AMR threshold.");
1322 args.
AddOption(&opt.device_config,
"-d",
"--device",
1323 "Device configuration string, see Device::Configure().");
1324 args.
AddOption(&opt.keys,
"-k",
"--keys",
"GLVis configuration keys.");
1325 args.
AddOption(&opt.vis,
"-vis",
"--visualization",
"-no-vis",
1326 "--no-visualization",
"Enable or disable visualization.");
1327 args.
AddOption(&opt.by_vdim,
"-c",
"--solve-byvdim",
1328 "-no-c",
"--solve-bynodes",
1329 "Enable or disable the 'ByVdim' solver");
1330 args.
AddOption(&opt.print,
"-print",
"--print",
"-no-print",
"--no-print",
1331 "Enable or disable result output (files in mfem format).");
1332 args.
AddOption(&opt.snapshot,
"-ss",
"--snapshot",
"-no-ss",
"--no-snapshot",
1333 "Enable or disable GLVis snapshot.");
1336 MFEM_VERIFY(opt.lambda >= 0.0 && opt.lambda <= 1.0,
"");
1340 Device device(opt.device_config);
1341 if (!opt.id) { device.
Print(); }
1343 if (opt.pb == 0) { Problem0(opt); }
1345 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.
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.
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
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
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
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)