Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Examples  

catenary.cpp

#include "Sundance.h"


/** \example catenary.cpp
 *
 * catenary.cpp finds the minimum energy configuration of a hanging
 * chain, or equivalently, the minimum area of a surface of
 * revolution. The functional to be minimized is
 * 
 * Integral( u * sqrt(1 + (dx*u)*(dx*u) )
 * 
 * We can derive a differential equation by taking the variation of this
 * functional. The differential equation is nonlinear, so we linearize
 * and solve with Newton's method. 
 *
 * We will solve the problem on the domain [-1, 1] with boundary conditions
 * u(-1) = u(1) = 2.0. With these boundary conditions, the exact solution is 
 * 
 * y = cosh(alpha*x)/alpha
 *
 *  where alpha is the solution of the nonlinear algebraic equation 
 *
 * 2*alpha = cosh(alpha).
 *
 * The auxiliary function catenaryConstant() uses Newton's method to solve
 * this equation for alpha. 
 */

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;  // newton solver tolerance on function residual
      double stol = 1.0e-13;  // newton solver tolerance on change in resi
      int maxiterlin = 100;
      int maxiter = 100;

      /* Create a mesh object. */
      MeshGenerator mesher = new PartitionedLineMesher(-a, a, nx);
      Mesh mesh = mesher.getMesh();

      /* compute the exact solution */
      Expr x = new CoordExpr(0);
      double alpha = catenaryConstant(y0, a, 0.75);
      Expr exactSoln = cosh(alpha*x)/alpha;

      /* create boundary cell sets */
      CellSet boundary = new BoundaryCellSet();
      CellSet left = boundary.subset( fabs(x + a) < 1.0e-10 );
      CellSet right = boundary.subset( fabs(x - a) < 1.0e-10 );

      /* Generate a discrete vector space of first-order 
       * Lagrange polynomials */
      TSFVectorSpace discreteSpace 
        = new SundanceVectorSpace(mesh,new Lagrange(2));
      Expr initial = 1.0;
      Expr u0 = DiscreteFunction::discretize(discreteSpace, initial );

      /* Define an unknown function and its variation. */

      Expr u = new UnknownFunction(new Lagrange(2), "u");
      Expr w = u.variation();
      
      /* Define differentiation operators */
      Expr dx = new Derivative(0);
      
      /* Write energy functional */
      Expr E = Integral( u*sqrt(1.0 + (dx*u)*(dx*u)) );
      
      /* take variations to obtain a nonlinear PDE */
      Expr nonLinEqn = E.variation(u);
       
      /* linearize */
      Expr linEqn = nonLinEqn.linearization(u,u0);
      Expr du = u.differential();

      /* specify the boundary conditions */
      EssentialBC nonLinBC = EssentialBC(boundary, (u-2.0)*w);

      /* linearize the BCs */
      EssentialBC linBC = nonLinBC.linearization(u,u0);

      /* create a solver */
      TSFPreconditionerFactory prec = new ILUKPreconditionerFactory(1);
      TSFLinearSolver solver = new BICGSTABSolver(prec, lintol, maxiterlin);

      /* create a linearized problem */
      StaticLinearProblem prob(mesh, linEqn, linBC, w, du);
      NewtonLinearization newton(prob, u0, solver);      

      /* solve the nonlinear problem */
      Expr soln = newton.solve(NewtonSolver(solver, maxiter, ftol, stol));
       
      /* write the solution */
      char fName[100];
      sprintf(fName, "catenary.dat.%d", MPIComm::world().getRank());
      FieldWriter writer = new MatlabWriter(fName);
      writer.writeField(soln);

      /* check against the exact solution */
      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();
}

Contact:
Kevin Long (krlong@ca.sandia.gov)


Documentation generated by