/**
     *  Solve the Field-Noyes system.
     *  This is a stiff ODE so Runge-Kutta won't work - program hangs if
     *  end time > 0.01 and variables go out of bounds.
     *  Can be solved ok with backward Euler.
     */
    void TestFieldNoyesReactionSystem()
    {
        FieldNoyesReactionSystem ode_system;
        RungeKutta4IvpOdeSolver rk4_solver;
        OdeSolution ode_solution;
        std::vector<double> ode_state_variables = ode_system.GetInitialConditions();

        // note small end time
        ode_solution = rk4_solver.Solve(&ode_system, ode_state_variables, 0.0, 0.01, 0.001, 0.001);

        int last = ode_solution.GetNumberOfTimeSteps();
        for (int i=0; i<=last; i++)
        {
            double x = ode_solution.rGetSolutions()[i][0];
            TS_ASSERT_LESS_THAN(x, 9.7e3);
            TS_ASSERT_LESS_THAN(0.99, x);
        }

        BackwardEulerIvpOdeSolver backward_euler_solver(ode_system.GetNumberOfStateVariables());
        OdeSolution ode_solution2;
        std::vector<double> ode_state_variables2 = ode_system.GetInitialConditions();
        ode_solution2 = backward_euler_solver.Solve(&ode_system, ode_state_variables2, 0.0, 0.1, 0.001, 0.001);

        last = ode_solution2.GetNumberOfTimeSteps();
        for (int i=0; i<=last; i++)
        {
            double x = ode_solution2.rGetSolutions()[i][0];
            TS_ASSERT_LESS_THAN(x, 9.7e3);
            TS_ASSERT_LESS_THAN(0.99, x);
        }
    }
