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) { }
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(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())
241 fes->GetEssentialTrueDofs(ess_bdr, bc);
246 static void Visualize(Opt &opt,
const Mesh *mesh,
247 const int w,
const int h,
251 glvis <<
"parallel " << opt.sz <<
" " << opt.id <<
"\n";
252 glvis <<
"solution\n" << *mesh << solution;
254 glvis <<
"window_size " << w <<
" " << h <<
"\n";
255 glvis <<
"keys " << opt.keys <<
"\n";
257 if (opt.wait) { glvis <<
"pause\n"; }
262 static void Visualize(
const Opt &opt,
const Mesh *mesh,
265 glvis <<
"parallel " << opt.sz <<
" " << opt.id <<
"\n";
267 glvis <<
"solution\n" << *mesh << solution;
268 if (opt.wait) { glvis <<
"pause\n"; }
269 if (opt.snapshot && opt.keys) { glvis <<
"keys " << opt.keys <<
"\n"; }
276 const char *mesh_file =
"surface.mesh";
277 const char *sol_file =
"sol.gf";
280 mfem::out <<
"Printing " << mesh_file <<
", " << sol_file << std::endl;
283 std::ostringstream mesh_name;
284 mesh_name << mesh_file <<
"." << std::setfill(
'0') << std::setw(6) << opt.id;
285 std::ofstream mesh_ofs(mesh_name.str().c_str());
286 mesh_ofs.precision(8);
287 mesh->
Print(mesh_ofs);
290 std::ostringstream sol_name;
291 sol_name << sol_file <<
"." << std::setfill(
'0') << std::setw(6) << opt.id;
292 std::ofstream sol_ofs(sol_name.str().c_str());
293 sol_ofs.precision(8);
310 const int print_iter = -1, max_num_iter = 2000;
311 const double RTOLERANCE =
EPS, ATOLERANCE =
EPS*
EPS;
313 Solver(Surface &S, Opt &opt): opt(opt), S(S), cg(MPI_COMM_WORLD),
314 a(S.fes), x(S.fes), x0(S.fes),
b(S.fes), one(1.0)
316 cg.SetRelTol(RTOLERANCE);
317 cg.SetAbsTol(ATOLERANCE);
318 cg.SetMaxIter(max_num_iter);
319 cg.SetPrintLevel(print_iter);
326 constexpr
bool converged =
true;
328 for (
int i=0; i < opt.niters; ++i)
330 if (opt.amr) { Amr(); }
331 if (opt.vis) { Surface::Visualize(opt, S.mesh); }
332 if (!opt.id) {
mfem::out <<
"Iteration " << i <<
": "; }
333 S.mesh->NodesUpdated();
336 if (Step() == converged) {
break; }
338 if (opt.print) {
Surface::Print(opt, S.mesh, S.mesh->GetNodes()); }
341 virtual bool Step() = 0;
344 bool Converged(
const double rnorm) {
return rnorm <
NRM; }
350 a.FormLinearSystem(S.bc, x,
b, A, X, B);
352 if (M) { cg.SetPreconditioner(*M); }
355 a.RecoverFEMSolution(X,
b, x);
356 const bool by_vdim = opt.by_vdim;
357 GridFunction *nodes = by_vdim ? &x0 : S.fes->GetMesh()->GetNodes();
362 MPI_Allreduce(&rnorm, &glob_norm, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
364 if (!opt.id) {
mfem::out <<
"rnorm = " << rnorm << std::endl; }
365 const double lambda = opt.lambda;
368 MFEM_VERIFY(!opt.radial,
"'VDim solver can't use radial option!");
369 return Converged(rnorm);
376 Vector ni(SDIM), di(SDIM);
377 for (
int i = 0; i <
delta.Size()/
SDIM; i++)
380 const int ndof = S.fes->GetNDofs();
381 for (
int d = 0; d <
SDIM; d++)
383 ni(d) = (*nodes)(d*ndof + i);
384 di(d) =
delta(d*ndof + i);
387 const double ndotd = (ni*di) / (ni*ni);
390 for (
int d = 0; d <
SDIM; d++) {
delta(d*ndof + i) = di(d); }
395 add(lambda, *nodes, (1.0-lambda), x, x);
396 return Converged(rnorm);
401 MFEM_VERIFY(opt.amr_threshold >= 0.0 && opt.amr_threshold <= 1.0,
"");
402 Mesh *smesh = S.mesh;
404 const int NE = smesh->
GetNE();
406 for (
int e = 0; e < NE; e++)
416 for (
int q = 0; q < NQ; q++)
423 const double w = Jadjt.
Weight();
424 minW = std::fmin(minW, w);
425 maxW = std::fmax(maxW, w);
427 if (std::fabs(maxW) != 0.0)
429 const double rho = minW / maxW;
430 MFEM_VERIFY(rho <= 1.0,
"");
444 S.BoundaryConditions();
450 class ByNodes:
public Solver
453 ByNodes(Surface &S, Opt &opt):
Solver(S, opt)
458 x = *S.fes->GetMesh()->GetNodes();
459 bool converge = ParAXeqB();
461 return converge ?
true :
false;
466 class ByVDim:
public Solver
471 auto d_Xi = Xi.
Read();
472 auto d_nodes = S.fes->GetMesh()->GetNodes()->Write();
473 const int ndof = S.fes->GetNDofs();
474 MFEM_FORALL(i, ndof, d_nodes[c*ndof + i] = d_Xi[i]; );
479 auto d_Xi = Xi.
Write();
480 const int ndof = S.fes->GetNDofs();
481 auto d_nodes = S.fes->GetMesh()->GetNodes()->Read();
482 MFEM_FORALL(i, ndof, d_Xi[i] = d_nodes[c*ndof + i]; );
485 ByVDim(Surface &S, Opt &opt):
Solver(S, opt)
490 bool cvg[
SDIM] {
false};
491 for (
int c=0; c <
SDIM; ++c)
498 const bool converged = cvg[0] && cvg[1] && cvg[2];
499 return converged ?
true :
false;
505 struct MeshFromFile:
public Surface
507 MeshFromFile(Opt &opt): Surface(opt, opt.mesh_file) { }
511 struct Catenoid:
public Surface
513 Catenoid(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
519 for (
int i = 0; i < v2v.Size(); i++) { v2v[i] = i; }
521 for (
int j = 0; j <= opt.ny; j++)
523 const int v_old = opt.nx + j * (opt.nx + 1);
524 const int v_new = j * (opt.nx + 1);
528 for (
int i = 0; i < GetNE(); i++)
533 for (
int j = 0; j < nv; j++)
539 for (
int i = 0; i < GetNBE(); i++)
541 Element *el = GetBdrElement(i);
544 for (
int j = 0; j < nv; j++)
549 RemoveUnusedVertices();
550 RemoveInternalBoundaries();
557 const double u = 2.0*
PI*x[0];
558 const double v =
PI*(x[1]-0.5)/3.;
566 struct Helicoid:
public Surface
568 Helicoid(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
574 const double u = 2.0*
PI*x[0];
575 const double v = 2.0*
PI*(2.0*x[1]-1.0)/3.0;
583 struct Enneper:
public Surface
585 Enneper(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
591 const double u = 4.0*(x[0]-0.5);
592 const double v = 4.0*(x[1]-0.5);
593 p[0] = +u - u*u*u/3.0 + u*v*v;
594 p[1] = -v - u*u*v + v*v*v/3.0;
600 struct Hold:
public Surface
602 Hold(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
608 for (
int i = 0; i < v2v.Size(); i++) { v2v[i] = i; }
610 for (
int j = 0; j <= opt.ny; j++)
612 const int v_old = opt.nx + j * (opt.nx + 1);
613 const int v_new = j * (opt.nx + 1);
617 for (
int i = 0; i < GetNE(); i++)
622 for (
int j = 0; j < nv; j++)
628 for (
int i = 0; i < GetNBE(); i++)
630 Element *el = GetBdrElement(i);
633 for (
int j = 0; j < nv; j++)
638 RemoveUnusedVertices();
639 RemoveInternalBoundaries();
646 const double u = 2.0*
PI*x[0];
647 const double v = x[1];
648 p[0] = cos(u)*(1.0 + 0.3*sin(3.*u +
PI*v));
649 p[1] = sin(u)*(1.0 + 0.3*sin(3.*u +
PI*v));
657 #define I cdouble(0.0, 1.0)
663 double delta = std::numeric_limits<double>::max();
667 for (
int n=0; delta >
EPS; n+=1)
669 const cdouble j = pow(-1,n)*pow(q,n*(n+1.0))*sin((2.0*n+1.0)*u);
673 return 2.0*pow(q,0.25)*J;
676 for (
int n=0; delta >
EPS; n+=1)
678 const cdouble j = pow(q,n*(n+1))*cos((2.0*n+1.0)*u);
682 return 2.0*pow(q,0.25)*J;
684 for (
int n=1; delta >
EPS; n+=1)
686 const cdouble j = pow(q,n*n)*cos(2.0*n*u);
692 for (
int n=1; delta >
EPS; n+=1)
694 const cdouble j =pow(-1,n)*pow(q,n*n)*cos(2.0*n*u);
709 const cdouble q = exp(I*M_PI*tau);
710 const cdouble e1 = M_PI*M_PI/(12.0*w1*w1)*
713 const cdouble u = M_PI*z / (2.0*w1);
722 double delta = std::numeric_limits<double>::max();
723 for (
int n=0; delta >
EPS; n+=1)
725 const double alpha = 2.0*n+1.0;
726 const cdouble Dcosine = pow(alpha,k)*sin(k*M_PI/2.0 + alpha*u);
727 const cdouble j = pow(-1,n)*pow(q,n*(n+1.0))*Dcosine;
731 return 2.0*pow(q,0.25)*J;
738 double delta = std::numeric_limits<double>::max();
739 for (
int n=1; delta >
EPS; n+=1)
742 if (abs(q2n) < EPS) { q2n = 0.0; }
743 const cdouble j = q2n/(1.0-q2n)*sin(2.0*n*u);
747 return 1.0/tan(u) + 4.0*J;
756 const cdouble q = exp(I*M_PI*tau);
757 const cdouble n1 = -M_PI*M_PI/(12.0*w1) *
760 const cdouble u = M_PI*z / (2.0*w1);
765 static double ALPHA[4] {0.0};
766 struct Costa:
public Surface
768 Costa(Opt &opt): Surface((opt.Tptr = Parametrization, opt), false) { }
773 const int nx = opt.nx, ny = opt.ny;
774 MFEM_VERIFY(nx>2 && ny>2,
"");
775 const int nXhalf = (nx%2)==0 ? 4 : 2;
776 const int nYhalf = (ny%2)==0 ? 4 : 2;
777 const int nxh = nXhalf + nYhalf;
778 const int NVert = (nx+1) * (ny+1);
779 const int NElem = nx*ny - 4 - nxh;
780 const int NBdrElem = 0;
781 InitMesh(
DIM, SDIM, NVert, NElem, NBdrElem);
783 for (
int j = 0; j <= ny; j++)
785 const double cy = ((double) j / ny) ;
786 for (
int i = 0; i <= nx; i++)
788 const double cx = ((double) i / nx);
789 const double coords[
SDIM] = {cx, cy, 0.0};
794 for (
int j = 0; j < ny; j++)
796 for (
int i = 0; i < nx; i++)
798 if (i == 0 && j == 0) {
continue; }
799 if (i+1 == nx && j == 0) {
continue; }
800 if (i == 0 && j+1 == ny) {
continue; }
801 if (i+1 == nx && j+1 == ny) {
continue; }
802 if ((j == 0 || j+1 == ny) && (abs(nx-(i<<1)-1)<=1)) {
continue; }
803 if ((i == 0 || i+1 == nx) && (abs(ny-(j<<1)-1)<=1)) {
continue; }
804 const int i0 = i + j*(nx+1);
805 const int i1 = i+1 + j*(nx+1);
806 const int i2 = i+1 + (j+1)*(nx+1);
807 const int i3 = i + (j+1)*(nx+1);
808 const int ind[4] = {i0, i1, i2, i3};
812 RemoveUnusedVertices();
813 FinalizeQuadMesh(
false, 0,
true);
820 const double tau = ALPHA[3];
827 const bool y_top = x[1] > 0.5;
828 const bool x_top = x[0] > 0.5;
831 if (y_top) { v = 1.0 - x[1]; }
832 if (x_top) { u = 1.0 - x[0]; }
840 p[0] = real(
PI*(u+
PI/(4.*e1))- zw +
PI/(2.*e1)*(dw));
841 p[1] = real(
PI*(v+
PI/(4.*e1))-I*zw-
PI*I/(2.*e1)*(dw));
842 p[2] = sqrt(
PI/2.)*log(abs((pw-e1)/(pw+e1)));
843 if (y_top) { p[1] *= -1.0; }
844 if (x_top) { p[0] *= -1.0; }
845 const bool nan = std::isnan(p[0]) || std::isnan(p[1]) || std::isnan(p[2]);
846 MFEM_VERIFY(!nan,
"nan");
847 ALPHA[0] = std::fmax(p[0], ALPHA[0]);
848 ALPHA[1] = std::fmax(p[1], ALPHA[1]);
849 ALPHA[2] = std::fmax(p[2], ALPHA[2]);
855 MFEM_VERIFY(ALPHA[0] > 0.0,
"");
856 MFEM_VERIFY(ALPHA[1] > 0.0,
"");
857 MFEM_VERIFY(ALPHA[2] > 0.0,
"");
859 const double phi = (1.0 + sqrt(5.0)) / 2.0;
862 for (
int d = 0; d <
SDIM; d++)
864 const double alpha = d==2 ? phi : 1.0;
866 nodes(vdof) /= alpha * ALPHA[d];
873 struct Shell:
public Surface
875 Shell(Opt &opt): Surface((opt.niters = 1, opt.Tptr = Parametrization, opt)) { }
881 const double u = 2.0*
PI*x[0];
882 const double v = 21.0*x[1]-15.0;
883 p[0] = +1.0*pow(1.16,v)*cos(v)*(1.0+cos(u));
884 p[1] = -1.0*pow(1.16,v)*sin(v)*(1.0+cos(u));
885 p[2] = -2.0*pow(1.16,v)*(1.0+sin(u));
890 struct Scherk:
public Surface
895 const double alpha = 0.49;
897 const double u = alpha*
PI*(2.0*x[0]-1.0);
898 const double v =
alpha*
PI*(2.0*x[1]-1.0);
901 p[2] = log(cos(v)/cos(u));
904 Scherk(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
908 struct FullPeach:
public Surface
910 static constexpr
int NV = 8;
911 static constexpr
int NE = 6;
914 Surface((opt.niters = std::min(4, opt.niters), opt), NV, NE, 0) { }
918 const double quad_v[NV][
SDIM] =
920 {-1, -1, -1}, {+1, -1, -1}, {+1, +1, -1}, {-1, +1, -1},
921 {-1, -1, +1}, {+1, -1, +1}, {+1, +1, +1}, {-1, +1, +1}
923 const int quad_e[NE][4] =
925 {3, 2, 1, 0}, {0, 1, 5, 4}, {1, 2, 6, 5},
926 {2, 3, 7, 6}, {3, 0, 4, 7}, {4, 5, 6, 7}
929 for (
int j = 0; j < NV; j++) { AddVertex(quad_v[j]); }
930 for (
int j = 0; j < NE; j++) { AddQuad(quad_e[j], j+1); }
932 FinalizeQuadMesh(
false, 0,
true);
933 FinalizeTopology(
false);
938 void Snap() { SnapNodesToUnitSphere(); }
940 void BoundaryConditions()
945 ess_vdofs.
SetSize(fes->GetVSize());
946 MFEM_VERIFY(fes->GetVSize() >= fes->GetTrueVSize(),
"");
950 for (
int e = 0; e < fes->GetNE(); e++)
952 fes->GetElementDofs(e, dofs);
957 for (
int dof = 0; dof < dofs.
Size(); dof++)
961 const int k = dofs[dof];
962 MFEM_ASSERT(k >= 0,
"");
963 PointMat.
Mult(one, X);
964 const bool halfX = std::fabs(X[0]) <
EPS && X[1] <= 0.0;
965 const bool halfY = std::fabs(X[2]) <
EPS && X[1] >= 0.0;
966 const bool is_on_bc = halfX || halfY;
967 for (
int c = 0; c <
SDIM; c++)
968 { ess_vdofs[fes->DofToVDof(k, c)] = is_on_bc; }
986 struct QuarterPeach:
public Surface
988 QuarterPeach(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
993 const double x = 2.0*X[0]-1.0;
994 const double y = X[1];
995 const double r = sqrt(x*x + y*y);
996 const double t = (x==0.0) ?
PI/2.0 :
997 (y==0.0 && x>0.0) ? 0. :
998 (y==0.0 && x<0.0) ?
PI : acos(x/r);
999 const double sqrtx = sqrt(1.0 + x*x);
1000 const double sqrty = sqrt(1.0 + y*y);
1001 const bool yaxis =
PI/4.0<t && t < 3.0*
PI/4.0;
1002 const double R = yaxis?sqrtx:sqrty;
1003 const double gamma = r/R;
1004 p[0] = gamma * cos(t);
1005 p[1] = gamma * sin(t);
1011 for (
int i = 0; i < GetNBE(); i++)
1013 Element *el = GetBdrElement(i);
1014 const int fn = GetBdrElementEdgeIndex(i);
1015 MFEM_VERIFY(!FaceIsTrueInterior(fn),
"");
1017 GetFaceVertices(fn, vertices);
1020 double R[2], X[2][
SDIM];
1021 for (
int v = 0; v < 2; v++)
1024 const int iv = vertices[v];
1025 for (
int d = 0; d <
SDIM; d++)
1028 const double x = X[v][d] = nval[iv];
1029 if (d < 2) { R[v] += x*x; }
1032 if (std::fabs(X[0][1])<=
EPS && std::fabs(X[1][1])<=
EPS &&
1033 (R[0]>0.1 || R[1]>0.1))
1041 struct SlottedSphere:
public Surface
1043 SlottedSphere(Opt &opt): Surface((opt.niters = 4, opt), 64, 40, 0) { }
1047 constexpr
double delta = 0.15;
1048 constexpr
int NV1D = 4;
1049 constexpr
int NV = NV1D*NV1D*NV1D;
1050 constexpr
int NEPF = (NV1D-1)*(NV1D-1);
1051 constexpr
int NE = NEPF*6;
1052 const double V1D[NV1D] = {-1.0, -
delta,
delta, 1.0};
1054 for (
int iv=0; iv<NV; ++iv)
1057 int iy = (iv / NV1D) % NV1D;
1058 int iz = (iv / NV1D) / NV1D;
1060 QV[iv][0] = V1D[ix];
1061 QV[iv][1] = V1D[iy];
1062 QV[iv][2] = V1D[iz];
1065 for (
int ix=0; ix<NV1D-1; ++ix)
1067 for (
int iy=0; iy<NV1D-1; ++iy)
1069 int el_offset = ix + iy*(NV1D-1);
1071 QE[0*NEPF + el_offset][0] = NV1D*ix + NV1D*NV1D*iy;
1072 QE[0*NEPF + el_offset][1] = NV1D*(ix+1) + NV1D*NV1D*iy;
1073 QE[0*NEPF + el_offset][2] = NV1D*(ix+1) + NV1D*NV1D*(iy+1);
1074 QE[0*NEPF + el_offset][3] = NV1D*ix + NV1D*NV1D*(iy+1);
1077 QE[1*NEPF + el_offset][3] = x_off + NV1D*ix + NV1D*NV1D*iy;
1078 QE[1*NEPF + el_offset][2] = x_off + NV1D*(ix+1) + NV1D*NV1D*iy;
1079 QE[1*NEPF + el_offset][1] = x_off + NV1D*(ix+1) + NV1D*NV1D*(iy+1);
1080 QE[1*NEPF + el_offset][0] = x_off + NV1D*ix + NV1D*NV1D*(iy+1);
1082 QE[2*NEPF + el_offset][0] = NV1D*NV1D*iy + ix;
1083 QE[2*NEPF + el_offset][1] = NV1D*NV1D*iy + ix + 1;
1084 QE[2*NEPF + el_offset][2] = NV1D*NV1D*(iy+1) + ix + 1;
1085 QE[2*NEPF + el_offset][3] = NV1D*NV1D*(iy+1) + ix;
1087 int y_off = NV1D*(NV1D-1);
1088 QE[3*NEPF + el_offset][0] = y_off + NV1D*NV1D*iy + ix;
1089 QE[3*NEPF + el_offset][1] = y_off + NV1D*NV1D*iy + ix + 1;
1090 QE[3*NEPF + el_offset][2] = y_off + NV1D*NV1D*(iy+1) + ix + 1;
1091 QE[3*NEPF + el_offset][3] = y_off + NV1D*NV1D*(iy+1) + ix;
1093 QE[4*NEPF + el_offset][0] = NV1D*iy + ix;
1094 QE[4*NEPF + el_offset][1] = NV1D*iy + ix + 1;
1095 QE[4*NEPF + el_offset][2] = NV1D*(iy+1) + ix + 1;
1096 QE[4*NEPF + el_offset][3] = NV1D*(iy+1) + ix;
1098 int z_off = NV1D*NV1D*(NV1D-1);
1099 QE[5*NEPF + el_offset][0] = z_off + NV1D*iy + ix;
1100 QE[5*NEPF + el_offset][1] = z_off + NV1D*iy + ix + 1;
1101 QE[5*NEPF + el_offset][2] = z_off + NV1D*(iy+1) + ix + 1;
1102 QE[5*NEPF + el_offset][3] = z_off + NV1D*(iy+1) + ix;
1106 QE[0*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1107 QE[0*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1109 QE[1*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1110 QE[1*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1112 QE[3*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1113 QE[3*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1115 QE[5*NEPF + 0 + 1*(NV1D-1)][0] = -1;
1116 QE[5*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1117 QE[5*NEPF + 2 + 1*(NV1D-1)][0] = -1;
1119 QE[4*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1120 QE[4*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1121 QE[4*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1123 QE[2*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1124 QE[2*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1125 for (
int j = 0; j < NV; j++) { AddVertex(QV[j]); }
1126 for (
int j = 0; j < NE; j++)
1128 if (QE[j][0] < 0) {
continue; }
1129 AddQuad(QE[j], j+1);
1131 RemoveUnusedVertices();
1132 FinalizeQuadMesh(
false, 0,
true);
1137 void Snap() { SnapNodesToUnitSphere(); }
1140 static int Problem0(Opt &opt)
1143 Surface *S =
nullptr;
1144 switch (opt.surface)
1146 case 0: S =
new MeshFromFile(opt);
break;
1147 case 1: S =
new Catenoid(opt);
break;
1148 case 2: S =
new Helicoid(opt);
break;
1149 case 3: S =
new Enneper(opt);
break;
1150 case 4: S =
new Hold(opt);
break;
1151 case 5: S =
new Costa(opt);
break;
1152 case 6: S =
new Shell(opt);
break;
1153 case 7: S =
new Scherk(opt);
break;
1154 case 8: S =
new FullPeach(opt);
break;
1155 case 9: S =
new QuarterPeach(opt);
break;
1156 case 10: S =
new SlottedSphere(opt);
break;
1157 default: MFEM_ABORT(
"Unknown surface (surface <= 10)!");
1167 static double u0(
const Vector &x) {
return sin(3.0 *
PI * (x[1] + x[0])); }
1171 static double qf(
const int order,
const int ker,
Mesh &m,
1178 const int NE(m.
GetNE());
1186 MFEM_VERIFY(ND == D1D*D1D,
"");
1187 MFEM_VERIFY(NQ == Q1D*Q1D,
"");
1189 Vector Eu(ND*NE), grad_u(
DIM*NQ*NE), sum(NE*NQ), one(NE*NQ);
1194 qi->Derivatives(Eu, grad_u);
1199 auto grdU =
Reshape(grad_u.Read(),
DIM, Q1D, Q1D, NE);
1200 auto S =
Reshape(sum.Write(), Q1D, Q1D, NE);
1202 MFEM_FORALL_2D(e, NE, Q1D, Q1D, 1,
1204 MFEM_FOREACH_THREAD(qy,y,Q1D)
1206 MFEM_FOREACH_THREAD(qx,x,Q1D)
1208 const double w = W(qx, qy);
1209 const double J11 = J(qx, qy, 0, 0, e);
1210 const double J12 = J(qx, qy, 1, 0, e);
1211 const double J21 = J(qx, qy, 0, 1, e);
1212 const double J22 = J(qx, qy, 1, 1, e);
1213 const double det = detJ(qx, qy, e);
1214 const double area = w * det;
1215 const double gu0 = grdU(0, qx, qy, e);
1216 const double gu1 = grdU(1, qx, qy, e);
1217 const double tgu0 = (J22*gu0 - J12*gu1)/det;
1218 const double tgu1 = (J11*gu1 - J21*gu0)/det;
1219 const double ngu = tgu0*tgu0 + tgu1*tgu1;
1220 const double s = (ker ==
AREA) ? sqrt(1.0 + ngu) :
1221 (ker ==
NORM) ? ngu : 0.0;
1222 S(qx, qy, e) = area *
s;
1230 static int Problem1(Opt &opt)
1232 const int order = opt.order;
1236 ParMesh mesh(MPI_COMM_WORLD, smesh);
1250 if (opt.vis) { Surface::Visualize(opt, &mesh,
GLVIZ_W,
GLVIZ_H, &u); }
1257 cg.SetPrintLevel(0);
1259 for (
int i = 0; i < opt.niters; i++)
1265 const double q_uold = qf(order,
AREA, mesh, fes, uold);
1266 MFEM_VERIFY(std::fabs(q_uold) > EPS,
"");
1270 a.FormLinearSystem(ess_tdof_list, u,
b, A, X, B);
1273 a.RecoverFEMSolution(X,
b, u);
1275 const double norm = sqrt(std::fabs(qf(order,
NORM, mesh, fes, eps)));
1276 const double area = qf(order,
AREA, mesh, fes, u);
1279 mfem::out <<
"Iteration " << i <<
", norm: " << norm
1280 <<
", area: " << area << std::endl;
1282 if (opt.vis) { Surface::Visualize(opt, &mesh, &u); }
1284 if (norm <
NRM) {
break; }
1299 args.
AddOption(&opt.pb,
"-p",
"--problem",
"Problem to solve.");
1300 args.
AddOption(&opt.mesh_file,
"-m",
"--mesh",
"Mesh file to use.");
1301 args.
AddOption(&opt.wait,
"-w",
"--wait",
"-no-w",
"--no-wait",
1302 "Enable or disable a GLVis pause.");
1303 args.
AddOption(&opt.radial,
"-rad",
"--radial",
"-no-rad",
"--no-radial",
1304 "Enable or disable radial constraints in solver.");
1305 args.
AddOption(&opt.nx,
"-x",
"--num-elements-x",
1306 "Number of elements in x-direction.");
1307 args.
AddOption(&opt.ny,
"-y",
"--num-elements-y",
1308 "Number of elements in y-direction.");
1309 args.
AddOption(&opt.order,
"-o",
"--order",
"Finite element order.");
1310 args.
AddOption(&opt.refine,
"-r",
"--ref-levels",
"Refinement");
1311 args.
AddOption(&opt.niters,
"-n",
"--niter-max",
"Max number of iterations");
1312 args.
AddOption(&opt.surface,
"-s",
"--surface",
"Choice of the surface.");
1313 args.
AddOption(&opt.pa,
"-pa",
"--partial-assembly",
"-no-pa",
1314 "--no-partial-assembly",
"Enable Partial Assembly.");
1315 args.
AddOption(&opt.tau,
"-t",
"--tau",
"Costa scale factor.");
1316 args.
AddOption(&opt.lambda,
"-l",
"--lambda",
"Lambda step toward solution.");
1317 args.
AddOption(&opt.amr,
"-a",
"--amr",
"-no-a",
"--no-amr",
"Enable AMR.");
1318 args.
AddOption(&opt.amr_threshold,
"-at",
"--amr-threshold",
"AMR threshold.");
1319 args.
AddOption(&opt.device_config,
"-d",
"--device",
1320 "Device configuration string, see Device::Configure().");
1321 args.
AddOption(&opt.keys,
"-k",
"--keys",
"GLVis configuration keys.");
1322 args.
AddOption(&opt.vis,
"-vis",
"--visualization",
"-no-vis",
1323 "--no-visualization",
"Enable or disable visualization.");
1324 args.
AddOption(&opt.by_vdim,
"-c",
"--solve-byvdim",
1325 "-no-c",
"--solve-bynodes",
1326 "Enable or disable the 'ByVdim' solver");
1327 args.
AddOption(&opt.print,
"-print",
"--print",
"-no-print",
"--no-print",
1328 "Enable or disable result output (files in mfem format).");
1329 args.
AddOption(&opt.snapshot,
"-ss",
"--snapshot",
"-no-ss",
"--no-snapshot",
1330 "Enable or disable GLVis snapshot.");
1333 MFEM_VERIFY(opt.lambda >= 0.0 && opt.lambda <= 1.0,
"");
1337 Device device(opt.device_config);
1338 if (!opt.id) { device.
Print(); }
1340 if (opt.pb == 0) { Problem0(opt); }
1342 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.
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.
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.
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.
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...
static int WorldSize()
Return the size of MPI_COMM_WORLD.
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.
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
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.
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 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
static void Init()
Singleton creation with Mpi::Init();.
FiniteElementSpace * FESpace()
void PrintUsage(std::ostream &out) const
Print the usage message.
virtual const double * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
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.
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)
void GetElementTransformation(int i, IsoparametricTransformation *ElTr)
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
virtual void Print(std::ostream &os=mfem::out) const
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.
virtual 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)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
const ElementRestrictionOperator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
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.
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.
void Print(std::ostream &out=mfem::out) const override
double u(const Vector &xvec)
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.
virtual const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims...dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
VDIM x NQPT x NE (values) / VDIM x DIM x NQPT x NE (grads)
bool Good() const
Return true if the command line options were parsed successfully.