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;
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 ParMesh(MPI_COMM_WORLD, *
this);
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 glvis <<
"parallel " << opt.sz <<
" " << opt.id <<
"\n";
251 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,
264 glvis <<
"parallel " << opt.sz <<
" " << opt.id <<
"\n";
266 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::ostringstream mesh_name;
283 mesh_name << mesh_file <<
"." << std::setfill(
'0') << std::setw(6) << opt.id;
284 std::ofstream mesh_ofs(mesh_name.str().c_str());
285 mesh_ofs.precision(8);
286 mesh->
Print(mesh_ofs);
289 std::ostringstream sol_name;
290 sol_name << sol_file <<
"." << std::setfill(
'0') << std::setw(6) << opt.id;
291 std::ofstream sol_ofs(sol_name.str().c_str());
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(MPI_COMM_WORLD),
313 a(S.fes), x(S.fes), x0(S.fes),
b(S.fes), one(1.0)
315 cg.SetRelTol(RTOLERANCE);
316 cg.SetAbsTol(ATOLERANCE);
317 cg.SetMaxIter(max_num_iter);
318 cg.SetPrintLevel(print_iter);
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(opt, S.mesh); }
331 if (!opt.id) {
mfem::out <<
"Iteration " << i <<
": "; }
332 S.mesh->DeleteGeometricFactors();
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);
351 if (M) { cg.SetPreconditioner(*M); }
354 a.RecoverFEMSolution(X,
b, x);
355 const bool by_vdim = opt.by_vdim;
356 GridFunction *nodes = by_vdim ? &x0 : S.fes->GetMesh()->GetNodes();
361 MPI_Allreduce(&rnorm, &glob_norm, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
363 if (!opt.id) {
mfem::out <<
"rnorm = " << rnorm << std::endl; }
364 const double lambda = opt.lambda;
367 MFEM_VERIFY(!opt.radial,
"'VDim solver can't use radial option!");
368 return Converged(rnorm);
375 Vector ni(SDIM), di(SDIM);
376 for (
int i = 0; i <
delta.Size()/
SDIM; i++)
379 const int ndof = S.fes->GetNDofs();
380 for (
int d = 0; d <
SDIM; d++)
382 ni(d) = (*nodes)(d*ndof + i);
383 di(d) =
delta(d*ndof + i);
386 const double ndotd = (ni*di) / (ni*ni);
389 for (
int d = 0; d <
SDIM; d++) {
delta(d*ndof + i) = di(d); }
394 add(lambda, *nodes, (1.0-lambda), x, x);
395 return Converged(rnorm);
400 MFEM_VERIFY(opt.amr_threshold >= 0.0 && opt.amr_threshold <= 1.0,
"");
403 const int NE = mesh->
GetNE();
405 for (
int e = 0; e < NE; e++)
413 for (
int q = 0; q < NQ; q++)
420 const double w = Jadjt.
Weight();
421 minW = std::fmin(minW, w);
422 maxW = std::fmax(maxW, w);
424 if (std::fabs(maxW) != 0.0)
426 const double rho = minW / maxW;
427 MFEM_VERIFY(rho <= 1.0,
"");
441 S.BoundaryConditions();
447 class ByNodes:
public Solver
450 ByNodes(Surface &S, Opt &opt):
Solver(S, opt)
455 x = *S.fes->GetMesh()->GetNodes();
456 bool converge = ParAXeqB();
458 return converge ?
true :
false;
463 class ByVDim:
public Solver
468 auto d_Xi = Xi.
Read();
469 auto d_nodes = S.fes->GetMesh()->GetNodes()->Write();
470 const int ndof = S.fes->GetNDofs();
471 MFEM_FORALL(i, ndof, d_nodes[c*ndof + i] = d_Xi[i]; );
476 auto d_Xi = Xi.
Write();
477 const int ndof = S.fes->GetNDofs();
478 auto d_nodes = S.fes->GetMesh()->GetNodes()->Read();
479 MFEM_FORALL(i, ndof, d_Xi[i] = d_nodes[c*ndof + i]; );
482 ByVDim(Surface &S, Opt &opt):
Solver(S, opt)
487 bool cvg[
SDIM] {
false};
488 for (
int c=0; c <
SDIM; ++c)
495 const bool converged = cvg[0] && cvg[1] && cvg[2];
496 return converged ?
true :
false;
502 struct MeshFromFile:
public Surface
504 MeshFromFile(Opt &opt): Surface(opt, opt.mesh_file) { }
508 struct Catenoid:
public Surface
510 Catenoid(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
516 for (
int i = 0; i < v2v.Size(); i++) { v2v[i] = i; }
518 for (
int j = 0; j <= opt.ny; j++)
520 const int v_old = opt.nx + j * (opt.nx + 1);
521 const int v_new = j * (opt.nx + 1);
525 for (
int i = 0; i < GetNE(); i++)
530 for (
int j = 0; j < nv; j++)
536 for (
int i = 0; i < GetNBE(); i++)
538 Element *el = GetBdrElement(i);
541 for (
int j = 0; j < nv; j++)
546 RemoveUnusedVertices();
547 RemoveInternalBoundaries();
554 const double u = 2.0*
PI*x[0];
555 const double v =
PI*(x[1]-0.5)/3.;
563 struct Helicoid:
public Surface
565 Helicoid(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
571 const double u = 2.0*
PI*x[0];
572 const double v = 2.0*
PI*(2.0*x[1]-1.0)/3.0;
580 struct Enneper:
public Surface
582 Enneper(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
588 const double u = 4.0*(x[0]-0.5);
589 const double v = 4.0*(x[1]-0.5);
590 p[0] = +u - u*u*u/3.0 + u*v*v;
591 p[1] = -v - u*u*v + v*v*v/3.0;
597 struct Hold:
public Surface
599 Hold(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
605 for (
int i = 0; i < v2v.Size(); i++) { v2v[i] = i; }
607 for (
int j = 0; j <= opt.ny; j++)
609 const int v_old = opt.nx + j * (opt.nx + 1);
610 const int v_new = j * (opt.nx + 1);
614 for (
int i = 0; i < GetNE(); i++)
619 for (
int j = 0; j < nv; j++)
625 for (
int i = 0; i < GetNBE(); i++)
627 Element *el = GetBdrElement(i);
630 for (
int j = 0; j < nv; j++)
635 RemoveUnusedVertices();
636 RemoveInternalBoundaries();
643 const double u = 2.0*
PI*x[0];
644 const double v = x[1];
645 p[0] = cos(u)*(1.0 + 0.3*sin(3.*u +
PI*v));
646 p[1] = sin(u)*(1.0 + 0.3*sin(3.*u +
PI*v));
654 #define I cdouble(0.0, 1.0)
660 double delta = std::numeric_limits<double>::max();
664 for (
int n=0; delta >
EPS; n+=1)
666 const cdouble j = pow(-1,n)*pow(q,n*(n+1.0))*sin((2.0*n+1.0)*u);
670 return 2.0*pow(q,0.25)*J;
673 for (
int n=0; delta >
EPS; n+=1)
675 const cdouble j = pow(q,n*(n+1))*cos((2.0*n+1.0)*u);
679 return 2.0*pow(q,0.25)*J;
681 for (
int n=1; delta >
EPS; n+=1)
683 const cdouble j = pow(q,n*n)*cos(2.0*n*u);
689 for (
int n=1; delta >
EPS; n+=1)
691 const cdouble j =pow(-1,n)*pow(q,n*n)*cos(2.0*n*u);
706 const cdouble q = exp(I*M_PI*tau);
707 const cdouble e1 = M_PI*M_PI/(12.0*w1*w1)*
710 const cdouble u = M_PI*z / (2.0*w1);
719 double delta = std::numeric_limits<double>::max();
720 for (
int n=0; delta >
EPS; n+=1)
722 const double alpha = 2.0*n+1.0;
723 const cdouble Dcosine = pow(alpha,k)*sin(k*M_PI/2.0 + alpha*u);
724 const cdouble j = pow(-1,n)*pow(q,n*(n+1.0))*Dcosine;
728 return 2.0*pow(q,0.25)*J;
735 double delta = std::numeric_limits<double>::max();
736 for (
int n=1; delta >
EPS; n+=1)
739 if (abs(q2n) < EPS) { q2n = 0.0; }
740 const cdouble j = q2n/(1.0-q2n)*sin(2.0*n*u);
744 return 1.0/tan(u) + 4.0*J;
753 const cdouble q = exp(I*M_PI*tau);
754 const cdouble n1 = -M_PI*M_PI/(12.0*w1) *
757 const cdouble u = M_PI*z / (2.0*w1);
762 static double ALPHA[4] {0.0};
763 struct Costa:
public Surface
765 Costa(Opt &opt): Surface((opt.Tptr = Parametrization, opt), false) { }
770 const int nx = opt.nx, ny = opt.ny;
771 MFEM_VERIFY(nx>2 && ny>2,
"");
772 const int nXhalf = (nx%2)==0 ? 4 : 2;
773 const int nYhalf = (ny%2)==0 ? 4 : 2;
774 const int nxh = nXhalf + nYhalf;
775 const int NVert = (nx+1) * (ny+1);
776 const int NElem = nx*ny - 4 - nxh;
777 const int NBdrElem = 0;
778 InitMesh(
DIM, SDIM, NVert, NElem, NBdrElem);
780 for (
int j = 0; j <= ny; j++)
782 const double cy = ((double) j / ny) ;
783 for (
int i = 0; i <= nx; i++)
785 const double cx = ((double) i / nx);
786 const double coords[
SDIM] = {cx, cy, 0.0};
791 for (
int j = 0; j < ny; j++)
793 for (
int i = 0; i < nx; i++)
795 if (i == 0 && j == 0) {
continue; }
796 if (i+1 == nx && j == 0) {
continue; }
797 if (i == 0 && j+1 == ny) {
continue; }
798 if (i+1 == nx && j+1 == ny) {
continue; }
799 if ((j == 0 || j+1 == ny) && (abs(nx-(i<<1)-1)<=1)) {
continue; }
800 if ((i == 0 || i+1 == nx) && (abs(ny-(j<<1)-1)<=1)) {
continue; }
801 const int i0 = i + j*(nx+1);
802 const int i1 = i+1 + j*(nx+1);
803 const int i2 = i+1 + (j+1)*(nx+1);
804 const int i3 = i + (j+1)*(nx+1);
805 const int ind[4] = {i0, i1, i2, i3};
809 RemoveUnusedVertices();
810 FinalizeQuadMesh(
false, 0,
true);
817 const double tau = ALPHA[3];
824 const bool y_top = x[1] > 0.5;
825 const bool x_top = x[0] > 0.5;
828 if (y_top) { v = 1.0 - x[1]; }
829 if (x_top) { u = 1.0 - x[0]; }
837 p[0] = real(
PI*(u+
PI/(4.*e1))- zw +
PI/(2.*e1)*(dw));
838 p[1] = real(
PI*(v+
PI/(4.*e1))-I*zw-
PI*I/(2.*e1)*(dw));
839 p[2] = sqrt(
PI/2.)*log(abs((pw-e1)/(pw+e1)));
840 if (y_top) { p[1] *= -1.0; }
841 if (x_top) { p[0] *= -1.0; }
842 const bool nan = std::isnan(p[0]) || std::isnan(p[1]) || std::isnan(p[2]);
843 MFEM_VERIFY(!nan,
"nan");
844 ALPHA[0] = std::fmax(p[0], ALPHA[0]);
845 ALPHA[1] = std::fmax(p[1], ALPHA[1]);
846 ALPHA[2] = std::fmax(p[2], ALPHA[2]);
852 MFEM_VERIFY(ALPHA[0] > 0.0,
"");
853 MFEM_VERIFY(ALPHA[1] > 0.0,
"");
854 MFEM_VERIFY(ALPHA[2] > 0.0,
"");
856 const double phi = (1.0 + sqrt(5.0)) / 2.0;
859 for (
int d = 0; d <
SDIM; d++)
861 const double alpha = d==2 ? phi : 1.0;
863 nodes(vdof) /= alpha * ALPHA[d];
870 struct Shell:
public Surface
872 Shell(Opt &opt): Surface((opt.niters = 1, opt.Tptr = Parametrization, opt)) { }
878 const double u = 2.0*
PI*x[0];
879 const double v = 21.0*x[1]-15.0;
880 p[0] = +1.0*pow(1.16,v)*cos(v)*(1.0+cos(u));
881 p[1] = -1.0*pow(1.16,v)*sin(v)*(1.0+cos(u));
882 p[2] = -2.0*pow(1.16,v)*(1.0+sin(u));
887 struct Scherk:
public Surface
892 const double alpha = 0.49;
894 const double u = alpha*
PI*(2.0*x[0]-1.0);
895 const double v =
alpha*
PI*(2.0*x[1]-1.0);
898 p[2] = log(cos(v)/cos(u));
901 Scherk(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
905 struct FullPeach:
public Surface
907 static constexpr
int NV = 8;
908 static constexpr
int NE = 6;
911 Surface((opt.niters = std::min(4, opt.niters), opt), NV, NE, 0) { }
915 const double quad_v[NV][
SDIM] =
917 {-1, -1, -1}, {+1, -1, -1}, {+1, +1, -1}, {-1, +1, -1},
918 {-1, -1, +1}, {+1, -1, +1}, {+1, +1, +1}, {-1, +1, +1}
920 const int quad_e[NE][4] =
922 {3, 2, 1, 0}, {0, 1, 5, 4}, {1, 2, 6, 5},
923 {2, 3, 7, 6}, {3, 0, 4, 7}, {4, 5, 6, 7}
926 for (
int j = 0; j < NV; j++) { AddVertex(quad_v[j]); }
927 for (
int j = 0; j < NE; j++) { AddQuad(quad_e[j], j+1); }
929 FinalizeQuadMesh(
false, 0,
true);
930 FinalizeTopology(
false);
935 void Snap() { SnapNodesToUnitSphere(); }
937 void BoundaryConditions()
942 ess_vdofs.
SetSize(fes->GetVSize());
943 MFEM_VERIFY(fes->GetVSize() >= fes->GetTrueVSize(),
"");
947 for (
int e = 0; e < fes->GetNE(); e++)
949 fes->GetElementDofs(e, dofs);
954 for (
int dof = 0; dof < dofs.
Size(); dof++)
958 const int k = dofs[dof];
959 MFEM_ASSERT(k >= 0,
"");
960 PointMat.
Mult(one, X);
961 const bool halfX = std::fabs(X[0]) <
EPS && X[1] <= 0.0;
962 const bool halfY = std::fabs(X[2]) <
EPS && X[1] >= 0.0;
963 const bool is_on_bc = halfX || halfY;
964 for (
int c = 0; c <
SDIM; c++)
965 { ess_vdofs[fes->DofToVDof(k, c)] = is_on_bc; }
983 struct QuarterPeach:
public Surface
985 QuarterPeach(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
990 const double x = 2.0*X[0]-1.0;
991 const double y = X[1];
992 const double r = sqrt(x*x + y*y);
993 const double t = (x==0.0) ?
PI/2.0 :
994 (y==0.0 && x>0.0) ? 0. :
995 (y==0.0 && x<0.0) ?
PI : acos(x/r);
996 const double sqrtx = sqrt(1.0 + x*x);
997 const double sqrty = sqrt(1.0 + y*y);
998 const bool yaxis =
PI/4.0<t && t < 3.0*
PI/4.0;
999 const double R = yaxis?sqrtx:sqrty;
1000 const double gamma = r/R;
1001 p[0] = gamma * cos(t);
1002 p[1] = gamma * sin(t);
1008 for (
int i = 0; i < GetNBE(); i++)
1010 Element *el = GetBdrElement(i);
1011 const int fn = GetBdrElementEdgeIndex(i);
1012 MFEM_VERIFY(!FaceIsTrueInterior(fn),
"");
1014 GetFaceVertices(fn, vertices);
1017 double R[2], X[2][
SDIM];
1018 for (
int v = 0; v < 2; v++)
1021 const int iv = vertices[v];
1022 for (
int d = 0; d <
SDIM; d++)
1025 const double x = X[v][d] = nval[iv];
1026 if (d < 2) { R[v] += x*x; }
1029 if (std::fabs(X[0][1])<=
EPS && std::fabs(X[1][1])<=
EPS &&
1030 (R[0]>0.1 || R[1]>0.1))
1038 struct SlottedSphere:
public Surface
1040 SlottedSphere(Opt &opt): Surface((opt.niters = 4, opt), 64, 40, 0) { }
1044 constexpr
double delta = 0.15;
1045 constexpr
int NV1D = 4;
1046 constexpr
int NV = NV1D*NV1D*NV1D;
1047 constexpr
int NEPF = (NV1D-1)*(NV1D-1);
1048 constexpr
int NE = NEPF*6;
1049 const double V1D[NV1D] = {-1.0, -
delta,
delta, 1.0};
1051 for (
int iv=0; iv<NV; ++iv)
1054 int iy = (iv / NV1D) % NV1D;
1055 int iz = (iv / NV1D) / NV1D;
1057 QV[iv][0] = V1D[ix];
1058 QV[iv][1] = V1D[iy];
1059 QV[iv][2] = V1D[iz];
1062 for (
int ix=0; ix<NV1D-1; ++ix)
1064 for (
int iy=0; iy<NV1D-1; ++iy)
1066 int el_offset = ix + iy*(NV1D-1);
1068 QE[0*NEPF + el_offset][0] = NV1D*ix + NV1D*NV1D*iy;
1069 QE[0*NEPF + el_offset][1] = NV1D*(ix+1) + NV1D*NV1D*iy;
1070 QE[0*NEPF + el_offset][2] = NV1D*(ix+1) + NV1D*NV1D*(iy+1);
1071 QE[0*NEPF + el_offset][3] = NV1D*ix + NV1D*NV1D*(iy+1);
1074 QE[1*NEPF + el_offset][3] = x_off + NV1D*ix + NV1D*NV1D*iy;
1075 QE[1*NEPF + el_offset][2] = x_off + NV1D*(ix+1) + NV1D*NV1D*iy;
1076 QE[1*NEPF + el_offset][1] = x_off + NV1D*(ix+1) + NV1D*NV1D*(iy+1);
1077 QE[1*NEPF + el_offset][0] = x_off + NV1D*ix + NV1D*NV1D*(iy+1);
1079 QE[2*NEPF + el_offset][0] = NV1D*NV1D*iy + ix;
1080 QE[2*NEPF + el_offset][1] = NV1D*NV1D*iy + ix + 1;
1081 QE[2*NEPF + el_offset][2] = NV1D*NV1D*(iy+1) + ix + 1;
1082 QE[2*NEPF + el_offset][3] = NV1D*NV1D*(iy+1) + ix;
1084 int y_off = NV1D*(NV1D-1);
1085 QE[3*NEPF + el_offset][0] = y_off + NV1D*NV1D*iy + ix;
1086 QE[3*NEPF + el_offset][1] = y_off + NV1D*NV1D*iy + ix + 1;
1087 QE[3*NEPF + el_offset][2] = y_off + NV1D*NV1D*(iy+1) + ix + 1;
1088 QE[3*NEPF + el_offset][3] = y_off + NV1D*NV1D*(iy+1) + ix;
1090 QE[4*NEPF + el_offset][0] = NV1D*iy + ix;
1091 QE[4*NEPF + el_offset][1] = NV1D*iy + ix + 1;
1092 QE[4*NEPF + el_offset][2] = NV1D*(iy+1) + ix + 1;
1093 QE[4*NEPF + el_offset][3] = NV1D*(iy+1) + ix;
1095 int z_off = NV1D*NV1D*(NV1D-1);
1096 QE[5*NEPF + el_offset][0] = z_off + NV1D*iy + ix;
1097 QE[5*NEPF + el_offset][1] = z_off + NV1D*iy + ix + 1;
1098 QE[5*NEPF + el_offset][2] = z_off + NV1D*(iy+1) + ix + 1;
1099 QE[5*NEPF + el_offset][3] = z_off + NV1D*(iy+1) + ix;
1103 QE[0*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1104 QE[0*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1106 QE[1*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1107 QE[1*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1109 QE[3*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1110 QE[3*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1112 QE[5*NEPF + 0 + 1*(NV1D-1)][0] = -1;
1113 QE[5*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1114 QE[5*NEPF + 2 + 1*(NV1D-1)][0] = -1;
1116 QE[4*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1117 QE[4*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1118 QE[4*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1120 QE[2*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1121 QE[2*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1122 for (
int j = 0; j < NV; j++) { AddVertex(QV[j]); }
1123 for (
int j = 0; j < NE; j++)
1125 if (QE[j][0] < 0) {
continue; }
1126 AddQuad(QE[j], j+1);
1128 RemoveUnusedVertices();
1129 FinalizeQuadMesh(
false, 0,
true);
1134 void Snap() { SnapNodesToUnitSphere(); }
1137 static int Problem0(Opt &opt)
1140 Surface *S =
nullptr;
1141 switch (opt.surface)
1143 case 0: S =
new MeshFromFile(opt);
break;
1144 case 1: S =
new Catenoid(opt);
break;
1145 case 2: S =
new Helicoid(opt);
break;
1146 case 3: S =
new Enneper(opt);
break;
1147 case 4: S =
new Hold(opt);
break;
1148 case 5: S =
new Costa(opt);
break;
1149 case 6: S =
new Shell(opt);
break;
1150 case 7: S =
new Scherk(opt);
break;
1151 case 8: S =
new FullPeach(opt);
break;
1152 case 9: S =
new QuarterPeach(opt);
break;
1153 case 10: S =
new SlottedSphere(opt);
break;
1154 default: MFEM_ABORT(
"Unknown surface (surface <= 10)!");
1164 static double u0(
const Vector &x) {
return sin(3.0 *
PI * (x[1] + x[0])); }
1168 static double qf(
const int order,
const int ker,
Mesh &m,
1175 const int NE(m.
GetNE());
1183 MFEM_VERIFY(ND == D1D*D1D,
"");
1184 MFEM_VERIFY(NQ == Q1D*Q1D,
"");
1186 Vector Eu(ND*NE), grad_u(
DIM*NQ*NE), sum(NE*NQ), one(NE*NQ);
1191 qi->Derivatives(Eu, grad_u);
1196 auto grdU =
Reshape(grad_u.Read(),
DIM, Q1D, Q1D, NE);
1197 auto S =
Reshape(sum.Write(), Q1D, Q1D, NE);
1199 MFEM_FORALL_2D(e, NE, Q1D, Q1D, 1,
1201 MFEM_FOREACH_THREAD(qy,y,Q1D)
1203 MFEM_FOREACH_THREAD(qx,x,Q1D)
1205 const double w = W(qx, qy);
1206 const double J11 = J(qx, qy, 0, 0, e);
1207 const double J12 = J(qx, qy, 1, 0, e);
1208 const double J21 = J(qx, qy, 0, 1, e);
1209 const double J22 = J(qx, qy, 1, 1, e);
1210 const double det = detJ(qx, qy, e);
1211 const double area = w * det;
1212 const double gu0 = grdU(0, qx, qy, e);
1213 const double gu1 = grdU(1, qx, qy, e);
1214 const double tgu0 = (J22*gu0 - J12*gu1)/det;
1215 const double tgu1 = (J11*gu1 - J21*gu0)/det;
1216 const double ngu = tgu0*tgu0 + tgu1*tgu1;
1217 const double s = (ker ==
AREA) ? sqrt(1.0 + ngu) :
1218 (ker ==
NORM) ? ngu : 0.0;
1219 S(qx, qy, e) = area * s;
1227 static int Problem1(Opt &opt)
1229 const int order = opt.order;
1232 for (
int l = 0; l < opt.refine; l++) { smesh.UniformRefinement(); }
1233 ParMesh mesh(MPI_COMM_WORLD, smesh);
1247 if (opt.vis) { Surface::Visualize(opt, &mesh,
GLVIZ_W,
GLVIZ_H, &u); }
1254 cg.SetPrintLevel(0);
1256 for (
int i = 0; i < opt.niters; i++)
1262 const double q_uold = qf(order,
AREA, mesh, fes, uold);
1263 MFEM_VERIFY(std::fabs(q_uold) > EPS,
"");
1267 a.FormLinearSystem(ess_tdof_list, u,
b, A, X, B);
1270 a.RecoverFEMSolution(X,
b, u);
1272 const double norm = sqrt(std::fabs(qf(order,
NORM, mesh, fes, eps)));
1273 const double area = qf(order,
AREA, mesh, fes, u);
1276 mfem::out <<
"Iteration " << i <<
", norm: " << norm
1277 <<
", area: " << area << std::endl;
1279 if (opt.vis) { Surface::Visualize(opt, &mesh, &u); }
1281 if (norm <
NRM) {
break; }
1289 MPI_Init(&argc, &argv);
1290 MPI_Comm_rank(MPI_COMM_WORLD, &opt.id);
1291 MPI_Comm_size(MPI_COMM_WORLD, &opt.sz);
1294 args.
AddOption(&opt.pb,
"-p",
"--problem",
"Problem to solve.");
1295 args.
AddOption(&opt.mesh_file,
"-m",
"--mesh",
"Mesh file to use.");
1296 args.
AddOption(&opt.wait,
"-w",
"--wait",
"-no-w",
"--no-wait",
1297 "Enable or disable a GLVis pause.");
1298 args.
AddOption(&opt.radial,
"-rad",
"--radial",
"-no-rad",
"--no-radial",
1299 "Enable or disable radial constraints in solver.");
1300 args.
AddOption(&opt.nx,
"-x",
"--num-elements-x",
1301 "Number of elements in x-direction.");
1302 args.
AddOption(&opt.ny,
"-y",
"--num-elements-y",
1303 "Number of elements in y-direction.");
1304 args.
AddOption(&opt.order,
"-o",
"--order",
"Finite element order.");
1305 args.
AddOption(&opt.refine,
"-r",
"--ref-levels",
"Refinement");
1306 args.
AddOption(&opt.niters,
"-n",
"--niter-max",
"Max number of iterations");
1307 args.
AddOption(&opt.surface,
"-s",
"--surface",
"Choice of the surface.");
1308 args.
AddOption(&opt.pa,
"-pa",
"--partial-assembly",
"-no-pa",
1309 "--no-partial-assembly",
"Enable Partial Assembly.");
1310 args.
AddOption(&opt.tau,
"-t",
"--tau",
"Costa scale factor.");
1311 args.
AddOption(&opt.lambda,
"-l",
"--lambda",
"Lambda step toward solution.");
1312 args.
AddOption(&opt.amr,
"-a",
"--amr",
"-no-a",
"--no-amr",
"Enable AMR.");
1313 args.
AddOption(&opt.amr_threshold,
"-at",
"--amr-threshold",
"AMR threshold.");
1314 args.
AddOption(&opt.device_config,
"-d",
"--device",
1315 "Device configuration string, see Device::Configure().");
1316 args.
AddOption(&opt.keys,
"-k",
"--keys",
"GLVis configuration keys.");
1317 args.
AddOption(&opt.vis,
"-vis",
"--visualization",
"-no-vis",
1318 "--no-visualization",
"Enable or disable visualization.");
1319 args.
AddOption(&opt.by_vdim,
"-c",
"--solve-byvdim",
1320 "-no-c",
"--solve-bynodes",
1321 "Enable or disable the 'ByVdim' solver");
1322 args.
AddOption(&opt.print,
"-print",
"--print",
"-no-print",
"--no-print",
1323 "Enable or disable result output (files in mfem format).");
1324 args.
AddOption(&opt.snapshot,
"-ss",
"--snapshot",
"-no-ss",
"--no-snapshot",
1325 "Enable or disable GLVis snapshot.");
1328 MFEM_VERIFY(opt.lambda >= 0.0 && opt.lambda <= 1.0,
"");
1332 Device device(opt.device_config);
1333 if (!opt.id) { device.
Print(); }
1335 if (opt.pb == 0) { Problem0(opt); }
1337 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.
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.
Abstract parallel finite element space.
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.
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).
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 GeometricFactors * GetGeometricFactors(const IntegrationRule &ir, const int flags)
Return the mesh geometric factors corresponding to the given integration rule.
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...
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)
virtual void Print(std::ostream &out=mfem::out) const
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.
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
double p(const Vector &x, double t)
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)
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
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.
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)
Class for parallel grid function.
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)
Class for parallel meshes.
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.