Example #2
0
  void compare_interval_in_range(struct timeval start, struct timeval finish,
				 suseconds_t tmin, suseconds_t tmax) {
    time_t sec = finish.tv_sec - start.tv_sec;
    suseconds_t actual = sec * 1000000 - start.tv_usec + finish.tv_usec;
    TS_ASSERT_LESS_THAN(tmin, actual);
    TS_ASSERT_LESS_THAN(actual,tmax);
  }
    void TestBackwardEulerSystemOf3EquationsWithEvents()
    {
        OdeThirdOrderWithEvents ode_system_with_events;

        double h_value = 0.01;

        // Euler solver solution worked out
        BackwardEulerIvpOdeSolver backward_euler_solver(ode_system_with_events.GetNumberOfStateVariables());
        OdeSolution solutions;

        std::vector<double> state_variables = ode_system_with_events.GetInitialConditions();
        solutions = backward_euler_solver.Solve(&ode_system_with_events, state_variables, 0.0, 2.0, h_value, h_value);
        unsigned last = solutions.GetNumberOfTimeSteps();

        // Final time should be pi/6 (?)
        TS_ASSERT_DELTA( solutions.rGetTimes()[last], 0.5236, 0.01);

        // Penultimate y0 should be greater than -0.5
        TS_ASSERT_LESS_THAN(-0.5,solutions.rGetSolutions()[last-1][0]);

        // Final y0 should be less than -0.5
        TS_ASSERT_LESS_THAN( solutions.rGetSolutions()[last][0], -0.5);

        // Solver should correctly state the stopping event occurred
        TS_ASSERT_EQUALS(backward_euler_solver.StoppingEventOccurred(), true);
    }
  // Test a given solver on an ODE which has a stopping event defined
  void MyTestSolverOnOdesWithEvents(AbstractIvpOdeSolver& rSolver)
  {
        // ODE which has solution y0 = cos(t), and stopping event y0<0,
        // ie should stop when t = pi/2;
        OdeSecondOrderWithEvents ode_with_events;

        OdeSolution solutions;
        std::vector<double> state_variables =
            ode_with_events.GetInitialConditions();
        solutions = rSolver.Solve(&ode_with_events, state_variables, 0.0, 2.0,
            0.001, 0.001);

        unsigned num_timesteps = solutions.GetNumberOfTimeSteps();

        // Final time should be around pi/2
        TS_ASSERT_DELTA( solutions.rGetTimes()[num_timesteps], M_PI_2, 0.01);

        // Penultimate y0 should be greater than zero
        TS_ASSERT_LESS_THAN( 0, solutions.rGetSolutions()[num_timesteps-1][0]);

        // Final y0 should be less than zero
        TS_ASSERT_LESS_THAN( solutions.rGetSolutions()[num_timesteps][0], 0);

        // Solver should correctly state the stopping event occurred
        TS_ASSERT_EQUALS(rSolver.StoppingEventOccurred(), true);

        // This is to cover the exception when a stopping event occurs before the first timestep.
        TS_ASSERT_THROWS_ANYTHING(rSolver.Solve(&ode_with_events, state_variables, 2.0, 3.0, 0.001));

        ///////////////////////////////////////////////
        // Repeat with sampling time larger than dt
        ///////////////////////////////////////////////

        state_variables = ode_with_events.GetInitialConditions();
        solutions = rSolver.Solve(&ode_with_events, state_variables, 0.0, 2.0,
            0.001, 0.01);

        num_timesteps = solutions.GetNumberOfTimeSteps();

        // Final time should be around pi/2
        TS_ASSERT_DELTA( solutions.rGetTimes()[num_timesteps], M_PI_2, 0.01);

        // Penultimate y0 should be greater than zero
        TS_ASSERT_LESS_THAN( 0, solutions.rGetSolutions()[num_timesteps-1][0]);

        // Final y0 should be less than zero
        TS_ASSERT_LESS_THAN( solutions.rGetSolutions()[num_timesteps][0], 0);

        // Solver should correctly state the stopping event occurred
        TS_ASSERT_EQUALS(rSolver.StoppingEventOccurred(), true);

        // Cover the check event isn't initially true exception
        std::vector<double> bad_init_cond;
        bad_init_cond.push_back(-1); //y0 < 0 so stopping event true
        bad_init_cond.push_back(0.0);
        TS_ASSERT_THROWS_ANYTHING(rSolver.Solve(&ode_with_events, bad_init_cond, 0.0, 2.0, 0.001, 0.01));
    }
    void TestWithCoarseSlightlyOutsideFine() throw(Exception)
    {
        // Fine mesh is has h=0.1, on unit cube (so 6000 elements)
        TetrahedralMesh<3,3> fine_mesh;
        fine_mesh.ConstructRegularSlabMesh(0.1, 1.0,1.0,1.0);

        // Coarse mesh is slightly bigger than in previous test
        QuadraticMesh<3> coarse_mesh(1.0, 1.0, 1.0, 1.0); // xmax > 1.0
        coarse_mesh.Scale(1.03, 1.0, 1.0);

        FineCoarseMeshPair<3> mesh_pair(fine_mesh,coarse_mesh);

        GaussianQuadratureRule<3> quad_rule(3);

        // Need to call SetUpBoxesOnFineMesh first
        TS_ASSERT_THROWS_CONTAINS(mesh_pair.ComputeFineElementsAndWeightsForCoarseQuadPoints(quad_rule, true), "Call");

        mesh_pair.SetUpBoxesOnFineMesh(0.3);
        TS_ASSERT_EQUALS(mesh_pair.mpFineMeshBoxCollection->GetNumBoxes(), 4*4*4u);

        mesh_pair.ComputeFineElementsAndWeightsForCoarseQuadPoints(quad_rule, true);

        TS_ASSERT_EQUALS(mesh_pair.mNotInMesh.size(), 2u); // hardcoded
        TS_ASSERT_EQUALS(mesh_pair.mNotInMeshNearestElementWeights.size(), 2u);

        TS_ASSERT_EQUALS(mesh_pair.rGetElementsAndWeights().size(), 6*8u);

        for (unsigned i=0; i<mesh_pair.rGetElementsAndWeights().size(); i++)
        {
            TS_ASSERT_LESS_THAN(mesh_pair.rGetElementsAndWeights()[i].ElementNum, fine_mesh.GetNumElements());

            // comment out this test as now some of the weights are negative/greater than one
            //for (unsigned j=0; j<4; j++)
            //{
            //    TS_ASSERT_LESS_THAN(-1e14, mesh_pair.rGetElementsAndWeights()[i].Weights(j));
            //    TS_ASSERT_LESS_THAN(mesh_pair.rGetElementsAndWeights()[i].Weights(j), 1.0+1e-14);
            //}
        }

        /*
         * For each quadrature point that was not found in the fine mesh, check
         * that its x-value is greater than one - this is the only way it could
         * be outside the fine mesh.
         */
        QuadraturePointsGroup<3> quad_point_posns(coarse_mesh, quad_rule);
        for (unsigned i=0; i<mesh_pair.mNotInMesh.size(); i++)
        {
            double x = quad_point_posns.rGet(mesh_pair.mNotInMesh[i])(0);
            TS_ASSERT_LESS_THAN(1.0, x);
        }

        mesh_pair.PrintStatistics();

        TS_ASSERT_EQUALS( Warnings::Instance()->GetNumWarnings(), 1u);
        Warnings::Instance()->QuietDestroy();
    }
    /**
     * Test for Tyson & Novak self-cycling cells without having their
     * initial conditions reset. When using CVODE, the cell-cycle model
     * resets itself by halving the mass of the cell.
     * When not using CVODE, the cell-cycle model resets its initial
     * conditions, since the oscillatory solution computed using the Chaste
     * ODE solver is not stable.
     */
    void TestTysonNovakCellCycleModelSolver() throw(Exception)
    {
        // Set up simulation time
        unsigned num_timesteps = 100000;
        double standard_divide_time = 75.19/60.0;
        SimulationTime::Instance()->SetEndTimeAndNumberOfTimeSteps(100.1*standard_divide_time, num_timesteps);

        // Create cell-cycle model and associated cell
        TysonNovakCellCycleModel* p_repeating_cell_model = new TysonNovakCellCycleModel;

        MAKE_PTR(ApcOneHitCellMutationState, p_mutation);
        MAKE_PTR(StemCellProliferativeType, p_stem_type);

        CellPtr p_tyson_novak_cell(new Cell(p_mutation, p_repeating_cell_model));
        p_tyson_novak_cell->SetCellProliferativeType(p_stem_type);
        p_tyson_novak_cell->InitialiseCellCycleModel();

        // Run through the cell-cycle model for a certain duration
        // and test how many times it has stopped for division
        unsigned num_divisions = 0;
        for (unsigned i=0; i<num_timesteps; i++)
        {
            SimulationTime::Instance()->IncrementTimeOneStep();
            bool result = p_repeating_cell_model->ReadyToDivide();
//                std::vector<double> proteins = p_repeating_cell_model->GetProteinConcentrations();
//                out << SimulationTime::Instance()->GetTime() << "\t";
//                for (unsigned j=0; j<proteins.size(); j++)
//                {
//                    out << proteins[j] << "\t";
//                }
//                out << "\n" << std::flush;

            if (result)
            {
                p_repeating_cell_model->ResetForDivision();
                p_repeating_cell_model->SetBirthTime(SimulationTime::Instance()->GetTime());
                num_divisions++;
            }
        }
        TS_ASSERT_LESS_THAN(num_divisions, 102u);
        TS_ASSERT_LESS_THAN(99u, num_divisions);
//            out.close();
        /*
         * Matlab code for plotting the output commented above:
         * cdchaste
         * data = load('TN_output.txt');
         * figure
         * for i=1:6
         *   subplot(3,2,i)
         *   plot(data(:,1),data(:,1+i))
         * end
         */
    }
    void TestImposeBoundaryConditionWithNoWntButWithJiggling() throw(Exception)
    {
        // Create a cell population
        CylindricalHoneycombMeshGenerator generator(4, 4, 0, 1.0);
        Cylindrical2dMesh* p_mesh = generator.GetCylindricalMesh();
        std::vector<unsigned> location_indices = generator.GetCellLocationIndices();

        std::vector<CellPtr> cells;
        MAKE_PTR(TransitCellProliferativeType, p_transit_type);
        CryptCellsGenerator<FixedDurationGenerationBasedCellCycleModel> cells_generator;
        cells_generator.Generate(cells, p_mesh, std::vector<unsigned>(), true);

        MeshBasedCellPopulationWithGhostNodes<2> crypt(*p_mesh, cells, location_indices);

        // Store the node locations
        std::map<Node<2>*, c_vector<double, 2> > node_locations_before;
        for (unsigned node_index=0; node_index<p_mesh->GetNumNodes(); node_index++)
        {
            node_locations_before[crypt.GetNode(node_index)] = crypt.GetNode(node_index)->rGetLocation();
        }

        // Move the first cell (which should be on y=0, and is a stem cell) down a bit
        AbstractCellPopulation<2>::Iterator cell_iter = crypt.Begin();
        crypt.GetNode(0)->rGetModifiableLocation()[1] = -0.1;

        // Also move the second cell (which should be on y=0, and we make a transit cell)
        ++cell_iter;
        TS_ASSERT_EQUALS(cell_iter->GetCellProliferativeType()->IsType<StemCellProliferativeType>(), true);
        cell_iter->SetCellProliferativeType(p_transit_type);
        TS_ASSERT_EQUALS(cell_iter->GetCellProliferativeType()->IsType<TransitCellProliferativeType>(), true);
        TS_ASSERT_DELTA(crypt.GetLocationOfCellCentre(*cell_iter)[1], 0.0, 1e-6);
        crypt.GetNode(1)->rGetModifiableLocation()[1] = -0.1;
        TS_ASSERT_LESS_THAN(crypt.GetLocationOfCellCentre(*cell_iter)[1], 0.0);

        // Create a boundary condition object
        CryptSimulationBoundaryCondition<2> boundary_condition(&crypt);
        boundary_condition.SetUseJiggledBottomCells(true);

        // Impose the boundary condition without a Wnt stimulus but with jiggled bottom cells
        boundary_condition.ImposeBoundaryCondition(node_locations_before);

        /*
         * The first cell should have been pulled up to y=0 since it is a stem cell and
         * there is no Wnt stimulus. It should then be unaffected by the jiggling. The
         * second cell should not have been pulled up since it is a stem cell, but should
         * then have been moved to above y=0 by the jiggling.
         */
        AbstractCellPopulation<2>::Iterator cell_iter2 = crypt.Begin();
        TS_ASSERT_DELTA(0.0, crypt.GetLocationOfCellCentre(*cell_iter2)[1], 1e-3);
        ++cell_iter2;
        TS_ASSERT_LESS_THAN(0.0, crypt.GetLocationOfCellCentre(*cell_iter2)[1]);
    }
    /*
     * Test when calling ComputeFineElementsAndWeightsForCoarseQuadPoints()
     * in non-safe mode, but using the default value of box width. It is
     * difficult to get the class to run incorrectly (ie fail without an
     * assertion failing) in non-safe mode (ie we can't just specify boxes
     * that are too small), so we just test we get the same results as in
     * safe mode.
     */
    void TestNonSafeMode() throw(Exception)
    {
        // Fine mesh is has h=0.1, on unit cube (so 6000 elements)
        TetrahedralMesh<3,3> fine_mesh;
        fine_mesh.ConstructRegularSlabMesh(0.1, 1.0, 1.0, 1.0);

        QuadraticMesh<3> coarse_mesh(1.0, 1.0, 1.0, 1.0); // xmax > 1.0
        coarse_mesh.Scale(1.03, 1.0, 1.0);

        FineCoarseMeshPair<3> mesh_pair(fine_mesh,coarse_mesh);
        GaussianQuadratureRule<3> quad_rule(3);

        // Call SetUpBoxesOnFineMesh() without providing a width
        mesh_pair.SetUpBoxesOnFineMesh();

        /*
         * Whereas before 4 by 4 by 4 boxes were explicitly chosen, here it
         * has been determined that 6 by 6 by 6 are needed.
         */
        TS_ASSERT_EQUALS(mesh_pair.mpFineMeshBoxCollection->GetNumBoxes(), 6*6*6u);

        mesh_pair.ComputeFineElementsAndWeightsForCoarseQuadPoints(quad_rule, false /* non-safe mode*/);

        TS_ASSERT_EQUALS(mesh_pair.mNotInMesh.size(), 2u); // hardcoded
        TS_ASSERT_EQUALS(mesh_pair.mNotInMeshNearestElementWeights.size(), 2u);
        TS_ASSERT_EQUALS(mesh_pair.rGetElementsAndWeights().size(), 6*8u);

        for (unsigned i=0; i<mesh_pair.rGetElementsAndWeights().size(); i++)
        {
            TS_ASSERT_LESS_THAN(mesh_pair.rGetElementsAndWeights()[i].ElementNum, fine_mesh.GetNumElements());
        }

        /*
         * For each quadrature point that was not found in the fine mesh, check
         * that its x-value is greater than one - this is the only way it could
         * be outside the fine mesh.
         */
        QuadraturePointsGroup<3> quad_point_posns(coarse_mesh, quad_rule);
        for (unsigned i=0; i<mesh_pair.mNotInMesh.size(); i++)
        {
            double x = quad_point_posns.rGet(mesh_pair.mNotInMesh[i])(0);
            TS_ASSERT_LESS_THAN(1.0, x);
        }

        mesh_pair.PrintStatistics();

        TS_ASSERT_EQUALS( Warnings::Instance()->GetNumWarnings(), 1u);
        Warnings::Instance()->QuietDestroy();
    }
    void TestGetLocationOfCellCentre() throw (Exception)
    {
        // Create a Potts-based cell population
        PottsMeshGenerator<2> generator(4, 2, 2, 4, 2, 2);
        PottsMesh<2>* p_mesh = generator.GetMesh();

        std::vector<CellPtr> cells;
        CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 2> cells_generator;
        cells_generator.GenerateBasic(cells, p_mesh->GetNumElements());

        PottsBasedCellPopulation<2> cell_population(*p_mesh, cells);

        // Test GetLocationOfCellCentre()
        AbstractCellPopulation<2>::Iterator cell_iter = cell_population.Begin();

        for (unsigned i=0; i<4; i++)
        {
            c_vector<double, 2> cell_location = cell_population.GetLocationOfCellCentre(*cell_iter);

            c_vector<double, 2> expected;
            expected(0) = 0.5 + 2*(i%2 != 0);
            expected(1) = 0.5 + 2*(i > 1);

            double drift = norm_2(cell_location-expected);
            TS_ASSERT_LESS_THAN(drift, 1e-6);

            ++cell_iter;
        }
    }
    /*
     * Note only solves one PDE
     */
    void TestMultipleCaBasedWithoutCoarseMeshUsingPdeHandlerOnCuboid() throw(Exception)
    {
        EXIT_IF_PARALLEL;

        // Create a simple 2D PottsMesh
        PottsMeshGenerator<2> generator(10, 0, 0, 10, 0, 0);
        PottsMesh<2>* p_mesh = generator.GetMesh();

        // Create cells
        std::vector<CellPtr> cells;
        CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 2> cells_generator;
        cells_generator.GenerateBasic(cells, 100);

        std::vector<unsigned> location_indices;
        for (unsigned i=0; i<100; i++)
        {
            location_indices.push_back(i);
        }

        // Create cell population
        MultipleCaBasedCellPopulation<2> cell_population(*p_mesh, cells, location_indices);

        // Set up cell-based simulation
        OnLatticeSimulation<2> simulator(cell_population);
        simulator.SetOutputDirectory("TestMultipleCaBasedCellPopulationWithPdesOnCuboid");
        simulator.SetDt(0.1);
        simulator.SetEndTime(1);

        // Set up a PDE with mixed boundary conditions (use zero uptake to check analytic solution)
        AveragedSourcePde<2> pde(cell_population, 0.0);
        ConstBoundaryCondition<2> bc(1.0);
        PdeAndBoundaryConditions<2> pde_and_bc(&pde, &bc, false);
        pde_and_bc.SetDependentVariableName("nutrient");

        // Pass this to the simulation object via a PDE handler
        CellBasedPdeHandlerOnCuboid<2> pde_handler(&cell_population);
        pde_handler.AddPdeAndBc(&pde_and_bc);
        pde_handler.SetImposeBcsOnCoarseBoundary(false);
        simulator.SetCellBasedPdeHandler(&pde_handler);

        // Solve the system
        simulator.Solve();

        // Test that PDE solver is working correctly
        for (AbstractCellPopulation<2>::Iterator cell_iter = cell_population.Begin();
             cell_iter != cell_population.End();
             ++cell_iter)
        {
            c_vector<double, 2> cell_location = simulator.rGetCellPopulation().GetLocationOfCellCentre(*cell_iter);

            if (cell_location[1] < 1e-6 || cell_location[1] > 9 - 1e-6)
            {
                TS_ASSERT_DELTA(cell_iter->GetCellData()->GetItem("nutrient"),1.0, 1e-2);
            }
            else
            {
                TS_ASSERT_LESS_THAN(1.0,cell_iter->GetCellData()->GetItem("nutrient"));
            }
        }
    }
    void TestComputeFineElemsAndWeightsForCoarseNodes() throw(Exception)
    {
        TetrahedralMesh<2,2> fine_mesh;
        TrianglesMeshReader<2,2> mesh_reader("mesh/test/data/square_4_elements");
        fine_mesh.ConstructFromMeshReader(mesh_reader);

        QuadraticMesh<2> coarse_mesh(0.5, 0.5, 0.5);
        coarse_mesh.Translate(0.2,0.1);

        FineCoarseMeshPair<2> mesh_pair(fine_mesh,coarse_mesh);

        // Need to call SetUpBoxesOnFineMesh first
        TS_ASSERT_THROWS_CONTAINS(mesh_pair.ComputeFineElementsAndWeightsForCoarseNodes(true), "Call");

        mesh_pair.SetUpBoxesOnFineMesh();
        mesh_pair.ComputeFineElementsAndWeightsForCoarseNodes(true);

        // All coarse quadrature points should have been found in the fine mesh
        TS_ASSERT_EQUALS(mesh_pair.mNotInMesh.size(), 0u);
        TS_ASSERT_EQUALS(mesh_pair.mNotInMeshNearestElementWeights.size(), 0u);

        // Check the elements and weights have been set up correctly
        TS_ASSERT_EQUALS(mesh_pair.rGetElementsAndWeights().size(), 9u);

        // Check the first four nodes against what they should be
        TS_ASSERT_EQUALS(mesh_pair.rGetElementsAndWeights()[0].ElementNum, 1u);
        TS_ASSERT_EQUALS(mesh_pair.rGetElementsAndWeights()[1].ElementNum, 1u);
        TS_ASSERT_EQUALS(mesh_pair.rGetElementsAndWeights()[2].ElementNum, 0u);
        TS_ASSERT_EQUALS(mesh_pair.rGetElementsAndWeights()[3].ElementNum, 2u);

        for (unsigned i=0; i<mesh_pair.rGetElementsAndWeights().size(); i++)
        {
            TS_ASSERT_LESS_THAN(mesh_pair.rGetElementsAndWeights()[i].ElementNum, fine_mesh.GetNumElements());

            // All the weights should be between 0 and 1 as no coarse nodes are
            // Note weights = (1-psi_x-psi_y-psi_z, psi_x, psi_y, psi_z), where psi is the position of the
            // point in that element when transformed to the canonical element
            for (unsigned j=0; j<3; j++)
            {
                TS_ASSERT_LESS_THAN(-1e14, mesh_pair.rGetElementsAndWeights()[i].Weights(j));
                TS_ASSERT_LESS_THAN(mesh_pair.rGetElementsAndWeights()[i].Weights(j), 1.0+1e-14);
            }
        }

        TS_ASSERT_EQUALS(mesh_pair.mStatisticsCounters[0], 9u);
        TS_ASSERT_EQUALS(mesh_pair.mStatisticsCounters[1], 0u);
    }
    void TestImposeBoundaryConditionWithNoWnt1d() throw(Exception)
    {
        // Create 1D cell population
        unsigned num_cells = 5;
        MutableMesh<1,1> mesh;
        mesh.ConstructLinearMesh(num_cells-1);

        std::vector<CellPtr> cells;
        CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 2> cells_generator;
        cells_generator.GenerateBasic(cells, mesh.GetNumNodes());
        MeshBasedCellPopulation<1> crypt(mesh, cells);

        // Store the node locations
        std::map<Node<1>*, c_vector<double, 1> > node_locations_before;
        for (unsigned node_index=0; node_index<mesh.GetNumNodes(); node_index++)
        {
            node_locations_before[crypt.GetNode(node_index)] = crypt.GetNode(node_index)->rGetLocation();
        }

        // Now move the first cell (which should be on x=0, and a stem cell) to the left a bit
        AbstractCellPopulation<1>::Iterator cell_iter = crypt.Begin();

        // Check is a stem cell
        TS_ASSERT_EQUALS(cell_iter->GetCellProliferativeType()->IsType<StemCellProliferativeType>(), true);

        // Check initially at x=0
        TS_ASSERT_DELTA(crypt.GetLocationOfCellCentre(*cell_iter)[0], 0.0, 1e-6);

        // Now move to the left a bit
        crypt.GetNode(0)->rGetModifiableLocation()[0] = -0.1;
        TS_ASSERT_LESS_THAN(crypt.GetLocationOfCellCentre(*cell_iter)[0], 0.0);

        // Pass this cell population to a boundary condition object
        CryptSimulationBoundaryCondition<1> boundary_condition(&crypt);

        // Impose the boundary condition without a Wnt stimulus
        boundary_condition.ImposeBoundaryCondition(node_locations_before);

        /*
         * The first cell should have been pulled back to x=0 since it is a stem cell and
         * there is no Wnt stimulus. It should be unaffected by jiggling, which is not imposed
         * in 1D.
         */
        TS_ASSERT_DELTA(0.0, crypt.GetLocationOfCellCentre(*cell_iter)[0], 1e-3);

        // The nodes should all now be at their original locations
        std::map<Node<1>*, c_vector<double, 1> > node_locations_after;
        for (unsigned node_index=0; node_index<mesh.GetNumNodes(); node_index++)
        {
            node_locations_after[crypt.GetNode(node_index)] = crypt.GetNode(node_index)->rGetLocation();
        }

        for (unsigned node_index=0; node_index<mesh.GetNumNodes(); node_index++)
        {
            TS_ASSERT_DELTA(node_locations_before[crypt.GetNode(node_index)](0), node_locations_after[crypt.GetNode(node_index)](0), 1e-3);
        }
    }
