void SolidMechanicsBCHandling::user_apply_neumann_bcs( AssemblyContext& context,
                                                         const GRINS::CachedValues& /*cache*/,
                                                         const bool /*request_jacobian*/,
                                                         const BoundaryID bc_id,
                                                         const BCType bc_type ) const
  {
    switch( bc_type )
      {
      case(CONSTANT_TRACTION):
        {
          const libMesh::Point& traction = this->get_neumann_bc_value(bc_id);

          _bound_conds.apply_neumann_normal( context, _disp_vars.u_var(), 1.0, traction(0) );

          if( _disp_vars.have_v() )
            _bound_conds.apply_neumann_normal( context, _disp_vars.v_var(), 1.0, traction(1) );

          if( _disp_vars.have_w() )
            _bound_conds.apply_neumann_normal( context, _disp_vars.w_var(), 1.0, traction(2) );
        }
        break;

      default:
        {
          std::cerr << "Error: Invalid Neumann BC type for " << _physics_name
                    << std::endl;
          libmesh_error();
        }

      } // switch( bc_type )

    return;
  }
// Update the coefficients associated with the patch field
void timeVaryingSolidTractionFvPatchVectorField::updateCoeffs()
{
    if (updated())
    {
        return;
    }

    traction() = timeSeries_(this->db().time().timeOutputValue());

    solidTractionFvPatchVectorField::updateCoeffs();
}
void ContinuumMechanicsNeumannBcsAssembler<DIM>::AssembleOnBoundaryElement(BoundaryElement<DIM-1,DIM>& rBoundaryElement,
                                                                           c_vector<double,STENCIL_SIZE>& rBelem,
                                                                           unsigned boundaryConditionIndex)
{
    rBelem.clear();

    c_vector<double, DIM> weighted_direction;
    double jacobian_determinant;
    mpMesh->GetWeightedDirectionForBoundaryElement(rBoundaryElement.GetIndex(), weighted_direction, jacobian_determinant);

    c_vector<double,NUM_NODES_PER_ELEMENT> phi;

    for (unsigned quad_index=0; quad_index<mpQuadRule->GetNumQuadPoints(); quad_index++)
    {
        double wJ = jacobian_determinant * mpQuadRule->GetWeight(quad_index);
        const ChastePoint<DIM-1>& quad_point = mpQuadRule->rGetQuadPoint(quad_index);
        QuadraticBasisFunction<DIM-1>::ComputeBasisFunctions(quad_point, phi);

        c_vector<double,DIM> traction = zero_vector<double>(DIM);
        switch (mpProblemDefinition->GetTractionBoundaryConditionType())
        {
            case ELEMENTWISE_TRACTION:
            {
                traction = mpProblemDefinition->rGetElementwiseTractions()[boundaryConditionIndex];
                break;
            }
            default:
                // Functional traction not implemented yet..
                NEVER_REACHED;
        }

        for (unsigned index=0; index<NUM_NODES_PER_ELEMENT*DIM; index++)
        {
            unsigned spatial_dim = index%DIM;
            unsigned node_index = (index-spatial_dim)/DIM;

            assert(node_index < NUM_NODES_PER_ELEMENT);

            rBelem(index) += traction(spatial_dim) * phi(node_index) * wJ;
        }
    }
}
timeVaryingSolidTractionFvPatchVectorField::
timeVaryingSolidTractionFvPatchVectorField
(
    const fvPatch& p,
    const DimensionedField<vector, volMesh>& iF,
    const dictionary& dict
)
:
solidTractionFvPatchVectorField(p, iF),
timeSeries_(dict)
{
    fieldName() = dimensionedInternalField().name();
    traction() = vector::zero;
    pressure() = 0.0;

    nonLinear() =
        nonLinearGeometry::nonLinearNames_.read(dict.lookup("nonLinear"));

    //- the leastSquares has zero non-orthogonal correction
    //- on the boundary
    //- so the gradient scheme should be extendedLeastSquares
    if
    (
      Foam::word
      (
          dimensionedInternalField().mesh().schemesDict().gradScheme
          (
              "grad(" + fieldName() + ")"
          )
      ) != "extendedLeastSquares"
    )
    {
        Warning << "The gradScheme for " << fieldName()
            << " should be \"extendedLeastSquares 0\" for the boundary "
            << "non-orthogonal correction to be right" << endl;
    }
}
    /* == Mechano-electric feedback, and alternative boundary conditions ==
     *
     * Let us now run a simulation with mechano-electric feedback (MEF), and with different boundary conditions.
     */
    void TestWithMef() throw(Exception)
    {
        /* If we want to use MEF, where the stretch (in the fibre-direction) couples back to the cell
         * model and is used in stretch-activated channels (SACs), we can't just let Chaste convert
         * from cellml to C++ code as usual (see electro-physiology tutorials on how cell model files
         * are autogenerated from CellML during compilation), since these files don't use stretch and don't
         * have SACs. We have to use pycml to create a cell model class for us, rename and save it, and
         * manually add the SAC current.
         *
         * There is one example of this already in the code-base, which we will use it the following
         * simulation. It is the Noble 98 model, with a SAC added that depends linearly on stretches (>1).
         * It is found in the file !NobleVargheseKohlNoble1998WithSac.hpp, and is called
         * `CML_noble_varghese_kohl_noble_1998_basic_with_sac`.
         *
         * To add a SAC current to (or otherwise alter) your favourite cell model, you have to do the following.
         * Auto-generate the C++ code, by running the following on the cellml file:
         * `./python/ConvertCellModel.py heart/src/odes/cellml/LuoRudy1991.cellml`
         * (see [wiki:ChasteGuides/CodeGenerationFromCellML#Usingthehelperscript ChasteGuides/CodeGenerationFromCellML#Usingthehelperscript]
         *  if you want further documentation on this script).
         *
         * Copy and rename the resultant .hpp and .cpp files (which can be found in the same folder as the
         * input cellml). For example, rename everything to `LuoRudy1991WithSac`. Then alter the class
         * to overload the method `AbstractCardiacCell::SetStretch(double stretch)` to store the stretch,
         * and then implement the SAC in the `GetIIonic()` method.  `CML_noble_varghese_kohl_noble_1998_basic_with_sac`
         * provides an example of the changes that need to be made.
         *
         * Let us create a cell factory returning these Noble98 SAC cells, but with no stimulus - the
         * SAC switching on will lead be to activation.
         */
        ZeroStimulusCellFactory<CML_noble_varghese_kohl_noble_1998_basic_with_sac, 2> cell_factory;

        /* Construct two meshes are before, in 2D */
        TetrahedralMesh<2,2> electrics_mesh;
        electrics_mesh.ConstructRegularSlabMesh(0.01/*stepsize*/, 0.1/*length*/, 0.1/*width*/, 0.1/*depth*/);

        QuadraticMesh<2> mechanics_mesh;
        mechanics_mesh.ConstructRegularSlabMesh(0.02, 0.1, 0.1, 0.1 /*as above with a different stepsize*/);

        /* Collect the fixed nodes. This time we directly specify the new locations. We say the
         * nodes on X=0 are to be fixed, setting the deformed x=0, but leaving y to be free
         * (sliding boundary conditions). This functionality is described in more detail in the
         * solid mechanics tutorials.
         */
        std::vector<unsigned> fixed_nodes;
        std::vector<c_vector<double,2> > fixed_node_locations;

        fixed_nodes.push_back(0);
        fixed_node_locations.push_back(zero_vector<double>(2));

        for(unsigned i=1; i<mechanics_mesh.GetNumNodes(); i++)
        {
            double X = mechanics_mesh.GetNode(i)->rGetLocation()[0];
            if(fabs(X) < 1e-6) // ie, if X==0
            {
                c_vector<double,2> new_position;
                new_position(0) = 0.0;
                new_position(1) = ElectroMechanicsProblemDefinition<2>::FREE;

                fixed_nodes.push_back(i);
                fixed_node_locations.push_back(new_position);
            }
        }

        /* Now specify tractions on the top and bottom surfaces. For full descriptions of how
         * to apply tractions see the solid mechanics tutorials. Here, we collect the boundary
         * elements on the bottom and top surfaces, and apply inward tractions - this will have the
         * effect of stretching the tissue in the X-direction.
         */
        std::vector<BoundaryElement<1,2>*> boundary_elems;
        std::vector<c_vector<double,2> > tractions;

        c_vector<double,2> traction;

        for (TetrahedralMesh<2,2>::BoundaryElementIterator iter = mechanics_mesh.GetBoundaryElementIteratorBegin();
             iter != mechanics_mesh.GetBoundaryElementIteratorEnd();
             ++iter)
        {
            if (fabs((*iter)->CalculateCentroid()[1] - 0.0) < 1e-6) // if Y=0
            {
                BoundaryElement<1,2>* p_element = *iter;
                boundary_elems.push_back(p_element);

                traction(0) =  0.0; // kPa, since the contraction model and material law use kPa for stiffnesses
                traction(1) =  1.0; // kPa, since the contraction model and material law use kPa for stiffnesses
                tractions.push_back(traction);
            }
            if (fabs((*iter)->CalculateCentroid()[1] - 0.1) < 1e-6) // if Y=0.1
            {
                BoundaryElement<1,2>* p_element = *iter;
                boundary_elems.push_back(p_element);

                traction(0) =  0.0;
                traction(1) = -1.0;
                tractions.push_back(traction);
            }
        }

        /* Now set up the problem. We will use a compressible approach. */
        ElectroMechanicsProblemDefinition<2> problem_defn(mechanics_mesh);
        problem_defn.SetContractionModel(KERCHOFFS2003,0.01/*contraction model ODE timestep*/);
        problem_defn.SetUseDefaultCardiacMaterialLaw(INCOMPRESSIBLE);
        problem_defn.SetMechanicsSolveTimestep(1.0);
        /* Set the fixed node and traction info. */
        problem_defn.SetFixedNodes(fixed_nodes, fixed_node_locations);
        problem_defn.SetTractionBoundaryConditions(boundary_elems, tractions);

        /* Now say that the deformation should affect the electro-physiology */
        problem_defn.SetDeformationAffectsElectrophysiology(false /*deformation affects conductivity*/, true /*deformation affects cell models*/);

        /* Set the end time, create the problem, and solve */
        HeartConfig::Instance()->SetSimulationDuration(50.0);

        CardiacElectroMechanicsProblem<2,1> problem(INCOMPRESSIBLE,
                                                    MONODOMAIN,
                                                    &electrics_mesh,
                                                    &mechanics_mesh,
                                                    &cell_factory,
                                                    &problem_defn,
                                                    "TestCardiacElectroMechanicsWithMef");
        problem.Solve();

        /* Nothing exciting happens in the simulation as it is currently written. To get some interesting occurring,
         * alter the SAC conductance in the cell model from 0.035 to 0.35 (micro-Siemens).
         * (look for the line `const double g_sac = 0.035` in `NobleVargheseKohlNoble1998WithSac.hpp`).
         *
         * Rerun and visualise as usual, using Cmgui. By visualising the voltage on the deforming mesh, you can see that the
         * voltage gradually increases due to the SAC, since the tissue is stretched, until the threshold is reached
         * and activation occurs.
         *
         * For MEF simulations, we may want to visualise the electrical results on the electrics mesh using
         * Meshalyzer, for example to more easily visualise action potentials. This isn't (and currently
         * can't be) created by `CardiacElectroMechanicsProblem`. We can use a converter as follows
         * to post-process:
         */
        FileFinder test_output_folder("TestCardiacElectroMechanicsWithMef/electrics", RelativeTo::ChasteTestOutput);
        Hdf5ToMeshalyzerConverter<2,2> converter(test_output_folder, "voltage",
                                                 &electrics_mesh, false,
                                                 HeartConfig::Instance()->GetVisualizerOutputPrecision());

        /* Some other notes. If you want to apply time-dependent traction boundary conditions, this is possible by
         * specifying the traction in functional form - see solid mechanics tutorials. Similarly, more natural
         * 'pressure acting on the deformed body' boundary conditions are possible - see below tutorial.
         *
         * '''Robustness:''' Sometimes the nonlinear solver doesn't converge, and will give an error. This can be due to either
         * a non-physical (or not very physical) situation, or just because the current guess is quite far
         * from the solution and the solver can't find the solution (this can occur in nonlinear elasticity
         * problems if the loading is large, for example). Current work in progress is on making the solver
         * more robust, and also on parallelising the solver. One option when a solve fails is to decrease the
         * mechanics timestep.
         */

        /* Ignore the following, it is just to check nothing has changed. */
        Hdf5DataReader reader("TestCardiacElectroMechanicsWithMef/electrics", "voltage");
        unsigned num_timesteps = reader.GetUnlimitedDimensionValues().size();
        Vec voltage = PetscTools::CreateVec(electrics_mesh.GetNumNodes());
        reader.GetVariableOverNodes(voltage, "V", num_timesteps-1);
        ReplicatableVector voltage_repl(voltage);
        for(unsigned i=0; i<voltage_repl.GetSize(); i++)
        {
            TS_ASSERT_DELTA(voltage_repl[i], -81.9080, 1e-3);
        }
        PetscTools::Destroy(voltage);
    }
