Example #1
0
    void TestAssigningModifiersToACellModel() throw(Exception)
    {
        boost::shared_ptr<ZeroStimulus> p_stimulus(new ZeroStimulus());
        boost::shared_ptr<EulerIvpOdeSolver> p_solver(new EulerIvpOdeSolver);
        CellShannon2004FromCellML* p_shannon = new CellShannon2004FromCellML(p_solver, p_stimulus);

        TS_ASSERT_EQUALS(p_shannon->HasModifier("Alan"), false);
        TS_ASSERT_THROWS_THIS(p_shannon->GetModifier("Alan"), "There is no modifier called Alan in this model.");


        // Default modifier shouldn't do anything to the value inputted to calc()
        TS_ASSERT_EQUALS(p_shannon->HasModifier("membrane_rapid_delayed_rectifier_potassium_current_conductance"), true);
        TS_ASSERT_DELTA(p_shannon->GetModifier("membrane_rapid_delayed_rectifier_potassium_current_conductance")->Calc(123,0),123,1e-9);

        // Make a new modifier
        boost::shared_ptr<AbstractModifier> p_new_modifier(new FixedModifier(-90.0));

        TS_ASSERT_THROWS_THIS(p_shannon->SetModifier("Alan",p_new_modifier), "There is no modifier called Alan in this model.");

        // Assign it to the Shannon model
        p_shannon->SetModifier("membrane_rapid_delayed_rectifier_potassium_current_conductance",p_new_modifier);

        // We should now get a new answer to this.
        TS_ASSERT_DELTA(p_shannon->GetModifier("membrane_rapid_delayed_rectifier_potassium_current_conductance")->Calc(0,0),-90,1e-9);

        delete p_shannon;
    }
    void TestProcessSpecificArchive() throw(Exception)
    {
        TS_ASSERT_THROWS_THIS(ProcessSpecificArchive<boost::archive::text_oarchive>::Get(),
                              "A ProcessSpecificArchive has not been set up.");
        TS_ASSERT_THROWS_THIS(ProcessSpecificArchive<boost::archive::text_iarchive>::Get(),
                              "A ProcessSpecificArchive has not been set up.");

        // Set up an output archive pointer
        OutputFileHandler handler("archive", false);
        handler.SetArchiveDirectory();
        std::string arch_path = ArchiveLocationInfo::GetProcessUniqueFilePath("test.arch");
        std::ofstream ofs(arch_path.c_str());
        boost::archive::text_oarchive* p_arch = new boost::archive::text_oarchive(ofs);

        // Test the ProcessSpecificArchive Get and Set methods with this
        ProcessSpecificArchive<boost::archive::text_oarchive>::Set(p_arch);
        TS_ASSERT(ProcessSpecificArchive<boost::archive::text_oarchive>::Get()==p_arch);
        delete p_arch;

        // Set up an input archive pointer
        std::ifstream ifs(arch_path.c_str());
        boost::archive::text_iarchive* p_arch2 = new boost::archive::text_iarchive(ifs);

        // Test the ProcessSpecificArchive Get and Set methods with this
        ProcessSpecificArchive<boost::archive::text_iarchive>::Set(p_arch2);
        TS_ASSERT(ProcessSpecificArchive<boost::archive::text_iarchive>::Get()==p_arch2);
        delete p_arch2;

        // Clean up
        ProcessSpecificArchive<boost::archive::text_iarchive>::Set(NULL);
        ProcessSpecificArchive<boost::archive::text_oarchive>::Set(NULL);
    }
    void TestReadingNclInformation() throw(Exception)
    {
        TrianglesMeshReader<3,3> mesh_reader_3d("mesh/test/data/simple_cube_binary");

        TS_ASSERT(mesh_reader_3d.HasNclFile());

        std::vector<unsigned> containing_element_indices = mesh_reader_3d.GetContainingElementIndices(0);
        TS_ASSERT_EQUALS(containing_element_indices.size(), 5u)
        TS_ASSERT_EQUALS(containing_element_indices[0], 0u);
        TS_ASSERT_EQUALS(containing_element_indices[1], 4u);
        TS_ASSERT_EQUALS(containing_element_indices[2], 8u);
        TS_ASSERT_EQUALS(containing_element_indices[3], 10u);
        TS_ASSERT_EQUALS(containing_element_indices[4], 11u);

        containing_element_indices = mesh_reader_3d.GetContainingElementIndices(7);
        TS_ASSERT_EQUALS(containing_element_indices.size(), 5u)
        TS_ASSERT_EQUALS(containing_element_indices[0], 3u);
        TS_ASSERT_EQUALS(containing_element_indices[1], 4u);
        TS_ASSERT_EQUALS(containing_element_indices[2], 5u);
        TS_ASSERT_EQUALS(containing_element_indices[3], 9u);
        TS_ASSERT_EQUALS(containing_element_indices[4], 10u);

        // Out of range
        TS_ASSERT_THROWS_THIS(containing_element_indices = mesh_reader_3d.GetContainingElementIndices(9), "Connectivity list does not exist - not enough nodes.");

        // Test exception if NCL file has wrong number of nodes
        TS_ASSERT_THROWS_THIS( READER_3D bad_mesh_reader("mesh/test/data/simple_cube_binary_ncl_corrupted"),
                           "NCL file does not contain the correct number of nodes for mesh");

    }
    void TestEnforceConstantTimeStep() throw(Exception)
    {
        TimeStepper stepper(0.0, 1.0, 0.3); // timestep does not divide, but no checking

        TS_ASSERT_THROWS_THIS( TimeStepper bad_const_dt_stepper(0.0, 1.0, 0.3, true),
                "TimeStepper estimates non-constant timesteps will need to be used: "
                "check timestep divides (end_time-start_time) (or divides printing timestep). "
                "[End time=1; start=0; dt=0.3; error=0.1]");

#ifdef _MSC_VER
        _set_output_format(_TWO_DIGIT_EXPONENT);
#endif
        TS_ASSERT_THROWS_THIS( TimeStepper bad_const_dt_stepper2(0.0, 1.0, 0.99999999, true),
                "TimeStepper estimates non-constant timesteps will need to be used: "
                "check timestep divides (end_time-start_time) (or divides printing timestep). "
                "[End time=1; start=0; dt=1; error=1e-08]");
        TimeStepper const_dt_stepper(0.0, 1.0, 0.1, true);
        unsigned counter = 0;
        while (!const_dt_stepper.IsTimeAtEnd())
        {
            counter++;
            TS_ASSERT_DELTA(const_dt_stepper.GetNextTimeStep(), 0.1, 1e-15);
            TS_ASSERT_EQUALS(const_dt_stepper.GetIdealTimeStep(), 0.1);
            const_dt_stepper.AdvanceOneTimeStep();
            if (const_dt_stepper.IsTimeAtEnd())
            {
                TS_ASSERT_EQUALS(const_dt_stepper.GetNextTimeStep(), 0.0);
            }
            else
            {
                TS_ASSERT_DELTA(const_dt_stepper.GetNextTimeStep(), 0.1, 1e-15);
            }
        }
        TS_ASSERT_EQUALS(counter,10u);
    }
