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();
103 bool by_vdim =
false;
104 bool snapshot =
false;
105 bool vis_mesh =
false;
108 double amr_threshold = 0.6;
109 const char *keys =
"gAm";
110 const char *device_config =
"cpu";
111 const char *mesh_file =
"../../data/mobius-strip.mesh";
115 class Surface:
public Mesh
125 Surface(Opt &opt,
const char *file):
Mesh(file, true), opt(opt) { }
128 Surface(Opt &opt,
bool):
Mesh(), opt(opt) { }
131 Surface(Opt &opt):
Mesh(opt.nx, opt.ny,
QUAD, true), opt(opt) { }
134 Surface(Opt &opt,
int nv,
int ne,
int nbe):
148 if (opt.amr) { EnsureNCMesh(); }
149 mesh =
new Mesh(*
this,
true);
151 BoundaryConditions();
163 ByVDim(*
this, opt).Solve();
167 ByNodes(*
this, opt).Solve();
169 if (opt.vis && opt.snapshot)
172 Visualize(opt, mesh, mesh->GetNodes());
179 if (opt.vis) { glvis.
close(); }
180 delete mesh;
delete fec;
delete fes;
183 virtual void Prefix()
188 virtual void Transform() {
if (opt.Tptr) {
Mesh::Transform(opt.Tptr); } }
190 virtual void Postfix()
195 virtual void Refine()
197 for (
int l = 0; l < opt.refine; l++)
206 for (
int i = 0; i < nodes.
Size(); i++)
208 if (std::abs(nodes(i)) <
EPS)
215 void SnapNodesToUnitSphere()
221 for (
int d = 0; d <
SDIM; d++)
226 for (
int d = 0; d <
SDIM; d++)
233 virtual void BoundaryConditions()
235 if (bdr_attributes.Size())
240 fes->GetEssentialTrueDofs(ess_bdr, bc);
245 static void Visualize(Opt &opt,
const Mesh *mesh,
246 const int w,
const int h,
250 if (opt.vis_mesh) { glvis <<
"mesh\n" << *mesh; }
251 else { glvis <<
"solution\n" << *mesh << solution; }
253 glvis <<
"window_size " << w <<
" " << h <<
"\n";
254 glvis <<
"keys " << opt.keys <<
"\n";
256 if (opt.wait) { glvis <<
"pause\n"; }
261 static void Visualize(
const Opt &opt,
const Mesh *mesh,
265 if (opt.vis_mesh) { glvis <<
"mesh\n" << *mesh; }
266 else { glvis <<
"solution\n" << *mesh << solution; }
267 if (opt.wait) { glvis <<
"pause\n"; }
268 if (opt.snapshot && opt.keys) { glvis <<
"keys " << opt.keys <<
"\n"; }
275 const char *mesh_file =
"surface.mesh";
276 const char *sol_file =
"sol.gf";
279 mfem::out <<
"Printing " << mesh_file <<
", " << sol_file << std::endl;
282 std::ofstream mesh_ofs(mesh_file);
283 mesh_ofs.precision(8);
284 mesh->
Print(mesh_ofs);
287 std::ofstream sol_ofs(sol_file);
288 sol_ofs.precision(8);
305 const int print_iter = -1, max_num_iter = 2000;
306 const double RTOLERANCE =
EPS, ATOLERANCE =
EPS*
EPS;
308 Solver(Surface &S, Opt &opt): opt(opt), S(S), cg(),
309 a(S.fes), x(S.fes), x0(S.fes),
b(S.fes), one(1.0)
311 cg.SetRelTol(RTOLERANCE);
312 cg.SetAbsTol(ATOLERANCE);
313 cg.SetMaxIter(max_num_iter);
314 cg.SetPrintLevel(print_iter);
321 constexpr
bool converged =
true;
323 for (
int i=0; i < opt.niters; ++i)
325 if (opt.amr) { Amr(); }
326 if (opt.vis) { Surface::Visualize(opt, S.mesh); }
327 if (!opt.id) {
mfem::out <<
"Iteration " << i <<
": "; }
328 S.mesh->DeleteGeometricFactors();
331 if (Step() == converged) {
break; }
333 if (opt.print) {
Surface::Print(opt, S.mesh, S.mesh->GetNodes()); }
336 virtual bool Step() = 0;
339 bool Converged(
const double rnorm) {
return rnorm <
NRM; }
345 a.FormLinearSystem(S.bc, x,
b, A, X, B);
347 if (M) { cg.SetPreconditioner(*M); }
350 a.RecoverFEMSolution(X,
b, x);
351 const bool by_vdim = opt.by_vdim;
352 GridFunction *nodes = by_vdim ? &x0 : S.fes->GetMesh()->GetNodes();
356 if (!opt.id) {
mfem::out <<
"rnorm = " << rnorm << std::endl; }
357 const double lambda = opt.lambda;
360 MFEM_VERIFY(!opt.radial,
"'VDim solver can't use radial option!");
361 return Converged(rnorm);
368 Vector ni(SDIM), di(SDIM);
369 for (
int i = 0; i <
delta.Size()/
SDIM; i++)
372 const int ndof = S.fes->GetNDofs();
373 for (
int d = 0; d <
SDIM; d++)
375 ni(d) = (*nodes)(d*ndof + i);
376 di(d) =
delta(d*ndof + i);
379 const double ndotd = (ni*di) / (ni*ni);
382 for (
int d = 0; d <
SDIM; d++) {
delta(d*ndof + i) = di(d); }
387 add(lambda, *nodes, (1.0-lambda), x, x);
388 return Converged(rnorm);
393 MFEM_VERIFY(opt.amr_threshold >= 0.0 && opt.amr_threshold <= 1.0,
"");
396 const int NE = mesh->
GetNE();
398 for (
int e = 0; e < NE; e++)
406 for (
int q = 0; q < NQ; q++)
413 const double w = Jadjt.
Weight();
414 minW = std::fmin(minW, w);
415 maxW = std::fmax(maxW, w);
417 if (std::fabs(maxW) != 0.0)
419 const double rho = minW / maxW;
420 MFEM_VERIFY(rho <= 1.0,
"");
434 S.BoundaryConditions();
440 class ByNodes:
public Solver
443 ByNodes(Surface &S, Opt &opt):
Solver(S, opt)
448 x = *S.fes->GetMesh()->GetNodes();
449 bool converge = ParAXeqB();
451 return converge ?
true :
false;
456 class ByVDim:
public Solver
461 auto d_Xi = Xi.
Read();
462 auto d_nodes = S.fes->GetMesh()->GetNodes()->Write();
463 const int ndof = S.fes->GetNDofs();
464 MFEM_FORALL(i, ndof, d_nodes[c*ndof + i] = d_Xi[i]; );
469 auto d_Xi = Xi.
Write();
470 const int ndof = S.fes->GetNDofs();
471 auto d_nodes = S.fes->GetMesh()->GetNodes()->Read();
472 MFEM_FORALL(i, ndof, d_Xi[i] = d_nodes[c*ndof + i]; );
475 ByVDim(Surface &S, Opt &opt):
Solver(S, opt)
480 bool cvg[
SDIM] {
false};
481 for (
int c=0; c <
SDIM; ++c)
488 const bool converged = cvg[0] && cvg[1] && cvg[2];
489 return converged ?
true :
false;
495 struct MeshFromFile:
public Surface
497 MeshFromFile(Opt &opt): Surface(opt, opt.mesh_file) { }
501 struct Catenoid:
public Surface
503 Catenoid(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
509 for (
int i = 0; i < v2v.Size(); i++) { v2v[i] = i; }
511 for (
int j = 0; j <= opt.ny; j++)
513 const int v_old = opt.nx + j * (opt.nx + 1);
514 const int v_new = j * (opt.nx + 1);
518 for (
int i = 0; i < GetNE(); i++)
523 for (
int j = 0; j < nv; j++)
529 for (
int i = 0; i < GetNBE(); i++)
531 Element *el = GetBdrElement(i);
534 for (
int j = 0; j < nv; j++)
539 RemoveUnusedVertices();
540 RemoveInternalBoundaries();
547 const double u = 2.0*
PI*x[0];
548 const double v =
PI*(x[1]-0.5)/3.;
556 struct Helicoid:
public Surface
558 Helicoid(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
564 const double u = 2.0*
PI*x[0];
565 const double v = 2.0*
PI*(2.0*x[1]-1.0)/3.0;
573 struct Enneper:
public Surface
575 Enneper(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
581 const double u = 4.0*(x[0]-0.5);
582 const double v = 4.0*(x[1]-0.5);
583 p[0] = +u - u*u*u/3.0 + u*v*v;
584 p[1] = -v - u*u*v + v*v*v/3.0;
590 struct Hold:
public Surface
592 Hold(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
598 for (
int i = 0; i < v2v.Size(); i++) { v2v[i] = i; }
600 for (
int j = 0; j <= opt.ny; j++)
602 const int v_old = opt.nx + j * (opt.nx + 1);
603 const int v_new = j * (opt.nx + 1);
607 for (
int i = 0; i < GetNE(); i++)
612 for (
int j = 0; j < nv; j++)
618 for (
int i = 0; i < GetNBE(); i++)
620 Element *el = GetBdrElement(i);
623 for (
int j = 0; j < nv; j++)
628 RemoveUnusedVertices();
629 RemoveInternalBoundaries();
636 const double u = 2.0*
PI*x[0];
637 const double v = x[1];
638 p[0] = cos(u)*(1.0 + 0.3*sin(3.*u +
PI*v));
639 p[1] = sin(u)*(1.0 + 0.3*sin(3.*u +
PI*v));
647 #define I cdouble(0.0, 1.0)
653 double delta = std::numeric_limits<double>::max();
657 for (
int n=0; delta >
EPS; n+=1)
659 const cdouble j = pow(-1,n)*pow(q,n*(n+1.0))*sin((2.0*n+1.0)*u);
663 return 2.0*pow(q,0.25)*J;
666 for (
int n=0; delta >
EPS; n+=1)
668 const cdouble j = pow(q,n*(n+1))*cos((2.0*n+1.0)*u);
672 return 2.0*pow(q,0.25)*J;
674 for (
int n=1; delta >
EPS; n+=1)
676 const cdouble j = pow(q,n*n)*cos(2.0*n*u);
682 for (
int n=1; delta >
EPS; n+=1)
684 const cdouble j =pow(-1,n)*pow(q,n*n)*cos(2.0*n*u);
699 const cdouble q = exp(I*M_PI*tau);
700 const cdouble e1 = M_PI*M_PI/(12.0*w1*w1)*
703 const cdouble u = M_PI*z / (2.0*w1);
712 double delta = std::numeric_limits<double>::max();
713 for (
int n=0; delta >
EPS; n+=1)
715 const double alpha = 2.0*n+1.0;
716 const cdouble Dcosine = pow(alpha,k)*sin(k*M_PI/2.0 + alpha*u);
717 const cdouble j = pow(-1,n)*pow(q,n*(n+1.0))*Dcosine;
721 return 2.0*pow(q,0.25)*J;
728 double delta = std::numeric_limits<double>::max();
729 for (
int n=1; delta >
EPS; n+=1)
732 if (abs(q2n) < EPS) { q2n = 0.0; }
733 const cdouble j = q2n/(1.0-q2n)*sin(2.0*n*u);
737 return 1.0/tan(u) + 4.0*J;
746 const cdouble q = exp(I*M_PI*tau);
747 const cdouble n1 = -M_PI*M_PI/(12.0*w1) *
750 const cdouble u = M_PI*z / (2.0*w1);
755 static double ALPHA[4] {0.0};
756 struct Costa:
public Surface
758 Costa(Opt &opt): Surface((opt.Tptr = Parametrization, opt), false) { }
763 const int nx = opt.nx, ny = opt.ny;
764 MFEM_VERIFY(nx>2 && ny>2,
"");
765 const int nXhalf = (nx%2)==0 ? 4 : 2;
766 const int nYhalf = (ny%2)==0 ? 4 : 2;
767 const int nxh = nXhalf + nYhalf;
768 const int NVert = (nx+1) * (ny+1);
769 const int NElem = nx*ny - 4 - nxh;
770 const int NBdrElem = 0;
771 InitMesh(
DIM, SDIM, NVert, NElem, NBdrElem);
773 for (
int j = 0; j <= ny; j++)
775 const double cy = ((double) j / ny) ;
776 for (
int i = 0; i <= nx; i++)
778 const double cx = ((double) i / nx);
779 const double coords[
SDIM] = {cx, cy, 0.0};
784 for (
int j = 0; j < ny; j++)
786 for (
int i = 0; i < nx; i++)
788 if (i == 0 && j == 0) {
continue; }
789 if (i+1 == nx && j == 0) {
continue; }
790 if (i == 0 && j+1 == ny) {
continue; }
791 if (i+1 == nx && j+1 == ny) {
continue; }
792 if ((j == 0 || j+1 == ny) && (abs(nx-(i<<1)-1)<=1)) {
continue; }
793 if ((i == 0 || i+1 == nx) && (abs(ny-(j<<1)-1)<=1)) {
continue; }
794 const int i0 = i + j*(nx+1);
795 const int i1 = i+1 + j*(nx+1);
796 const int i2 = i+1 + (j+1)*(nx+1);
797 const int i3 = i + (j+1)*(nx+1);
798 const int ind[4] = {i0, i1, i2, i3};
802 RemoveUnusedVertices();
803 FinalizeQuadMesh(
false, 0,
true);
810 const double tau = ALPHA[3];
817 const bool y_top = x[1] > 0.5;
818 const bool x_top = x[0] > 0.5;
821 if (y_top) { v = 1.0 - x[1]; }
822 if (x_top) { u = 1.0 - x[0]; }
830 p[0] = real(
PI*(u+
PI/(4.*e1))- zw +
PI/(2.*e1)*(dw));
831 p[1] = real(
PI*(v+
PI/(4.*e1))-I*zw-
PI*I/(2.*e1)*(dw));
832 p[2] = sqrt(
PI/2.)*log(abs((pw-e1)/(pw+e1)));
833 if (y_top) { p[1] *= -1.0; }
834 if (x_top) { p[0] *= -1.0; }
835 const bool nan = std::isnan(p[0]) || std::isnan(p[1]) || std::isnan(p[2]);
836 MFEM_VERIFY(!nan,
"nan");
837 ALPHA[0] = std::fmax(p[0], ALPHA[0]);
838 ALPHA[1] = std::fmax(p[1], ALPHA[1]);
839 ALPHA[2] = std::fmax(p[2], ALPHA[2]);
845 MFEM_VERIFY(ALPHA[0] > 0.0,
"");
846 MFEM_VERIFY(ALPHA[1] > 0.0,
"");
847 MFEM_VERIFY(ALPHA[2] > 0.0,
"");
849 const double phi = (1.0 + sqrt(5.0)) / 2.0;
852 for (
int d = 0; d <
SDIM; d++)
854 const double alpha = d==2 ? phi : 1.0;
856 nodes(vdof) /= alpha * ALPHA[d];
863 struct Shell:
public Surface
865 Shell(Opt &opt): Surface((opt.niters = 1, opt.Tptr = Parametrization, opt)) { }
871 const double u = 2.0*
PI*x[0];
872 const double v = 21.0*x[1]-15.0;
873 p[0] = +1.0*pow(1.16,v)*cos(v)*(1.0+cos(u));
874 p[1] = -1.0*pow(1.16,v)*sin(v)*(1.0+cos(u));
875 p[2] = -2.0*pow(1.16,v)*(1.0+sin(u));
880 struct Scherk:
public Surface
885 const double alpha = 0.49;
887 const double u = alpha*
PI*(2.0*x[0]-1.0);
888 const double v =
alpha*
PI*(2.0*x[1]-1.0);
891 p[2] = log(cos(v)/cos(u));
894 Scherk(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
898 struct FullPeach:
public Surface
900 static constexpr
int NV = 8;
901 static constexpr
int NE = 6;
904 Surface((opt.niters = std::min(4, opt.niters), opt), NV, NE, 0) { }
908 const double quad_v[NV][
SDIM] =
910 {-1, -1, -1}, {+1, -1, -1}, {+1, +1, -1}, {-1, +1, -1},
911 {-1, -1, +1}, {+1, -1, +1}, {+1, +1, +1}, {-1, +1, +1}
913 const int quad_e[NE][4] =
915 {3, 2, 1, 0}, {0, 1, 5, 4}, {1, 2, 6, 5},
916 {2, 3, 7, 6}, {3, 0, 4, 7}, {4, 5, 6, 7}
919 for (
int j = 0; j < NV; j++) { AddVertex(quad_v[j]); }
920 for (
int j = 0; j < NE; j++) { AddQuad(quad_e[j], j+1); }
922 FinalizeQuadMesh(
false, 0,
true);
923 FinalizeTopology(
false);
928 void Snap() { SnapNodesToUnitSphere(); }
930 void BoundaryConditions()
935 ess_vdofs.
SetSize(fes->GetVSize());
936 MFEM_VERIFY(fes->GetVSize() >= fes->GetTrueVSize(),
"");
940 for (
int e = 0; e < fes->GetNE(); e++)
942 fes->GetElementDofs(e, dofs);
947 for (
int dof = 0; dof < dofs.
Size(); dof++)
951 const int k = dofs[dof];
952 MFEM_ASSERT(k >= 0,
"");
953 PointMat.
Mult(one, X);
954 const bool halfX = std::fabs(X[0]) <
EPS && X[1] <= 0.0;
955 const bool halfY = std::fabs(X[2]) <
EPS && X[1] >= 0.0;
956 const bool is_on_bc = halfX || halfY;
957 for (
int c = 0; c <
SDIM; c++)
958 { ess_vdofs[fes->DofToVDof(k, c)] = is_on_bc; }
976 struct QuarterPeach:
public Surface
978 QuarterPeach(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
983 const double x = 2.0*X[0]-1.0;
984 const double y = X[1];
985 const double r = sqrt(x*x + y*y);
986 const double t = (x==0.0) ?
PI/2.0 :
987 (y==0.0 && x>0.0) ? 0. :
988 (y==0.0 && x<0.0) ?
PI : acos(x/r);
989 const double sqrtx = sqrt(1.0 + x*x);
990 const double sqrty = sqrt(1.0 + y*y);
991 const bool yaxis =
PI/4.0<t && t < 3.0*
PI/4.0;
992 const double R = yaxis?sqrtx:sqrty;
993 const double gamma = r/R;
994 p[0] = gamma * cos(t);
995 p[1] = gamma * sin(t);
1001 for (
int i = 0; i < GetNBE(); i++)
1003 Element *el = GetBdrElement(i);
1004 const int fn = GetBdrElementEdgeIndex(i);
1005 MFEM_VERIFY(!FaceIsTrueInterior(fn),
"");
1007 GetFaceVertices(fn, vertices);
1010 double R[2], X[2][
SDIM];
1011 for (
int v = 0; v < 2; v++)
1014 const int iv = vertices[v];
1015 for (
int d = 0; d <
SDIM; d++)
1018 const double x = X[v][d] = nval[iv];
1019 if (d < 2) { R[v] += x*x; }
1022 if (std::fabs(X[0][1])<=
EPS && std::fabs(X[1][1])<=
EPS &&
1023 (R[0]>0.1 || R[1]>0.1))
1031 struct SlottedSphere:
public Surface
1033 SlottedSphere(Opt &opt): Surface((opt.niters = 4, opt), 64, 40, 0) { }
1037 constexpr
double delta = 0.15;
1038 constexpr
int NV1D = 4;
1039 constexpr
int NV = NV1D*NV1D*NV1D;
1040 constexpr
int NEPF = (NV1D-1)*(NV1D-1);
1041 constexpr
int NE = NEPF*6;
1042 const double V1D[NV1D] = {-1.0, -
delta,
delta, 1.0};
1044 for (
int iv=0; iv<NV; ++iv)
1047 int iy = (iv / NV1D) % NV1D;
1048 int iz = (iv / NV1D) / NV1D;
1050 QV[iv][0] = V1D[ix];
1051 QV[iv][1] = V1D[iy];
1052 QV[iv][2] = V1D[iz];
1055 for (
int ix=0; ix<NV1D-1; ++ix)
1057 for (
int iy=0; iy<NV1D-1; ++iy)
1059 int el_offset = ix + iy*(NV1D-1);
1061 QE[0*NEPF + el_offset][0] = NV1D*ix + NV1D*NV1D*iy;
1062 QE[0*NEPF + el_offset][1] = NV1D*(ix+1) + NV1D*NV1D*iy;
1063 QE[0*NEPF + el_offset][2] = NV1D*(ix+1) + NV1D*NV1D*(iy+1);
1064 QE[0*NEPF + el_offset][3] = NV1D*ix + NV1D*NV1D*(iy+1);
1067 QE[1*NEPF + el_offset][3] = x_off + NV1D*ix + NV1D*NV1D*iy;
1068 QE[1*NEPF + el_offset][2] = x_off + NV1D*(ix+1) + NV1D*NV1D*iy;
1069 QE[1*NEPF + el_offset][1] = x_off + NV1D*(ix+1) + NV1D*NV1D*(iy+1);
1070 QE[1*NEPF + el_offset][0] = x_off + NV1D*ix + NV1D*NV1D*(iy+1);
1072 QE[2*NEPF + el_offset][0] = NV1D*NV1D*iy + ix;
1073 QE[2*NEPF + el_offset][1] = NV1D*NV1D*iy + ix + 1;
1074 QE[2*NEPF + el_offset][2] = NV1D*NV1D*(iy+1) + ix + 1;
1075 QE[2*NEPF + el_offset][3] = NV1D*NV1D*(iy+1) + ix;
1077 int y_off = NV1D*(NV1D-1);
1078 QE[3*NEPF + el_offset][0] = y_off + NV1D*NV1D*iy + ix;
1079 QE[3*NEPF + el_offset][1] = y_off + NV1D*NV1D*iy + ix + 1;
1080 QE[3*NEPF + el_offset][2] = y_off + NV1D*NV1D*(iy+1) + ix + 1;
1081 QE[3*NEPF + el_offset][3] = y_off + NV1D*NV1D*(iy+1) + ix;
1083 QE[4*NEPF + el_offset][0] = NV1D*iy + ix;
1084 QE[4*NEPF + el_offset][1] = NV1D*iy + ix + 1;
1085 QE[4*NEPF + el_offset][2] = NV1D*(iy+1) + ix + 1;
1086 QE[4*NEPF + el_offset][3] = NV1D*(iy+1) + ix;
1088 int z_off = NV1D*NV1D*(NV1D-1);
1089 QE[5*NEPF + el_offset][0] = z_off + NV1D*iy + ix;
1090 QE[5*NEPF + el_offset][1] = z_off + NV1D*iy + ix + 1;
1091 QE[5*NEPF + el_offset][2] = z_off + NV1D*(iy+1) + ix + 1;
1092 QE[5*NEPF + el_offset][3] = z_off + NV1D*(iy+1) + ix;
1096 QE[0*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1097 QE[0*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1099 QE[1*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1100 QE[1*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1102 QE[3*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1103 QE[3*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1105 QE[5*NEPF + 0 + 1*(NV1D-1)][0] = -1;
1106 QE[5*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1107 QE[5*NEPF + 2 + 1*(NV1D-1)][0] = -1;
1109 QE[4*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1110 QE[4*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1111 QE[4*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1113 QE[2*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1114 QE[2*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1115 for (
int j = 0; j < NV; j++) { AddVertex(QV[j]); }
1116 for (
int j = 0; j < NE; j++)
1118 if (QE[j][0] < 0) {
continue; }
1119 AddQuad(QE[j], j+1);
1121 RemoveUnusedVertices();
1122 FinalizeQuadMesh(
false, 0,
true);
1127 void Snap() { SnapNodesToUnitSphere(); }
1130 static int Problem0(Opt &opt)
1133 Surface *S =
nullptr;
1134 switch (opt.surface)
1136 case 0: S =
new MeshFromFile(opt);
break;
1137 case 1: S =
new Catenoid(opt);
break;
1138 case 2: S =
new Helicoid(opt);
break;
1139 case 3: S =
new Enneper(opt);
break;
1140 case 4: S =
new Hold(opt);
break;
1141 case 5: S =
new Costa(opt);
break;
1142 case 6: S =
new Shell(opt);
break;
1143 case 7: S =
new Scherk(opt);
break;
1144 case 8: S =
new FullPeach(opt);
break;
1145 case 9: S =
new QuarterPeach(opt);
break;
1146 case 10: S =
new SlottedSphere(opt);
break;
1147 default: MFEM_ABORT(
"Unknown surface (surface <= 10)!");
1157 static double u0(
const Vector &x) {
return sin(3.0 *
PI * (x[1] + x[0])); }
1161 static double qf(
const int order,
const int ker,
Mesh &m,
1168 const int NE(m.
GetNE());
1176 MFEM_VERIFY(ND == D1D*D1D,
"");
1177 MFEM_VERIFY(NQ == Q1D*Q1D,
"");
1179 Vector Eu(ND*NE), grad_u(
DIM*NQ*NE), sum(NE*NQ), one(NE*NQ);
1184 qi->Derivatives(Eu, grad_u);
1189 auto grdU =
Reshape(grad_u.Read(),
DIM, Q1D, Q1D, NE);
1190 auto S =
Reshape(sum.Write(), Q1D, Q1D, NE);
1192 MFEM_FORALL_2D(e, NE, Q1D, Q1D, 1,
1194 MFEM_FOREACH_THREAD(qy,y,Q1D)
1196 MFEM_FOREACH_THREAD(qx,x,Q1D)
1198 const double w = W(qx, qy);
1199 const double J11 = J(qx, qy, 0, 0, e);
1200 const double J12 = J(qx, qy, 1, 0, e);
1201 const double J21 = J(qx, qy, 0, 1, e);
1202 const double J22 = J(qx, qy, 1, 1, e);
1203 const double det = detJ(qx, qy, e);
1204 const double area = w * det;
1205 const double gu0 = grdU(0, qx, qy, e);
1206 const double gu1 = grdU(1, qx, qy, e);
1207 const double tgu0 = (J22*gu0 - J12*gu1)/det;
1208 const double tgu1 = (J11*gu1 - J21*gu0)/det;
1209 const double ngu = tgu0*tgu0 + tgu1*tgu1;
1210 const double s = (ker ==
AREA) ? sqrt(1.0 + ngu) :
1211 (ker ==
NORM) ? ngu : 0.0;
1212 S(qx, qy, e) = area * s;
1220 static int Problem1(Opt &opt)
1222 const int order = opt.order;
1239 if (opt.vis) { Surface::Visualize(opt, &mesh,
GLVIZ_W,
GLVIZ_H, &u); }
1248 for (
int i = 0; i < opt.niters; i++)
1254 const double q_uold = qf(order,
AREA, mesh, fes, uold);
1255 MFEM_VERIFY(std::fabs(q_uold) > EPS,
"");
1259 a.FormLinearSystem(ess_tdof_list, u,
b, A, X, B);
1262 a.RecoverFEMSolution(X,
b, u);
1264 const double norm = sqrt(std::fabs(qf(order,
NORM, mesh, fes, eps)));
1265 const double area = qf(order,
AREA, mesh, fes, u);
1268 mfem::out <<
"Iteration " << i <<
", norm: " << norm
1269 <<
", area: " << area << std::endl;
1271 if (opt.vis) { Surface::Visualize(opt, &mesh, &u); }
1273 if (norm <
NRM) {
break; }
1281 opt.sz = opt.id = 0;
1284 args.
AddOption(&opt.pb,
"-p",
"--problem",
"Problem to solve.");
1285 args.
AddOption(&opt.mesh_file,
"-m",
"--mesh",
"Mesh file to use.");
1286 args.
AddOption(&opt.wait,
"-w",
"--wait",
"-no-w",
"--no-wait",
1287 "Enable or disable a GLVis pause.");
1288 args.
AddOption(&opt.radial,
"-rad",
"--radial",
"-no-rad",
"--no-radial",
1289 "Enable or disable radial constraints in solver.");
1290 args.
AddOption(&opt.nx,
"-x",
"--num-elements-x",
1291 "Number of elements in x-direction.");
1292 args.
AddOption(&opt.ny,
"-y",
"--num-elements-y",
1293 "Number of elements in y-direction.");
1294 args.
AddOption(&opt.order,
"-o",
"--order",
"Finite element order.");
1295 args.
AddOption(&opt.refine,
"-r",
"--ref-levels",
"Refinement");
1296 args.
AddOption(&opt.niters,
"-n",
"--niter-max",
"Max number of iterations");
1297 args.
AddOption(&opt.surface,
"-s",
"--surface",
"Choice of the surface.");
1298 args.
AddOption(&opt.pa,
"-pa",
"--partial-assembly",
"-no-pa",
1299 "--no-partial-assembly",
"Enable Partial Assembly.");
1300 args.
AddOption(&opt.tau,
"-t",
"--tau",
"Costa scale factor.");
1301 args.
AddOption(&opt.lambda,
"-l",
"--lambda",
"Lambda step toward solution.");
1302 args.
AddOption(&opt.amr,
"-a",
"--amr",
"-no-a",
"--no-amr",
"Enable AMR.");
1303 args.
AddOption(&opt.amr_threshold,
"-at",
"--amr-threshold",
"AMR threshold.");
1304 args.
AddOption(&opt.device_config,
"-d",
"--device",
1305 "Device configuration string, see Device::Configure().");
1306 args.
AddOption(&opt.keys,
"-k",
"--keys",
"GLVis configuration keys.");
1307 args.
AddOption(&opt.vis,
"-vis",
"--visualization",
"-no-vis",
1308 "--no-visualization",
"Enable or disable visualization.");
1309 args.
AddOption(&opt.vis_mesh,
"-vm",
"--vis-mesh",
"-no-vm",
1310 "--no-vis-mesh",
"Enable or disable mesh visualization.");
1311 args.
AddOption(&opt.by_vdim,
"-c",
"--solve-byvdim",
1312 "-no-c",
"--solve-bynodes",
1313 "Enable or disable the 'ByVdim' solver");
1314 args.
AddOption(&opt.print,
"-print",
"--print",
"-no-print",
"--no-print",
1315 "Enable or disable result output (files in mfem format).");
1316 args.
AddOption(&opt.snapshot,
"-ss",
"--snapshot",
"-no-ss",
"--no-snapshot",
1317 "Enable or disable GLVis snapshot.");
1320 MFEM_VERIFY(opt.lambda >= 0.0 && opt.lambda <= 1.0,
"");
1324 Device device(opt.device_config);
1325 if (!opt.id) { device.
Print(); }
1327 if (opt.pb == 0) { Problem0(opt); }
1329 if (opt.pb == 1) { Problem1(opt); }
int GetNPoints() const
Returns the number of the points in the integration rule.
Geometry::Type GetGeometryType() const
T * HostReadWrite()
Shortcut for mfem::ReadWrite(a.GetMemory(), a.Size(), false).
int Size() const
Return the logical size of the array.
virtual void Print(std::ostream &out=mfem::out) const
Conjugate gradient method.
int GetNDofs() const
Returns number of degrees of freedom.
Class for an integration rule - an Array of IntegrationPoint.
Class for grid function - Vector with associated FE space.
int DofToVDof(int dof, int vd, int ndofs=-1) const
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.
virtual void GetVertices(Array< int > &v) const =0
Returns element's vertices.
virtual void Mult(const Vector &b, Vector &x) const
Operator application: y=A(x).
cdouble WeierstrassZeta(const cdouble z, const cdouble w1=0.5, const cdouble w3=0.5 *I)
void SetSize(int s)
Resize the vector to size s.
void BooleanMult(const Array< int > &x, Array< int > &y) const
y = A * x, treating all entries as booleans (zero=false, nonzero=true).
double Norml2() const
Returns the l2 norm of the vector.
Pointer to an Operator of a specified type.
std::complex< double > cdouble
void CalcAdjugate(const DenseMatrix &a, DenseMatrix &adja)
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Data type dense matrix using column-major storage.
int Size() const
Returns the size of the vector.
void Transform(void(*f)(const Vector &, Vector &))
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 ...
int GetNE() const
Returns number of elements.
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 Array< double > & GetWeights() const
Return the quadrature weights in a contiguous array.
constexpr Element::Type QUAD
Structure for storing mesh geometric factors: coordinates, Jacobians, and determinants of the Jacobia...
double * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
int main(int argc, char *argv[])
void GetNodalValues(int i, Array< double > &nval, int vdim=1) const
Returns the values in the vertices of i'th element for dimension vdim.
Geometry::Type GetElementBaseGeometry(int i) const
void add(const Vector &v1, const Vector &v2, Vector &v)
static void MarkerToList(const Array< int > &marker, Array< int > &list)
Convert a Boolean marker array to a list containing all marked indices.
int close()
Close the socketstream.
Data type for Gauss-Seidel smoother of sparse matrix.
const Operator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims...dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
const double * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
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 GeometricFactors * GetGeometricFactors(const IntegrationRule &ir, const int flags)
Return the mesh geometric factors corresponding to the given integration rule.
void SetPrintLevel(int print_lvl)
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.
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 *)
void SetMaxIter(int max_it)
virtual void SetCurvature(int order, bool discont=false, int space_dim=-1, int ordering=1)
Type
Constants for the classes derived from Element.
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
cdouble EllipticTheta(const int a, const cdouble u, const cdouble q)
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
const Element * GetElement(int i) const
FiniteElementSpace * FESpace()
void PrintUsage(std::ostream &out) const
Print the usage message.
double DistanceTo(const double *p) const
Compute the Euclidean distance to another vector.
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...
int GetDof() const
Returns the number of degrees of freedom in the finite element.
void subtract(const Vector &x, const Vector &y, Vector &z)
int GetOrder() const
Returns the order of the integration rule.
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.
const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
void GetElementTransformation(int i, IsoparametricTransformation *ElTr)
const QuadratureInterpolator * GetQuadratureInterpolator(const IntegrationRule &ir) const
Return a QuadratureInterpolator that interpolates E-vectors to quadrature point values and/or derivat...
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
void PrintOptions(std::ostream &out) const
Print the options.
Lexicographic ordering for tensor-product FiniteElements.
virtual int GetNVertices() const =0
void SetAttribute(const int attr)
Set element's attribute.
virtual void ProjectCoefficient(Coefficient &coeff)
int open(const char hostname[], int port)
Open the socket stream on 'port' at 'hostname'.
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.
void Mult(const double *x, double *y) const
Matrix vector multiplication.
void GetNodes(Vector &node_coord) const
Arbitrary order H1-conforming (continuous) finite elements.
cdouble EllipticTheta1Prime(const int k, 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...
The MFEM Device class abstracts hardware devices such as GPUs, as well as programming models such as ...
void GeneralRefinement(const Array< Refinement > &refinements, int nonconforming=-1, int nc_limit=0)
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Abstract data type element.
bool Good() const
Return true if the command line options were parsed successfully.