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();
469 MFEM_FORALL(i, ndof, d_nodes[c*ndof + i] = d_Xi[i]; );
474 auto d_Xi = Xi.
Write();
475 const int ndof = S.fes->GetNDofs();
476 auto d_nodes = S.fes->GetMesh()->GetNodes()->Read();
477 MFEM_FORALL(i, ndof, d_Xi[i] = d_nodes[c*ndof + i]; );
480 ByVDim(Surface &S, Opt &opt):
Solver(S, opt)
485 bool cvg[
SDIM] {
false};
486 for (
int c=0; c <
SDIM; ++c)
493 const bool converged = cvg[0] && cvg[1] && cvg[2];
494 return converged ? true :
false;
500 struct MeshFromFile:
public Surface
502 MeshFromFile(Opt &opt): Surface(opt, opt.mesh_file) { }
506 struct Catenoid:
public Surface
508 Catenoid(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
514 for (
int i = 0; i < v2v.Size(); i++) { v2v[i] = i; }
516 for (
int j = 0; j <= opt.ny; j++)
518 const int v_old = opt.nx + j * (opt.nx + 1);
519 const int v_new = j * (opt.nx + 1);
523 for (
int i = 0; i < GetNE(); i++)
528 for (
int j = 0; j < nv; j++)
534 for (
int i = 0; i < GetNBE(); i++)
536 Element *el = GetBdrElement(i);
539 for (
int j = 0; j < nv; j++)
544 RemoveUnusedVertices();
545 RemoveInternalBoundaries();
552 const double u = 2.0*
PI*x[0];
553 const double v =
PI*(x[1]-0.5)/3.;
561 struct Helicoid:
public Surface
563 Helicoid(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
569 const double u = 2.0*
PI*x[0];
570 const double v = 2.0*
PI*(2.0*x[1]-1.0)/3.0;
578 struct Enneper:
public Surface
580 Enneper(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
586 const double u = 4.0*(x[0]-0.5);
587 const double v = 4.0*(x[1]-0.5);
588 p[0] = +
u -
u*
u*
u/3.0 +
u*v*v;
589 p[1] = -v -
u*
u*v + v*v*v/3.0;
595 struct Hold:
public Surface
597 Hold(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
603 for (
int i = 0; i < v2v.Size(); i++) { v2v[i] = i; }
605 for (
int j = 0; j <= opt.ny; j++)
607 const int v_old = opt.nx + j * (opt.nx + 1);
608 const int v_new = j * (opt.nx + 1);
612 for (
int i = 0; i < GetNE(); i++)
617 for (
int j = 0; j < nv; j++)
623 for (
int i = 0; i < GetNBE(); i++)
625 Element *el = GetBdrElement(i);
628 for (
int j = 0; j < nv; j++)
633 RemoveUnusedVertices();
634 RemoveInternalBoundaries();
641 const double u = 2.0*
PI*x[0];
642 const double v = x[1];
643 p[0] = cos(
u)*(1.0 + 0.3*sin(3.*
u +
PI*v));
644 p[1] = sin(
u)*(1.0 + 0.3*sin(3.*
u +
PI*v));
652 #define I cdouble(0.0, 1.0) 658 double delta = std::numeric_limits<double>::max();
664 const cdouble j = pow(-1,n)*pow(q,n*(n+1.0))*sin((2.0*n+1.0)*
u);
668 return 2.0*pow(q,0.25)*J;
673 const cdouble j = pow(q,n*(n+1))*cos((2.0*n+1.0)*
u);
677 return 2.0*pow(q,0.25)*J;
681 const cdouble j = pow(q,n*n)*cos(2.0*n*
u);
689 const cdouble j =pow(-1,n)*pow(q,n*n)*cos(2.0*n*
u);
704 const cdouble q = exp(I*M_PI*tau);
705 const cdouble e1 = M_PI*M_PI/(12.0*w1*w1)*
708 const cdouble u = M_PI*z / (2.0*w1);
717 double delta = std::numeric_limits<double>::max();
720 const double alpha = 2.0*n+1.0;
722 const cdouble j = pow(-1,n)*pow(q,n*(n+1.0))*Dcosine;
726 return 2.0*pow(q,0.25)*J;
733 double delta = std::numeric_limits<double>::max();
737 if (abs(q2n) <
EPS) { q2n = 0.0; }
738 const cdouble j = q2n/(1.0-q2n)*sin(2.0*n*
u);
742 return 1.0/tan(
u) + 4.0*J;
751 const cdouble q = exp(I*M_PI*tau);
752 const cdouble n1 = -M_PI*M_PI/(12.0*w1) *
755 const cdouble u = M_PI*z / (2.0*w1);
760 static double ALPHA[4] {0.0};
761 struct Costa:
public Surface
763 Costa(Opt &opt): Surface((opt.Tptr = Parametrization, opt), false) { }
768 const int nx = opt.nx, ny = opt.ny;
769 MFEM_VERIFY(nx>2 && ny>2,
"");
770 const int nXhalf = (nx%2)==0 ? 4 : 2;
771 const int nYhalf = (ny%2)==0 ? 4 : 2;
772 const int nxh = nXhalf + nYhalf;
773 const int NVert = (nx+1) * (ny+1);
774 const int NElem = nx*ny - 4 - nxh;
775 const int NBdrElem = 0;
776 InitMesh(
DIM,
SDIM, NVert, NElem, NBdrElem);
778 for (
int j = 0; j <= ny; j++)
780 const double cy = ((double) j / ny) ;
781 for (
int i = 0; i <= nx; i++)
783 const double cx = ((double) i / nx);
784 const double coords[
SDIM] = {cx, cy, 0.0};
789 for (
int j = 0; j < ny; j++)
791 for (
int i = 0; i < nx; i++)
793 if (i == 0 && j == 0) {
continue; }
794 if (i+1 == nx && j == 0) {
continue; }
795 if (i == 0 && j+1 == ny) {
continue; }
796 if (i+1 == nx && j+1 == ny) {
continue; }
797 if ((j == 0 || j+1 == ny) && (abs(nx-(i<<1)-1)<=1)) {
continue; }
798 if ((i == 0 || i+1 == nx) && (abs(ny-(j<<1)-1)<=1)) {
continue; }
799 const int i0 = i + j*(nx+1);
800 const int i1 = i+1 + j*(nx+1);
801 const int i2 = i+1 + (j+1)*(nx+1);
802 const int i3 = i + (j+1)*(nx+1);
803 const int ind[4] = {i0, i1, i2, i3};
807 RemoveUnusedVertices();
808 FinalizeQuadMesh(
false, 0,
true);
815 const double tau = ALPHA[3];
822 const bool y_top = x[1] > 0.5;
823 const bool x_top = x[0] > 0.5;
826 if (y_top) { v = 1.0 - x[1]; }
827 if (x_top) {
u = 1.0 - x[0]; }
835 p[0] = real(
PI*(
u+
PI/(4.*e1))- zw +
PI/(2.*e1)*(dw));
836 p[1] = real(
PI*(v+
PI/(4.*e1))-I*zw-
PI*I/(2.*e1)*(dw));
837 p[2] = sqrt(
PI/2.)*log(abs((pw-e1)/(pw+e1)));
838 if (y_top) {
p[1] *= -1.0; }
839 if (x_top) {
p[0] *= -1.0; }
840 const bool nan = std::isnan(
p[0]) || std::isnan(
p[1]) || std::isnan(
p[2]);
841 MFEM_VERIFY(!nan,
"nan");
842 ALPHA[0] = std::fmax(
p[0], ALPHA[0]);
843 ALPHA[1] = std::fmax(
p[1], ALPHA[1]);
844 ALPHA[2] = std::fmax(
p[2], ALPHA[2]);
850 MFEM_VERIFY(ALPHA[0] > 0.0,
"");
851 MFEM_VERIFY(ALPHA[1] > 0.0,
"");
852 MFEM_VERIFY(ALPHA[2] > 0.0,
"");
854 const double phi = (1.0 + sqrt(5.0)) / 2.0;
857 for (
int d = 0; d <
SDIM; d++)
859 const double alpha = d==2 ? phi : 1.0;
861 nodes(vdof) /=
alpha * ALPHA[d];
868 struct Shell:
public Surface
870 Shell(Opt &opt): Surface((opt.niters = 1, opt.Tptr = Parametrization, opt)) { }
876 const double u = 2.0*
PI*x[0];
877 const double v = 21.0*x[1]-15.0;
878 p[0] = +1.0*pow(1.16,v)*cos(v)*(1.0+cos(
u));
879 p[1] = -1.0*pow(1.16,v)*sin(v)*(1.0+cos(
u));
880 p[2] = -2.0*pow(1.16,v)*(1.0+sin(
u));
885 struct Scherk:
public Surface
890 const double alpha = 0.49;
892 const double u =
alpha*
PI*(2.0*x[0]-1.0);
893 const double v =
alpha*
PI*(2.0*x[1]-1.0);
896 p[2] = log(cos(v)/cos(
u));
899 Scherk(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
903 struct FullPeach:
public Surface
905 static constexpr
int NV = 8;
906 static constexpr
int NE = 6;
909 Surface((opt.niters =
std::min(4, opt.niters), opt), NV, NE, 0) { }
913 const double quad_v[NV][
SDIM] =
915 {-1, -1, -1}, {+1, -1, -1}, {+1, +1, -1}, {-1, +1, -1},
916 {-1, -1, +1}, {+1, -1, +1}, {+1, +1, +1}, {-1, +1, +1}
918 const int quad_e[NE][4] =
920 {3, 2, 1, 0}, {0, 1, 5, 4}, {1, 2, 6, 5},
921 {2, 3, 7, 6}, {3, 0, 4, 7}, {4, 5, 6, 7}
924 for (
int j = 0; j < NV; j++) { AddVertex(quad_v[j]); }
925 for (
int j = 0; j < NE; j++) { AddQuad(quad_e[j], j+1); }
927 FinalizeQuadMesh(
false, 0,
true);
928 FinalizeTopology(
false);
933 void Snap() { SnapNodesToUnitSphere(); }
935 void BoundaryConditions()
945 for (
int e = 0; e < fes->
GetNE(); e++)
952 for (
int dof = 0; dof < dofs.
Size(); dof++)
956 const int k = dofs[dof];
957 MFEM_ASSERT(k >= 0,
"");
958 PointMat.
Mult(one, X);
959 const bool halfX = std::fabs(X[0]) <
EPS && X[1] <= 0.0;
960 const bool halfY = std::fabs(X[2]) <
EPS && X[1] >= 0.0;
961 const bool is_on_bc = halfX || halfY;
962 for (
int c = 0; c <
SDIM; c++)
963 { ess_vdofs[fes->
DofToVDof(k, c)] = is_on_bc; }
981 struct QuarterPeach:
public Surface
983 QuarterPeach(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
988 const double x = 2.0*X[0]-1.0;
989 const double y = X[1];
990 const double r = sqrt(x*x + y*y);
991 const double t = (x==0.0) ?
PI/2.0 :
992 (y==0.0 && x>0.0) ? 0. :
993 (y==0.0 && x<0.0) ?
PI : acos(x/r);
994 const double sqrtx = sqrt(1.0 + x*x);
995 const double sqrty = sqrt(1.0 + y*y);
996 const bool yaxis =
PI/4.0<
t &&
t < 3.0*
PI/4.0;
997 const double R = yaxis?sqrtx:sqrty;
998 const double gamma = r/R;
999 p[0] = gamma * cos(
t);
1000 p[1] = gamma * sin(
t);
1006 for (
int i = 0; i < GetNBE(); i++)
1008 Element *el = GetBdrElement(i);
1009 const int fn = GetBdrElementEdgeIndex(i);
1010 MFEM_VERIFY(!FaceIsTrueInterior(fn),
"");
1012 GetFaceVertices(fn, vertices);
1015 double R[2], X[2][
SDIM];
1016 for (
int v = 0; v < 2; v++)
1019 const int iv = vertices[v];
1020 for (
int d = 0; d <
SDIM; d++)
1023 const double x = X[v][d] = nval[iv];
1024 if (d < 2) { R[v] += x*x; }
1027 if (std::fabs(X[0][1])<=
EPS && std::fabs(X[1][1])<=
EPS &&
1028 (R[0]>0.1 || R[1]>0.1))
1036 struct SlottedSphere:
public Surface
1038 SlottedSphere(Opt &opt): Surface((opt.niters = 4, opt), 64, 40, 0) { }
1042 constexpr
double delta = 0.15;
1043 constexpr
int NV1D = 4;
1044 constexpr
int NV = NV1D*NV1D*NV1D;
1045 constexpr
int NEPF = (NV1D-1)*(NV1D-1);
1046 constexpr
int NE = NEPF*6;
1047 const double V1D[NV1D] = {-1.0, -
delta,
delta, 1.0};
1049 for (
int iv=0; iv<NV; ++iv)
1052 int iy = (iv / NV1D) % NV1D;
1053 int iz = (iv / NV1D) / NV1D;
1055 QV[iv][0] = V1D[ix];
1056 QV[iv][1] = V1D[iy];
1057 QV[iv][2] = V1D[iz];
1060 for (
int ix=0; ix<NV1D-1; ++ix)
1062 for (
int iy=0; iy<NV1D-1; ++iy)
1064 int el_offset = ix + iy*(NV1D-1);
1066 QE[0*NEPF + el_offset][0] = NV1D*ix + NV1D*NV1D*iy;
1067 QE[0*NEPF + el_offset][1] = NV1D*(ix+1) + NV1D*NV1D*iy;
1068 QE[0*NEPF + el_offset][2] = NV1D*(ix+1) + NV1D*NV1D*(iy+1);
1069 QE[0*NEPF + el_offset][3] = NV1D*ix + NV1D*NV1D*(iy+1);
1072 QE[1*NEPF + el_offset][3] = x_off + NV1D*ix + NV1D*NV1D*iy;
1073 QE[1*NEPF + el_offset][2] = x_off + NV1D*(ix+1) + NV1D*NV1D*iy;
1074 QE[1*NEPF + el_offset][1] = x_off + NV1D*(ix+1) + NV1D*NV1D*(iy+1);
1075 QE[1*NEPF + el_offset][0] = x_off + NV1D*ix + NV1D*NV1D*(iy+1);
1077 QE[2*NEPF + el_offset][0] = NV1D*NV1D*iy + ix;
1078 QE[2*NEPF + el_offset][1] = NV1D*NV1D*iy + ix + 1;
1079 QE[2*NEPF + el_offset][2] = NV1D*NV1D*(iy+1) + ix + 1;
1080 QE[2*NEPF + el_offset][3] = NV1D*NV1D*(iy+1) + ix;
1082 int y_off = NV1D*(NV1D-1);
1083 QE[3*NEPF + el_offset][0] = y_off + NV1D*NV1D*iy + ix;
1084 QE[3*NEPF + el_offset][1] = y_off + NV1D*NV1D*iy + ix + 1;
1085 QE[3*NEPF + el_offset][2] = y_off + NV1D*NV1D*(iy+1) + ix + 1;
1086 QE[3*NEPF + el_offset][3] = y_off + NV1D*NV1D*(iy+1) + ix;
1088 QE[4*NEPF + el_offset][0] = NV1D*iy + ix;
1089 QE[4*NEPF + el_offset][1] = NV1D*iy + ix + 1;
1090 QE[4*NEPF + el_offset][2] = NV1D*(iy+1) + ix + 1;
1091 QE[4*NEPF + el_offset][3] = NV1D*(iy+1) + ix;
1093 int z_off = NV1D*NV1D*(NV1D-1);
1094 QE[5*NEPF + el_offset][0] = z_off + NV1D*iy + ix;
1095 QE[5*NEPF + el_offset][1] = z_off + NV1D*iy + ix + 1;
1096 QE[5*NEPF + el_offset][2] = z_off + NV1D*(iy+1) + ix + 1;
1097 QE[5*NEPF + el_offset][3] = z_off + NV1D*(iy+1) + ix;
1101 QE[0*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1102 QE[0*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1104 QE[1*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1105 QE[1*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1107 QE[3*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1108 QE[3*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1110 QE[5*NEPF + 0 + 1*(NV1D-1)][0] = -1;
1111 QE[5*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1112 QE[5*NEPF + 2 + 1*(NV1D-1)][0] = -1;
1114 QE[4*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1115 QE[4*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1116 QE[4*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1118 QE[2*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1119 QE[2*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1120 for (
int j = 0; j < NV; j++) { AddVertex(QV[j]); }
1121 for (
int j = 0; j < NE; j++)
1123 if (QE[j][0] < 0) {
continue; }
1124 AddQuad(QE[j], j+1);
1126 RemoveUnusedVertices();
1127 FinalizeQuadMesh(
false, 0,
true);
1132 void Snap() { SnapNodesToUnitSphere(); }
1135 static int Problem0(Opt &opt)
1138 Surface *S =
nullptr;
1139 switch (opt.surface)
1141 case 0: S =
new MeshFromFile(opt);
break;
1142 case 1: S =
new Catenoid(opt);
break;
1143 case 2: S =
new Helicoid(opt);
break;
1144 case 3: S =
new Enneper(opt);
break;
1145 case 4: S =
new Hold(opt);
break;
1146 case 5: S =
new Costa(opt);
break;
1147 case 6: S =
new Shell(opt);
break;
1148 case 7: S =
new Scherk(opt);
break;
1149 case 8: S =
new FullPeach(opt);
break;
1150 case 9: S =
new QuarterPeach(opt);
break;
1151 case 10: S =
new SlottedSphere(opt);
break;
1152 default: MFEM_ABORT(
"Unknown surface (surface <= 10)!");
1162 static double u0(
const Vector &x) {
return sin(3.0 *
PI * (x[1] + x[0])); }
1166 static double qf(
const int order,
const int ker,
Mesh &m,
1173 const int NE(m.
GetNE());
1181 MFEM_VERIFY(ND == D1D*D1D,
"");
1182 MFEM_VERIFY(NQ == Q1D*Q1D,
"");
1184 Vector Eu(ND*NE), grad_u(
DIM*NQ*NE), sum(NE*NQ), one(NE*NQ);
1189 qi->Derivatives(Eu, grad_u);
1194 auto grdU =
Reshape(grad_u.Read(),
DIM, Q1D, Q1D, NE);
1195 auto S =
Reshape(sum.Write(), Q1D, Q1D, NE);
1197 MFEM_FORALL_2D(e, NE, Q1D, Q1D, 1,
1199 MFEM_FOREACH_THREAD(qy,y,Q1D)
1201 MFEM_FOREACH_THREAD(qx,x,Q1D)
1203 const double w = W(qx, qy);
1204 const double J11 = J(qx, qy, 0, 0, e);
1205 const double J12 = J(qx, qy, 1, 0, e);
1206 const double J21 = J(qx, qy, 0, 1, e);
1207 const double J22 = J(qx, qy, 1, 1, e);
1208 const double det = detJ(qx, qy, e);
1209 const double area = w * det;
1210 const double gu0 = grdU(0, qx, qy, e);
1211 const double gu1 = grdU(1, qx, qy, e);
1212 const double tgu0 = (J22*gu0 - J12*gu1)/det;
1213 const double tgu1 = (J11*gu1 - J21*gu0)/det;
1214 const double ngu = tgu0*tgu0 + tgu1*tgu1;
1215 const double s = (ker ==
AREA) ? sqrt(1.0 + ngu) :
1216 (ker ==
NORM) ? ngu : 0.0;
1217 S(qx, qy, e) = area *
s;
1225 static int Problem1(Opt &opt)
1227 const int order = opt.order;
1242 u.ProjectCoefficient(u0_fc);
1245 if (opt.vis) { Surface::Visualize(glvis, opt, &mesh,
GLVIZ_W,
GLVIZ_H, &
u); }
1254 for (
int i = 0; i < opt.niters; i++)
1260 const double q_uold = qf(order,
AREA, mesh, fes, uold);
1261 MFEM_VERIFY(std::fabs(q_uold) >
EPS,
"");
1265 a.FormLinearSystem(ess_tdof_list,
u,
b, A, X, B);
1268 a.RecoverFEMSolution(X,
b,
u);
1270 const double norm = sqrt(std::fabs(qf(order,
NORM, mesh, fes, eps)));
1271 const double area = qf(order,
AREA, mesh, fes,
u);
1274 mfem::out <<
"Iteration " << i <<
", norm: " << norm
1275 <<
", area: " << area << std::endl;
1277 if (opt.vis) { Surface::Visualize(glvis, opt, &mesh, &
u); }
1279 if (norm <
NRM) {
break; }
1287 opt.sz = opt.id = 0;
1290 args.
AddOption(&opt.pb,
"-p",
"--problem",
"Problem to solve.");
1291 args.
AddOption(&opt.mesh_file,
"-m",
"--mesh",
"Mesh file to use.");
1292 args.
AddOption(&opt.wait,
"-w",
"--wait",
"-no-w",
"--no-wait",
1293 "Enable or disable a GLVis pause.");
1294 args.
AddOption(&opt.radial,
"-rad",
"--radial",
"-no-rad",
"--no-radial",
1295 "Enable or disable radial constraints in solver.");
1296 args.
AddOption(&opt.nx,
"-x",
"--num-elements-x",
1297 "Number of elements in x-direction.");
1298 args.
AddOption(&opt.ny,
"-y",
"--num-elements-y",
1299 "Number of elements in y-direction.");
1300 args.
AddOption(&opt.order,
"-o",
"--order",
"Finite element order.");
1301 args.
AddOption(&opt.refine,
"-r",
"--ref-levels",
"Refinement");
1302 args.
AddOption(&opt.niters,
"-n",
"--niter-max",
"Max number of iterations");
1303 args.
AddOption(&opt.surface,
"-s",
"--surface",
"Choice of the surface.");
1304 args.
AddOption(&opt.pa,
"-pa",
"--partial-assembly",
"-no-pa",
1305 "--no-partial-assembly",
"Enable Partial Assembly.");
1306 args.
AddOption(&opt.tau,
"-t",
"--tau",
"Costa scale factor.");
1307 args.
AddOption(&opt.lambda,
"-l",
"--lambda",
"Lambda step toward solution.");
1308 args.
AddOption(&opt.amr,
"-a",
"--amr",
"-no-a",
"--no-amr",
"Enable AMR.");
1309 args.
AddOption(&opt.amr_threshold,
"-at",
"--amr-threshold",
"AMR threshold.");
1310 args.
AddOption(&opt.device_config,
"-d",
"--device",
1311 "Device configuration string, see Device::Configure().");
1312 args.
AddOption(&opt.keys,
"-k",
"--keys",
"GLVis configuration keys.");
1313 args.
AddOption(&opt.vis,
"-vis",
"--visualization",
"-no-vis",
1314 "--no-visualization",
"Enable or disable visualization.");
1315 args.
AddOption(&opt.vis_mesh,
"-vm",
"--vis-mesh",
"-no-vm",
1316 "--no-vis-mesh",
"Enable or disable mesh visualization.");
1317 args.
AddOption(&opt.by_vdim,
"-c",
"--solve-byvdim",
1318 "-no-c",
"--solve-bynodes",
1319 "Enable or disable the 'ByVdim' solver");
1320 args.
AddOption(&opt.print,
"-print",
"--print",
"-no-print",
"--no-print",
1321 "Enable or disable result output (files in mfem format).");
1322 args.
AddOption(&opt.snapshot,
"-ss",
"--snapshot",
"-no-ss",
"--no-snapshot",
1323 "Enable or disable GLVis snapshot.");
1326 MFEM_VERIFY(opt.lambda >= 0.0 && opt.lambda <= 1.0,
"");
1330 Device device(opt.device_config);
1331 if (!opt.id) { device.
Print(); }
1333 if (opt.pb == 0) { Problem0(opt); }
1335 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.
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.
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
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
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'.
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
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)