Example #5
0
    // For #1199
    void TestFactorySetFromFactory()
    {
        unsigned num_procs = PetscTools::GetNumProcs();
        unsigned total_elements = (num_procs+1)*num_procs/2;
        unsigned my_rank = PetscTools::GetMyRank();

        DistributedVectorFactory uneven_factory(total_elements, my_rank+1);
        DistributedVectorFactory even_factory(total_elements);
        DistributedVectorFactory* p_even_orig = even_factory.GetOriginalFactory();

        TS_ASSERT_EQUALS(uneven_factory.GetNumProcs(), even_factory.GetNumProcs());
        TS_ASSERT_EQUALS(uneven_factory.GetProblemSize(), even_factory.GetProblemSize());
        bool any_differ = PetscTools::ReplicateBool(uneven_factory.GetLow() != even_factory.GetLow());
        TS_ASSERT(PetscTools::IsSequential() || any_differ);

        // Now make them equal
        even_factory.SetFromFactory(&uneven_factory);
        TS_ASSERT_EQUALS(uneven_factory.GetNumProcs(), even_factory.GetNumProcs());
        TS_ASSERT_EQUALS(uneven_factory.GetProblemSize(), even_factory.GetProblemSize());
        TS_ASSERT_EQUALS(uneven_factory.GetLow(), even_factory.GetLow());
        TS_ASSERT_EQUALS(uneven_factory.GetHigh(), even_factory.GetHigh());
        TS_ASSERT(even_factory.GetOriginalFactory() == p_even_orig);

        // Exceptions
        DistributedVectorFactory diff_procs(1, 2, total_elements, num_procs+1);
        TS_ASSERT_THROWS_THIS(even_factory.SetFromFactory(&diff_procs),
                              "Cannot set from a factory for a different number of processes.");
        DistributedVectorFactory diff_total(1, 2, total_elements+1, num_procs);
        TS_ASSERT_THROWS_THIS(even_factory.SetFromFactory(&diff_total),
                              "Cannot set from a factory for a different problem size.");
    }
 void TestOtherExceptions() throw(Exception)
 {
     TS_ASSERT_THROWS_THIS(READER_2D mesh_reader("mesh/test/data/nonexistent_file"),
             "Could not open data file: mesh/test/data/nonexistent_file.node");
     TS_ASSERT_THROWS_THIS(READER_2D mesh_reader("mesh/test/data/baddata/vertex_mesh_without_element_file"),
             "Could not open data file: mesh/test/data/baddata/vertex_mesh_without_element_file.cell");
 }
    void TestDerivedQuantities() throw (Exception)
    {
        ParameterisedOde ode;
        boost::shared_ptr<const AbstractOdeSystemInformation> p_info = ode.GetSystemInformation();

        TS_ASSERT_EQUALS(ode.GetNumberOfDerivedQuantities(), 1u);
        TS_ASSERT_EQUALS(ode.HasDerivedQuantity("2a_plus_y"), true);
        TS_ASSERT_EQUALS(ode.HasDerivedQuantity("Not_there"), false);
        TS_ASSERT_EQUALS(ode.GetDerivedQuantityIndex("2a_plus_y"), 0u);
        TS_ASSERT_EQUALS(ode.GetDerivedQuantityUnits(0u), "dimensionless");
        TS_ASSERT_EQUALS(ode.rGetDerivedQuantityNames().size(), 1u);
        TS_ASSERT_EQUALS(ode.rGetDerivedQuantityUnits().size(), 1u);
        TS_ASSERT_EQUALS(ode.rGetDerivedQuantityNames()[0], "2a_plus_y");
        TS_ASSERT_EQUALS(ode.rGetDerivedQuantityUnits()[0], "dimensionless");

        TS_ASSERT_EQUALS(p_info->HasDerivedQuantity("2a_plus_y"), true);
        TS_ASSERT_EQUALS(p_info->HasDerivedQuantity("Not_there"), false);
        TS_ASSERT_EQUALS(p_info->GetDerivedQuantityIndex("2a_plus_y"), 0u);
        TS_ASSERT_EQUALS(p_info->GetDerivedQuantityUnits(0u), "dimensionless");
        TS_ASSERT_EQUALS(p_info->rGetDerivedQuantityNames().size(), 1u);
        TS_ASSERT_EQUALS(p_info->rGetDerivedQuantityUnits().size(), 1u);
        TS_ASSERT_EQUALS(p_info->rGetDerivedQuantityNames()[0], "2a_plus_y");
        TS_ASSERT_EQUALS(p_info->rGetDerivedQuantityUnits()[0], "dimensionless");

        TS_ASSERT_EQUALS(ode.HasAnyVariable("2a_plus_y"), true);
        TS_ASSERT_EQUALS(ode.HasAnyVariable("Not_there"), false);
        TS_ASSERT_EQUALS(ode.GetAnyVariableIndex("2a_plus_y"), 2u);
        TS_ASSERT_EQUALS(ode.GetAnyVariableUnits(2u), "dimensionless");
        TS_ASSERT_EQUALS(p_info->GetAnyVariableIndex("2a_plus_y"), 2u);
        TS_ASSERT_EQUALS(p_info->GetAnyVariableUnits(2u), "dimensionless");

        std::vector<double> derived = ode.ComputeDerivedQuantitiesFromCurrentState(0.0);
        double a = ode.GetParameter(0);
        TS_ASSERT_EQUALS(a, 0.0);
        TS_ASSERT_DELTA(derived[0], 2*a, 1e-4);
        TS_ASSERT_DELTA(ode.GetAnyVariable(2u, 0.0), 2*a, 1e-4);
        TS_ASSERT_DELTA(ode.GetAnyVariable(2u, 0.0, &derived), 2*a, 1e-4);
        a = 1.0;
        ode.SetParameter(0, a);
        derived = ode.ComputeDerivedQuantities(0.0, ode.GetInitialConditions());
        TS_ASSERT_DELTA(derived[0], 2*a, 1e-4);
        double y = 10.0;
        ode.SetStateVariable(0, y);
        derived = ode.ComputeDerivedQuantitiesFromCurrentState(0.0);
        TS_ASSERT_DELTA(derived[0], 2*a+y, 1e-4);
        TS_ASSERT_DELTA(ode.GetAnyVariable(2u, 1.0/* ignored for this ODE */), 2*a+y, 1e-4);

        // Exceptions
        TS_ASSERT_THROWS_THIS(ode.GetDerivedQuantityIndex("Missing"), "No derived quantity named 'Missing'.");
        TS_ASSERT_THROWS_THIS(ode.GetDerivedQuantityUnits(1u), "The index passed in must be less than the number of derived quantities.");

        TwoDimOdeSystem ode2;
        TS_ASSERT_THROWS_THIS(ode2.ComputeDerivedQuantitiesFromCurrentState(0.0),
                              "This ODE system does not define derived quantities.");
        std::vector<double> doesnt_matter;
        TS_ASSERT_THROWS_THIS(ode2.ComputeDerivedQuantities(0.0, doesnt_matter),
                              "This ODE system does not define derived quantities.");
    }
    void TestVolumeConstraintPottsUpdateRuleIn2d() throw (Exception)
    {
        // Create a simple 2D PottsMesh with 2 elements
        PottsMeshGenerator<2> generator(4, 1, 2, 4, 2, 2, 1, 1, 1, true); // last bool makes elements start in bottom left
        PottsMesh<2>* p_mesh = generator.GetMesh();

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

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

        // Create an update law system
        VolumeConstraintPottsUpdateRule<2> volume_constraint;

        // Test get/set methods
        TS_ASSERT_DELTA(volume_constraint.GetDeformationEnergyParameter(), 0.5, 1e-12);
        TS_ASSERT_DELTA(volume_constraint.GetMatureCellTargetVolume(), 16.0, 1e-12);

        volume_constraint.SetDeformationEnergyParameter(1.0);
        volume_constraint.SetMatureCellTargetVolume(0.6);

        TS_ASSERT_DELTA(volume_constraint.GetDeformationEnergyParameter(), 1.0, 1e-12);
        TS_ASSERT_DELTA(volume_constraint.GetMatureCellTargetVolume(), 0.6, 1e-12);

        volume_constraint.SetDeformationEnergyParameter(0.5);
        volume_constraint.SetMatureCellTargetVolume(4.0);

        // Test EvaluateHamiltonianContribution()

        double alpha = volume_constraint.GetDeformationEnergyParameter();

        // Both points lie within cell 0
        TS_ASSERT_THROWS_THIS(volume_constraint.EvaluateHamiltonianContribution(0, 1, cell_population),
                              "The current node and target node must not be in the same element.");

        // Both points lie within cell 1
        TS_ASSERT_THROWS_THIS(volume_constraint.EvaluateHamiltonianContribution(8, 9, cell_population),
                              "The current node and target node must not be in the same element.");

        // Both points lie within cell medium
        TS_ASSERT_THROWS_THIS(volume_constraint.EvaluateHamiltonianContribution(2, 3, cell_population),
                              "At least one of the current node or target node must be in an element.");

        // Current site in cell 0; target site in cell medium
        double contribution = volume_constraint.EvaluateHamiltonianContribution(5, 6, cell_population);
        TS_ASSERT_DELTA(contribution, alpha, 1e-6);

        // Current site in cell medium; target site in cell 0
        contribution = volume_constraint.EvaluateHamiltonianContribution(6, 5, cell_population);
        TS_ASSERT_DELTA(contribution, alpha, 1e-6);

        // Current site in cell 0; target site in cell 1
        contribution = volume_constraint.EvaluateHamiltonianContribution(5, 9, cell_population);
        TS_ASSERT_DELTA(contribution, 2.0*alpha, 1e-6);
    }
    void TestAdhesionPottsUpdateRuleIn3d() throw (Exception)
    {
        // Create a simple 2D PottsMesh with 2 elements
        PottsMeshGenerator<3> generator(4, 2, 2, 2, 1, 2, 4, 1, 2, true);
        PottsMesh<3>* p_mesh = generator.GetMesh();

        TS_ASSERT_EQUALS(p_mesh->GetNumElements(), 2u);
        TS_ASSERT_EQUALS(p_mesh->GetNumNodes(), 32u);

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

        // Label cells 0 and 1
        MAKE_PTR(CellLabel, p_label);
        cells[0]->AddCellProperty(p_label);
        cells[1]->AddCellProperty(p_label);

        // Create cell population
        PottsBasedCellPopulation<3> cell_population(*p_mesh, cells);

        // Create an update law system
        AdhesionPottsUpdateRule<3> adhesion_update;

        // Set the parameters to facilitate calculations below.
        adhesion_update.SetCellCellAdhesionEnergyParameter(0.1);
        adhesion_update.SetCellBoundaryAdhesionEnergyParameter(0.2);

        // Test EvaluateHamiltonianContribution(). Note that the boundary of the domain is a void not medium.

        double gamma_cell_cell = adhesion_update.GetCellCellAdhesionEnergyParameter();
        double gamma_cell_boundary = adhesion_update.GetCellBoundaryAdhesionEnergyParameter();

        // Both points lie within cell 0
        TS_ASSERT_THROWS_THIS(adhesion_update.EvaluateHamiltonianContribution(0, 1, cell_population),
                              "The current node and target node must not be in the same element.");

        // Both points lie within cell 1
        TS_ASSERT_THROWS_THIS(adhesion_update.EvaluateHamiltonianContribution(2, 3, cell_population),
                              "The current node and target node must not be in the same element.");

        // Both points lie within cell medium
        TS_ASSERT_THROWS_THIS(adhesion_update.EvaluateHamiltonianContribution(16, 17, cell_population),
                               "At least one of the current node or target node must be in an element.");

        // Current site in cell 0; target site in cell medium
        double contribution = adhesion_update.EvaluateHamiltonianContribution(9, 17, cell_population);
        TS_ASSERT_DELTA(contribution, 3.0*gamma_cell_boundary, 1e-6);

        // Current site in cell medium; target site in cell 0
        contribution = adhesion_update.EvaluateHamiltonianContribution(17, 9, cell_population);
        TS_ASSERT_DELTA(contribution, 3.0*gamma_cell_boundary - gamma_cell_cell, 1e-6);

        // Current site in cell 0; target site in cell 1
        contribution = adhesion_update.EvaluateHamiltonianContribution(9, 10, cell_population);
        TS_ASSERT_DELTA(contribution, 2.0*gamma_cell_cell, 1e-6);
    }