/* This function is used in the first test */
c_vector<double,2> MyTraction(c_vector<double,2>& rX, double time)
{
    c_vector<double,2> traction = zero_vector<double>(2);
    traction(0) = rX(0);
    return traction;
}
    void TestAssembler2d() throw (Exception)
    {
        QuadraticMesh<2> mesh;
        TrianglesMeshReader<2,2> mesh_reader("mesh/test/data/canonical_triangle_quadratic", 2, 2, false);
        mesh.ConstructFromMeshReader(mesh_reader);

        ContinuumMechanicsProblemDefinition<2> problem_defn(mesh);

        double t1 = 2.6854233;
        double t2 = 3.2574578;

        // for the boundary element on the y=0 surface, create a traction
        std::vector<BoundaryElement<1,2>*> boundary_elems;
        std::vector<c_vector<double,2> > tractions;
        c_vector<double,2> traction;
        traction(0) = t1;
        traction(1) = t2;
        for (TetrahedralMesh<2,2>::BoundaryElementIterator iter
              = mesh.GetBoundaryElementIteratorBegin();
             iter != mesh.GetBoundaryElementIteratorEnd();
             ++iter)
        {
            if (fabs((*iter)->CalculateCentroid()[1])<1e-4)
            {
                BoundaryElement<1,2>* p_element = *iter;
                boundary_elems.push_back(p_element);
                tractions.push_back(traction);
            }
        }
        assert(boundary_elems.size()==1);
        problem_defn.SetTractionBoundaryConditions(boundary_elems, tractions);


        ContinuumMechanicsNeumannBcsAssembler<2> assembler(&mesh, &problem_defn);

        TS_ASSERT_THROWS_THIS(assembler.AssembleVector(), "Vector to be assembled has not been set");
        Vec bad_sized_vec = PetscTools::CreateVec(2);
        assembler.SetVectorToAssemble(bad_sized_vec, true);
        TS_ASSERT_THROWS_THIS(assembler.AssembleVector(), "Vector provided to be assembled has size 2, not expected size of 18 ((dim+1)*num_nodes)");


        Vec vec = PetscTools::CreateVec(3*mesh.GetNumNodes());

        assembler.SetVectorToAssemble(vec, true);
        assembler.AssembleVector();

        ReplicatableVector vec_repl(vec);

        // Note: on a 1d boundary element,  intgl phi_i dx = 1/6 for the bases on the vertices
        // and intgl phi_i dx = 4/6 for the basis at the interior node. (Here the integrals
        // are over the canonical 1d element, [0,1], which is also the physical element for this
        // mesh.

        // node 0 is on the surface, and is a vertex
        TS_ASSERT_DELTA(vec_repl[0], t1/6.0, 1e-8);
        TS_ASSERT_DELTA(vec_repl[1], t2/6.0, 1e-8);

        // node 1 is on the surface, and is a vertex
        TS_ASSERT_DELTA(vec_repl[3], t1/6.0, 1e-8);
        TS_ASSERT_DELTA(vec_repl[4], t2/6.0, 1e-8);

        // nodes 2, 3, 4 are not on the surface
        for(unsigned i=2; i<5; i++)
        {
            TS_ASSERT_DELTA(vec_repl[3*i], 0.0, 1e-8);
            TS_ASSERT_DELTA(vec_repl[3*i], 0.0, 1e-8);
        }

        // node 5 is on the surface, and is an interior node
        TS_ASSERT_DELTA(vec_repl[15], 4*t1/6.0, 1e-8);
        TS_ASSERT_DELTA(vec_repl[16], 4*t2/6.0, 1e-8);


        // the rest of the vector is the pressure block and should be zero.
        TS_ASSERT_DELTA(vec_repl[2], 0.0, 1e-8);
        TS_ASSERT_DELTA(vec_repl[5], 0.0, 1e-8);
        TS_ASSERT_DELTA(vec_repl[8], 0.0, 1e-8);
        TS_ASSERT_DELTA(vec_repl[11], 0.0, 1e-8);
        TS_ASSERT_DELTA(vec_repl[14], 0.0, 1e-8);
        TS_ASSERT_DELTA(vec_repl[17], 0.0, 1e-8);

        PetscTools::Destroy(vec);
        PetscTools::Destroy(bad_sized_vec);
    }
    void TestAssembler3d() throw (Exception)
    {
        QuadraticMesh<3> mesh(1.0, 1.0, 1.0, 1.0);

        ContinuumMechanicsProblemDefinition<3> problem_defn(mesh);

        double t1 = 2.6854233;
        double t2 = 3.2574578;
        double t3 = 4.5342308;

        // for the boundary element on the z=0 surface, create a traction
        std::vector<BoundaryElement<2,3>*> boundary_elems;
        std::vector<c_vector<double,3> > tractions;
        c_vector<double,3> traction;
        traction(0) = t1;
        traction(1) = t2;
        traction(2) = t3;

        for (TetrahedralMesh<3,3>::BoundaryElementIterator iter
              = mesh.GetBoundaryElementIteratorBegin();
             iter != mesh.GetBoundaryElementIteratorEnd();
             ++iter)
        {
            if (fabs((*iter)->CalculateCentroid()[2])<1e-4)
            {
                BoundaryElement<2,3>* p_element = *iter;
                boundary_elems.push_back(p_element);
                tractions.push_back(traction);
            }
        }
        assert(boundary_elems.size()==2);
        problem_defn.SetTractionBoundaryConditions(boundary_elems, tractions);

        Vec vec = PetscTools::CreateVec(4*mesh.GetNumNodes());

        ContinuumMechanicsNeumannBcsAssembler<3> assembler(&mesh, &problem_defn);
        assembler.SetVectorToAssemble(vec, true);
        assembler.AssembleVector();

        ReplicatableVector vec_repl(vec);

        // For boundary elements in 3d - ie for 2d elements - and with QUADRATIC basis functions, we have
        // \intgl_{canonical element} \phi_i dV = 0.0  for i=0,1,2 (ie bases on vertices)
        // and
        // \intgl_{canonical element} \phi_i dV = 1/6  for i=3,4,5 (ie bases on mid-nodes)

        for(unsigned i=0; i<mesh.GetNumNodes(); i++)
        {
            double x = mesh.GetNode(i)->rGetLocation()[0];
            double y = mesh.GetNode(i)->rGetLocation()[1];
            double z = mesh.GetNode(i)->rGetLocation()[2];

            if(fabs(z)<1e-8) // ie if z=0
            {
                if( fabs(x-0.5)<1e-8 || fabs(y-0.5)<1e-8 ) // if x=0.5 or y=0.5
                {
                    unsigned num_surf_elems_contained_in = 1;
                    if( fabs(x+y-1.0)<1e-8 ) // if x=0.5 AND y=0.5
                    {
                        num_surf_elems_contained_in = 2;
                    }

                    // interior node on traction surface
                    TS_ASSERT_DELTA(vec_repl[4*i],   num_surf_elems_contained_in * t1/6.0, 1e-8);
                    TS_ASSERT_DELTA(vec_repl[4*i+1], num_surf_elems_contained_in * t2/6.0, 1e-8);
                    TS_ASSERT_DELTA(vec_repl[4*i+2], num_surf_elems_contained_in * t3/6.0, 1e-8);
                }
                else
                {
                    TS_ASSERT_DELTA(vec_repl[4*i],   0.0, 1e-8);
                    TS_ASSERT_DELTA(vec_repl[4*i+1], 0.0, 1e-8);
                    TS_ASSERT_DELTA(vec_repl[4*i+2], 0.0, 1e-8);
                }
            }
            else
            {
                TS_ASSERT_DELTA(vec_repl[4*i],   0.0, 1e-8);
                TS_ASSERT_DELTA(vec_repl[4*i+1], 0.0, 1e-8);
                TS_ASSERT_DELTA(vec_repl[4*i+2], 0.0, 1e-8);
            }
        }

        for(unsigned i=0; i<mesh.GetNumNodes(); i++)
        {
            TS_ASSERT_DELTA(vec_repl[4*i+3],   0.0, 1e-8);
        }

        PetscTools::Destroy(vec);
    }
