Exemplo n.º 1
0
    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();
    }
Exemplo n.º 2
0
    /*
     * 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();
    }
Exemplo n.º 3
0
    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);
    }
Exemplo n.º 4
0
    // Covers some bits that aren't covered in the tests above,
    void TestOtherCoverage() throw(Exception)
    {
        TetrahedralMesh<2,2> fine_mesh;
        fine_mesh.ConstructRegularSlabMesh(0.1, 1.0, 1.0);

        QuadraticMesh<2> coarse_mesh(1.0, 1.0, 1.0);

        /*
         * Rotate the mesh by 45 degrees, makes it possible (since boxes no
         * longer lined up with elements) for the containing element of a
         * quad point to be in a *local* box, ie not an element contained
         * in the box containing this point.
         */
        c_matrix<double,2,2> rotation_mat;
        rotation_mat(0,0) = 1.0/sqrt(2.0);
        rotation_mat(1,0) = -1.0/sqrt(2.0);
        rotation_mat(0,1) = 1.0/sqrt(2.0);
        rotation_mat(1,1) = 1.0/sqrt(2.0);

        fine_mesh.Rotate(rotation_mat);
        coarse_mesh.Rotate(rotation_mat);

        GaussianQuadratureRule<2> quad_rule(3);

        FineCoarseMeshPair<2> mesh_pair(fine_mesh,coarse_mesh);
        mesh_pair.SetUpBoxesOnFineMesh();
        mesh_pair.ComputeFineElementsAndWeightsForCoarseQuadPoints(quad_rule, true);
        TS_ASSERT_EQUALS(mesh_pair.mNotInMesh.size(), 0u);

        /*
         * Repeat again with smaller boxes, covers the bit requiring the whole
         * mesh to be searched to find an element for a particular quad point.
         */
        FineCoarseMeshPair<2> mesh_pair2(fine_mesh,coarse_mesh);
        mesh_pair2.SetUpBoxesOnFineMesh(0.01);
        mesh_pair2.ComputeFineElementsAndWeightsForCoarseQuadPoints(quad_rule, true);
        TS_ASSERT_EQUALS(mesh_pair.mNotInMesh.size(), 0u);
    }
Exemplo n.º 5
0
    void TestWithDefaultBoxWidth() throw(Exception)
    {
        TetrahedralMesh<2,2> fine_mesh;
        fine_mesh.ConstructRegularSlabMesh(0.1, 1.0, 1.0);

        QuadraticMesh<2> coarse_mesh(1.0, 1.0, 1.0);

        FineCoarseMeshPair<2> mesh_pair(fine_mesh,coarse_mesh);

        mesh_pair.SetUpBoxesOnFineMesh();

        /*
         * With this mesh the proposed width - the width that would correspond to 20 boxes
         * in the x-direction is:
         *   Proposed width = 0.0552632
         * but
         *   max_edge_length = 0.141421
         * and we want width > max_edge_length, so end up with
         *   box width = 0.155563
         * (1.1 times max edge length)
         */
        TS_ASSERT_EQUALS(mesh_pair.mpFineMeshBoxCollection->GetNumBoxes(), 64u);

        // Now use a mesh with a smaller edge length
        TetrahedralMesh<2,2> fine_mesh2;
        fine_mesh2.ConstructRegularSlabMesh(0.01, 1.0,1.0);

        /*
         * Can use smaller boxes
         *  Proposed width = 0.0552632
         *  max_edge_length = 0.0141421
         *  box width = 0.0552632
         */
        FineCoarseMeshPair<2> mesh_pair2(fine_mesh2,coarse_mesh);
        mesh_pair2.SetUpBoxesOnFineMesh();
        TS_ASSERT_EQUALS(mesh_pair2.mpFineMeshBoxCollection->GetNumBoxes(), 20*20u);
    }