Example #10
0
    void TestSurfaceAreaConstraintPottsUpdateRuleIn3d() throw (Exception)
    {
        // Create a simple 3D PottsMesh with 2 elements
        PottsMeshGenerator<3> generator(4, 2, 2, 4, 1, 2, 4, 1, 2, true);
        PottsMesh<3>* p_mesh = generator.GetMesh();

        TS_ASSERT_EQUALS(p_mesh->GetNumElements(), 2u);
        TS_ASSERT_EQUALS(p_mesh->GetNumNodes(), 64u);

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

        // Create cell population
        PottsBasedCellPopulation<3> cell_population(*p_mesh, cells);

        // Create an update law system
        SurfaceAreaConstraintPottsUpdateRule<3> surface_area_constraint;

        surface_area_constraint.SetDeformationEnergyParameter(0.5);
        surface_area_constraint.SetMatureCellTargetSurfaceArea(24.0);

        // Test EvaluateHamiltonianContribution()
        double gamma = surface_area_constraint.GetDeformationEnergyParameter();

        // Both points lie within cell 0
        TS_ASSERT_THROWS_THIS(surface_area_constraint.EvaluateHamiltonianContribution(0, 1, cell_population),
                              "The current node and target node must not be in the same element.");

        // Both points lie within cell 1
        TS_ASSERT_THROWS_THIS(surface_area_constraint.EvaluateHamiltonianContribution(2, 3, cell_population),
                              "The current node and target node must not be in the same element.");

        // Both points lie within cell medium
        TS_ASSERT_THROWS_THIS(surface_area_constraint.EvaluateHamiltonianContribution(8, 9, cell_population),
                               "At least one of the current node or target node must be in an element.");

        // Current site in cell 0; target site in cell medium Cell on edge of domain
        double contribution = surface_area_constraint.EvaluateHamiltonianContribution(4, 8, cell_population);
        TS_ASSERT_DELTA(contribution, 4.0*4.0*gamma, 1e-6);

        // Current site in cell medium; target site in cell 1
        contribution = surface_area_constraint.EvaluateHamiltonianContribution(10, 6, cell_population);
        TS_ASSERT_DELTA(contribution, 0.0, 1e-6);

        // Current site in cell 0; target site in cell 1
        contribution = surface_area_constraint.EvaluateHamiltonianContribution(17, 18, cell_population);
        TS_ASSERT_DELTA(contribution, 4.0*4.0*gamma, 1e-6);

        // Current site in cell 0; target site in cell 1 (diagonal switch)
        contribution = surface_area_constraint.EvaluateHamiltonianContribution(1, 18, cell_population);
        TS_ASSERT_DELTA(contribution, 4.0*4.0*gamma, 1e-6);

        // Current site in cell 0; target site in medium
        contribution = surface_area_constraint.EvaluateHamiltonianContribution(5, 9, cell_population);
        TS_ASSERT_DELTA(contribution, 4.0*4.0*gamma, 1e-6);
    }