Example #9
0
//------------------------------------------------------------------------------
int main( int argc, char * argv[] )
{
    //--------------------------------------------------------------------------
    const unsigned    geomDeg   = 1;
    const unsigned    dim       = 2;
    // degrees of lowest-order TH element
    const unsigned    fieldDegU = 2; 
    const unsigned    fieldDegP = 1;

    const unsigned    tiOrder   = 1;
    typedef  base::time::BDF<tiOrder> MSM;
    
    const base::Shape shape     = base::SimplexShape<dim>::value;
    const base::Shape surfShape = base::SimplexShape<dim-1>::value;

    //--------------------------------------------------------------------------
    if ( argc != 2 ) {
        std::cout << "Usage:  " << argv[0] << " input.dat \n\n";
        return -1;
    }

    const std::string inputFile = boost::lexical_cast<std::string>( argv[1] );

    //--------------------------------------------------------------------------
    std::string meshFile, surfFile;
    double viscosity, density, tolerance, penaltyFactor, stepSize;
    unsigned maxIter, numSteps;
    {    
        //Feed properties parser with the variables to be read
        base::io::PropertiesParser prop;
        prop.registerPropertiesVar( "meshFile",         meshFile );
        prop.registerPropertiesVar( "surfFile",         surfFile );
        prop.registerPropertiesVar( "viscosity",        viscosity );
        prop.registerPropertiesVar( "density",          density );
        prop.registerPropertiesVar( "maxIter",          maxIter );
        prop.registerPropertiesVar( "tolerance",        tolerance );
        prop.registerPropertiesVar( "penaltyFactor",    penaltyFactor );
        prop.registerPropertiesVar( "stepSize",         stepSize );
        prop.registerPropertiesVar( "numSteps",         numSteps );

        // Read variables from the input file
        std::ifstream inp( inputFile.c_str()  );
        VERIFY_MSG( inp.is_open(), "Cannot open input file" );
        prop.readValues( inp );
        inp.close( );

        // Make sure all variables have been found
        if ( not prop.isEverythingRead() ) {
            prop.writeUnread( std::cerr );
            VERIFY_MSG( false, "Could not find above variables" );
        }
    }

    const std::string baseName = base::io::baseName( meshFile, ".smf" );

    //--------------------------------------------------------------------------
    typedef base::Unstructured<shape,geomDeg>     Mesh;

    Mesh mesh;
    {
        std::ifstream smf( meshFile.c_str() );
        VERIFY_MSG( smf.is_open(), "Cannot open mesh file" );
        base::io::smf::readMesh( smf, mesh );
        smf.close();
    }

    //--------------------------------------------------------------------------
    // Surface mesh
    typedef base::Unstructured<surfShape,1,dim>    SurfMesh;

    SurfMesh surfMesh;
    {
        std::ifstream smf( surfFile.c_str() );
        base::io::smf::readMesh( smf, surfMesh );
        smf.close();
    }

    //--------------------------------------------------------------------------
    // Compute the level set data
    typedef base::cut::LevelSet<dim> LevelSet;
    std::vector<LevelSet> levelSet;
    const bool isSigned = true;
    base::cut::bruteForce( mesh, surfMesh, isSigned, levelSet );

    const unsigned kernelDegEstimate = 5;

    //--------------------------------------------------------------------------
    // Make cut cell structure
    typedef base::cut::Cell<shape> Cell;
    std::vector<Cell> cells;
    base::cut::generateCutCells( mesh, levelSet, cells );

    // Quadrature 
    typedef base::cut::Quadrature<kernelDegEstimate,shape> CutQuadrature;
    CutQuadrature quadrature( cells, true );

    // for surface
    typedef base::SurfaceQuadrature<kernelDegEstimate,shape> SurfaceQuadrature;
    SurfaceQuadrature surfaceQuadrature;

    //------------------------------------------------------------------------------
    // Finite element bases
    const unsigned    nHist = MSM::numSteps;
    
    const unsigned    doFSizeU = dim;
    typedef base::fe::Basis<shape,fieldDegU>                FEBasisU;
    typedef base::cut::ScaledField<FEBasisU,doFSizeU,nHist> Velocity;
    Velocity velocity;
    base::dof::generate<FEBasisU>( mesh, velocity );
    
    const unsigned    doFSizeP = 1;
    typedef base::fe::Basis<shape,fieldDegP>                FEBasisP;
    typedef base::cut::ScaledField<FEBasisP,doFSizeP,nHist> Pressure;
    Pressure pressure;
    base::dof::generate<FEBasisP>( mesh, pressure );

    const unsigned    doFSizeS = dim;
    typedef base::fe::Basis<surfShape,1>              FEBasisS;
    typedef base::Field<FEBasisS,doFSizeS>            SurfField;
    SurfField surfVelocity, surfForces;
    base::dof::generate<FEBasisS>( surfMesh, surfVelocity );
    base::dof::generate<FEBasisS>( surfMesh, surfForces   );

    // set initial condition to the identity 
    base::dof::setField( surfMesh, surfVelocity,
                         boost::bind( &surfaceVelocity<dim,
                                      SurfField::DegreeOfFreedom>, _1, _2 ) );


    // boundary datum    
    base::cut::TransferSurfaceDatum<SurfMesh,SurfField,Mesh::Element>
        s2d( surfMesh, surfVelocity, levelSet );
    
    //--------------------------------------------------------------------------
    //  surface mesh
    typedef base::mesh::BoundaryMeshBinder<Mesh>::Type BoundaryMesh;
    BoundaryMesh boundaryMesh, immersedMesh;

    // from boundary
    {
        // identify list of element boundary faces
        base::mesh::MeshBoundary meshBoundary;
        meshBoundary.create( mesh.elementsBegin(), mesh.elementsEnd() );

        // generate a mesh from that list (with a filter)
        base::mesh::generateBoundaryMesh( meshBoundary.begin(),
                                          meshBoundary.end(),
                                          mesh, boundaryMesh,
                                          boost::bind( &boundaryFilter<dim>, _1 ) );

        // make a surface mesh from the implicit surface
        base::cut::generateSurfaceMesh<Mesh,Cell>( mesh, cells, immersedMesh );
    }

    // the composite field with geometry, velocity and pressure
    typedef base::asmb::FieldBinder<Mesh,Velocity,Pressure> Field;
    Field field( mesh, velocity, pressure );

    // define the system blocks (U,U), (U,P), and (P,U)
    typedef Field::TupleBinder<1,1,1>::Type TopLeft;
    typedef Field::TupleBinder<1,2>::Type   TopRight;
    typedef Field::TupleBinder<2,1>::Type   BotLeft;


    std::vector<double> supportsU, supportsP;
    std::size_t numDoFsU = std::distance( velocity.doFsBegin(), velocity.doFsEnd() );
    supportsU.resize( numDoFsU );
    std::size_t numDoFsP = std::distance( pressure.doFsBegin(), pressure.doFsEnd() );
    supportsP.resize( numDoFsP );

    base::cut::supportComputation( mesh, velocity, quadrature, supportsU );
    base::cut::supportComputation( mesh, pressure, quadrature, supportsP );

    velocity.scaleAndTagBasis( supportsU, 1.e-8 );
    pressure.scaleAndTagBasis( supportsP, 1.e-8 ); 
    //velocity.tagBasis( supportsU, 1.e-8 );
    //pressure.tagBasis( supportsP, 1.e-8 ); 

    // Fix one pressure dof
    // Pressure::DoFPtrIter pIter = pressure.doFsBegin();
    // std::advance( pIter, std::distance( pressure.doFsBegin(), pressure.doFsEnd() )/5 );
    // (*pIter) -> constrainValue( 0, 0.0 );

    // Number of DoFs after constraint application!
    numDoFsU =
        base::dof::numberDoFsConsecutively( velocity.doFsBegin(), velocity.doFsEnd() );
    std::cout << "# Number of velocity dofs " << numDoFsU << std::endl;

    numDoFsP =
        base::dof::numberDoFsConsecutively( pressure.doFsBegin(), pressure.doFsEnd(),
            numDoFsU );
    std::cout << "# Number of pressure dofs " << numDoFsP << std::endl;

    // kernels
    typedef fluid::StressDivergence<  TopLeft::Tuple>  StressDivergence;
    typedef fluid::Convection<        TopLeft::Tuple>  Convection;
    typedef fluid::PressureGradient<  TopRight::Tuple> GradP;
    typedef fluid::VelocityDivergence<BotLeft::Tuple>  DivU;

    StressDivergence stressDivergence( viscosity );
    Convection       convection(       density );
    GradP            gradP;
    DivU             divU( true );

    // for surface fields
    typedef base::asmb::SurfaceFieldBinder<BoundaryMesh,Velocity,Pressure> SurfaceFieldBinder;
    typedef SurfaceFieldBinder::TupleBinder<1,1,1>::Type STBUU;
    typedef SurfaceFieldBinder::TupleBinder<1,2  >::Type STBUP;
    SurfaceFieldBinder   boundaryFieldBinder(  boundaryMesh, velocity, pressure );
    SurfaceFieldBinder   immersedFieldBinder(  immersedMesh, velocity, pressure );

    std::ofstream forces( "forces.dat" );

    for ( unsigned step = 0; step < numSteps; step++ ) {

        const double time = step * stepSize;
        const double factor = ( time < 1.0 ? time : 1.0 );
    
        std::cout << step << ":  time=" << time << ", factor=" << factor
                  << "\n";

        //base::dof::clearDoFs( velocity );
        //base::dof::clearDoFs( pressure );
        
        //--------------------------------------------------------------------------
        // Nonlinear iterations
        unsigned iter = 0;
        while( iter < maxIter ) {

            // Create a solver object
            typedef base::solver::Eigen3           Solver;
            Solver solver( numDoFsU + numDoFsP );

            std::cout << "* Iteration " << iter << std::flush;

            // compute inertia terms, d/dt, due to time integration
            base::time::computeInertiaTerms<TopLeft,MSM>( quadrature, solver,
                                                          field, stepSize, step,
                                                          density );
    
            // Compute system matrix
            base::asmb::stiffnessMatrixComputation<TopLeft>( quadrature, solver,
                                                             field, stressDivergence );

            base::asmb::stiffnessMatrixComputation<TopLeft>( quadrature, solver,
                                                             field, convection );

            base::asmb::stiffnessMatrixComputation<TopRight>( quadrature, solver,
                                                              field, gradP );

            base::asmb::stiffnessMatrixComputation<BotLeft>( quadrature, solver,
                                                             field, divU );
            // compute residual forces
            base::asmb::computeResidualForces<TopLeft >( quadrature, solver, field,
                                                         stressDivergence );
            base::asmb::computeResidualForces<TopLeft >( quadrature, solver, field, convection );
            base::asmb::computeResidualForces<TopRight>( quadrature, solver, field, gradP );
            base::asmb::computeResidualForces<BotLeft >( quadrature, solver, field, divU );
        
            // Parameter classes
            base::nitsche::OuterBoundary ob( viscosity );
            base::nitsche::ImmersedBoundary<Cell> ib( viscosity, cells );

            // Penalty method
            base::nitsche::penaltyLHS<STBUU>( surfaceQuadrature, solver,
                                              boundaryFieldBinder, ob, penaltyFactor );
        
            base::nitsche::penaltyRHS<STBUU>( surfaceQuadrature, solver, boundaryFieldBinder, 
                                              boost::bind( &dirichlet<dim>, _1, factor),
                                              ob, penaltyFactor );

            base::nitsche::penaltyLHS<STBUU>( surfaceQuadrature, solver,
                                              immersedFieldBinder, ib, penaltyFactor );
        
            base::nitsche::penaltyRHS2<STBUU>( surfaceQuadrature, solver, immersedFieldBinder,
                                               s2d, ib, penaltyFactor );

            // Nitsche terms
            base::nitsche::primalEnergyLHS<STBUU>( stressDivergence, surfaceQuadrature, solver,
                                                   boundaryFieldBinder, ob );
            base::nitsche::dualEnergyLHS<STBUU>( stressDivergence, surfaceQuadrature, solver,
                                                 boundaryFieldBinder, ob );
            base::nitsche::energyRHS<STBUU>( stressDivergence, surfaceQuadrature, solver,
                                             boundaryFieldBinder,
                                             boost::bind( &dirichlet<dim>, _1, factor),
                                             ob );
        
            base::nitsche::primalEnergyLHS<STBUP>( gradP, surfaceQuadrature, solver,
                                                   boundaryFieldBinder, ob );
            base::nitsche::dualEnergyLHS<STBUP>( gradP, surfaceQuadrature, solver,
                                                 boundaryFieldBinder, ob );
         
            base::nitsche::energyRHS<STBUP>( gradP, surfaceQuadrature, solver,
                                             boundaryFieldBinder,
                                             boost::bind( &dirichlet<dim>, _1, factor), ob );

            base::nitsche::energyResidual<STBUU>( stressDivergence, surfaceQuadrature, solver,
                                                  boundaryFieldBinder, ob );
            
            base::nitsche::energyResidual<STBUP>( gradP, surfaceQuadrature, solver,
                                                  boundaryFieldBinder, ob );

            base::nitsche::primalEnergyLHS<STBUU>( stressDivergence, surfaceQuadrature, solver,
                                                   immersedFieldBinder, ib );
            base::nitsche::dualEnergyLHS<STBUU>( stressDivergence, surfaceQuadrature, solver,
                                                 immersedFieldBinder, ib );

            base::nitsche::energyRHS2<STBUU>( stressDivergence, surfaceQuadrature, solver,
                                              immersedFieldBinder, s2d, ib );
            
            base::nitsche::primalEnergyLHS<STBUP>( gradP, surfaceQuadrature, solver,
                                                   immersedFieldBinder, ib );
            base::nitsche::dualEnergyLHS<STBUP>( gradP, surfaceQuadrature, solver,
                                                 immersedFieldBinder, ib );

            base::nitsche::energyRHS2<STBUP>( gradP, surfaceQuadrature, solver,
                                              immersedFieldBinder, s2d, ib );

            base::nitsche::energyResidual<STBUU>( stressDivergence, surfaceQuadrature, solver,
                                                  immersedFieldBinder, ib );

            base::nitsche::energyResidual<STBUP>( gradP, surfaceQuadrature, solver,
                                                  immersedFieldBinder, ib );
        
            // Finalise assembly
            solver.finishAssembly();

            // check convergence via solver norms
            const double residualNorm = solver.norm();
            std::cout << " |R| = " << residualNorm << std::flush;

            if ( residualNorm < tolerance * viscosity) {
                std::cout << std::endl;
                break;
            }

            // Solve
            solver.superLUSolve();

            // distribute results back to dofs
            base::dof::addToDoFsFromSolver( solver, velocity );
            base::dof::addToDoFsFromSolver( solver, pressure );
            //base::dof::setDoFsFromSolver( solver, pressure );
        
            // check convergence via solver norms
            const double incrementNorm = solver.norm(0, numDoFsU );
            std::cout << " |dU| = " << incrementNorm << std::endl;

            // push history
            base::dof::pushHistory( velocity );
            base::dof::pushHistory( pressure );
        
            if ( incrementNorm < tolerance ) break;

            iter++;

        }

        writeVTKFile( baseName, step, mesh, velocity, pressure, levelSet, viscosity );
        {
            base::Vector<dim>::Type sumOfForces = base::constantVector<dim>( 0. );
            
            typedef Field::TupleBinder<1,2>::Type UP;
            //typedef fluid::Stress<UP::Tuple> Stress;
            //Stress stress( viscosity );
            typedef fluid::Traction<UP::Tuple> Traction;
            Traction traction( viscosity );
                
            base::cut::ComputeSurfaceForces<SurfMesh,SurfField,
                                            SurfaceQuadrature,STBUP::Tuple,Traction>
                computeSurfaceForces( surfMesh, surfForces, surfaceQuadrature, levelSet, traction );

            SurfaceFieldBinder::FieldIterator first = immersedFieldBinder.elementsBegin();
            SurfaceFieldBinder::FieldIterator  last = immersedFieldBinder.elementsEnd();
            for ( ; first != last; ++first ) {
                
                sumOfForces +=
                    computeSurfaceForces( STBUP::makeTuple( *first ) );
                
            }

            writeSurfaceVTKFile( baseName, step, surfMesh, surfVelocity, surfForces );


            std::cout << "  F= " << sumOfForces.transpose() << " \n";

            forces << time << " " << sumOfForces.transpose() << std::endl;;
        }

    }

    forces.close();

    return 0;
}
  void ElasticMembranePressure<PressureType>::element_time_derivative
  ( bool compute_jacobian, AssemblyContext & context )
  {
    unsigned int u_var = this->_disp_vars.u();
    unsigned int v_var = this->_disp_vars.v();
    unsigned int w_var = this->_disp_vars.w();

    const unsigned int n_u_dofs = context.get_dof_indices(u_var).size();

    const std::vector<libMesh::Real> &JxW =
      this->get_fe(context)->get_JxW();

    const std::vector<std::vector<libMesh::Real> >& u_phi =
      this->get_fe(context)->get_phi();

    const MultiphysicsSystem & system = context.get_multiphysics_system();

    unsigned int u_dot_var = system.get_second_order_dot_var(u_var);
    unsigned int v_dot_var = system.get_second_order_dot_var(v_var);
    unsigned int w_dot_var = system.get_second_order_dot_var(w_var);

    libMesh::DenseSubVector<libMesh::Number> &Fu = context.get_elem_residual(u_dot_var);
    libMesh::DenseSubVector<libMesh::Number> &Fv = context.get_elem_residual(v_dot_var);
    libMesh::DenseSubVector<libMesh::Number> &Fw = context.get_elem_residual(w_dot_var);

    libMesh::DenseSubMatrix<libMesh::Number>& Kuv = context.get_elem_jacobian(u_dot_var,v_var);
    libMesh::DenseSubMatrix<libMesh::Number>& Kuw = context.get_elem_jacobian(u_dot_var,w_var);

    libMesh::DenseSubMatrix<libMesh::Number>& Kvu = context.get_elem_jacobian(v_dot_var,u_var);
    libMesh::DenseSubMatrix<libMesh::Number>& Kvw = context.get_elem_jacobian(v_dot_var,w_var);

    libMesh::DenseSubMatrix<libMesh::Number>& Kwu = context.get_elem_jacobian(w_dot_var,u_var);
    libMesh::DenseSubMatrix<libMesh::Number>& Kwv = context.get_elem_jacobian(w_dot_var,v_var);

    unsigned int n_qpoints = context.get_element_qrule().n_points();

    // All shape function gradients are w.r.t. master element coordinates
    const std::vector<std::vector<libMesh::Real> >& dphi_dxi =
      this->get_fe(context)->get_dphidxi();

    const std::vector<std::vector<libMesh::Real> >& dphi_deta =
      this->get_fe(context)->get_dphideta();

    const libMesh::DenseSubVector<libMesh::Number>& u_coeffs = context.get_elem_solution( u_var );
    const libMesh::DenseSubVector<libMesh::Number>& v_coeffs = context.get_elem_solution( v_var );
    const libMesh::DenseSubVector<libMesh::Number>& w_coeffs = context.get_elem_solution( w_var );

    const std::vector<libMesh::RealGradient>& dxdxi  = this->get_fe(context)->get_dxyzdxi();
    const std::vector<libMesh::RealGradient>& dxdeta = this->get_fe(context)->get_dxyzdeta();

    for (unsigned int qp=0; qp != n_qpoints; qp++)
      {
        // sqrt(det(a_cov)), a_cov being the covariant metric tensor of undeformed body
        libMesh::Real sqrt_a = sqrt( dxdxi[qp]*dxdxi[qp]*dxdeta[qp]*dxdeta[qp]
                                     - dxdxi[qp]*dxdeta[qp]*dxdeta[qp]*dxdxi[qp] );

        // Gradients are w.r.t. master element coordinates
        libMesh::Gradient grad_u, grad_v, grad_w;
        for( unsigned int d = 0; d < n_u_dofs; d++ )
          {
            libMesh::RealGradient u_gradphi( dphi_dxi[d][qp], dphi_deta[d][qp] );
            grad_u += u_coeffs(d)*u_gradphi;
            grad_v += v_coeffs(d)*u_gradphi;
            grad_w += w_coeffs(d)*u_gradphi;
          }

        libMesh::RealGradient dudxi( grad_u(0), grad_v(0), grad_w(0) );
        libMesh::RealGradient dudeta( grad_u(1), grad_v(1), grad_w(1) );

        libMesh::RealGradient A_1 = dxdxi[qp] + dudxi;
        libMesh::RealGradient A_2 = dxdeta[qp] + dudeta;

        libMesh::RealGradient A_3 = A_1.cross(A_2);

        // Compute pressure at this quadrature point
        libMesh::Real press = (*_pressure)(context,qp);

        // Small optimization
        libMesh::Real p_over_sa = press/sqrt_a;

        /* The formula here is actually
           P*\sqrt{\frac{A}{a}}*A_3, where A_3 is a unit vector
           But, |A_3| = \sqrt{A} so the normalizing part kills
           the \sqrt{A} in the numerator, so we can leave it out
           and *not* normalize A_3.
        */
        libMesh::RealGradient traction = p_over_sa*A_3;

        for (unsigned int i=0; i != n_u_dofs; i++)
          {
            // Small optimization
            libMesh::Real phi_times_jac = u_phi[i][qp]*JxW[qp];

            Fu(i) -= traction(0)*phi_times_jac;
            Fv(i) -= traction(1)*phi_times_jac;
            Fw(i) -= traction(2)*phi_times_jac;

            if( compute_jacobian )
              {
                for (unsigned int j=0; j != n_u_dofs; j++)
                  {
                    libMesh::RealGradient u_gradphi( dphi_dxi[j][qp], dphi_deta[j][qp] );

                    const libMesh::Real dt0_dv = p_over_sa*(u_gradphi(0)*A_2(2) - A_1(2)*u_gradphi(1));
                    const libMesh::Real dt0_dw = p_over_sa*(A_1(1)*u_gradphi(1) - u_gradphi(0)*A_2(1));

                    const libMesh::Real dt1_du = p_over_sa*(A_1(2)*u_gradphi(1) - u_gradphi(0)*A_2(2));
                    const libMesh::Real dt1_dw = p_over_sa*(u_gradphi(0)*A_2(0) - A_1(0)*u_gradphi(1));

                    const libMesh::Real dt2_du = p_over_sa*(u_gradphi(0)*A_2(1) - A_1(1)*u_gradphi(1));
                    const libMesh::Real dt2_dv = p_over_sa*(A_1(0)*u_gradphi(1) - u_gradphi(0)*A_2(0));

                    Kuv(i,j) -= dt0_dv*phi_times_jac;
                    Kuw(i,j) -= dt0_dw*phi_times_jac;

                    Kvu(i,j) -= dt1_du*phi_times_jac;
                    Kvw(i,j) -= dt1_dw*phi_times_jac;

                    Kwu(i,j) -= dt2_du*phi_times_jac;
                    Kwv(i,j) -= dt2_dv*phi_times_jac;
                  }
              }
          }
      }
  }
    /* == Incompressible deformation: 2D shape hanging under gravity with a balancing traction ==
     *
     * We now repeat the above test but include a traction on the bottom surface (Y=0). We apply this
     * in the inward direction so that is counters (somewhat) the effect of gravity. We also show how stresses
     * and strains can be written to file.
     */
    void TestIncompressibleProblemWithTractions() throw(Exception)
    {
        /* All of this is exactly as above */
        QuadraticMesh<2> mesh;
        mesh.ConstructRegularSlabMesh(0.1 /*stepsize*/, 0.8 /*width*/, 1.0 /*height*/);

        MooneyRivlinMaterialLaw<2> law(1.0);

        c_vector<double,2> body_force;
        body_force(0) =  0.0;
        body_force(1) = -2.0;

        std::vector<unsigned> fixed_nodes = NonlinearElasticityTools<2>::GetNodesByComponentValue(mesh, 1, 1.0);

        /* Now the traction boundary conditions. We need to collect all the boundary elements on the surface which we want to
         * apply non-zero tractions, put them in a `std::vector`, and create a corresponding `std::vector` of the tractions
         * for each of the boundary elements. Note that the each traction is a 2D vector with dimensions of pressure.
         *
         * First, declare the data structures:
         */
        std::vector<BoundaryElement<1,2>*> boundary_elems;
        std::vector<c_vector<double,2> > tractions;
        /* Create a constant traction */
        c_vector<double,2> traction;
        traction(0) = 0;
        traction(1) = 1.0; // this choice of sign corresponds to an inward force (if applied to the bottom surface)
        /* Loop over boundary elements */
        for (TetrahedralMesh<2,2>::BoundaryElementIterator iter = mesh.GetBoundaryElementIteratorBegin();
             iter != mesh.GetBoundaryElementIteratorEnd();
             ++iter)
        {
            /* If the centre of the element has Y value of 0.0, it is on the surface we need */
            if (fabs((*iter)->CalculateCentroid()[1] - 0.0) < 1e-6)
            {
                /* Put the boundary element and the constant traction into the stores. */
                BoundaryElement<1,2>* p_element = *iter;
                boundary_elems.push_back(p_element);
                tractions.push_back(traction);
            }
        }
        /* A quick check */
        assert(boundary_elems.size() == 8u);

        /* Now create the problem definition object, setting the material law, fixed nodes and body force as
         * before (this time not calling `SetDensity()`, so using the default density of 1.0,
         * and also calling a method for setting tractions, which takes in the boundary elements
         * and tractions for each of those elements.
         */
        SolidMechanicsProblemDefinition<2> problem_defn(mesh);
        problem_defn.SetMaterialLaw(INCOMPRESSIBLE,&law);
        problem_defn.SetZeroDisplacementNodes(fixed_nodes);
        problem_defn.SetBodyForce(body_force);
        problem_defn.SetTractionBoundaryConditions(boundary_elems, tractions);

        /* Create solver as before */
        IncompressibleNonlinearElasticitySolver<2> solver(mesh,
                                                          problem_defn,
                                                          "IncompressibleElasticityWithTractionsTutorial");

        /* In this test we also output the stress and strain. For the former, we have to tell the solver to store
         * the stresses that are computed during the solve.
         */
        solver.SetComputeAverageStressPerElementDuringSolve();


        /* Call `Solve()` */
        solver.Solve();

        /* If VTK output is written (discussed above) strains can be visualised. Alternatively, we can create text files
         * for strains and stresses by doing the following.
         *
         * Write the final deformation gradients to file. The i-th line of this file provides the deformation gradient F,
         * written as 'F(0,0) F(0,1) F(1,0) F(1,1)', evaluated at the centroid of the i-th element. The first variable
         * can also be DEFORMATION_TENSOR_C or LAGRANGE_STRAIN_E to write C or E. The second parameter is the file name.
         */
        solver.WriteCurrentStrains(DEFORMATION_GRADIENT_F,"deformation_grad");

        /* Since we called `SetComputeAverageStressPerElementDuringSolve`, we can write the stresses to file too. However,
         * note that for each element this is not the stress evaluated at the centroid, but the mean average of the stresses
         * evaluated at the quadrature points - for technical cardiac electromechanics reasons, it is difficult to
         * define the stress at non-quadrature points.
         */
        solver.WriteCurrentAverageElementStresses("2nd_PK_stress");


        /* Another quick check */
        TS_ASSERT_EQUALS(solver.GetNumNewtonIterations(), 4u);

        /* Visualise as before by going to the output directory and doing
         * `x=load('solution.nodes'); plot(x(:,1),x(:,2),'m*')` in Matlab/octave, or by using Cmgui.
         * The effect of the traction should be clear (especially when compared to
         * the results of the first test).
         *
         * Create Cmgui output
         */
        solver.CreateCmguiOutput();

        /* This is just to check that nothing has been accidentally changed in this test */
        TS_ASSERT_DELTA(solver.rGetDeformedPosition()[8](0), 0.8561, 1e-3);
        TS_ASSERT_DELTA(solver.rGetDeformedPosition()[8](1), 0.0310, 1e-3);
    }
    static c_vector<double,3> GetTraction(c_vector<double,3>& rX, double t)
    {
        c_vector<double,3> traction = zero_vector<double>(3);

        double lam1 = 1+a*rX(0);
        double lam2 = 1+b*rX(1);

        double invlam1 = 1.0/lam1;
        double invlam2 = 1.0/lam2;

        double Z = rX(2);

        if ( fabs(rX(0)-1)<1e-6 )
        {
            traction(0) =  lam1 - invlam1;
            traction(1) =  0.0;
            traction(2) =  -a*Z*invlam1*invlam1*invlam2;
        }
        else if ( fabs(rX(1)-0)<1e-6 )
        {
            traction(0) =  0.0;
            traction(1) =  0.0;
            traction(2) =  b*Z*invlam1;
        }
        else if ( fabs(rX(1)-1)<1e-6 )
        {
            traction(0) =  0.0;
            traction(1) =  lam2 - invlam2;
            traction(2) =  -b*Z*invlam2*invlam2*invlam1;
        }
        else if ( fabs(rX(2)-0)<1e-6 )
        {
            traction(0) =  0.0;
            traction(1) =  0.0;
            traction(2) =  lam1*lam2 - invlam1*invlam2;
        }
        else if ( fabs(rX(2)-1)<1e-6 )
        {
            traction(0) =  -a*invlam1*invlam1;
            traction(1) =  -b*invlam2*invlam2;
            traction(2) =  invlam1*invlam2 - lam1*lam2;
        }
        else
        {
            NEVER_REACHED;
        }
        return 2*c1*traction;
    }