Exemplo n.º 6
0
    void TestComputeCoarseElementsForFineElementCentroids() throw(Exception)
    {
        TetrahedralMesh<2,2> fine_mesh;
        fine_mesh.ConstructRegularSlabMesh(0.2, 1.0, 1.0);

        QuadraticMesh<2> coarse_mesh(1.0, 1.0, 1.0); // 2 triangular elements

        FineCoarseMeshPair<2> mesh_pair(fine_mesh,coarse_mesh);

        TS_ASSERT_THROWS_CONTAINS(mesh_pair.ComputeCoarseElementsForFineElementCentroids(true),"Call SetUpBoxesOnCoarseMesh()");

        mesh_pair.SetUpBoxesOnCoarseMesh();
        mesh_pair.ComputeCoarseElementsForFineElementCentroids(true);

        //Check that the indices of the coarse mesh elements are as expected
        unsigned lower_left_element_index=1u;
        ChastePoint<2> lower_left(0.25, 0.25);
        TS_ASSERT_EQUALS(coarse_mesh.GetContainingElementIndex(lower_left), lower_left_element_index);

        unsigned upper_right_element_index=0u;
        ChastePoint<2> upper_right(0.75, 0.75);
        TS_ASSERT_EQUALS(coarse_mesh.GetContainingElementIndex(upper_right), upper_right_element_index);

        TS_ASSERT_EQUALS( mesh_pair.rGetCoarseElementsForFineElementCentroids().size(), fine_mesh.GetNumElements());
        for (unsigned i=0; i<fine_mesh.GetNumElements(); i++)
        {
            double x = fine_mesh.GetElement(i)->CalculateCentroid()(0);
            double y = fine_mesh.GetElement(i)->CalculateCentroid()(1);
            if (x+y < 1.0)
            {
                TS_ASSERT_EQUALS(mesh_pair.rGetCoarseElementsForFineElementCentroids()[i], lower_left_element_index);
            }
            else
            {
                TS_ASSERT_EQUALS(mesh_pair.rGetCoarseElementsForFineElementCentroids()[i], upper_right_element_index);
            }
        }

        // Coverage
        mesh_pair.DeleteCoarseBoxCollection();
        mesh_pair.SetUpBoxesOnCoarseMesh(0.8); // force a point to be found in a neighbouring box
        mesh_pair.ComputeCoarseElementsForFineElementCentroids(true);

        mesh_pair.DeleteCoarseBoxCollection();
        mesh_pair.SetUpBoxesOnCoarseMesh(0.1); // force a point to be found in a nonlocal box
        mesh_pair.ComputeCoarseElementsForFineElementCentroids(true);

        mesh_pair.DeleteCoarseBoxCollection();
        mesh_pair.SetUpBoxesOnCoarseMesh(); // back to default

        /*
         * Translate the fine mesh in the (-1, -1) direction --> all fine elements
         * nearest to (not contained in) element 0. We have to make the fine mesh
         * tiny and then translate a small amount so that it is still in the box
         * collection for the coarse (normally the two meshes should overlap).
         */
        fine_mesh.Scale(1e-2, 1e-2);
        fine_mesh.Translate(-1.1e-2, -1.1e-2);
        mesh_pair.ComputeCoarseElementsForFineElementCentroids(true);
        TS_ASSERT_EQUALS( mesh_pair.rGetCoarseElementsForFineElementCentroids().size(), fine_mesh.GetNumElements());
        for (unsigned i=0; i<fine_mesh.GetNumElements(); i++)
        {
            TS_ASSERT_EQUALS( mesh_pair.rGetCoarseElementsForFineElementCentroids()[i], lower_left_element_index);
        }
    }