Example #11
0
    void TestExceptions()
    {
        TrianglesMeshReader<1,1> mesh_reader("mesh/test/data/1D_0_to_10_100_elements");
        TetrahedralMesh<1,1> mesh;
        mesh.ConstructFromMeshReader(mesh_reader);

        TS_ASSERT_THROWS_THIS(mesh.RotateZ(1.4),"This rotation is not valid in less than 2D");
        TS_ASSERT_THROWS_THIS(mesh.RotateY(0.3),"This rotation is only valid in 3D");
        TS_ASSERT_THROWS_THIS(mesh.RotateX(0.7),"This rotation is only valid in 3D");
    }
    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");
    }
    void TestExceptions() throw(Exception)
    {
        TS_ASSERT_THROWS_THIS(MatrixVentilationProblem bad_problem("mesh/test/data/y_branch_3d_mesh", 1u),
                "Outlet node is not a boundary node");

        MatrixVentilationProblem problem("lung/test/data/three_bifurcations");
        TS_ASSERT_THROWS_THIS(problem.SolveProblemFromFile("DoesNotExist.txt", "out", "out"), "Could not open file DoesNotExist.txt");

        TS_ASSERT_THROWS_THIS(problem.SetPressureAtBoundaryNode(3u, 0.0), "Boundary conditions cannot be set at internal nodes");
        TS_ASSERT_THROWS_THIS(problem.SetFluxAtBoundaryNode(3u, 0.0), "Boundary conditions cannot be set at internal nodes");

    }
    /*
    * Here we set up a test with 5 nodes, make a cell for each. We then set cell
    * 0 to be associated with node 1 instead of node 0, and Validate() throws an
    * exception. We then set node 0 to be a particle node, and Validate() passes.
    */
    void TestValidateNodeBasedCellPopulationWithParticles() throw(Exception)
    {
        EXIT_IF_PARALLEL;    // This test doesn't work in parallel.

        // Create a simple mesh
        TrianglesMeshReader<2,2> mesh_reader("mesh/test/data/square_4_elements");
        TetrahedralMesh<2,2> generating_mesh;
        generating_mesh.ConstructFromMeshReader(mesh_reader);

        // Convert this to a NodesOnlyMesh
        NodesOnlyMesh<2> mesh;
        mesh.ConstructNodesWithoutMesh(generating_mesh, 1.5);

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

        std::vector<unsigned> cell_location_indices;
        for (unsigned i=0; i<cells.size(); i++)
        {
            cell_location_indices.push_back(i);
        }

        // Fails as the cell population constructor is not given the location indices
        // corresponding to real cells, so cannot work out which nodes are
        // particles
        std::vector<CellPtr> cells_copy(cells);
        TS_ASSERT_THROWS_THIS(NodeBasedCellPopulationWithParticles<2> dodgy_cell_population(mesh, cells_copy),
                              "Node 4 does not appear to be a particle or has a cell associated with it");

        // Passes as the cell population constructor automatically works out which
        // cells are particles using the mesh and cell_location_indices
        NodeBasedCellPopulationWithParticles<2> cell_population(mesh, cells, cell_location_indices);

        // Here we set the particles to what they already are
        std::set<unsigned> particle_indices;
        particle_indices.insert(mesh.GetNumNodes()-1);
        cell_population.SetParticles(particle_indices);

        // So validate passes at the moment
        cell_population.Validate();

        // Test GetCellUsingLocationIndex()
        TS_ASSERT_THROWS_NOTHING(cell_population.GetCellUsingLocationIndex(0)); // real cell
        TS_ASSERT_THROWS_THIS(cell_population.GetCellUsingLocationIndex(mesh.GetNumNodes()-1u),"Location index input argument does not correspond to a Cell"); // particles

        // Now we label a real cell's node as particle
        particle_indices.insert(1);

        // Validate detects this inconsistency
        TS_ASSERT_THROWS_THIS(cell_population.SetParticles(particle_indices),"Node 1 is labelled as a particle and has a cell attached");
    }
    void TestArchiveOpenerReadAndWrite() throw(Exception)
    {
        // Should this test fail with an exception involving
        // apps/texttest/chaste/resume_bidomain/save_bidomain
        // then look at TestCardiacSimulationArchiver
        mArchiveDir = "archiving_helpers";
        FileFinder archive_dir(mArchiveDir, RelativeTo::ChasteTestOutput);
        std::string archive_file = "archive_opener.arch";
        const unsigned test_int = 123;

        // Write
        {
            OutputArchiveOpener archive_opener_out(archive_dir, archive_file);
            boost::archive::text_oarchive* p_arch = archive_opener_out.GetCommonArchive();
            boost::archive::text_oarchive* p_process_arch = ProcessSpecificArchive<boost::archive::text_oarchive>::Get();

            (*p_arch) & test_int; // All can write to the common archive - non-masters will write to /dev/null.
            (*p_process_arch) & test_int;

            // archive_opener_out will do a PetscTools::Barrier when it is destructed
        }

        // Read
        {
            TS_ASSERT_THROWS_THIS(ProcessSpecificArchive<boost::archive::text_oarchive>::Get(),
                                  "A ProcessSpecificArchive has not been set up.");
            TS_ASSERT_THROWS_THIS(ProcessSpecificArchive<boost::archive::text_iarchive>::Get(),
                                  "A ProcessSpecificArchive has not been set up.");

            InputArchiveOpener archive_opener_in(archive_dir, archive_file);
            boost::archive::text_iarchive* p_arch = archive_opener_in.GetCommonArchive();
            boost::archive::text_iarchive* p_process_arch = ProcessSpecificArchive<boost::archive::text_iarchive>::Get();

            unsigned test_int1, test_int2;
            (*p_arch) & test_int1;
            (*p_process_arch) & test_int2;

            TS_ASSERT_EQUALS(test_int1, test_int);
            TS_ASSERT_EQUALS(test_int2, test_int);
        }

        // Cover the case of an archive in the chaste folder (i.e. a path relative to the working directory)
        if (PetscTools::IsSequential())
        {
            // Read
            FileFinder save_bidomain_dir("apps/texttest/chaste/resume_bidomain/save_bidomain", RelativeTo::ChasteSourceRoot);
            InputArchiveOpener archive_opener_relative(save_bidomain_dir, "archive.arch");
        }

        PetscTools::Barrier(); // Make sure all processes have finished this test before proceeding
    }