Example #13
0
void main(){
int gdriver = EGA, gmode = EGAHI, errorcode;
initgraph(&gdriver, &gmode, "c:\\tc\\bgi");
bk(); travel(); gravitas();
tvar=0;
m1c=m2c=adc=chdc=0;
signup_traction();

while(ch!=27)
{
if(kbhit())
{
ch=getch();
if(ch==77) {way(1);}
if(ch==75) {way(0);}
if(ch==80) {menu1();setcolor(6);settextstyle(2,0,4);
outtextxy(68,180,"<-");break;}
}}
flag1:
city();
m1c=0;
while(ch!=27)
{
gravitas();
if(kbhit())
{
ch=getch();

if(ch==80 && m1c<=15)                         //i city
{menu1();city();++m1c;ibar();tarrow(m1c);mcounter(m1c);}

if(ch==72 && m1c>=1 && m1c<=15)
{menu1();city();m1c--;ibar();tarrow(m1c);mcounter(m1c);}

if(ch==80 && m1c>=16 && m1c<=33)                 //2 city
{menu1();city2();m1c++;ibar();tarrow(m1c);mcounter(m1c);}

if(ch==72 && m1c>=16 && m1c<=33)
{menu1();city2();m1c--;ibar();tarrow(m1c);mcounter(m1c);}

if(ch==80 && m1c>=34 && m1c<=51)                 //3 city
{menu1();city3();m1c++;ibar();tarrow(m1c);mcounter(m1c);}

if(ch==72 && m1c>=34 && m1c<=51)
{menu1();city3();m1c--;ibar();tarrow(m1c);mcounter(m1c);}

if(ch==80 && m1c>=52 && m1c<56)                //4 city
{menu1();city4();m1c++;ibar();tarrow(m1c);mcounter(m1c);}

if(ch==72 && m1c>=52 && m1c<=56)
{menu1();city4();m1c--;ibar();tarrow(m1c);mcounter(m1c);}

if(ch==13)
{from=m1c; bk(); travel(); mcounter(m1c);from=m1c;if(tvar)tmcounter(m2c);break;}

if(ch==77) { bk();travel();menu2();tcity();mcounter(m1c);from=m1c;menu2();break;}
}}

//flag2:
m2c=0;
while(ch!=27)
{
gravitas();
if(kbhit())
{
ch=getch();

if(ch==80 && m2c<=15)                         //i city
{menu2();tcity();++m2c;tbar();arrow(m2c);tmcounter(m2c);}

if(ch==72 && m2c>=1 && m2c<=15)
{menu2();tcity();m2c--;tbar();arrow(m2c);tmcounter(m2c);}

if(ch==80 && m2c>=16 && m2c<=33)                 //2 city
{menu2();tcity2();m2c++;tbar();arrow(m2c);tmcounter(m2c);}

if(ch==72 && m2c>=16 && m2c<=33)
{menu2();tcity2();m2c--;tbar();arrow(m2c);tmcounter(m2c);}

if(ch==80 && m2c>=34 && m2c<=51)                 //3 city
{menu2();tcity3();m2c++;tbar();arrow(m2c);tmcounter(m2c);}

if(ch==72 && m2c>=34 && m2c<=51)
{menu2();tcity3();m2c--;tbar();arrow(m2c);tmcounter(m2c);}

if(ch==80 && m2c>=52 && m2c<56)                //4 city
{menu2();tcity4();m2c++;tbar();arrow(m2c);tmcounter(m2c);}

if(ch==72 && m2c>=52 && m2c<=56)
{menu2();tcity4();m2c--;tbar();arrow(m2c);tmcounter(m2c);}

if(ch==13)
{to=m2c; bk(); travel(); tvar=1;tmcounter(m2c);to=m2c;mcounter(m1c);break;}

if(ch==75)
{bk();travel(); to =m2c; tvar=1; tmcounter(m2c);to=m2c;menu1(); //goto flag1;
break;}

}
}

while(ch!=27)
{
gravitas();
if(kbhit())
{
ch=getch();
if(ch==80 && adc<10)
{admenu();adult();  adc++; adarrow(adc); adcounter(adc);}
if(ch==72 && adc>0)
{admenu();adult(); adc--; adarrow(adc);adcounter(adc);}
if(ch==77)
{adno=adc;chmenu();bk(); travel();tmcounter(m2c);mcounter(m1c);adcounter(adc);break;}
if(ch==13)
{adno=adc;bk(); travel();tmcounter(m2c);mcounter(m1c);adcounter(adc);break;}
}}

while(ch!=27)
{
gravitas();
if(kbhit())
{
ch=getch();
if(ch==80 && chdc<10)
{chmenu();child(); chdc++; charrow(chdc); chcounter(chdc);}
if(ch==72 && chdc>0)
{chmenu();child(); chdc--; charrow(chdc);chcounter(chdc);}
if(ch==77)
{chno=chdc;chmenu();bk(); travel();tmcounter(m2c);mcounter(m1c);adcounter(adc);chcounter(chdc); break;}
if(ch==13)
{chno=chdc;bk(); travel();tmcounter(m2c);mcounter(m1c);adcounter(adc);chcounter(chdc); break;}
}}

while(ch!=27)
{ gravitas();
if(kbhit())
{
ch=getch();
if(ch==80 && inc<10)
{inmenu();infant(); inc++; inarrow(inc); incounter(inc);}
if(ch==72 && inc>0)
{inmenu();infant(); inc--; inarrow(inc);incounter(inc);}
if(ch==77)
{inno=inc;inmenu();bk(); travel();tmcounter(m2c);mcounter(m1c);adcounter(adc);chcounter(chdc);incounter(inc); break;}
if(ch==13)
{inno=chdc;bk(); travel();tmcounter(m2c);mcounter(m1c);adcounter(adc);chcounter(chdc);incounter(inc); break;}
}}

while(ch!=27)
{
gravitas();
if(kbhit())
{
ch=getch();
if(ch==77) {ecob(1);suit=1;}
if(ch==75) {ecob(0);suit=0;}
if(ch==13) {break;}
}
}

setcolor(1);settextstyle(2,0,4);
ch=0;
while(ch!=13)
{
if(kbhit())
{da+=8;
ch=getch();
if(isalnum(ch) && da<=95)
{sprintf(dater,"%c",ch);
outtextxy(da,272,dater);}

if(ch==8 && da>=45 && da<=180)
{da=da-8;
setfillstyle(1,15);  bar(da,272,da+8,285);
da=da-8;}
}}

if(suit==0)flight(to);
if(suit==1)bflight(to);
traction();
secure();
money_transfer();

getch();
closegraph();}
Example #14
0
  void ElasticMembraneConstantPressure::element_time_derivative( bool compute_jacobian,
                                                                 AssemblyContext& context,
                                                                 CachedValues& /*cache*/ )
  {
    const unsigned int n_u_dofs = context.get_dof_indices(_disp_vars.u()).size();

    const std::vector<libMesh::Real> &JxW =
      this->get_fe(context)->get_JxW();

    const std::vector<std::vector<libMesh::Real> >& u_phi =
      this->get_fe(context)->get_phi();

    libMesh::DenseSubVector<libMesh::Number> &Fu = context.get_elem_residual(_disp_vars.u());
    libMesh::DenseSubVector<libMesh::Number> &Fv = context.get_elem_residual(_disp_vars.v());
    libMesh::DenseSubVector<libMesh::Number> &Fw = context.get_elem_residual(_disp_vars.w());

    libMesh::DenseSubMatrix<libMesh::Number>& Kuv = context.get_elem_jacobian(_disp_vars.u(),_disp_vars.v());
    libMesh::DenseSubMatrix<libMesh::Number>& Kuw = context.get_elem_jacobian(_disp_vars.u(),_disp_vars.w());

    libMesh::DenseSubMatrix<libMesh::Number>& Kvu = context.get_elem_jacobian(_disp_vars.v(),_disp_vars.u());
    libMesh::DenseSubMatrix<libMesh::Number>& Kvw = context.get_elem_jacobian(_disp_vars.v(),_disp_vars.w());

    libMesh::DenseSubMatrix<libMesh::Number>& Kwu = context.get_elem_jacobian(_disp_vars.w(),_disp_vars.u());
    libMesh::DenseSubMatrix<libMesh::Number>& Kwv = context.get_elem_jacobian(_disp_vars.w(),_disp_vars.v());

    unsigned int n_qpoints = context.get_element_qrule().n_points();

    // All shape function gradients are w.r.t. master element coordinates
    const std::vector<std::vector<libMesh::Real> >& dphi_dxi =
      this->get_fe(context)->get_dphidxi();

    const std::vector<std::vector<libMesh::Real> >& dphi_deta =
      this->get_fe(context)->get_dphideta();

    const libMesh::DenseSubVector<libMesh::Number>& u_coeffs = context.get_elem_solution( _disp_vars.u() );
    const libMesh::DenseSubVector<libMesh::Number>& v_coeffs = context.get_elem_solution( _disp_vars.v() );
    const libMesh::DenseSubVector<libMesh::Number>& w_coeffs = context.get_elem_solution( _disp_vars.w() );

    const std::vector<libMesh::RealGradient>& dxdxi  = this->get_fe(context)->get_dxyzdxi();
    const std::vector<libMesh::RealGradient>& dxdeta = this->get_fe(context)->get_dxyzdeta();

    for (unsigned int qp=0; qp != n_qpoints; qp++)
      {
        // sqrt(det(a_cov)), a_cov being the covariant metric tensor of undeformed body
        libMesh::Real sqrt_a = sqrt( dxdxi[qp]*dxdxi[qp]*dxdeta[qp]*dxdeta[qp]
                                     - dxdxi[qp]*dxdeta[qp]*dxdeta[qp]*dxdxi[qp] );

        // Gradients are w.r.t. master element coordinates
        libMesh::Gradient grad_u, grad_v, grad_w;
        for( unsigned int d = 0; d < n_u_dofs; d++ )
          {
            libMesh::RealGradient u_gradphi( dphi_dxi[d][qp], dphi_deta[d][qp] );
            grad_u += u_coeffs(d)*u_gradphi;
            grad_v += v_coeffs(d)*u_gradphi;
            grad_w += w_coeffs(d)*u_gradphi;
          }

        libMesh::RealGradient dudxi( grad_u(0), grad_v(0), grad_w(0) );
        libMesh::RealGradient dudeta( grad_u(1), grad_v(1), grad_w(1) );

        libMesh::RealGradient A_1 = dxdxi[qp] + dudxi;
        libMesh::RealGradient A_2 = dxdeta[qp] + dudeta;

        libMesh::RealGradient A_3 = A_1.cross(A_2);

        /* The formula here is actually
           P*\sqrt{\frac{A}{a}}*A_3, where A_3 is a unit vector
           But, |A_3| = \sqrt{A} so the normalizing part kills
           the \sqrt{A} in the numerator, so we can leave it out
           and *not* normalize A_3.
         */
        libMesh::RealGradient traction = _pressure/sqrt_a*A_3;

        libMesh::Real jac = JxW[qp];

        for (unsigned int i=0; i != n_u_dofs; i++)
	  {
            Fu(i) -= traction(0)*u_phi[i][qp]*jac;

            Fv(i) -= traction(1)*u_phi[i][qp]*jac;

            Fw(i) -= traction(2)*u_phi[i][qp]*jac;

            if( compute_jacobian )
              {
                for (unsigned int j=0; j != n_u_dofs; j++)
                  {
                    libMesh::RealGradient u_gradphi( dphi_dxi[j][qp], dphi_deta[j][qp] );

                    const libMesh::Real dt0_dv = _pressure/sqrt_a*(u_gradphi(0)*A_2(2) - A_1(2)*u_gradphi(1));
                    const libMesh::Real dt0_dw = _pressure/sqrt_a*(A_1(1)*u_gradphi(1) - u_gradphi(0)*A_2(1));

                    const libMesh::Real dt1_du = _pressure/sqrt_a*(A_1(2)*u_gradphi(1) - u_gradphi(0)*A_2(2));
                    const libMesh::Real dt1_dw = _pressure/sqrt_a*(u_gradphi(0)*A_2(0) - A_1(0)*u_gradphi(1));

                    const libMesh::Real dt2_du = _pressure/sqrt_a*(u_gradphi(0)*A_2(1) - A_1(1)*u_gradphi(1));
                    const libMesh::Real dt2_dv = _pressure/sqrt_a*(A_1(0)*u_gradphi(1) - u_gradphi(0)*A_2(0));

                    Kuv(i,j) -= dt0_dv*u_phi[i][qp]*jac;
                    Kuw(i,j) -= dt0_dw*u_phi[i][qp]*jac;

                    Kvu(i,j) -= dt1_du*u_phi[i][qp]*jac;
                    Kvw(i,j) -= dt1_dw*u_phi[i][qp]*jac;

                    Kwu(i,j) -= dt2_du*u_phi[i][qp]*jac;
                    Kwv(i,j) -= dt2_dv*u_phi[i][qp]*jac;
                  }
              }
          }
      }

    return;
  }