Example #13
0
    void TestSplitPointCloud() throw(Exception)
    {
#if defined(CHASTE_VTK) && ( (VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION >= 6) || VTK_MAJOR_VERSION >= 6)
        EXIT_IF_PARALLEL;

        vtkSmartPointer<vtkPolyData> sphere = CreateSphere();

        AirwayGenerator generator(sphere);
        vtkSmartPointer<vtkPolyData> point_cloud = generator.CreatePointCloudUsingTargetPoints(50);

        double normal[3] = {0.0, 1.0, 0.0 };
        double origin[3] = {0.0, 0.0, 0.0};
        vtkSmartPointer<vtkPolyData> top_half_sphere = generator.SplitPointCloud(point_cloud,
                                                                                 normal,
                                                                                 origin,
                                                                                 false);

        TS_ASSERT_EQUALS(top_half_sphere->GetNumberOfPoints(), 21);

        for (int i = 0; i < top_half_sphere->GetNumberOfPoints(); ++i)
        {
            double coords[3];
            top_half_sphere->GetPoint(i, coords);

            TS_ASSERT_LESS_THAN(0.0, coords[1]);
        }

        top_half_sphere = generator.SplitPointCloud(point_cloud,
                                                    normal,
                                                    origin,
                                                    true);

        TS_ASSERT_EQUALS(top_half_sphere->GetNumberOfPoints(), 28);

        for (int i = 0; i < top_half_sphere->GetNumberOfPoints(); ++i)
        {
            double coords[3];
            top_half_sphere->GetPoint(i, coords);

            TS_ASSERT_LESS_THAN(coords[1], 0.0);
        }

#endif
    }
    void TestNodeAndMeshMethods() throw(Exception)
    {
        // Create a Potts-based cell population
        PottsMeshGenerator<2> generator(4, 2, 2, 4, 2, 2);
        PottsMesh<2>* p_mesh = generator.GetMesh();

        std::vector<CellPtr> cells;
        CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 2> cells_generator;
        cells_generator.GenerateBasic(cells, p_mesh->GetNumElements());

        PottsBasedCellPopulation<2> cell_population(*p_mesh, cells);

        // Test GetNumNodes()
        TS_ASSERT_EQUALS(cell_population.GetNumNodes(), 16u);

        // Test GetNode()
        for (unsigned index=0; index<cell_population.GetNumNodes(); index++)
        {
            Node<2>* p_node = cell_population.GetNode(index);
            TS_ASSERT_EQUALS(p_node->GetIndex(), index);

            c_vector<double, 2> node_location = p_node->rGetLocation();
            c_vector<double, 2> expected;
            expected(0) = (double)(index%4);
            expected(1) = (double)(index>3) + (double)(index>7) + (double)(index>11);

            double drift = norm_2(node_location-expected);
            TS_ASSERT_LESS_THAN(drift, 1e-6);
        }

        // Test GetElement()
        for (unsigned index=0; index<cell_population.GetNumElements(); index++)
        {
            PottsElement<2>* p_element = cell_population.GetElement(index);
            TS_ASSERT_EQUALS(p_element->GetIndex(), index);

            TS_ASSERT_EQUALS(p_element->GetNumNodes(), 4u);
        }

        // Test SetNode()
        ChastePoint<2> unused_point;
        TS_ASSERT_THROWS_THIS(cell_population.SetNode(0, unused_point),
                              "SetNode() cannot be called on a subclass of AbstractOnLatticeCellPopulation.");

        // Test GetWidth() method
        double width_x = cell_population.GetWidth(0);
        TS_ASSERT_DELTA(width_x, 3.0, 1e-4);

        double width_y = cell_population.GetWidth(1);
        TS_ASSERT_DELTA(width_y, 3.0, 1e-4);

        // Test GetNeighbouringNodeIndices() method
        TS_ASSERT_THROWS_THIS(cell_population.GetNeighbouringNodeIndices(10),
            "Cannot call GetNeighbouringNodeIndices() on a subclass of AbstractOnLatticeCellPopulation, need to go through the PottsMesh instead");
    }
