#include "Sundance.h"
double catenaryConstant(double y0, double x0, double guess)
{
double a0 = guess;
for (int i=0; i<10; i++)
{
double f = y0*a0 - cosh(a0*x0);
double df = y0 - x0*sinh(a0*x0);
if (fabs(f/df) < 1.0e-14) return a0;
a0 = a0 - f/df;
}
TSFError::raise("Newton's method failed to converge in determining "
"the exact solution to the catenary problem");
}
int main(int argc, void** argv)
{
try
{
Sundance::init(&argc, &argv);
int nx = 32;
double a = 1.0;
double y0 = 2.0;
double lintol = 1.0e-14;
double ftol = 1.0e-13;
double stol = 1.0e-13;
int maxiterlin = 100;
int maxiter = 100;
MeshGenerator mesher = new PartitionedLineMesher(-a, a, nx);
Mesh mesh = mesher.getMesh();
Expr x = new CoordExpr(0);
double alpha = catenaryConstant(y0, a, 0.75);
Expr exactSoln = cosh(alpha*x)/alpha;
CellSet boundary = new BoundaryCellSet();
CellSet left = boundary.subset( fabs(x + a) < 1.0e-10 );
CellSet right = boundary.subset( fabs(x - a) < 1.0e-10 );
TSFVectorSpace discreteSpace
= new SundanceVectorSpace(mesh,new Lagrange(2));
Expr initial = 1.0;
Expr u0 = DiscreteFunction::discretize(discreteSpace, initial );
Expr u = new UnknownFunction(new Lagrange(2), "u");
Expr w = u.variation();
Expr dx = new Derivative(0);
Expr E = Integral( u*sqrt(1.0 + (dx*u)*(dx*u)) );
Expr nonLinEqn = E.variation(u);
Expr linEqn = nonLinEqn.linearization(u,u0);
Expr du = u.differential();
EssentialBC nonLinBC = EssentialBC(boundary, (u-2.0)*w);
EssentialBC linBC = nonLinBC.linearization(u,u0);
TSFPreconditionerFactory prec = new ILUKPreconditionerFactory(1);
TSFLinearSolver solver = new BICGSTABSolver(prec, lintol, maxiterlin);
StaticLinearProblem prob(mesh, linEqn, linBC, w, du);
NewtonLinearization newton(prob, u0, solver);
Expr soln = newton.solve(NewtonSolver(solver, maxiter, ftol, stol));
char fName[100];
sprintf(fName, "catenary.dat.%d", MPIComm::world().getRank());
FieldWriter writer = new MatlabWriter(fName);
writer.writeField(soln);
double errorNorm = (exactSoln - soln).norm(2);
double tolerance = 1.0e-6;
TSFOut::printf("error = %g\n", errorNorm);
Testing::passFailCheck(__FILE__, errorNorm, tolerance);
}
catch(exception& e)
{
TSFOut::println(e.what());
Testing::crash(__FILE__);
Testing::timeStamp(__FILE__, __DATE__, __TIME__);
}
Sundance::finalize();
}