Example #16
0
    void TestVolumeConstraintPottsUpdateRuleIn3d() throw (Exception)
    {
        // Create a simple 2D PottsMesh with 2 elements
        PottsMeshGenerator<3> generator(4, 2, 2, 2, 1, 2, 4, 1, 2, true);
        PottsMesh<3>* p_mesh = generator.GetMesh();

        TS_ASSERT_EQUALS(p_mesh->GetNumElements(), 2u);
        TS_ASSERT_EQUALS(p_mesh->GetNumNodes(), 32u);

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

        // Create cell population
        PottsBasedCellPopulation<3> cell_population(*p_mesh, cells);

        // Create an update law system
        VolumeConstraintPottsUpdateRule<3> volume_constraint;

        // Test EvaluateHamiltonianContribution()
        volume_constraint.SetDeformationEnergyParameter(0.5);
        volume_constraint.SetMatureCellTargetVolume(8.0);

        double alpha = volume_constraint.GetDeformationEnergyParameter();

        // Both points lie within cell 0
        TS_ASSERT_THROWS_THIS(volume_constraint.EvaluateHamiltonianContribution(0, 1, cell_population),
                             "The current node and target node must not be in the same element.");

        // Both points lie within cell 1
        TS_ASSERT_THROWS_THIS(volume_constraint.EvaluateHamiltonianContribution(2, 3, cell_population),
                             "The current node and target node must not be in the same element.");

        // Both points lie within cell medium
        TS_ASSERT_THROWS_THIS(volume_constraint.EvaluateHamiltonianContribution(16, 17, cell_population),
                             "At least one of the current node or target node must be in an element.");

        // Current site in cell 0; target site in cell medium
        double contribution = volume_constraint.EvaluateHamiltonianContribution(9, 17, cell_population);
        TS_ASSERT_DELTA(contribution, alpha, 1e-6);

        // Current site in cell medium; target site in cell 0
        contribution = volume_constraint.EvaluateHamiltonianContribution(17, 9, cell_population);
        TS_ASSERT_DELTA(contribution, alpha, 1e-6);

        // Current site in cell 0; target site in cell 1
        contribution = volume_constraint.EvaluateHamiltonianContribution(9, 10, cell_population);
        TS_ASSERT_DELTA(contribution, 2.0*alpha, 1e-6);
    }
 void TestExceptions()
 {
     Ode1 ode;
     TS_ASSERT_EQUALS(ode.GetNumberOfStateVariables(), 1u);
     std::vector<double> v(2);
     v[0] = -1.0;
     v[1] = -2.0;
     TS_ASSERT_THROWS_THIS(ode.SetDefaultInitialConditions(v),
             "The number of initial conditions must be that of the number of state variables.");
     TS_ASSERT_THROWS_THIS(ode.SetDefaultInitialCondition(2, -3.0),
             "Index is greater than the number of state variables.");
     TS_ASSERT_THROWS_THIS(ode.SetStateVariables(v),
             "The size of the passed in vector must be that of the number of state variables.");
 }
    void TestEventExceptions() throw(Exception)
    {
        // Should not be able to end and event that has not yet begun
        TS_ASSERT_THROWS_THIS(HeartEventHandler::EndEvent(HeartEventHandler::EVERYTHING),
                "Error: The event associated with the counter for \'Total\' had not begun when EndEvent was called.");

        HeartEventHandler::BeginEvent(HeartEventHandler::EVERYTHING);

        // Beginning an event already begun should print an error message and disable the handler
        HeartEventHandler::BeginEvent(HeartEventHandler::EVERYTHING);
        TS_ASSERT(!HeartEventHandler::IsEnabled());
        // Report should then throw
        TS_ASSERT_THROWS_THIS(HeartEventHandler::Report(),
                "Asked to report on a disabled event handler.  Check for contributory errors above.");
    }
    /**
     * Check that GetNextNode() returns the coordinates of the correct node and the correct node attributes.
     * Compares the coordinates of the first two nodes with their known
     * values, checks that no errors are thrown for the remaining nodes and
     * that an error is thrown if we try to call the function too many times.
     */
    void TestGetNextNode() throw(Exception)
    {
        TrianglesMeshReader<2,2> mesh_reader("mesh/test/data/disk_984_elements");

        std::vector<double> first_node;
        first_node = mesh_reader.GetNextNode();

        TS_ASSERT_DELTA(first_node[0],  0.9980267283, 1e-6);
        TS_ASSERT_DELTA(first_node[1], -0.0627905195, 1e-6);

        // This mesh has zero attributes and one marker in the node file (as the header specifies).
        // we have to ensure that in such situation the last number in each node line is not mistakenly
        // read and interpreted as a node attribute (it is a node marker instead).
        TS_ASSERT_EQUALS(mesh_reader.GetNodeAttributes().size(), 0u);

        std::vector<double> next_node;
        next_node = mesh_reader.GetNextNode();

        TS_ASSERT_DELTA(next_node[0], 1.0, 1e-6);
        TS_ASSERT_DELTA(next_node[1], 0.0, 1e-6);

        for (int i=0; i<541; i++)
        {
            TS_ASSERT_THROWS_NOTHING(next_node = mesh_reader.GetNextNode());
        }

        TS_ASSERT_EQUALS(mesh_reader.GetNodeAttributes().size(), 0u);

        TS_ASSERT_THROWS_THIS(next_node = mesh_reader.GetNextNode(),
                              "File contains incomplete data: unexpected end of file.");
    }
    void TestCellProliferativeTypeMethods() throw(Exception)
    {
        MAKE_PTR(StemCellProliferativeType, p_type);
        TS_ASSERT_EQUALS(p_type->GetCellCount(), 0u);

        p_type->IncrementCellCount();
        TS_ASSERT_EQUALS(p_type->GetCellCount(), 1u);

        p_type->DecrementCellCount();
        TS_ASSERT_EQUALS(p_type->GetCellCount(), 0u);

        TS_ASSERT_THROWS_THIS(p_type->DecrementCellCount(),
                "Cannot decrement cell count: no cells have this cell property");
        TS_ASSERT_EQUALS(p_type->GetColour(), 0u);

        TS_ASSERT_EQUALS(p_type->IsType<StemCellProliferativeType>(), true);
        TS_ASSERT_EQUALS(p_type->IsType<TransitCellProliferativeType>(), false);

        MAKE_PTR(StemCellProliferativeType, p_stem_type);
        MAKE_PTR(TransitCellProliferativeType, p_transit_type);

        TS_ASSERT(p_stem_type->IsSame(p_type.get()));
        TS_ASSERT(p_type->IsSame(p_stem_type));

        TS_ASSERT_EQUALS(p_stem_type->IsSame(p_transit_type.get()), false);
        TS_ASSERT_EQUALS(p_transit_type->IsSame(p_stem_type), false);

        // Check that const-ness doesn't matter
        TS_ASSERT(p_stem_type->IsType<const StemCellProliferativeType>());
        const StemCellProliferativeType const_stem_type;

        TS_ASSERT(p_stem_type->IsSame(&const_stem_type));
        TS_ASSERT(const_stem_type.IsSame(p_stem_type));
        TS_ASSERT(const_stem_type.IsSame(p_stem_type.get()));
    }
    void TestConstruct1dParallelPopulation() throw (Exception)
    {
        NodesOnlyMesh<1> mesh;
        mesh.SetMaximumInteractionDistance(0.5);

        std::vector<CellPtr> cells;

        ParallelCellsGenerator<FixedDurationGenerationBasedCellCycleModel, 1> generator;
        c_vector<double, 2> bounding_box = generator.GetArchiveBoundingBox("cell_based/test/data/TestParallelConstruction/Population1d.dat");

        TS_ASSERT_DELTA(bounding_box[0], 0.0, 1e-4);
        TS_ASSERT_DELTA(bounding_box[1], 1.0, 1e-4);

        // Check an assertion which tests whether the space dimensions of the mesh and archive file are consistent.
        TS_ASSERT_THROWS_THIS(generator.GetArchiveBoundingBox("cell_based/test/data/TestParallelConstruction/Population2d.dat"), "Space dimension of ParallelCellsGenerator and archive file do not match");

        generator.GenerateParallelCells("cell_based/test/data/TestParallelConstruction/Population1d.dat", cells, mesh, CellPropertyRegistry::Instance()->Get<DifferentiatedCellProliferativeType>());

        unsigned num_nodes = mesh.GetNumNodes();
        unsigned total_nodes;

        MPI_Allreduce(&num_nodes, &total_nodes, 1, MPI_UNSIGNED, MPI_SUM, PetscTools::GetWorld());
        TS_ASSERT_EQUALS(total_nodes, 2u);

        unsigned num_cells = cells.size();
        unsigned total_cells;

        MPI_Allreduce(&num_cells, &total_cells, 1, MPI_UNSIGNED, MPI_SUM, PetscTools::GetWorld());
        TS_ASSERT_EQUALS(total_cells, 2u);

        for (unsigned i=0; i<cells.size(); i++)
        {
            TS_ASSERT(cells[i]->GetCellProliferativeType()->IsType<DifferentiatedCellProliferativeType>());
        }
    }
    /**
     * Check that the elements 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 elements) then an exception is thrown.
     */
    void TestElementsDataRead() throw(Exception)
    {
        TrianglesMeshReader<2,2> mesh_reader("mesh/test/data/disk_984_elements_indexed_from_1");

        TS_ASSERT_EQUALS( mesh_reader.GetNumElements(), 984u);

        ElementData data1 = mesh_reader.GetNextElementData();
        TS_ASSERT_EQUALS(data1.NodeIndices.size(), 3u);
        TS_ASSERT_EQUALS(data1.NodeIndices[0], 309u);
        TS_ASSERT_EQUALS(data1.NodeIndices[1], 144u);
        TS_ASSERT_EQUALS(data1.NodeIndices[2], 310u);
        TS_ASSERT_EQUALS( mesh_reader.GetNumElementAttributes(), 0u);

        for (unsigned i=1; i<mesh_reader.GetNumElements(); i++)
        {
            ElementData data = mesh_reader.GetNextElementData();
            TS_ASSERT_EQUALS(data.AttributeValue, 0u);
        }

        TrianglesMeshReader<2,2> mesh_reader2("mesh/test/data/baddata/bad_elements_disk_522_elements");

        // Reads element 0 from file
        TS_ASSERT_THROWS_NOTHING(mesh_reader2.GetNextElementData());
        // Reads element 2 from file when expecting number 1
        TS_ASSERT_THROWS_THIS(mesh_reader2.GetNextElementData(),"Data for item 1 missing");
    }
    void TestAttributes() throw (Exception)
    {
        ParameterisedOde ode;
        TS_ASSERT_EQUALS(ode.GetNumberOfAttributes(), 1u);
        TS_ASSERT(ode.HasAttribute("attr"));
        TS_ASSERT_DELTA(ode.GetAttribute("attr"), 1.1, 1e-12);
        TS_ASSERT(!ode.HasAttribute("missing"));
        TS_ASSERT_THROWS_THIS(ode.GetAttribute("missing"), "No attribute 'missing' found.");

        boost::shared_ptr<const AbstractOdeSystemInformation> p_info = ode.GetSystemInformation();
        TS_ASSERT_EQUALS(p_info->GetNumberOfAttributes(), 1u);
        TS_ASSERT(p_info->HasAttribute("attr"));
        TS_ASSERT_DELTA(p_info->GetAttribute("attr"), 1.1, 1e-12);
        TS_ASSERT(!p_info->HasAttribute("missing"));
        TS_ASSERT_THROWS_THIS(p_info->GetAttribute("missing"), "No attribute 'missing' found.");
    }
    void TestRefreshHaloCells() throw (Exception)
    {
#if BOOST_VERSION < 103700
        TS_ASSERT_THROWS_THIS(mpNodeBasedCellPopulation->SendCellsToNeighbourProcesses(),
                              "Parallel cell-based Chaste requires Boost >= 1.37");
#else
        // Set up the halo boxes and nodes.
        mpNodeBasedCellPopulation->Update();

        // Send and receive halo nodes.
        mpNodeBasedCellPopulation->RefreshHaloCells();

        mpNodeBasedCellPopulation->AddReceivedHaloCells();

        if (!PetscTools::AmMaster() && !PetscTools::AmTopMost())
        {
           TS_ASSERT_EQUALS(mpNodeBasedCellPopulation->mHaloCells.size(), 2u);
           TS_ASSERT_EQUALS(mpNodeBasedCellPopulation->mHaloCellLocationMap[mpNodeBasedCellPopulation->mHaloCells[0]], PetscTools::GetMyRank() - 1);
           TS_ASSERT_EQUALS(mpNodeBasedCellPopulation->mHaloCellLocationMap[mpNodeBasedCellPopulation->mHaloCells[1]], PetscTools::GetMyRank() + 1);
        }
        else if (!PetscTools::AmMaster() || !PetscTools::AmTopMost())
        {
           TS_ASSERT_EQUALS(mpNodeBasedCellPopulation->mHaloCells.size(), 1u);
        }
#endif
    }
    void TestSendAndRecieveCellsNonBlocking() throw (Exception)
    {
        unsigned index_of_node_to_send = mpNodesOnlyMesh->GetNodeIteratorBegin()->GetIndex();;
        mpNodeBasedCellPopulation->AddNodeAndCellToSendRight(index_of_node_to_send);
        mpNodeBasedCellPopulation->AddNodeAndCellToSendLeft(index_of_node_to_send);

        TS_ASSERT_EQUALS(mpNodeBasedCellPopulation->mCellCommunicationTag, 123u);

        TS_ASSERT(!(mpNodeBasedCellPopulation->mpCellsRecvRight));
        TS_ASSERT(!(mpNodeBasedCellPopulation->mpCellsRecvLeft));

#if BOOST_VERSION < 103700
        TS_ASSERT_THROWS_THIS(mpNodeBasedCellPopulation->SendCellsToNeighbourProcesses(),
                              "Parallel cell-based Chaste requires Boost >= 1.37");
#else
        mpNodeBasedCellPopulation->NonBlockingSendCellsToNeighbourProcesses();

        mpNodeBasedCellPopulation->GetReceivedCells();

        if (!PetscTools::AmTopMost())
        {
            TS_ASSERT_EQUALS(mpNodeBasedCellPopulation->mpCellsRecvRight->size(), 1u);

            unsigned index = (*mpNodeBasedCellPopulation->mpCellsRecvRight->begin()).second->GetIndex();
            TS_ASSERT_EQUALS(index, PetscTools::GetMyRank() + 1);
        }
        if (!PetscTools::AmMaster())
        {
            TS_ASSERT_EQUALS(mpNodeBasedCellPopulation->mpCellsRecvLeft->size(), 1u);

            unsigned index = (*mpNodeBasedCellPopulation->mpCellsRecvLeft->begin()).second->GetIndex();
            TS_ASSERT_EQUALS(index, PetscTools::GetMyRank() - 1);
        }
#endif
    }