Example #15
0
    /**
     * Initializes a matrix with the specified id.
     *   Global matrices are set to the corresponding values,
     *   local matrices initialized with random values.
     *
     * @param i_id id of the matrix {0, .., 51} -> flux matrix, {52} -> jacobian (flux solver), {53, 54, 55} -> stiffness matrices, {56, 57, 58} -> transposed stiffness matrices, {59} -> jacobian (star matrix)
     * @param i_numberOfRows number of rows.
     * @param i_numberOfColumns number of columns.
     * @param o_matrix matrix, which is initialized.
     **/
    void initializeMatrix( unsigned int i_id,
                           unsigned int i_numberOfRows,
                           unsigned int i_numberOfColumns,
                           real*        o_matrix ) {
      // assert the matrices have been read
      assert( m_matrixIds.size() > 0 );

      // get the position of our matrix
      unsigned int l_position;
      for( l_position = 0; l_position < m_matrixIds.size(); l_position++ ) {
        if( i_id == m_matrixIds[l_position] ) {
          break;
        }
        else {
          // matrix with the given id couldn't be found
          TS_ASSERT_DIFFERS( l_position, m_matrixIds.size() -1 );
        }
      }

      // flux solver -> random values
      if( i_id == 52 ) {
        // assert correct matrix id
        TS_ASSERT_EQUALS( m_matrixIds[l_position], 52 );
        setRandomValues( i_numberOfRows * i_numberOfColumns,
                         o_matrix );
      } 
      // flux matrix, stiffness matrix or star matrix
      else {
        std::fill( o_matrix, o_matrix + i_numberOfRows * i_numberOfColumns, 0 );
        for( unsigned int l_element = 0; l_element < m_matrixRows[l_position].size(); l_element++ ) {
          // assert that we can save the non-zero element
          TS_ASSERT_LESS_THAN_EQUALS( m_matrixRows[l_position][l_element],    i_numberOfRows);
          TS_ASSERT_LESS_THAN_EQUALS( m_matrixColumns[l_position][l_element], i_numberOfColumns);

          unsigned int l_denseIndex = (m_matrixColumns[l_position][l_element]-1) * i_numberOfRows + (m_matrixRows[l_position][l_element]-1);

          // assert this a valid index
          TS_ASSERT_LESS_THAN( l_denseIndex, i_numberOfRows*i_numberOfColumns );

          if( i_id == 59 ) { // star matrix
            o_matrix[ l_denseIndex ] = ((real)rand()/(real)RAND_MAX)*10.0;
          }
          else if( i_id >= 56 && i_id <= 58 ) { // add minus-sign for time kernel
            o_matrix[ l_denseIndex ] = -m_matrixValues[l_position][l_element];
          }
          else{ // flux or stiffness matrix
            o_matrix[ l_denseIndex ] =  m_matrixValues[l_position][l_element];
          }
        }
      }
    }
    void TestOn3dNonlinearProblem() throw (Exception)
    {
        SimplePetscNonlinearSolver solver_petsc;
        SimpleNewtonNonlinearSolver solver_newton;

        // Set up solution guess for residuals
        int length = 3;

        // Set up initial Guess
        Vec initial_guess=PetscTools::CreateVec(length);
        PetscVecTools::SetElement(initial_guess, 0, 1);
        PetscVecTools::SetElement(initial_guess, 1, 1);
        PetscVecTools::SetElement(initial_guess, 2, 1);
        PetscVecTools::Finalise(initial_guess);

        // Solve using petsc solver
        Vec answer_petsc = solver_petsc.Solve(&ComputeTestResidual3d, &ComputeTestJacobian3d,
                                              initial_guess, length, NULL);

        // Solve using newton method
        solver_newton.SetTolerance(1e-10);                      // to cover this method
        solver_newton.SetWriteStats();                          // to cover this method
        Vec answer_newton = solver_newton.Solve(&ComputeTestResidual3d, &ComputeTestJacobian3d,
                                                initial_guess, length, NULL);

        // Replicate the answers so we can access them without worrying about parallel stuff
        ReplicatableVector answer_petsc_repl(answer_petsc);
        ReplicatableVector answer_newton_repl(answer_newton);

        double tol = 1e-6;

        for (int i=0; i<3; i++)
        {
            // the solution is x = 1/sqrt(3.0), y = 1/sqrt(3.0),  z = 1/sqrt(3.0)
            TS_ASSERT_DELTA(answer_petsc_repl[i] ,1/sqrt(3.0),tol);
            TS_ASSERT_DELTA(answer_newton_repl[i],1/sqrt(3.0),tol);
        }

        // Check the residual really did have scaled norm within the tolerance
        Vec residual;
        VecDuplicate(answer_newton, &residual);
        ComputeTestResidual3d(NULL, answer_newton, residual, NULL);
        double norm;
        VecNorm(residual, NORM_2, &norm);
        TS_ASSERT_LESS_THAN(norm/length, 1e-10);

        PetscTools::Destroy(residual);
        PetscTools::Destroy(initial_guess);
        PetscTools::Destroy(answer_petsc);
        PetscTools::Destroy(answer_newton);
    }
    void TestInitialiseCellPdeElementMapAndFindCoarseElementContainingCell() throw(Exception)
    {
        EXIT_IF_PARALLEL;

        // Create a cell population
        HoneycombMeshGenerator generator(4, 4, 0);
        MutableMesh<2,2>* p_generating_mesh = generator.GetMesh();
        NodesOnlyMesh<2> mesh;
        mesh.ConstructNodesWithoutMesh(*p_generating_mesh, 1.5);

        std::vector<CellPtr> cells;
        CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 2> cells_generator;
        cells_generator.GenerateBasic(cells, mesh.GetNumNodes());

        NodeBasedCellPopulation<2> cell_population(mesh, cells);

        // Create a PDE handler object using this cell population
        CellBasedPdeHandler<2> pde_handler(&cell_population);

        TS_ASSERT_EQUALS(pde_handler.mCellPdeElementMap.size(), 0u);

        // Test that InitialiseCellPdeElementMap() throws an exception if mpCoarsePdeMesh is not set up
        TS_ASSERT_THROWS_THIS(pde_handler.InitialiseCellPdeElementMap(),
            "InitialiseCellPdeElementMap() should only be called if mpCoarsePdeMesh is set up.");

        // Set up PDE and pass to handler
        AveragedSourcePde<2> pde(cell_population, -0.1);
        ConstBoundaryCondition<2> bc(1.0);
        PdeAndBoundaryConditions<2> pde_and_bc(&pde, &bc, false);
        pde_handler.AddPdeAndBc(&pde_and_bc);

        // Use a coarse PDE mesh
        ChastePoint<2> lower(0.0, 0.0);
        ChastePoint<2> upper(9.0, 9.0);
        ChasteCuboid<2> cuboid(lower, upper);

        pde_handler.UseCoarsePdeMesh(3.0, cuboid, true);

        // Test that mCellPdeElementMap is initialised correctly
        pde_handler.InitialiseCellPdeElementMap();

        TS_ASSERT_EQUALS(pde_handler.mCellPdeElementMap.size(), cell_population.GetNumRealCells());
        for (AbstractCellPopulation<2>::Iterator cell_iter = cell_population.Begin();
             cell_iter != cell_population.End();
             ++cell_iter)
        {
            unsigned containing_element_index = pde_handler.mCellPdeElementMap[*cell_iter];
            TS_ASSERT_LESS_THAN(containing_element_index, pde_handler.GetCoarsePdeMesh()->GetNumElements());
            TS_ASSERT_EQUALS(containing_element_index, pde_handler.FindCoarseElementContainingCell(*cell_iter));
        }
    }
    void TestRKFehlbergSystemOf3EquationsWithEvents() throw(Exception)
    {
        OdeThirdOrderWithEvents ode_system_with_events;

        double h_value = 0.1;

        // Euler solver solution worked out
        RungeKuttaFehlbergIvpOdeSolver rkf_solver;
        OdeSolution solutions;

        std::vector<double> state_variables = ode_system_with_events.GetInitialConditions();
        solutions = rkf_solver.Solve(&ode_system_with_events, state_variables, 0.0, 2.0, h_value, 1e-5);
        unsigned last = solutions.GetNumberOfTimeSteps();

//        for (unsigned i=0; i<last+1; i++)
//        {
//            std::cout << "Time = " << solutions.rGetTimes()[i] <<
//                " x = " << solutions.rGetSolutions()[i][0] << "\n" << std::flush;
//        }

        // Final time should be pi/6 (?)
        TS_ASSERT_DELTA( solutions.rGetTimes()[last], M_PI/6.0, h_value);

        // Penultimate y0 should be greater than -0.5
        TS_ASSERT_LESS_THAN(-0.5,solutions.rGetSolutions()[last-1][0]);

        // Final y0 should be less than -0.5
        TS_ASSERT_LESS_THAN( solutions.rGetSolutions()[last][0], -0.5);

        // Solver should correctly state the stopping event occurred
        TS_ASSERT_EQUALS(rkf_solver.StoppingEventOccurred(), true);

        // Coverage of exceptions
        TS_ASSERT_THROWS_THIS(rkf_solver.Solve(&ode_system_with_events, solutions.rGetSolutions()[last], M_PI/6.0, 2.0, 0.1, 1e-5),
                "(Solve with sampling) Stopping event is true for initial condition");
        TS_ASSERT_THROWS_THIS(rkf_solver.Solve(&ode_system_with_events, solutions.rGetSolutions()[last], M_PI/6.0, 2.0, 0.1),
                "(Solve without sampling) Stopping event is true for initial condition");
    }
    void TestImposeBoundaryConditionWithNoWntOrJiggling2d() throw(Exception)
    {
        // Create a cell population
        CylindricalHoneycombMeshGenerator generator(4, 4, 0, 1.0);
        Cylindrical2dMesh* p_mesh = generator.GetCylindricalMesh();
        std::vector<unsigned> location_indices = generator.GetCellLocationIndices();

        std::vector<CellPtr> cells;
        CryptCellsGenerator<FixedDurationGenerationBasedCellCycleModel> cells_generator;
        cells_generator.Generate(cells, p_mesh, std::vector<unsigned>(), true);

        MeshBasedCellPopulationWithGhostNodes<2> crypt(*p_mesh, cells, location_indices);

        // Store the node locations
        std::map<Node<2>*, c_vector<double, 2> > node_locations_before;
        for (unsigned node_index=0; node_index<p_mesh->GetNumNodes(); node_index++)
        {
            node_locations_before[crypt.GetNode(node_index)] = crypt.GetNode(node_index)->rGetLocation();
        }

        // Now move the first cell (which should be on y=0) down a bit
        AbstractCellPopulation<2>::Iterator cell_iter = crypt.Begin();
        TS_ASSERT_DELTA(crypt.GetLocationOfCellCentre(*cell_iter)[1], 0.0, 1e-6);
        crypt.GetNode(0)->rGetModifiableLocation()[1] = -0.1;
        TS_ASSERT_LESS_THAN(crypt.GetLocationOfCellCentre(*cell_iter)[1], 0.0);

        // Create a boundary condition object
        CryptSimulationBoundaryCondition<2> boundary_condition(&crypt);
        boundary_condition.SetUseJiggledBottomCells(false);

        // Impose the boundary condition without a Wnt stimulus or jiggled bottom cells
        boundary_condition.ImposeBoundaryCondition(node_locations_before);

        // The first cell should have been moved back by the boundary condition object
        TS_ASSERT_DELTA(crypt.GetLocationOfCellCentre(*cell_iter)[1], 0.0, 1e-4);

        // The nodes should all now be at their original locations
        std::map<Node<2>*, c_vector<double, 2> > node_locations_after;
        for (unsigned node_index=0; node_index<p_mesh->GetNumNodes(); node_index++)
        {
            node_locations_after[crypt.GetNode(node_index)] = crypt.GetNode(node_index)->rGetLocation();
        }

        for (unsigned node_index=0; node_index<p_mesh->GetNumNodes(); node_index++)
        {
            TS_ASSERT_DELTA(node_locations_before[crypt.GetNode(node_index)](0), node_locations_after[crypt.GetNode(node_index)](0), 1e-3);
            TS_ASSERT_DELTA(node_locations_before[crypt.GetNode(node_index)](1), node_locations_after[crypt.GetNode(node_index)](1), 1e-3);
        }
    }