Exemplo n.º 7
0
    void TestComputeCoarseElementsForFineNodes() throw(Exception)
    {
        TetrahedralMesh<2,2> fine_mesh;
        fine_mesh.ConstructRegularSlabMesh(0.2, 1.0, 1.0);

        QuadraticMesh<2> coarse_mesh(1.0, 1.0, 1.0); // 2 triangular elements

        FineCoarseMeshPair<2> mesh_pair(fine_mesh,coarse_mesh);
        TS_ASSERT_THROWS_CONTAINS(mesh_pair.ComputeCoarseElementsForFineNodes(true),"Call SetUpBoxesOnCoarseMesh()");

        mesh_pair.SetUpBoxesOnCoarseMesh();
        mesh_pair.ComputeCoarseElementsForFineNodes(true);

        //Check that the indices of the coarse mesh elements are as expected
        unsigned lower_left_element_index=1u;
        ChastePoint<2> lower_left(0.25, 0.25);
        TS_ASSERT_EQUALS(coarse_mesh.GetContainingElementIndex(lower_left), lower_left_element_index);
        ChastePoint<2> lower_left1(0.1, 0.25); //Double check that there is a `backslash`
        ChastePoint<2> lower_left2(0.25, 0.1);
        TS_ASSERT_EQUALS(coarse_mesh.GetContainingElementIndex(lower_left1), lower_left_element_index);
        TS_ASSERT_EQUALS(coarse_mesh.GetContainingElementIndex(lower_left2), lower_left_element_index);

        unsigned upper_right_element_index=0u;
        ChastePoint<2> upper_right(0.75, 0.75);
        TS_ASSERT_EQUALS(coarse_mesh.GetContainingElementIndex(upper_right), upper_right_element_index);

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

            if ( x+y < 1.0 - 1e-5 )  // x+y < 1
            {
                TS_ASSERT_EQUALS(mesh_pair.rGetCoarseElementsForFineNodes()[i], lower_left_element_index);
            }
            else if ( x+y > 1.0 + 1e-5 )  // x+y > 1
            {
                TS_ASSERT_EQUALS(mesh_pair.rGetCoarseElementsForFineNodes()[i], upper_right_element_index);
            }
            else // x=1-y, so in both elements, result could be either. However, it should find 0 first
            {
                //TS_ASSERT_LESS_THAN(mesh_pair.rGetCoarseElementsForFineNodes()[i], 2u);
                TS_ASSERT_EQUALS(mesh_pair.rGetCoarseElementsForFineNodes()[i], 0u);
            }
        }

        /*
         * Translate the fine mesh in the (-1, -1) direction --> all fine nodes
         * nearest to (not contained in) element 0. We have to make the fine mesh
         * tiny and then translate a small amount so that it is still in the box
         * collection for the coarse (normally the two meshes should overlap).
         */
        fine_mesh.Scale(1e-2, 1e-2);
        fine_mesh.Translate(-1.1e-2, -1.1e-2);
        mesh_pair.ComputeCoarseElementsForFineNodes(true);
        for (unsigned i=0; i<fine_mesh.GetNumNodes(); i++)
        {
            TS_ASSERT_EQUALS(mesh_pair.rGetCoarseElementsForFineNodes()[i], lower_left_element_index);
        }

        // Call again with safeMode=false this time (same results, faster)
        mesh_pair.rGetCoarseElementsForFineNodes()[0] = 189342958;
        mesh_pair.ComputeCoarseElementsForFineNodes(false);
        for (unsigned i=0; i<fine_mesh.GetNumNodes(); i++)
        {
            TS_ASSERT_EQUALS(mesh_pair.rGetCoarseElementsForFineNodes()[i], lower_left_element_index);
        }

        // Coverage:
        //  call again
        mesh_pair.SetUpBoxesOnCoarseMesh();
        //  delete
        mesh_pair.DeleteCoarseBoxCollection();
    }