Example #26
0
    void TestAddInitialApex() 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);

        double origin[3] = {0.0, 1.0, 0.0};
        double direction[3] = {0.0, 1.0, 0.0};
        double parent_direction[3] = {1.0, 0.0, 0.0};

        generator.AddInitialApex(origin, direction, parent_direction, 10.0, 0);
        generator.AddInitialApex(origin, direction, parent_direction, 10.0, 1);
        generator.AddInitialApex(origin, direction, parent_direction, 10.0, 1);
        generator.AddInitialApex(origin, direction, parent_direction, 10.0, 3);

        TS_ASSERT_EQUALS(generator.GetGenerations().size(), 30u);
        TS_ASSERT_EQUALS(generator.GetGenerations()[0].GetApices().size(), 1u);
        TS_ASSERT_EQUALS(generator.GetGenerations()[1].GetApices().size(), 2u);
        TS_ASSERT_EQUALS(generator.GetGenerations()[2].GetApices().size(), 0u);
        TS_ASSERT_EQUALS(generator.GetGenerations()[3].GetApices().size(), 1u);

        TS_ASSERT_EQUALS(generator.GetAirwayTree()->GetNumberOfPoints(), 4);

        //The generator only supports generations up to 30
        TS_ASSERT_THROWS_THIS(generator.AddInitialApex(origin, direction, parent_direction, 10.0, 35),
                              "Error: Airway generation can only generate up to 30 generations.");