Example #20
0
 //Experiments with ksp_atol follow.
 //This first one has to be done with GMRES as 1D are known to be a bit flakey
 void TestSpaceConvergencein1DWithAtol()
 {
     HeartConfig::Instance()->SetKSPSolver("gmres");
     HeartConfig::Instance()->SetKSPPreconditioner("jacobi");
     SpaceConvergenceTester<CellLuoRudy1991FromCellMLBackwardEuler, BidomainProblem<1>, 1, 2> tester;
     HeartConfig::Instance()->SetUseAbsoluteTolerance(1e-5);
    //tester.SetKspAbsoluteTolerance(1e-5);
     tester.Converge(__FUNCTION__);
     TS_ASSERT(tester.Converged);
     TS_ASSERT_EQUALS(tester.MeshNum, 5u);
     TS_ASSERT_LESS_THAN(tester.LastDifference, 0.0041039);
     //Has to be at least as good as the 1D with Rtol=1e-7
     //Note the final line fails with ksp_atol=1e-4
     HeartConfig::Instance()->Reset();
 }
    /* == Sliding boundary conditions ==
     *
     * It is common to require a Dirichlet boundary condition where the displacement/position in one dimension
     * is fixed, but the displacement/position in the others are free. This can be easily done when
     * collecting the new locations for the fixed nodes, as shown in the following example. Here, we
     * take a unit square, apply gravity downward, and suppose the Y=0 surface is like a frictionless boundary,
     * so that, for the nodes on Y=0, we specify y=0 but leave x free (Here (X,Y)=old position, (x,y)=new position).
     * (Note though that this wouldn't be enough to uniquely specify the final solution - an arbitrary
     * translation in the Y direction could be added a solution to obtain another valid solution, so we
     * fully fix the node at the origin.)
     */
    void TestWithSlidingDirichletBoundaryConditions() throw(Exception)
    {
        QuadraticMesh<2> mesh;
        mesh.ConstructRegularSlabMesh(0.1 /*stepsize*/, 1.0 /*width*/, 1.0 /*height*/);

        ExponentialMaterialLaw<2> law(1.0, 0.5); // First parameter is 'a', second 'b', in W=a*exp(b(I1-3))

        /* Create fixed nodes and locations... */
        std::vector<unsigned> fixed_nodes;
        std::vector<c_vector<double,2> > locations;

        /* Fix node 0 (the node at the origin) */
        fixed_nodes.push_back(0);
        locations.push_back(zero_vector<double>(2));

        /* For the rest, if the node is on the Y=0 surface.. */
        for (unsigned i=1; i<mesh.GetNumNodes(); i++)
        {
            if ( fabs(mesh.GetNode(i)->rGetLocation()[1])<1e-6)
            {
                /* ..add it to the list of fixed nodes.. */
                fixed_nodes.push_back(i);
                /* ..and define y to be 0 but x is fixed */
                c_vector<double,2> new_location;
                new_location(0) = SolidMechanicsProblemDefinition<2>::FREE;
                new_location(1) = 0.0;
                locations.push_back(new_location);
            }
        }

        /* Set the material law and fixed nodes, add some gravity, and solve */
        SolidMechanicsProblemDefinition<2> problem_defn(mesh);
        problem_defn.SetMaterialLaw(INCOMPRESSIBLE,&law);
        problem_defn.SetFixedNodes(fixed_nodes, locations);
        c_vector<double,2> gravity = zero_vector<double>(2);
        gravity(1) = -0.5;
        problem_defn.SetBodyForce(gravity);

        IncompressibleNonlinearElasticitySolver<2> solver(mesh,
                                                          problem_defn,
                                                          "ElasticitySlidingBcsExample");
        solver.Solve();
        solver.CreateCmguiOutput();

        /* Check the node at (1,0) has moved but has stayed on Y=0 */
        TS_ASSERT_LESS_THAN(1.0, solver.rGetDeformedPosition()[10](0));
        TS_ASSERT_DELTA(solver.rGetDeformedPosition()[10](1), 0.0, 1e-3);
    }
Example #22
0
    //More experiments with ksp_atol follow.
    void TestSpaceConvergencein2DWithAtol()
    {
        HeartConfig::Instance()->SetKSPSolver("symmlq");
        HeartConfig::Instance()->SetKSPPreconditioner("bjacobi");
        SpaceConvergenceTester<CellLuoRudy1991FromCellMLBackwardEuler, BidomainProblem<2>, 2, 2> tester;
        //tester.SetKspAbsoluteTolerance(1e-5);
        HeartConfig::Instance()->SetUseAbsoluteTolerance(1e-5);
        tester.Converge(__FUNCTION__);
        TS_ASSERT(tester.Converged);
        TS_ASSERT_EQUALS(tester.MeshNum, 5u);
        TS_ASSERT_LESS_THAN(tester.LastDifference, 0.0081583);
        //Comes in at 1.17118e-5
        //Has to be at least as good as the 2D with Rtol=5e-8
        HeartConfig::Instance()->Reset();

    }