Exemplo n.º 8
0
    void TestWithCoarseContainedInFine() 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 has h=1 on unit cube (so 6 elements)
        QuadraticMesh<3> coarse_mesh(1.0, 1.0, 1.0, 1.0);

        FineCoarseMeshPair<3> mesh_pair(fine_mesh,coarse_mesh);

        mesh_pair.SetUpBoxesOnFineMesh(0.3);

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

        // For each node, find containing box. That box should contain any element that node is in.
        for (unsigned i=0; i<fine_mesh.GetNumNodes(); i++)
        {
            unsigned box_index = mesh_pair.mpFineMeshBoxCollection->CalculateContainingBox(fine_mesh.GetNode(i));

            assert(fine_mesh.GetNode(i)->rGetContainingElementIndices().size() > 0);

            for (std::set<unsigned>::iterator iter = fine_mesh.GetNode(i)->rGetContainingElementIndices().begin();
                iter != fine_mesh.GetNode(i)->rGetContainingElementIndices().end();
                ++iter)
            {
                Element<3,3>* p_element = fine_mesh.GetElement(*iter);
                TS_ASSERT_DIFFERS( mesh_pair.mpFineMeshBoxCollection->rGetBox(box_index).rGetElementsContained().find(p_element), mesh_pair.mpFineMeshBoxCollection->rGetBox(box_index).rGetElementsContained().end() )
            }
        }

        GaussianQuadratureRule<3> quad_rule(3);
        mesh_pair.ComputeFineElementsAndWeightsForCoarseQuadPoints(quad_rule, 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
        // 6 elements, 8 quad points
        TS_ASSERT_EQUALS(mesh_pair.rGetElementsAndWeights().size(), 6*8u);

        // Some hardcoded values, just to check element_nums not all zero
        TS_ASSERT_EQUALS(mesh_pair.rGetElementsAndWeights()[0].ElementNum,  3816u);
        TS_ASSERT_EQUALS(mesh_pair.rGetElementsAndWeights()[10].ElementNum, 217u);
        TS_ASSERT_EQUALS(mesh_pair.rGetElementsAndWeights()[20].ElementNum, 1094u);

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

            /*
             * As all the quadrature points should have been found in the fine mesh,
             * all the weights should be between 0 and 1.
             * 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<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);
            }
        }

        TS_ASSERT_EQUALS(mesh_pair.mStatisticsCounters[0], 6*8u);
        TS_ASSERT_EQUALS(mesh_pair.mStatisticsCounters[1], 0u);
        mesh_pair.PrintStatistics();

        mesh_pair.DeleteFineBoxCollection();
        TS_ASSERT(mesh_pair.mpFineMeshBoxCollection==NULL);
    }
VoltageInterpolaterOntoMechanicsMesh<DIM>::VoltageInterpolaterOntoMechanicsMesh(
                                     TetrahedralMesh<DIM,DIM>& rElectricsMesh,
                                     QuadraticMesh<DIM>& rMechanicsMesh,
                                     std::vector<std::string>& rVariableNames,
                                     std::string directory,
                                     std::string inputFileNamePrefix)
{
    // Read the data from the HDF5 file
    Hdf5DataReader reader(directory,inputFileNamePrefix);

    unsigned num_timesteps = reader.GetUnlimitedDimensionValues().size();

    // set up the elements and weights for the coarse nodes in the fine mesh
    FineCoarseMeshPair<DIM> mesh_pair(rElectricsMesh, rMechanicsMesh);
    mesh_pair.SetUpBoxesOnFineMesh();
    mesh_pair.ComputeFineElementsAndWeightsForCoarseNodes(true);
    assert(mesh_pair.rGetElementsAndWeights().size()==rMechanicsMesh.GetNumNodes());

    // create and setup a writer
    Hdf5DataWriter* p_writer = new Hdf5DataWriter(*rMechanicsMesh.GetDistributedVectorFactory(),
                                                  directory,
                                                  "voltage_mechanics_mesh",
                                                  false, //don't clean
                                                  false);

    std::vector<int> columns_id;
    for (unsigned var_index = 0; var_index < rVariableNames.size(); var_index++)
    {
        std::string var_name = rVariableNames[var_index];
        columns_id.push_back( p_writer->DefineVariable(var_name,"mV") );
    }

    p_writer->DefineUnlimitedDimension("Time","msecs", num_timesteps);
    p_writer->DefineFixedDimension( rMechanicsMesh.GetNumNodes() );
    p_writer->EndDefineMode();

    assert(columns_id.size() == rVariableNames.size());

    // set up a vector to read into
    DistributedVectorFactory factory(rElectricsMesh.GetNumNodes());
    Vec voltage = factory.CreateVec();
    std::vector<double> interpolated_voltages(rMechanicsMesh.GetNumNodes());
    Vec voltage_coarse = NULL;

    for(unsigned time_step=0; time_step<num_timesteps; time_step++)
    {
        for (unsigned var_index = 0; var_index < rVariableNames.size(); var_index++)
        {
            std::string var_name = rVariableNames[var_index];
            // read
            reader.GetVariableOverNodes(voltage, var_name, time_step);
            ReplicatableVector voltage_repl(voltage);

            // interpolate
            for(unsigned i=0; i<mesh_pair.rGetElementsAndWeights().size(); i++)
            {
                double interpolated_voltage = 0;

                Element<DIM,DIM>& element = *(rElectricsMesh.GetElement(mesh_pair.rGetElementsAndWeights()[i].ElementNum));
                for(unsigned node_index = 0; node_index<element.GetNumNodes(); node_index++)
                {
                    unsigned global_node_index = element.GetNodeGlobalIndex(node_index);
                    interpolated_voltage += voltage_repl[global_node_index]*mesh_pair.rGetElementsAndWeights()[i].Weights(node_index);
                }

                interpolated_voltages[i] = interpolated_voltage;
            }

            if(voltage_coarse!=NULL)
            {
                PetscTools::Destroy(voltage_coarse);
            }
            voltage_coarse = PetscTools::CreateVec(interpolated_voltages);
            // write
            p_writer->PutVector(columns_id[var_index], voltage_coarse);
        }
        p_writer->PutUnlimitedVariable(time_step);
        p_writer->AdvanceAlongUnlimitedDimension();
    }

    if(voltage_coarse!=NULL)
    {
        PetscTools::Destroy(voltage);
        PetscTools::Destroy(voltage_coarse);
    }

    // delete to flush
    delete p_writer;

    // Convert the new data to CMGUI format.
    // alter the directory in HeartConfig as that is where Hdf5ToCmguiConverter decides
    // where to output
    std::string config_directory = HeartConfig::Instance()->GetOutputDirectory();
    HeartConfig::Instance()->SetOutputDirectory(directory);
    Hdf5ToCmguiConverter<DIM,DIM> converter(FileFinder(directory, RelativeTo::ChasteTestOutput),
                                            "voltage_mechanics_mesh",
                                            &rMechanicsMesh,
                                            false);
    HeartConfig::Instance()->SetOutputDirectory(config_directory);
}