#endif
    }
    void TestCellMutationStateMethods() throw(Exception)
    {
        MAKE_PTR(WildTypeCellMutationState, p_state);
        TS_ASSERT_EQUALS(p_state->GetCellCount(), 0u);
        p_state->IncrementCellCount();
        TS_ASSERT_EQUALS(p_state->GetCellCount(), 1u);
        p_state->DecrementCellCount();
        TS_ASSERT_EQUALS(p_state->GetCellCount(), 0u);
        TS_ASSERT_THROWS_THIS(p_state->DecrementCellCount(),
                              "Cannot decrement cell count: no cells have this cell property");
        TS_ASSERT_EQUALS(p_state->GetColour(), 0u);

        TS_ASSERT_EQUALS(p_state->IsType<WildTypeCellMutationState>(), true);
        TS_ASSERT_EQUALS(p_state->IsType<ApcOneHitCellMutationState>(), false);

        MAKE_PTR(WildTypeCellMutationState, p_wt_state);
        MAKE_PTR(ApcTwoHitCellMutationState, p_apc2_state);

        TS_ASSERT(p_wt_state->IsSame(p_state.get()));
        TS_ASSERT(p_state->IsSame(p_wt_state));
        TS_ASSERT_EQUALS(p_wt_state->IsSame(p_apc2_state.get()), false);
        TS_ASSERT_EQUALS(p_apc2_state->IsSame(p_wt_state), false);

        // Check that const-ness doesn't matter
        TS_ASSERT(p_wt_state->IsType<const WildTypeCellMutationState>());
        const WildTypeCellMutationState const_wt_state;
        TS_ASSERT(p_wt_state->IsSame(&const_wt_state));
        TS_ASSERT(const_wt_state.IsSame(p_wt_state));
        TS_ASSERT(const_wt_state.IsSame(p_wt_state.get()));
    }
 void TestExceptions() throw (Exception)
 {
     // Only TrianglesMeshReader supports cables
     MemfemMeshReader<3,3> memfem_reader("mesh/test/data/Memfem_slab");
     TS_ASSERT_EQUALS(memfem_reader.GetNumCableElements(), 0u);
     TS_ASSERT_EQUALS(memfem_reader.GetNumCableElementAttributes(), 0u);
     TS_ASSERT_THROWS_THIS(memfem_reader.GetNextCableElementData(), "Cable elements are not supported by this mesh format.");
 }
    void TestReading3dMeshWithPermutation() throw (Exception)
    {
        const unsigned ELEMENT_DIM = 3;
        const unsigned SPACE_DIM = 3;

        TrianglesMeshReader<ELEMENT_DIM,SPACE_DIM> mesh_reader_3d_ascii("mesh/test/data/simple_cube");
        TrianglesMeshReader<ELEMENT_DIM,SPACE_DIM> mesh_reader_3d("mesh/test/data/simple_cube_binary");
        TrianglesMeshReader<ELEMENT_DIM,SPACE_DIM> mesh_reader_3d_permuted("mesh/test/data/simple_cube_binary");

        unsigned num_nodes = mesh_reader_3d.GetNumNodes();
        std::vector<unsigned> permutation(num_nodes);
        for (unsigned node_index=0; node_index < num_nodes; node_index++)
        {
            permutation[node_index] = num_nodes-node_index-1;
        }

        TS_ASSERT_THROWS_THIS(mesh_reader_3d_ascii.SetNodePermutation(permutation),
                              "Permuted read can only be used with binary files since it requires random access to the node file.");

        TS_ASSERT_EQUALS(mesh_reader_3d_permuted.HasNodePermutation(), false);
        TS_ASSERT_EQUALS(mesh_reader_3d_permuted.rGetNodePermutation().size(), 0u);

        mesh_reader_3d_permuted.SetNodePermutation(permutation);

        TS_ASSERT_EQUALS(mesh_reader_3d_permuted.HasNodePermutation(), true);
        TS_ASSERT_EQUALS(mesh_reader_3d_permuted.rGetNodePermutation().size(), 9u);
        TS_ASSERT_EQUALS(mesh_reader_3d_permuted.rGetNodePermutation()[8], 0u);
        TS_ASSERT_EQUALS(mesh_reader_3d_permuted.rGetNodePermutation()[0], 8u);

        for (unsigned node_index=0; node_index < num_nodes; node_index++)
        {
            for (unsigned dimension=0; dimension<SPACE_DIM; dimension++)
            {
                TS_ASSERT_EQUALS( mesh_reader_3d.GetNode(permutation[node_index])[dimension],
                                  mesh_reader_3d_permuted.GetNode(node_index)[dimension]);
            }
        }

        for (unsigned element_index=0; element_index < mesh_reader_3d.GetNumElements(); element_index++)
        {
            for (unsigned local_node_index = 0; local_node_index < ELEMENT_DIM+1; local_node_index++)
            {
                unsigned original_mesh_global_index = mesh_reader_3d.GetElementData(element_index).NodeIndices[local_node_index];
                unsigned permuted_mesh_global_index = mesh_reader_3d_permuted.GetElementData(element_index).NodeIndices[local_node_index];
                TS_ASSERT_EQUALS(permutation[original_mesh_global_index], permuted_mesh_global_index);
            }
        }

        for (unsigned boundary_ele_index=0; boundary_ele_index < mesh_reader_3d.GetNumElements(); boundary_ele_index++)
        {
            for (unsigned local_node_index = 0; local_node_index < ELEMENT_DIM; local_node_index++)
            {
                unsigned original_mesh_global_index = mesh_reader_3d.GetFaceData(boundary_ele_index).NodeIndices[local_node_index];
                unsigned permuted_mesh_global_index = mesh_reader_3d_permuted.GetFaceData(boundary_ele_index).NodeIndices[local_node_index];
                TS_ASSERT_EQUALS(permutation[original_mesh_global_index], permuted_mesh_global_index);
            }
        }
    }
    void TestSpecifyingSecondaryArchive() throw (Exception)
    {
        FileFinder archive_dir("archive", RelativeTo::ChasteTestOutput);
        std::string archive_file = "specific_secondary.arch";
        const unsigned test_int = 321;
        const unsigned proc_id = PetscTools::GetMyRank();

        // Writing when specifying the secondary archive doesn't make sense
        {
            TS_ASSERT_THROWS_THIS(OutputArchiveOpener archive_opener_out(archive_dir, archive_file, UINT_MAX),
                                  "Specifying the secondary archive file ID doesn't make sense when writing.");
        }

        // Write normally so we can test reading
        {
            OutputArchiveOpener archive_opener_out(archive_dir, archive_file);
            boost::archive::text_oarchive* p_arch = archive_opener_out.GetCommonArchive();
            boost::archive::text_oarchive* p_process_arch = ProcessSpecificArchive<boost::archive::text_oarchive>::Get();

            (*p_arch) & test_int; // All can write to the common archive - non-masters will write to /dev/null.
            (*p_process_arch) & proc_id;

            // archive_opener_out will do a PetscTools::Barrier when it is destructed
        }

        // Read
        {
            TS_ASSERT_THROWS_THIS(ProcessSpecificArchive<boost::archive::text_oarchive>::Get(),
                                  "A ProcessSpecificArchive has not been set up.");
            TS_ASSERT_THROWS_THIS(ProcessSpecificArchive<boost::archive::text_iarchive>::Get(),
                                  "A ProcessSpecificArchive has not been set up.");

            InputArchiveOpener archive_opener_in(archive_dir, archive_file, 0);
            boost::archive::text_iarchive* p_arch = archive_opener_in.GetCommonArchive();
            boost::archive::text_iarchive* p_process_arch = ProcessSpecificArchive<boost::archive::text_iarchive>::Get();

            unsigned test_int1, test_int2;
            (*p_arch) & test_int1;
            (*p_process_arch) & test_int2;

            TS_ASSERT_EQUALS(test_int1, test_int);
            TS_ASSERT_EQUALS(test_int2, 0u);
        }
    }