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->DeleteGeometricFactors();
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,
"");
404 const int NE = mesh->
GetNE();
406 for (
int e = 0; e < NE; e++)
414 for (
int q = 0; q < NQ; q++)
421 const double w = Jadjt.
Weight();
422 minW = std::fmin(minW, w);
423 maxW = std::fmax(maxW, w);
425 if (std::fabs(maxW) != 0.0)
427 const double rho = minW / maxW;
428 MFEM_VERIFY(rho <= 1.0,
"");
442 S.BoundaryConditions();
448 class ByNodes:
public Solver
451 ByNodes(Surface &S, Opt &opt):
Solver(S, opt)
456 x = *S.fes->GetMesh()->GetNodes();
457 bool converge = ParAXeqB();
459 return converge ?
true :
false;
464 class ByVDim:
public Solver
469 auto d_Xi = Xi.
Read();
470 auto d_nodes = S.fes->GetMesh()->GetNodes()->Write();
471 const int ndof = S.fes->GetNDofs();
472 MFEM_FORALL(i, ndof, d_nodes[c*ndof + i] = d_Xi[i]; );
477 auto d_Xi = Xi.
Write();
478 const int ndof = S.fes->GetNDofs();
479 auto d_nodes = S.fes->GetMesh()->GetNodes()->Read();
480 MFEM_FORALL(i, ndof, d_Xi[i] = d_nodes[c*ndof + i]; );
483 ByVDim(Surface &S, Opt &opt):
Solver(S, opt)
488 bool cvg[
SDIM] {
false};
489 for (
int c=0; c <
SDIM; ++c)
496 const bool converged = cvg[0] && cvg[1] && cvg[2];
497 return converged ?
true :
false;
503 struct MeshFromFile:
public Surface
505 MeshFromFile(Opt &opt): Surface(opt, opt.mesh_file) { }
509 struct Catenoid:
public Surface
511 Catenoid(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
517 for (
int i = 0; i < v2v.Size(); i++) { v2v[i] = i; }
519 for (
int j = 0; j <= opt.ny; j++)
521 const int v_old = opt.nx + j * (opt.nx + 1);
522 const int v_new = j * (opt.nx + 1);
526 for (
int i = 0; i < GetNE(); i++)
531 for (
int j = 0; j < nv; j++)
537 for (
int i = 0; i < GetNBE(); i++)
539 Element *el = GetBdrElement(i);
542 for (
int j = 0; j < nv; j++)
547 RemoveUnusedVertices();
548 RemoveInternalBoundaries();
555 const double u = 2.0*
PI*x[0];
556 const double v =
PI*(x[1]-0.5)/3.;
564 struct Helicoid:
public Surface
566 Helicoid(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
572 const double u = 2.0*
PI*x[0];
573 const double v = 2.0*
PI*(2.0*x[1]-1.0)/3.0;
581 struct Enneper:
public Surface
583 Enneper(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
589 const double u = 4.0*(x[0]-0.5);
590 const double v = 4.0*(x[1]-0.5);
591 p[0] = +u - u*u*u/3.0 + u*v*v;
592 p[1] = -v - u*u*v + v*v*v/3.0;
598 struct Hold:
public Surface
600 Hold(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
606 for (
int i = 0; i < v2v.Size(); i++) { v2v[i] = i; }
608 for (
int j = 0; j <= opt.ny; j++)
610 const int v_old = opt.nx + j * (opt.nx + 1);
611 const int v_new = j * (opt.nx + 1);
615 for (
int i = 0; i < GetNE(); i++)
620 for (
int j = 0; j < nv; j++)
626 for (
int i = 0; i < GetNBE(); i++)
628 Element *el = GetBdrElement(i);
631 for (
int j = 0; j < nv; j++)
636 RemoveUnusedVertices();
637 RemoveInternalBoundaries();
644 const double u = 2.0*
PI*x[0];
645 const double v = x[1];
646 p[0] = cos(u)*(1.0 + 0.3*sin(3.*u +
PI*v));
647 p[1] = sin(u)*(1.0 + 0.3*sin(3.*u +
PI*v));
655 #define I cdouble(0.0, 1.0)
661 double delta = std::numeric_limits<double>::max();
665 for (
int n=0; delta >
EPS; n+=1)
667 const cdouble j = pow(-1,n)*pow(q,n*(n+1.0))*sin((2.0*n+1.0)*u);
671 return 2.0*pow(q,0.25)*J;
674 for (
int n=0; delta >
EPS; n+=1)
676 const cdouble j = pow(q,n*(n+1))*cos((2.0*n+1.0)*u);
680 return 2.0*pow(q,0.25)*J;
682 for (
int n=1; delta >
EPS; n+=1)
684 const cdouble j = pow(q,n*n)*cos(2.0*n*u);
690 for (
int n=1; delta >
EPS; n+=1)
692 const cdouble j =pow(-1,n)*pow(q,n*n)*cos(2.0*n*u);
707 const cdouble q = exp(I*M_PI*tau);
708 const cdouble e1 = M_PI*M_PI/(12.0*w1*w1)*
711 const cdouble u = M_PI*z / (2.0*w1);
720 double delta = std::numeric_limits<double>::max();
721 for (
int n=0; delta >
EPS; n+=1)
723 const double alpha = 2.0*n+1.0;
724 const cdouble Dcosine = pow(alpha,k)*sin(k*M_PI/2.0 + alpha*u);
725 const cdouble j = pow(-1,n)*pow(q,n*(n+1.0))*Dcosine;
729 return 2.0*pow(q,0.25)*J;
736 double delta = std::numeric_limits<double>::max();
737 for (
int n=1; delta >
EPS; n+=1)
740 if (abs(q2n) < EPS) { q2n = 0.0; }
741 const cdouble j = q2n/(1.0-q2n)*sin(2.0*n*u);
745 return 1.0/tan(u) + 4.0*J;
754 const cdouble q = exp(I*M_PI*tau);
755 const cdouble n1 = -M_PI*M_PI/(12.0*w1) *
758 const cdouble u = M_PI*z / (2.0*w1);
763 static double ALPHA[4] {0.0};
764 struct Costa:
public Surface
766 Costa(Opt &opt): Surface((opt.Tptr = Parametrization, opt), false) { }
771 const int nx = opt.nx, ny = opt.ny;
772 MFEM_VERIFY(nx>2 && ny>2,
"");
773 const int nXhalf = (nx%2)==0 ? 4 : 2;
774 const int nYhalf = (ny%2)==0 ? 4 : 2;
775 const int nxh = nXhalf + nYhalf;
776 const int NVert = (nx+1) * (ny+1);
777 const int NElem = nx*ny - 4 - nxh;
778 const int NBdrElem = 0;
779 InitMesh(
DIM, SDIM, NVert, NElem, NBdrElem);
781 for (
int j = 0; j <= ny; j++)
783 const double cy = ((double) j / ny) ;
784 for (
int i = 0; i <= nx; i++)
786 const double cx = ((double) i / nx);
787 const double coords[
SDIM] = {cx, cy, 0.0};
792 for (
int j = 0; j < ny; j++)
794 for (
int i = 0; i < nx; i++)
796 if (i == 0 && j == 0) {
continue; }
797 if (i+1 == nx && j == 0) {
continue; }
798 if (i == 0 && j+1 == ny) {
continue; }
799 if (i+1 == nx && j+1 == ny) {
continue; }
800 if ((j == 0 || j+1 == ny) && (abs(nx-(i<<1)-1)<=1)) {
continue; }
801 if ((i == 0 || i+1 == nx) && (abs(ny-(j<<1)-1)<=1)) {
continue; }
802 const int i0 = i + j*(nx+1);
803 const int i1 = i+1 + j*(nx+1);
804 const int i2 = i+1 + (j+1)*(nx+1);
805 const int i3 = i + (j+1)*(nx+1);
806 const int ind[4] = {i0, i1, i2, i3};
810 RemoveUnusedVertices();
811 FinalizeQuadMesh(
false, 0,
true);
818 const double tau = ALPHA[3];
825 const bool y_top = x[1] > 0.5;
826 const bool x_top = x[0] > 0.5;
829 if (y_top) { v = 1.0 - x[1]; }
830 if (x_top) { u = 1.0 - x[0]; }
838 p[0] = real(
PI*(u+
PI/(4.*e1))- zw +
PI/(2.*e1)*(dw));
839 p[1] = real(
PI*(v+
PI/(4.*e1))-I*zw-
PI*I/(2.*e1)*(dw));
840 p[2] = sqrt(
PI/2.)*log(abs((pw-e1)/(pw+e1)));
841 if (y_top) { p[1] *= -1.0; }
842 if (x_top) { p[0] *= -1.0; }
843 const bool nan = std::isnan(p[0]) || std::isnan(p[1]) || std::isnan(p[2]);
844 MFEM_VERIFY(!nan,
"nan");
845 ALPHA[0] = std::fmax(p[0], ALPHA[0]);
846 ALPHA[1] = std::fmax(p[1], ALPHA[1]);
847 ALPHA[2] = std::fmax(p[2], ALPHA[2]);
853 MFEM_VERIFY(ALPHA[0] > 0.0,
"");
854 MFEM_VERIFY(ALPHA[1] > 0.0,
"");
855 MFEM_VERIFY(ALPHA[2] > 0.0,
"");
857 const double phi = (1.0 + sqrt(5.0)) / 2.0;
860 for (
int d = 0; d <
SDIM; d++)
862 const double alpha = d==2 ? phi : 1.0;
864 nodes(vdof) /= alpha * ALPHA[d];
871 struct Shell:
public Surface
873 Shell(Opt &opt): Surface((opt.niters = 1, opt.Tptr = Parametrization, opt)) { }
879 const double u = 2.0*
PI*x[0];
880 const double v = 21.0*x[1]-15.0;
881 p[0] = +1.0*pow(1.16,v)*cos(v)*(1.0+cos(u));
882 p[1] = -1.0*pow(1.16,v)*sin(v)*(1.0+cos(u));
883 p[2] = -2.0*pow(1.16,v)*(1.0+sin(u));
888 struct Scherk:
public Surface
893 const double alpha = 0.49;
895 const double u = alpha*
PI*(2.0*x[0]-1.0);
896 const double v =
alpha*
PI*(2.0*x[1]-1.0);
899 p[2] = log(cos(v)/cos(u));
902 Scherk(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
906 struct FullPeach:
public Surface
908 static constexpr
int NV = 8;
909 static constexpr
int NE = 6;
912 Surface((opt.niters = std::min(4, opt.niters), opt), NV, NE, 0) { }
916 const double quad_v[NV][
SDIM] =
918 {-1, -1, -1}, {+1, -1, -1}, {+1, +1, -1}, {-1, +1, -1},
919 {-1, -1, +1}, {+1, -1, +1}, {+1, +1, +1}, {-1, +1, +1}
921 const int quad_e[NE][4] =
923 {3, 2, 1, 0}, {0, 1, 5, 4}, {1, 2, 6, 5},
924 {2, 3, 7, 6}, {3, 0, 4, 7}, {4, 5, 6, 7}
927 for (
int j = 0; j < NV; j++) { AddVertex(quad_v[j]); }
928 for (
int j = 0; j < NE; j++) { AddQuad(quad_e[j], j+1); }
930 FinalizeQuadMesh(
false, 0,
true);
931 FinalizeTopology(
false);
936 void Snap() { SnapNodesToUnitSphere(); }
938 void BoundaryConditions()
943 ess_vdofs.
SetSize(fes->GetVSize());
944 MFEM_VERIFY(fes->GetVSize() >= fes->GetTrueVSize(),
"");
948 for (
int e = 0; e < fes->GetNE(); e++)
950 fes->GetElementDofs(e, dofs);
955 for (
int dof = 0; dof < dofs.
Size(); dof++)
959 const int k = dofs[dof];
960 MFEM_ASSERT(k >= 0,
"");
961 PointMat.
Mult(one, X);
962 const bool halfX = std::fabs(X[0]) <
EPS && X[1] <= 0.0;
963 const bool halfY = std::fabs(X[2]) <
EPS && X[1] >= 0.0;
964 const bool is_on_bc = halfX || halfY;
965 for (
int c = 0; c <
SDIM; c++)
966 { ess_vdofs[fes->DofToVDof(k, c)] = is_on_bc; }
984 struct QuarterPeach:
public Surface
986 QuarterPeach(Opt &opt): Surface((opt.Tptr = Parametrization, opt)) { }
991 const double x = 2.0*X[0]-1.0;
992 const double y = X[1];
993 const double r = sqrt(x*x + y*y);
994 const double t = (x==0.0) ?
PI/2.0 :
995 (y==0.0 && x>0.0) ? 0. :
996 (y==0.0 && x<0.0) ?
PI : acos(x/r);
997 const double sqrtx = sqrt(1.0 + x*x);
998 const double sqrty = sqrt(1.0 + y*y);
999 const bool yaxis =
PI/4.0<t && t < 3.0*
PI/4.0;
1000 const double R = yaxis?sqrtx:sqrty;
1001 const double gamma = r/R;
1002 p[0] = gamma * cos(t);
1003 p[1] = gamma * sin(t);
1009 for (
int i = 0; i < GetNBE(); i++)
1011 Element *el = GetBdrElement(i);
1012 const int fn = GetBdrElementEdgeIndex(i);
1013 MFEM_VERIFY(!FaceIsTrueInterior(fn),
"");
1015 GetFaceVertices(fn, vertices);
1018 double R[2], X[2][
SDIM];
1019 for (
int v = 0; v < 2; v++)
1022 const int iv = vertices[v];
1023 for (
int d = 0; d <
SDIM; d++)
1026 const double x = X[v][d] = nval[iv];
1027 if (d < 2) { R[v] += x*x; }
1030 if (std::fabs(X[0][1])<=
EPS && std::fabs(X[1][1])<=
EPS &&
1031 (R[0]>0.1 || R[1]>0.1))
1039 struct SlottedSphere:
public Surface
1041 SlottedSphere(Opt &opt): Surface((opt.niters = 4, opt), 64, 40, 0) { }
1045 constexpr
double delta = 0.15;
1046 constexpr
int NV1D = 4;
1047 constexpr
int NV = NV1D*NV1D*NV1D;
1048 constexpr
int NEPF = (NV1D-1)*(NV1D-1);
1049 constexpr
int NE = NEPF*6;
1050 const double V1D[NV1D] = {-1.0, -
delta,
delta, 1.0};
1052 for (
int iv=0; iv<NV; ++iv)
1055 int iy = (iv / NV1D) % NV1D;
1056 int iz = (iv / NV1D) / NV1D;
1058 QV[iv][0] = V1D[ix];
1059 QV[iv][1] = V1D[iy];
1060 QV[iv][2] = V1D[iz];
1063 for (
int ix=0; ix<NV1D-1; ++ix)
1065 for (
int iy=0; iy<NV1D-1; ++iy)
1067 int el_offset = ix + iy*(NV1D-1);
1069 QE[0*NEPF + el_offset][0] = NV1D*ix + NV1D*NV1D*iy;
1070 QE[0*NEPF + el_offset][1] = NV1D*(ix+1) + NV1D*NV1D*iy;
1071 QE[0*NEPF + el_offset][2] = NV1D*(ix+1) + NV1D*NV1D*(iy+1);
1072 QE[0*NEPF + el_offset][3] = NV1D*ix + NV1D*NV1D*(iy+1);
1075 QE[1*NEPF + el_offset][3] = x_off + NV1D*ix + NV1D*NV1D*iy;
1076 QE[1*NEPF + el_offset][2] = x_off + NV1D*(ix+1) + NV1D*NV1D*iy;
1077 QE[1*NEPF + el_offset][1] = x_off + NV1D*(ix+1) + NV1D*NV1D*(iy+1);
1078 QE[1*NEPF + el_offset][0] = x_off + NV1D*ix + NV1D*NV1D*(iy+1);
1080 QE[2*NEPF + el_offset][0] = NV1D*NV1D*iy + ix;
1081 QE[2*NEPF + el_offset][1] = NV1D*NV1D*iy + ix + 1;
1082 QE[2*NEPF + el_offset][2] = NV1D*NV1D*(iy+1) + ix + 1;
1083 QE[2*NEPF + el_offset][3] = NV1D*NV1D*(iy+1) + ix;
1085 int y_off = NV1D*(NV1D-1);
1086 QE[3*NEPF + el_offset][0] = y_off + NV1D*NV1D*iy + ix;
1087 QE[3*NEPF + el_offset][1] = y_off + NV1D*NV1D*iy + ix + 1;
1088 QE[3*NEPF + el_offset][2] = y_off + NV1D*NV1D*(iy+1) + ix + 1;
1089 QE[3*NEPF + el_offset][3] = y_off + NV1D*NV1D*(iy+1) + ix;
1091 QE[4*NEPF + el_offset][0] = NV1D*iy + ix;
1092 QE[4*NEPF + el_offset][1] = NV1D*iy + ix + 1;
1093 QE[4*NEPF + el_offset][2] = NV1D*(iy+1) + ix + 1;
1094 QE[4*NEPF + el_offset][3] = NV1D*(iy+1) + ix;
1096 int z_off = NV1D*NV1D*(NV1D-1);
1097 QE[5*NEPF + el_offset][0] = z_off + NV1D*iy + ix;
1098 QE[5*NEPF + el_offset][1] = z_off + NV1D*iy + ix + 1;
1099 QE[5*NEPF + el_offset][2] = z_off + NV1D*(iy+1) + ix + 1;
1100 QE[5*NEPF + el_offset][3] = z_off + NV1D*(iy+1) + ix;
1104 QE[0*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1105 QE[0*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1107 QE[1*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1108 QE[1*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1110 QE[3*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1111 QE[3*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1113 QE[5*NEPF + 0 + 1*(NV1D-1)][0] = -1;
1114 QE[5*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1115 QE[5*NEPF + 2 + 1*(NV1D-1)][0] = -1;
1117 QE[4*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1118 QE[4*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1119 QE[4*NEPF + 1 + 2*(NV1D-1)][0] = -1;
1121 QE[2*NEPF + 1 + 0*(NV1D-1)][0] = -1;
1122 QE[2*NEPF + 1 + 1*(NV1D-1)][0] = -1;
1123 for (
int j = 0; j < NV; j++) { AddVertex(QV[j]); }
1124 for (
int j = 0; j < NE; j++)
1126 if (QE[j][0] < 0) {
continue; }
1127 AddQuad(QE[j], j+1);
1129 RemoveUnusedVertices();
1130 FinalizeQuadMesh(
false, 0,
true);
1135 void Snap() { SnapNodesToUnitSphere(); }
1138 static int Problem0(Opt &opt)
1141 Surface *S =
nullptr;
1142 switch (opt.surface)
1144 case 0: S =
new MeshFromFile(opt);
break;
1145 case 1: S =
new Catenoid(opt);
break;
1146 case 2: S =
new Helicoid(opt);
break;
1147 case 3: S =
new Enneper(opt);
break;
1148 case 4: S =
new Hold(opt);
break;
1149 case 5: S =
new Costa(opt);
break;
1150 case 6: S =
new Shell(opt);
break;
1151 case 7: S =
new Scherk(opt);
break;
1152 case 8: S =
new FullPeach(opt);
break;
1153 case 9: S =
new QuarterPeach(opt);
break;
1154 case 10: S =
new SlottedSphere(opt);
break;
1155 default: MFEM_ABORT(
"Unknown surface (surface <= 10)!");
1165 static double u0(
const Vector &x) {
return sin(3.0 *
PI * (x[1] + x[0])); }
1169 static double qf(
const int order,
const int ker,
Mesh &m,
1176 const int NE(m.
GetNE());
1184 MFEM_VERIFY(ND == D1D*D1D,
"");
1185 MFEM_VERIFY(NQ == Q1D*Q1D,
"");
1187 Vector Eu(ND*NE), grad_u(
DIM*NQ*NE), sum(NE*NQ), one(NE*NQ);
1192 qi->Derivatives(Eu, grad_u);
1197 auto grdU =
Reshape(grad_u.Read(),
DIM, Q1D, Q1D, NE);
1198 auto S =
Reshape(sum.Write(), Q1D, Q1D, NE);
1200 MFEM_FORALL_2D(e, NE, Q1D, Q1D, 1,
1202 MFEM_FOREACH_THREAD(qy,y,Q1D)
1204 MFEM_FOREACH_THREAD(qx,x,Q1D)
1206 const double w = W(qx, qy);
1207 const double J11 = J(qx, qy, 0, 0, e);
1208 const double J12 = J(qx, qy, 1, 0, e);
1209 const double J21 = J(qx, qy, 0, 1, e);
1210 const double J22 = J(qx, qy, 1, 1, e);
1211 const double det = detJ(qx, qy, e);
1212 const double area = w * det;
1213 const double gu0 = grdU(0, qx, qy, e);
1214 const double gu1 = grdU(1, qx, qy, e);
1215 const double tgu0 = (J22*gu0 - J12*gu1)/det;
1216 const double tgu1 = (J11*gu1 - J21*gu0)/det;
1217 const double ngu = tgu0*tgu0 + tgu1*tgu1;
1218 const double s = (ker ==
AREA) ? sqrt(1.0 + ngu) :
1219 (ker ==
NORM) ? ngu : 0.0;
1220 S(qx, qy, e) = area *
s;
1228 static int Problem1(Opt &opt)
1230 const int order = opt.order;
1234 ParMesh mesh(MPI_COMM_WORLD, smesh);
1248 if (opt.vis) { Surface::Visualize(opt, &mesh,
GLVIZ_W,
GLVIZ_H, &u); }
1255 cg.SetPrintLevel(0);
1257 for (
int i = 0; i < opt.niters; i++)
1263 const double q_uold = qf(order,
AREA, mesh, fes, uold);
1264 MFEM_VERIFY(std::fabs(q_uold) > EPS,
"");
1268 a.FormLinearSystem(ess_tdof_list, u,
b, A, X, B);
1271 a.RecoverFEMSolution(X,
b, u);
1273 const double norm = sqrt(std::fabs(qf(order,
NORM, mesh, fes, eps)));
1274 const double area = qf(order,
AREA, mesh, fes, u);
1277 mfem::out <<
"Iteration " << i <<
", norm: " << norm
1278 <<
", area: " << area << std::endl;
1280 if (opt.vis) { Surface::Visualize(opt, &mesh, &u); }
1282 if (norm <
NRM) {
break; }
1290 MPI_Init(&argc, &argv);
1291 MPI_Comm_rank(MPI_COMM_WORLD, &opt.id);
1292 MPI_Comm_size(MPI_COMM_WORLD, &opt.sz);
1295 args.
AddOption(&opt.pb,
"-p",
"--problem",
"Problem to solve.");
1296 args.
AddOption(&opt.mesh_file,
"-m",
"--mesh",
"Mesh file to use.");
1297 args.
AddOption(&opt.wait,
"-w",
"--wait",
"-no-w",
"--no-wait",
1298 "Enable or disable a GLVis pause.");
1299 args.
AddOption(&opt.radial,
"-rad",
"--radial",
"-no-rad",
"--no-radial",
1300 "Enable or disable radial constraints in solver.");
1301 args.
AddOption(&opt.nx,
"-x",
"--num-elements-x",
1302 "Number of elements in x-direction.");
1303 args.
AddOption(&opt.ny,
"-y",
"--num-elements-y",
1304 "Number of elements in y-direction.");
1305 args.
AddOption(&opt.order,
"-o",
"--order",
"Finite element order.");
1306 args.
AddOption(&opt.refine,
"-r",
"--ref-levels",
"Refinement");
1307 args.
AddOption(&opt.niters,
"-n",
"--niter-max",
"Max number of iterations");
1308 args.
AddOption(&opt.surface,
"-s",
"--surface",
"Choice of the surface.");
1309 args.
AddOption(&opt.pa,
"-pa",
"--partial-assembly",
"-no-pa",
1310 "--no-partial-assembly",
"Enable Partial Assembly.");
1311 args.
AddOption(&opt.tau,
"-t",
"--tau",
"Costa scale factor.");
1312 args.
AddOption(&opt.lambda,
"-l",
"--lambda",
"Lambda step toward solution.");
1313 args.
AddOption(&opt.amr,
"-a",
"--amr",
"-no-a",
"--no-amr",
"Enable AMR.");
1314 args.
AddOption(&opt.amr_threshold,
"-at",
"--amr-threshold",
"AMR threshold.");
1315 args.
AddOption(&opt.device_config,
"-d",
"--device",
1316 "Device configuration string, see Device::Configure().");
1317 args.
AddOption(&opt.keys,
"-k",
"--keys",
"GLVis configuration keys.");
1318 args.
AddOption(&opt.vis,
"-vis",
"--visualization",
"-no-vis",
1319 "--no-visualization",
"Enable or disable visualization.");
1320 args.
AddOption(&opt.by_vdim,
"-c",
"--solve-byvdim",
1321 "-no-c",
"--solve-bynodes",
1322 "Enable or disable the 'ByVdim' solver");
1323 args.
AddOption(&opt.print,
"-print",
"--print",
"-no-print",
"--no-print",
1324 "Enable or disable result output (files in mfem format).");
1325 args.
AddOption(&opt.snapshot,
"-ss",
"--snapshot",
"-no-ss",
"--no-snapshot",
1326 "Enable or disable GLVis snapshot.");
1329 MFEM_VERIFY(opt.lambda >= 0.0 && opt.lambda <= 1.0,
"");
1333 Device device(opt.device_config);
1334 if (!opt.id) { device.
Print(); }
1336 if (opt.pb == 0) { Problem0(opt); }
1338 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.
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...
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.
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)
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.
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.
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...
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.
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).
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.