Example #23
0
    void TestCreatePointCloud() throw(Exception)
    {
#if defined(CHASTE_VTK) && ( (VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION >= 6) || VTK_MAJOR_VERSION >= 6)

        EXIT_IF_PARALLEL;

        vtkSmartPointer<vtkPolyData> sphere = CreateSphere(50);

        AirwayGenerator generator(sphere);

        double test_point[3];
        test_point[0] = 1.0;
        test_point[1] = 1.0;
        test_point[2] = 0.0;
        TS_ASSERT(!generator.IsInsideLobeSurface(test_point));
        TS_ASSERT_DELTA(generator.DistanceFromLobeSurface(test_point), sqrt(2.0) - 1, 5e-3);

        vtkSmartPointer<vtkPolyData> point_data = generator.CreatePointCloud(std::pow(4*M_PI/3/50, 1.0/3.0)); //Gives spacing for ~50 points

        //Check that all points created are inside the sphere
        std::cout << point_data->GetNumberOfPoints() << std::endl;
        TS_ASSERT_EQUALS(point_data->GetNumberOfPoints(), 51);
        for (int i = 0; i < point_data->GetNumberOfPoints(); ++i)
        {
            double coords[3];
            point_data->GetPoint(i, coords);

            TS_ASSERT_LESS_THAN(std::sqrt(coords[0]*coords[0] + coords[1]*coords[1] + coords[2]*coords[2]), 1.0);
        }

        //Check that the centre of mass is close to zero
        double centre[3];
        generator.GetCentreOfMass(point_data, centre);

        TS_ASSERT_DELTA(centre[0], 0.0, 5e-2);
        TS_ASSERT_DELTA(centre[1], 0.0, 5e-2);
        TS_ASSERT_DELTA(centre[2], 0.0, 5e-2);

        std::set<unsigned>& invalid_ids = generator.GetInvalidIds();
        TS_ASSERT_EQUALS(invalid_ids.size(), 0u);
#endif
    }
    /**
     * Check that the faces are read correctly. Checks that the output vector
     * for a given input file is the correct length and that if the input file
     * is corrupted (missing faces) then an exception is thrown.
     */
    void TestFacesDataReadWithAttributes() throw(Exception)
    {
        TrianglesMeshReader<3,3> mesh_reader("heart/test/data/box_shaped_heart/box_heart_nonnegative_flags");

        TS_ASSERT_EQUALS( mesh_reader.GetNumFaces(), 92u); // just boundary faces are read
        TS_ASSERT_EQUALS( mesh_reader.GetNumFaceAttributes(), 1u);

        bool read_zero_attribute = false;
        for (unsigned i=0; i<mesh_reader.GetNumFaces(); i++)
        {
            ElementData data = mesh_reader.GetNextFaceData();
            // Attributes are 0, 1, 2, or 3.
            TS_ASSERT_LESS_THAN(data.AttributeValue, 4u);
            if (data.AttributeValue == 0u)
            {
                read_zero_attribute = true;
            }
            TS_ASSERT(read_zero_attribute);
        }
    }
    // Test the functionality specific to SolidMechanicsProblemDefinition
    void TestSolidMechanicsProblemDefinition() throw(Exception)
    {
        TS_ASSERT_EQUALS(SolidMechanicsProblemDefinition<2>::FREE, DBL_MAX);
        TS_ASSERT_LESS_THAN(0, SolidMechanicsProblemDefinition<2>::FREE);

        QuadraticMesh<2> mesh(0.5, 1.0, 1.0);

        SolidMechanicsProblemDefinition<2> problem_defn(mesh);

        //////////////////////////////////
        // Fixed nodes
        //////////////////////////////////

        std::vector<unsigned> fixed_nodes;
        fixed_nodes.push_back(0);
        fixed_nodes.push_back(4);
        problem_defn.SetZeroDisplacementNodes(fixed_nodes);
        TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodes().size(), 2u);
        TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodes()[0], 0u);
        TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodes()[1], 4u);
        TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodeValues().size(), 2u);

        TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[0](0), 0.0, 1e-12);
        TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[0](1), 0.0, 1e-12);
        TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[1](0), 0.0, 1e-12);
        TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[1](1), 0.0, 1e-12);

        fixed_nodes.push_back(8);
        fixed_nodes.push_back(9);
        fixed_nodes.push_back(10);


        std::vector<c_vector<double,2> > locations;
        c_vector<double,2> location = zero_vector<double>(2);
        // Node 0 is to be placed at (0,0)
        locations.push_back(location);

        // Node 4 is to be placed at (0,0.1)
        location(1)=0.1;
        locations.push_back(location);

        // Node 8 is to be placed at (0.1,0.1)
        location(0)=0.1;
        locations.push_back(location);

        // Node 9 is to be placed at (0.5,FREE)
        location(0) = 0.5;
        location(1) = SolidMechanicsProblemDefinition<2>::FREE;
        locations.push_back(location);

        // Node 9 is to be placed at (FREE,1.5)
        location(0) = SolidMechanicsProblemDefinition<2>::FREE;
        location(1) = 1.5;
        locations.push_back(location);

        problem_defn.SetFixedNodes(fixed_nodes, locations);

        TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodes().size(), 5u);
        TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodeValues().size(), 5u);

        // the fully fixed nodes
        TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodes()[0], 0u);
        TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodes()[1], 4u);
        TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodes()[2], 8u);

        TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[0](0), 0.0 - mesh.GetNode(0)->rGetLocation()[0], 1e-12);
        TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[0](1), 0.0 - mesh.GetNode(0)->rGetLocation()[1], 1e-12);
        TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[1](0), 0.0 - mesh.GetNode(4)->rGetLocation()[0], 1e-12);
        TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[1](1), 0.1 - mesh.GetNode(4)->rGetLocation()[1], 1e-12);
        TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[2](0), 0.1 - mesh.GetNode(8)->rGetLocation()[0], 1e-12);
        TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[2](1), 0.1 - mesh.GetNode(8)->rGetLocation()[1], 1e-12);

        // the partial fixed nodes
        TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodes()[3], 9u);
        TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodes()[4], 10u);
        TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[3](0), 0.5 - mesh.GetNode(9)->rGetLocation()[0], 1e-12);
        TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[3](1), SolidMechanicsProblemDefinition<2>::FREE, 1e-12);
        TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[4](0), SolidMechanicsProblemDefinition<2>::FREE, 1e-12);
        TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[4](1), 1.5 - mesh.GetNode(10)->rGetLocation()[1], 1e-12);


        ///////////////////////////////////////
        // Set an incompressible material law
        ///////////////////////////////////////
        TS_ASSERT_THROWS_THIS(problem_defn.Validate(), "No material law has been set");

        // set a homogeneous law
        MooneyRivlinMaterialLaw<2> incomp_mooney_rivlin_law(1.0);
        problem_defn.SetMaterialLaw(INCOMPRESSIBLE,&incomp_mooney_rivlin_law);

        TS_ASSERT_EQUALS(problem_defn.IsHomogeneousMaterial(), true);
        TS_ASSERT_EQUALS(problem_defn.GetCompressibilityType(), INCOMPRESSIBLE);
        TS_ASSERT_EQUALS(problem_defn.GetIncompressibleMaterialLaw(0), &incomp_mooney_rivlin_law);

        // set a heterogeneous law
        MooneyRivlinMaterialLaw<2> incomp_mooney_rivlin_law_2(2.0);
        std::vector<AbstractMaterialLaw<2>*> laws;
        for(unsigned i=0; i<mesh.GetNumElements()/2; i++)
        {
            laws.push_back(&incomp_mooney_rivlin_law);
        }
        for(unsigned i=mesh.GetNumElements()/2; i<mesh.GetNumElements(); i++)
        {
            laws.push_back(&incomp_mooney_rivlin_law_2);
        }

        problem_defn.SetMaterialLaw(INCOMPRESSIBLE,laws);

        TS_ASSERT_EQUALS(problem_defn.IsHomogeneousMaterial(), false);
        for(unsigned i=0; i<mesh.GetNumElements()/2; i++)
        {
            TS_ASSERT_EQUALS(problem_defn.GetIncompressibleMaterialLaw(i), &incomp_mooney_rivlin_law);
        }
        for(unsigned i=mesh.GetNumElements()/2; i<mesh.GetNumElements(); i++)
        {
            TS_ASSERT_EQUALS(problem_defn.GetIncompressibleMaterialLaw(i), &incomp_mooney_rivlin_law_2);
        }

        /////////////////////////////////////////////////////////////////////////
        // Set a compressible material law (clears the incompressible laws)
        /////////////////////////////////////////////////////////////////////////

        CompressibleMooneyRivlinMaterialLaw<2> comp_mooney_rivlin_law(2.0, 1.0);
        problem_defn.SetMaterialLaw(COMPRESSIBLE,&comp_mooney_rivlin_law);

        TS_ASSERT_EQUALS(problem_defn.IsHomogeneousMaterial(), true);
        TS_ASSERT_EQUALS(problem_defn.GetCompressibilityType(), COMPRESSIBLE);
        TS_ASSERT_EQUALS(problem_defn.GetCompressibleMaterialLaw(0), &comp_mooney_rivlin_law);

        // set a heterogeneous law
        CompressibleMooneyRivlinMaterialLaw<2> comp_mooney_rivlin_law_2(4.0, 1.0);
        std::vector<AbstractMaterialLaw<2>*> comp_laws;
        for(unsigned i=0; i<mesh.GetNumElements()/2; i++)
        {
            comp_laws.push_back(&comp_mooney_rivlin_law);
        }
        for(unsigned i=mesh.GetNumElements()/2; i<mesh.GetNumElements(); i++)
        {
            comp_laws.push_back(&comp_mooney_rivlin_law_2);
        }

        problem_defn.SetMaterialLaw(COMPRESSIBLE,comp_laws);

        TS_ASSERT_EQUALS(problem_defn.IsHomogeneousMaterial(), false);
        for(unsigned i=0; i<mesh.GetNumElements()/2; i++)
        {
            TS_ASSERT_EQUALS(problem_defn.GetCompressibleMaterialLaw(i), &comp_mooney_rivlin_law);
        }
        for(unsigned i=mesh.GetNumElements()/2; i<mesh.GetNumElements(); i++)
        {
            TS_ASSERT_EQUALS(problem_defn.GetCompressibleMaterialLaw(i), &comp_mooney_rivlin_law_2);
        }

        // should not throw anything
        problem_defn.Validate();

        TS_ASSERT_THROWS_THIS(problem_defn.SetMaterialLaw(INCOMPRESSIBLE,&comp_mooney_rivlin_law),"Compressibility type was declared as INCOMPRESSIBLE but a compressible material law was given");
        TS_ASSERT_THROWS_THIS(problem_defn.SetMaterialLaw(COMPRESSIBLE,&incomp_mooney_rivlin_law),"Incompressibility type was declared as COMPRESSIBLE but an incompressible material law was given");

        ///////////////////////////////
        // solver stuff
        ///////////////////////////////
        TS_ASSERT_EQUALS(problem_defn.GetSolveUsingSnes(), false);
        TS_ASSERT_EQUALS(problem_defn.GetVerboseDuringSolve(), false);

        problem_defn.SetSolveUsingSnes();
        problem_defn.SetVerboseDuringSolve();

        TS_ASSERT_EQUALS(problem_defn.GetSolveUsingSnes(), true);
        TS_ASSERT_EQUALS(problem_defn.GetVerboseDuringSolve(), true);

        problem_defn.SetSolveUsingSnes(false);
        problem_defn.SetVerboseDuringSolve(false);

        TS_ASSERT_EQUALS(problem_defn.GetSolveUsingSnes(), false);
        TS_ASSERT_EQUALS(problem_defn.GetVerboseDuringSolve(), false);

    }
    /* HOW_TO_TAG Cardiac/Electro-mechanics
     * Run electro-mechanical simulations using bidomain instead of monodomain
     *
     * This test is the same as above but with bidomain instead of monodomain.
     * Extracellular conductivities are set very high so the results should be the same.
     */
    void TestWithHomogeneousEverythingCompressibleBidomain() throw(Exception)
    {
        EntirelyStimulatedTissueCellFactory cell_factory;

        TetrahedralMesh<2,2> electrics_mesh;
        electrics_mesh.ConstructRegularSlabMesh(0.01, 0.05, 0.05);

        QuadraticMesh<2> mechanics_mesh;
        mechanics_mesh.ConstructRegularSlabMesh(0.025, 0.05, 0.05);

        std::vector<unsigned> fixed_nodes;
        std::vector<c_vector<double,2> > fixed_node_locations;

        // fix the node at the origin so that the solution is well-defined (ie unique)
        fixed_nodes.push_back(0);
        fixed_node_locations.push_back(zero_vector<double>(2));

        // for the rest of the nodes, if they lie on X=0, fix x=0 but leave y free.
        for(unsigned i=1 /*not 0*/; i<mechanics_mesh.GetNumNodes(); i++)
        {
            if(fabs(mechanics_mesh.GetNode(i)->rGetLocation()[0])<1e-6)
            {
                c_vector<double,2> new_position;
                new_position(0) = 0.0;
                new_position(1) = SolidMechanicsProblemDefinition<2>::FREE;
                fixed_nodes.push_back(i);
                fixed_node_locations.push_back(new_position);
            }
        }

        ElectroMechanicsProblemDefinition<2> problem_defn(mechanics_mesh);
        problem_defn.SetContractionModel(KERCHOFFS2003,1.0);
        problem_defn.SetUseDefaultCardiacMaterialLaw(COMPRESSIBLE);
        problem_defn.SetFixedNodes(fixed_nodes, fixed_node_locations);
        problem_defn.SetMechanicsSolveTimestep(1.0);

        // the following is just for coverage - applying a zero pressure so has no effect on deformation
        std::vector<BoundaryElement<1,2>*> boundary_elems;
        boundary_elems.push_back(* (mechanics_mesh.GetBoundaryElementIteratorBegin()));
        problem_defn.SetApplyNormalPressureOnDeformedSurface(boundary_elems, 0.0);

        HeartConfig::Instance()->SetSimulationDuration(10.0);
        HeartConfig::Instance()->SetExtracellularConductivities(Create_c_vector(1500,1500,1500));
        //creates the EM problem with ELEC_PROB_DIM=2
        CardiacElectroMechanicsProblem<2,2> problem(COMPRESSIBLE,
                                                    BIDOMAIN,
                                                    &electrics_mesh,
                                                    &mechanics_mesh,
                                                    &cell_factory,
                                                    &problem_defn,
                                                    "TestCardiacEmHomogeneousEverythingCompressibleBidomain");

        problem.Solve();
        std::vector<c_vector<double,2> >& r_deformed_position = problem.rGetDeformedPosition();

        // not sure how easy is would be determine what the deformation should be
        // exactly, but it certainly should be constant squash in X direction, constant
        // stretch in Y.

        // first, check node 8 starts is the far corner
        assert(fabs(mechanics_mesh.GetNode(8)->rGetLocation()[0] - 0.05)<1e-8);
        assert(fabs(mechanics_mesh.GetNode(8)->rGetLocation()[1] - 0.05)<1e-8);

        double X_scale_factor = r_deformed_position[8](0)/0.05;
        double Y_scale_factor = r_deformed_position[8](1)/0.05;

        std::cout << "Scale_factors = " << X_scale_factor << " " << Y_scale_factor << ", product = " << X_scale_factor*Y_scale_factor<<"\n";

        for(unsigned i=0; i<mechanics_mesh.GetNumNodes(); i++)
        {
            double X = mechanics_mesh.GetNode(i)->rGetLocation()[0];
            double Y = mechanics_mesh.GetNode(i)->rGetLocation()[1];

            TS_ASSERT_DELTA( r_deformed_position[i](0), X * X_scale_factor, 1e-6);
            TS_ASSERT_DELTA( r_deformed_position[i](1), Y * Y_scale_factor, 1e-6);
        }

        //check interpolated voltages and calcium

        unsigned quad_points = problem.mpCardiacMechSolver->GetTotalNumQuadPoints();
        TS_ASSERT_EQUALS(problem.mInterpolatedVoltages.size(), quad_points);
        TS_ASSERT_EQUALS(problem.mInterpolatedCalciumConcs.size(), quad_points);

        //two hardcoded values
        TS_ASSERT_DELTA(problem.mInterpolatedVoltages[0],9.267,1e-3);
        TS_ASSERT_DELTA(problem.mInterpolatedCalciumConcs[0],0.001464,1e-6);

        //for the rest, we check that, at the end of this simulation, all quad nodes have V and Ca above a certain threshold
        for(unsigned i = 0; i < quad_points; i++)
        {
            TS_ASSERT_LESS_THAN(9.2,problem.mInterpolatedVoltages[i]);
            TS_ASSERT_LESS_THAN(0.0014,problem.mInterpolatedCalciumConcs[i]);
        }

        //check default value of whether there is a bath or not
        TS_ASSERT_EQUALS(problem.mpElectricsProblem->GetHasBath(), false);

        //test the functionality of having phi_e on the mechanics mesh (values are tested somewhere else)
        Hdf5DataReader data_reader("TestCardiacEmHomogeneousEverythingCompressibleBidomain/electrics","voltage_mechanics_mesh");
        TS_ASSERT_THROWS_NOTHING(data_reader.GetVariableOverTime("Phi_e",0u));
    }
    void TestSteadyStateRunnerConverges(void) throw(Exception)
    {
#ifdef CHASTE_CVODE
        //////////// DEFINE PARAMETERS ///////////////
        // Get the frequency
        double hertz = 1.0;

        ///////// END DEFINE PARAMETERS ////////////////////////

        // Setup a CVODE model that has empty solver and stimulus
        boost::shared_ptr<RegularStimulus> p_stimulus;
        boost::shared_ptr<AbstractIvpOdeSolver> p_solver;
        boost::shared_ptr<AbstractCvodeCell> p_model(new CellShannon2004FromCellMLCvode(p_solver, p_stimulus));

        // Get it to use the default stimulus from CellML
        boost::shared_ptr<RegularStimulus> p_reg_stim = p_model->UseCellMLDefaultStimulus();

        { // Test that the steady state analysis throws a nice error if we try to run it with a non-RegularStimulus

            boost::shared_ptr<ZeroStimulus> p_stim(new ZeroStimulus());
            p_model->SetStimulusFunction(p_stim);

            SteadyStateRunner bad_steady_runner(p_model);
            TS_ASSERT_THROWS_THIS(bad_steady_runner.RunToSteadyState(),
                                  "Steady State approximations only work for models with RegularStimulus objects.");

            // Reset to a sensible stimulus function.
            p_model->SetStimulusFunction(p_reg_stim);
        }

        p_reg_stim->SetPeriod(1000.0/hertz);

        // Note that increasing the strictness of the tolerances here (default is 1e-5, 1e-7)
        // actually leads to a faster convergence to steady state, as a model solved in
        // a sloppy way might never actually get close to its true limit cycle!
        p_model->SetTolerances(1e-6,1e-8);

        /**
         * STEADY STATE PACING EXPERIMENT
         */
        /*
         * HOW_TO_TAG Cardiac/Cell Models
         * Get a cardiac cell model to (roughly) a steady state, given a regular stimulus, using the `SteadyStateRunner` class.
         */
        SteadyStateRunner steady_runner(p_model);

        bool result;

        // Here we don't reach steady state by max num paces
        steady_runner.SetMaxNumPaces(1u);
        result = steady_runner.RunToSteadyState();

        TS_ASSERT_EQUALS(result,false);

        // Here we do reach the steady state OK.
        steady_runner.SetMaxNumPaces(10000u);
        result = steady_runner.RunToSteadyState();

        TS_ASSERT_EQUALS(result,true);
        // Your mileage may vary. 32-bit machine, default build gives 520 evaluations, 484 on recent 64-bit CVODE.
        TS_ASSERT_LESS_THAN(steady_runner.GetNumEvaluations(),550u);

        // For coverage
        TS_ASSERT_THROWS_THIS(steady_runner.SetMaxNumPaces(0u),
                "Please set a maximum number of paces that is positive");
#else
        std::cout << "CVODE must be enabled for the steady state runner to work." << std::endl;
#endif //_CHASTE_CVODE
    }
    void TestPerformRosetteRankIncrease() throw (Exception)
    {
        // Create the standard five-cell rosette
        MutableVertexMesh<2,2>* p_mesh = ConstructFiveCellRosette();

        /**
         * Modify the mesh to incorporate an additional element which will go on to increase the rosette rank
         */

        // One new node will be needed
        unsigned new_node_idx = p_mesh->AddNode(new Node<2>(11, false, 0.5, 0.0));

        // One new element will be needed, consisting of four nodes
        std::vector<Node<2>* > nodes_new_elem;
        nodes_new_elem.push_back(p_mesh->GetNode(new_node_idx));
        nodes_new_elem.push_back(p_mesh->GetNode(10));
        nodes_new_elem.push_back(p_mesh->GetNode(1));
        nodes_new_elem.push_back(p_mesh->GetNode(2));

        unsigned new_elem_idx = p_mesh->AddElement(new VertexElement<2,2>(5, nodes_new_elem));
        p_mesh->GetElement(new_elem_idx)->RegisterWithNodes();

        // Add new node in to elements 0 and 4, and remove node with global index 1 from elements 0 and 4
        VertexElement<2,2>* p_elem_0 = p_mesh->GetElement(0);
        VertexElement<2,2>* p_elem_4 = p_mesh->GetElement(4);
        VertexElement<2,2>* p_elem_n = p_mesh->GetElement(new_elem_idx);

        p_elem_0->AddNode(p_mesh->GetNode(new_node_idx), p_elem_0->GetNodeLocalIndex(0));
        p_elem_4->AddNode(p_mesh->GetNode(new_node_idx), p_elem_4->GetNodeLocalIndex(1));

        p_elem_0->DeleteNode(p_elem_0->GetNodeLocalIndex(1));
        p_elem_4->DeleteNode(p_elem_4->GetNodeLocalIndex(1));

        /**
         * Now the mesh is as desired, we can get the necessary numbers, perform the rosette rank increase, and assert
         * that everything is as intended after the operation
         */

        unsigned num_nodes_before = p_mesh->GetNumNodes();
        assert(num_nodes_before == 12);

        unsigned num_nodes_elem_0_before = p_elem_0->GetNumNodes();
        assert(num_nodes_elem_0_before == 4);

        unsigned num_nodes_elem_4_before = p_elem_4->GetNumNodes();
        assert(num_nodes_elem_4_before == 4);

        unsigned num_nodes_new_elem_before = p_elem_n->GetNumNodes();
        assert(num_nodes_new_elem_before == 4);

        c_vector<double, 2> node_0_location_before = p_mesh->GetNode(0)->rGetLocation();

        // Perform the rosette rank increase
        p_mesh->PerformRosetteRankIncrease(p_mesh->GetNode(0), p_mesh->GetNode(new_node_idx));

        // The mesh should have lost one node
        TS_ASSERT_EQUALS(num_nodes_before - 1, p_mesh->GetNumNodes());

        // Elements 0 and 4 should have lost a node, but the new element should not have lost any
        TS_ASSERT_EQUALS(num_nodes_elem_0_before - 1, p_elem_0->GetNumNodes());
        TS_ASSERT_EQUALS(num_nodes_elem_4_before - 1, p_elem_4->GetNumNodes());
        TS_ASSERT_EQUALS(num_nodes_new_elem_before, p_elem_n->GetNumNodes());

        // The node with global index 0 should remain in the same location
        TS_ASSERT_DELTA(node_0_location_before[0], p_mesh->GetNode(0)->rGetLocation()[0], 1e-10);
        TS_ASSERT_DELTA(node_0_location_before[1], p_mesh->GetNode(0)->rGetLocation()[1], 1e-10);

        // The node with global index 0 should now be included in the new element
        TS_ASSERT_LESS_THAN(p_elem_n->GetNodeLocalIndex(0), UINT_MAX);

        delete p_mesh;
    }
    void TestChebyshevAdaptiveVsNoAdaptive() throw (Exception)
    {
        unsigned num_nodes = 1331;
        DistributedVectorFactory factory(num_nodes);
        Vec parallel_layout = factory.CreateVec(2);

        // Solving with zero guess for coverage
        Vec zero_guess = factory.CreateVec(2);
        double zero = 0.0;
#if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2)
        VecSet(&zero, zero_guess);
#else
        VecSet(zero_guess, zero);
#endif

        Mat system_matrix;
        // Note that this test deadlocks if the file's not on the disk
        PetscTools::ReadPetscObject(system_matrix, "linalg/test/data/matrices/cube_6000elems_half_activated.mat", parallel_layout);

        Vec system_rhs;
        // Note that this test deadlocks if the file's not on the disk
        PetscTools::ReadPetscObject(system_rhs, "linalg/test/data/matrices/cube_6000elems_half_activated.vec", parallel_layout);

        // Make sure we are not inheriting a non-default number of iterations from previous test
        std::stringstream num_it_str;
        num_it_str << 1000;
        PetscOptionsSetValue("-ksp_max_it", num_it_str.str().c_str());

        try
        {
            LinearSystem ls = LinearSystem(system_rhs, system_matrix);

            ls.SetMatrixIsSymmetric();
            // Solve to relative convergence for coverage
            ls.SetRelativeTolerance(1e-6);
            ls.SetPcType("jacobi");
            ls.SetKspType("chebychev");
            ls.SetUseFixedNumberIterations(true, 64);

            // Solving with zero guess for coverage.
            Vec solution = ls.Solve(zero_guess);
            unsigned chebyshev_adaptive_its = ls.GetNumIterations();

            TS_ASSERT_EQUALS(chebyshev_adaptive_its, 40u);
            TS_ASSERT_DELTA(ls.mEigMin, 0.0124, 1e-4);
            TS_ASSERT_DELTA(ls.mEigMax, 1.8810, 1e-4);

            PetscTools::Destroy(solution);
        }
        catch (Exception& e)
        {
            if (e.GetShortMessage() == "Chebyshev with fixed number of iterations is known to be broken in PETSc <= 2.3.2")
            {
                WARNING(e.GetShortMessage());
            }
            else
            {
                TS_FAIL(e.GetShortMessage());
            }
        }


        // Make sure we are not inheriting a non-default number of iterations from previous test
        PetscOptionsSetValue("-ksp_max_it", num_it_str.str().c_str());
        {
            LinearSystem ls = LinearSystem(system_rhs, system_matrix);

            ls.SetMatrixIsSymmetric();
            ls.SetRelativeTolerance(1e-6);
            ls.SetPcType("jacobi");
            ls.SetKspType("chebychev");

            Vec solution = ls.Solve(zero_guess);
            unsigned chebyshev_no_adaptive_its = ls.GetNumIterations();

            TS_ASSERT_LESS_THAN(chebyshev_no_adaptive_its, 100u); // Normally 88, but 99 on maverick & natty
            TS_ASSERT_DELTA(ls.mEigMin, 0.0124, 1e-4);
            TS_ASSERT_DELTA(ls.mEigMax, 1.8841, 1e-4);

            PetscTools::Destroy(solution);
        }

        // Make sure we are not inheriting a non-default number of iterations from previous test
        PetscOptionsSetValue("-ksp_max_it", num_it_str.str().c_str());
        {
            LinearSystem ls = LinearSystem(system_rhs, system_matrix);

            ls.SetMatrixIsSymmetric();
            ls.SetRelativeTolerance(1e-6);
            ls.SetPcType("jacobi");
            ls.SetKspType("cg");
            Vec solution = ls.Solve(zero_guess);
            unsigned cg_its = ls.GetNumIterations();

            TS_ASSERT_EQUALS(cg_its, 40u);
            TS_ASSERT_EQUALS(ls.mEigMin, DBL_MAX);
            TS_ASSERT_EQUALS(ls.mEigMax, DBL_MIN);

            PetscTools::Destroy(solution);
        }

        PetscTools::Destroy(system_matrix);
        PetscTools::Destroy(system_rhs);

        PetscTools::Destroy(parallel_layout);
        PetscTools::Destroy(zero_guess);
    }
    void TestChebyshevVsCG() throw (Exception)
    {
        unsigned num_nodes = 1331;
        DistributedVectorFactory factory(num_nodes);
        Vec parallel_layout = factory.CreateVec(2);

        unsigned cg_its;
        unsigned chebyshev_its;

        Timer::Reset();
        {
            Mat system_matrix;
            // Note that this test deadlocks if the file's not on the disk
            PetscTools::ReadPetscObject(system_matrix, "linalg/test/data/matrices/cube_6000elems_half_activated.mat", parallel_layout);

            Vec system_rhs;
            // Note that this test deadlocks if the file's not on the disk
            PetscTools::ReadPetscObject(system_rhs, "linalg/test/data/matrices/cube_6000elems_half_activated.vec", parallel_layout);

            LinearSystem ls = LinearSystem(system_rhs, system_matrix);

            ls.SetMatrixIsSymmetric();
            ls.SetAbsoluteTolerance(1e-9);
            ls.SetKspType("cg");
            ls.SetPcType("bjacobi");

            Vec solution = ls.Solve();

            cg_its = ls.GetNumIterations();

            PetscTools::Destroy(system_matrix);
            PetscTools::Destroy(system_rhs);
            PetscTools::Destroy(solution);
        }
        Timer::PrintAndReset("CG");

        {
            Mat system_matrix;
            // Note that this test deadlocks if the file's not on the disk
            PetscTools::ReadPetscObject(system_matrix, "linalg/test/data/matrices/cube_6000elems_half_activated.mat", parallel_layout);

            Vec system_rhs;
            // Note that this test deadlocks if the file's not on the disk
            PetscTools::ReadPetscObject(system_rhs, "linalg/test/data/matrices/cube_6000elems_half_activated.vec", parallel_layout);

            LinearSystem ls = LinearSystem(system_rhs, system_matrix);

            ls.SetMatrixIsSymmetric();
            ls.SetAbsoluteTolerance(1e-9);
            ls.SetKspType("chebychev");
            ls.SetPcType("bjacobi");

            Vec solution = ls.Solve();

            chebyshev_its = ls.GetNumIterations();

            PetscTools::Destroy(system_matrix);
            PetscTools::Destroy(system_rhs);
            PetscTools::Destroy(solution);
        }
        Timer::Print("Chebyshev");

        TS_ASSERT_LESS_THAN(cg_its, 15u); // Takes 14 iterations with 16 cores
        TS_ASSERT_LESS_THAN(chebyshev_its, 17u); // Takes 16 iterations with 16 cores

        PetscTools::Destroy(parallel_layout);
    }