// This test relies on TestArchiveOpenerReadAndWrite succeeding void TestArchiveOpenerExceptions() throw(Exception) { OutputFileHandler handler(mArchiveDir, false); handler.SetArchiveDirectory(); FileFinder archive_dir_finder(mArchiveDir, RelativeTo::ChasteTestOutput); std::string archive_base_name = "archive_opener.arch"; // Remove the process-specific archive for this process FileFinder(ArchiveLocationInfo::GetProcessUniqueFilePath(archive_base_name)).Remove(); TS_ASSERT_THROWS_CONTAINS(InputArchiveOpener archive_opener_in(archive_dir_finder, archive_base_name), "Cannot load secondary archive file: "); PetscTools::Barrier("TestArchiveOpenerExceptions-1"); // Remove the main archive if (PetscTools::AmMaster()) { ABORT_IF_THROWS(handler.FindFile(archive_base_name).Remove()); } PetscTools::Barrier("TestArchiveOpenerExceptions-2"); TS_ASSERT_THROWS_CONTAINS(InputArchiveOpener archive_opener_in(archive_dir_finder, archive_base_name), "Cannot load main archive file: "); // Remove write permissions on the archive dir //Note: changing *directory* permissions and other attributes does not work on Windows //See http://support.microsoft.com/kb/326549 #ifndef _MSC_VER if (PetscTools::AmMaster()) { chmod(handler.GetOutputDirectoryFullPath().c_str(), CHASTE_READONLY); } PetscTools::Barrier("TestArchiveOpenerExceptions-3"); /* * Now neither the master nor the slaves can write to their output files. * This avoids hitting a PetscBarrier() in the ~ArchiveOpener() because they * all throw an error first. * * If this test starts hanging it is because these TS_ASSERT_THROWS_CONTAINS * are not being thrown (rather than a real parallel calling problem). */ if (PetscTools::AmMaster()) { TS_ASSERT_THROWS_CONTAINS(OutputArchiveOpener archive_opener_out(archive_dir_finder, archive_base_name), "Failed to open main archive file for writing: "); } else { TS_ASSERT_THROWS_CONTAINS(OutputArchiveOpener archive_opener_out(archive_dir_finder, archive_base_name), "Failed to open secondary archive file for writing: "); } PetscTools::Barrier("TestArchiveOpenerExceptions-4"); if (PetscTools::AmMaster()) { // Restore permissions on the folder before allowing processes to continue. chmod(handler.GetOutputDirectoryFullPath().c_str(), CHASTE_READ_WRITE_EXECUTE); } #endif // _MSC_VER PetscTools::Barrier("TestArchiveOpenerExceptions-5"); }
void TestAssemblerMeshType() { TetrahedralMesh<2,2> mesh; ContinuumMechanicsProblemDefinition<2> problem_defn(mesh); TS_ASSERT_THROWS_CONTAINS(ContinuumMechanicsNeumannBcsAssembler<2>(&mesh, &problem_defn), "Continuum mechanics solvers require a quadratic mesh"); TetrahedralMesh<3,3> mesh3d; ContinuumMechanicsProblemDefinition<3> problem_defn3d(mesh3d); TS_ASSERT_THROWS_CONTAINS(ContinuumMechanicsNeumannBcsAssembler<3>(&mesh3d, &problem_defn3d), "Continuum mechanics solvers require a quadratic mesh"); }
void TestGetNodesByComponentValue() throw(Exception) { QuadraticMesh<2> mesh(0.1,1.0,1.0); mesh.Scale(1.0, 2.0); //historical reasons std::vector<unsigned> indices = NonlinearElasticityTools<2>::GetNodesByComponentValue(mesh,0,0); TS_ASSERT_EQUALS(indices.size(), 21u); for (unsigned i=0; i<indices.size(); i++) { TS_ASSERT_DELTA(mesh.GetNode(indices[i])->rGetLocation()[0], 0.0, 1e-12); } TrianglesMeshReader<3,3> reader("mesh/test/data/cube_136_elements"); TetrahedralMesh<3,3> mesh3d; mesh3d.ConstructFromMeshReader(reader); mesh3d.Scale(0.3423244,1.343244325,6.23435); std::vector<unsigned> indices3d = NonlinearElasticityTools<3>::GetNodesByComponentValue(mesh3d,2,6.23435); TS_ASSERT_EQUALS(indices3d.size(), 13u); for (unsigned i=0; i<indices3d.size(); i++) { TS_ASSERT_DELTA(mesh3d.GetNode(indices3d[i])->rGetLocation()[2], 6.23435, 1e-12); } TS_ASSERT_THROWS_CONTAINS(NonlinearElasticityTools<3>::GetNodesByComponentValue(mesh3d, 2, 6.234), "Could not find any nodes on requested surface (note: tolerance = 1e-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(); }
void TestReadingMissingAttributes() throw(Exception) { // The reader immediately reads and caches face data so missing attributes // immediately cause an Exception to be thrown TS_ASSERT_THROWS_CONTAINS(READER_2D mesh_reader("mesh/test/data/baddata/canonical_triangle_missing_edge_attribute"),"Error in reading attribute"); // The reader doesn't read node data until GetNextNode() is called READER_2D mesh_reader("mesh/test/data/baddata/canonical_triangle_missing_node_attribute"); TS_ASSERT_EQUALS(mesh_reader.GetNumNodes(), 3u); // Read the data for the first node successfully mesh_reader.GetNextNode(); TS_ASSERT_EQUALS(mesh_reader.GetNodeAttributes().size(), 2u); TS_ASSERT_DELTA(mesh_reader.GetNodeAttributes()[0], 8.234, 1e-6); TS_ASSERT_DELTA(mesh_reader.GetNodeAttributes()[1], 25.4, 1e-6); // The second node has a missing attribute TS_ASSERT_THROWS_CONTAINS(mesh_reader.GetNextNode(),"Error in reading attribute"); }
void TestReadingWithGenericReader() throw(Exception) { std::auto_ptr<AbstractMeshReader<2,2> > p_mesh_reader = GenericMeshReader<2,2>("mesh/test/data/disk_522_elements"); TS_ASSERT_EQUALS(p_mesh_reader->GetNumNodes(), 312u); TS_ASSERT_EQUALS(p_mesh_reader->GetNumElements(), 522u); TS_ASSERT_EQUALS(p_mesh_reader->GetNumFaceAttributes(), 1u); TS_ASSERT_EQUALS(p_mesh_reader->GetNumElementAttributes(), 0u); TS_ASSERT_THROWS_CONTAINS((GenericMeshReader<2,2>("mesh/test/data/no_such_file")), "Could not open appropriate mesh files for mesh/test/data/no_such_file"); }
void TestNodeExchange() throw(Exception) { HeartConfig::Instance()->Reset(); HeartConfig::Instance()->Reset(); DistributedTetrahedralMesh<1,1> mesh; mesh.ConstructRegularSlabMesh(0.1, 1.0); // [0,1] with h=0.1, ie 11 node mesh MyCardiacCellFactory cell_factory; cell_factory.SetMesh(&mesh); MonodomainTissue<1> monodomain_tissue( &cell_factory, true ); if ( PetscTools::GetNumProcs() == 1 ) { TS_ASSERT_EQUALS( mesh.GetNumHaloNodes(), 0u ); } else { if ( PetscTools::AmMaster() || PetscTools::AmTopMost() ) { TS_ASSERT_EQUALS( mesh.GetNumHaloNodes(), 1u ); } else { TS_ASSERT_EQUALS( mesh.GetNumHaloNodes(), 2u ); } } for (DistributedTetrahedralMesh<1,1>::HaloNodeIterator it=mesh.GetHaloNodeIteratorBegin(); it != mesh.GetHaloNodeIteratorEnd(); ++it) { AbstractCardiacCellInterface* cell = monodomain_tissue.GetCardiacCellOrHaloCell( (*it)->GetIndex() ); TS_ASSERT_DELTA(cell->GetStimulus(0.001),0,1e-10); } if ( PetscTools::AmMaster() ) { // Master owns node 0 AbstractCardiacCellInterface* cell = monodomain_tissue.GetCardiacCellOrHaloCell(0); TS_ASSERT_DELTA(cell->GetStimulus(0.001), -80.0, 1e-10); } else { // Zero is not halo owned by any process (unless we have a lot of them). TS_ASSERT_THROWS_CONTAINS(monodomain_tissue.GetCardiacCellOrHaloCell(0), "Requested node/halo 0 does not belong to processor "); } }
void TestGenericReader() throw (Exception) { std::auto_ptr<AbstractMeshReader<3, 3> > p_mesh_reader = GenericMeshReader<3,3>("mesh/test/data/Memfem_slab"); TS_ASSERT_EQUALS(p_mesh_reader->GetNumNodes(), 381u); TS_ASSERT_EQUALS(p_mesh_reader->GetNumElements(), 1030u); TS_ASSERT_EQUALS(p_mesh_reader->GetNumFaces(), 758u); TS_ASSERT_EQUALS(p_mesh_reader->GetNumElementAttributes(), 0u); TS_ASSERT_EQUALS(p_mesh_reader->GetNumFaceAttributes(), 0u); // The file does not exist TS_ASSERT_THROWS_CONTAINS((GenericMeshReader<3,3>("no_file")), "Could not open appropriate mesh files for no_file"); }
void TestExceptions() throw(Exception) { std::vector<double> freqs; freqs.push_back(4); freqs.push_back(7); freqs.push_back(20); std::vector<std::complex<double> > imps; imps.push_back(std::complex<double>(5, 2)); imps.push_back(std::complex<double>(4, 4)); imps.push_back(std::complex<double>(3.5, 4.5)); TS_ASSERT_THROWS_CONTAINS(ImpedancePostProcessor(freqs, imps), "Impedance post processor requires data points at 5 Hz & 20 Hz"); }
void TestOpenFutureBoostArchive() throw (Exception) { //Check testout/archive/specific_secondary.arch FileFinder archive_dir("global/test/data", RelativeTo::ChasteSourceRoot); std::string archive_file = "future_boost.arch"; // future_boost has got archive version 14 in it // 33 => 3 // 34 => 4 // 36 => 5 // 37 => 5 // 40 => 5 // 42 => 7 // 46 => 9 // 48 => 9 // 49 => 9 // 51 => 9 // 52 => ?? // 53 => 10 // 54 => 10 // 55 => 10 // 56 => 11 // 57 => 11 // 58 => 12 // 59 => 13 #ifndef BOOST_VERSION TS_FAIL("This test needs to know the version of Boost with which it was compiled."); return; #endif //#if BOOST_VERSION >= 999999 // 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(); // // const unsigned test_int = 321; // 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); //#else //Current Boost can't read this archive... TS_ASSERT_THROWS_CONTAINS(InputArchiveOpener archive_opener_in(archive_dir, archive_file, 0), "Could not open Boost archive '"); //#endif }
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 TestAcinarImpedance() throw(Exception) { TetrahedralMesh<1,3> mesh; TrianglesMeshReader<1,3> mesh_reader("mesh/test/data/y_branch_3d_mesh"); mesh.ConstructFromMeshReader(mesh_reader); TS_ASSERT_THROWS_CONTAINS(SimpleImpedanceProblem(mesh, 1u), "Outlet node is not a boundary node"); SimpleImpedanceProblem problem(mesh, 0u); problem.rGetMesh(); //for coverage unsigned node_index = 3; //Arbitrary terminal node problem.SetElastance(2*M_PI/2.0); TS_ASSERT_DELTA(real(problem.CalculateAcinusImpedance(mesh.GetNode(node_index), 0.0)), 0.0, 1e-6); TS_ASSERT_DELTA(real(problem.CalculateAcinusImpedance(mesh.GetNode(node_index), 1.0)), 0.0, 1e-6); TS_ASSERT_DELTA(imag(problem.CalculateAcinusImpedance(mesh.GetNode(node_index), 1.0)), -1.0, 1e-6); }
// Solve with a space step of 0.5mm. // // Note that this space step ought to be too big! // // NOTE: This test uses NON-PHYSIOLOGICAL parameters values (conductivities, // surface-area-to-volume ratio, capacitance, stimulus amplitude). Essentially, // the equations have been divided through by the surface-area-to-volume ratio. // (Historical reasons...) void TestMonodomainFailing() { if (PetscTools::GetNumProcs() > 3u) { TS_TRACE("This test is not suitable for more than 3 processes."); return; } HeartConfig::Instance()->SetIntracellularConductivities(Create_c_vector(0.0005)); HeartConfig::Instance()->SetSimulationDuration(1); //ms // HeartConfig::Instance()->SetMeshFileName("mesh/test/data/1D_0_to_1_20_elements"); // HeartConfig::Instance()->SetSpaceDimension(1); // HeartConfig::Instance()->SetFibreLength(1.0, 1.0/20.0); HeartConfig::Instance()->SetSpaceDimension(3); HeartConfig::Instance()->SetSlabDimensions(0.2, 0.1, 0.1, 0.05); HeartConfig::Instance()->SetOutputDirectory("MonoFailing"); HeartConfig::Instance()->SetOutputFilenamePrefix("MonodomainLR91_SVI"); HeartConfig::Instance()->SetUseStateVariableInterpolation(true); PlaneStimulusCellFactory<CellLuoRudy1991FromCellML, 3> cell_factory; MonodomainProblem<3> monodomain_problem(&cell_factory); monodomain_problem.Initialise(); HeartConfig::Instance()->SetSurfaceAreaToVolumeRatio(1.0); // HeartConfig::Instance()->SetCapacitance(1.0); // the mesh is too coarse, and this simulation will result in cell gating // variables going out of range. An exception should be thrown in the // EvaluateYDerivatives() method of the cell model TS_ASSERT_THROWS_CONTAINS(monodomain_problem.Solve(), #ifndef NDEBUG // VerifyStateVariables is only called when debug is on "State variable fast_sodium_current_m_gate__m has gone out of range. " "Check numerical parameters, for example time and space stepsizes"); #else // This test hits a later assert(!isnan) if we do a ndebug build. "Assertion tripped: !std::isnan(i_ionic)"); #endif // NDEBUG }
/** * Create a simulation of a NodeBasedCellPopulation to test movement threshold. */ void TestMovementThreshold() throw (Exception) { EXIT_IF_PARALLEL; // This test doesn't work in parallel because only one process will throw. // Creates nodes and mesh std::vector<Node<2>*> nodes; nodes.push_back(new Node<2>(0, false, 0.0, 0.0)); nodes.push_back(new Node<2>(0, false, 0.0, 0.3)); NodesOnlyMesh<2> mesh; mesh.ConstructNodesWithoutMesh(nodes, 1.5); // Create cells std::vector<CellPtr> cells; CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 2> cells_generator; cells_generator.GenerateBasicRandom(cells, mesh.GetNumNodes()); // Create a node based cell population NodeBasedCellPopulation<2> node_based_cell_population(mesh, cells); node_based_cell_population.SetAbsoluteMovementThreshold(1e-6); // Set up cell-based simulation OffLatticeSimulation<2> simulator(node_based_cell_population); simulator.SetEndTime(0.1); simulator.SetOutputDirectory("TestOffLatticeSimulationWithNodeBasedCellPopulationThreshold"); // Create a force law and pass it to the simulation MAKE_PTR(GeneralisedLinearSpringForce<2>, p_linear_force); p_linear_force->SetCutOffLength(1.5); simulator.AddForce(p_linear_force); // Solve TS_ASSERT_THROWS_CONTAINS(simulator.Solve(), "which is more than the AbsoluteMovementThreshold:"); // Avoid memory leak delete nodes[0]; delete nodes[1]; }
void TestKspExceptionsForCoverage() { TS_ASSERT_THROWS_NOTHING( KSPEXCEPT(2)); /* * These next few lines are designed to force the coverage test to pass. * Some are hard to throw in normal circumstances -- * "Unknown KSP error code" ought never to be thrown. */ TS_ASSERT_THROWS_CONTAINS( KSPEXCEPT(KSP_DIVERGED_ITS), "DIVERGED_ITS in function \'User provided function\' on line"); // The next one is deliberately fragile because it contains the line number in this test suite (to check that the line number is output correctly). TS_ASSERT_THROWS_THIS( KSPEXCEPT(KSP_DIVERGED_DTOL), "DIVERGED_DTOL in function \'User provided function\' on line 102 of file ./global/test/TestPetscSetup.hpp"); TS_ASSERT_THROWS( KSPEXCEPT(KSP_DIVERGED_BREAKDOWN), Exception ); TS_ASSERT_THROWS( KSPEXCEPT(KSP_DIVERGED_BREAKDOWN_BICG), Exception ); TS_ASSERT_THROWS( KSPEXCEPT(KSP_DIVERGED_NONSYMMETRIC), Exception ); TS_ASSERT_THROWS( KSPEXCEPT(KSP_DIVERGED_INDEFINITE_PC), Exception ); TS_ASSERT_THROWS( KSPEXCEPT(-735827), Exception ); KSPWARNIFFAILED(KSP_DIVERGED_ITS); TS_ASSERT_EQUALS(Warnings::Instance()->GetNumWarnings(), 1u); Warnings::QuietDestroy(); }
void RunTest(const std::string& rOutputDirName, const std::string& rModelName, const std::vector<std::string>& rArgs, bool testLookupTables=false, double tableTestV=-1000) { // Copy CellML file (and .out if present) into output dir OutputFileHandler handler(rOutputDirName, true); FileFinder cellml_file("heart/test/data/cellml/" + rModelName + ".cellml", RelativeTo::ChasteSourceRoot); handler.CopyFileTo(cellml_file); FileFinder out_file("heart/test/data/cellml/" + rModelName + ".out", RelativeTo::ChasteSourceRoot); if (out_file.Exists()) { handler.CopyFileTo(out_file); } // Create options file std::vector<std::string> args(rArgs); // args.push_back("--profile"); CellMLToSharedLibraryConverter converter(true); if (!args.empty()) { converter.CreateOptionsFile(handler, rModelName, args); } // Do the conversion FileFinder copied_file(rOutputDirName + "/" + rModelName + ".cellml", RelativeTo::ChasteTestOutput); DynamicCellModelLoaderPtr p_loader = converter.Convert(copied_file); // Apply a stimulus of -40 uA/cm^2 - should work for all models boost::shared_ptr<AbstractCardiacCellInterface> p_cell(CreateCellWithStandardStimulus(*p_loader, -40.0)); // Check that the default stimulus units are correct if (p_cell->HasCellMLDefaultStimulus()) { // Record the existing stimulus and re-apply it at the end boost::shared_ptr<AbstractStimulusFunction> original_stim = p_cell->GetStimulusFunction(); // Tell the cell to use the default stimulus and retrieve it boost::shared_ptr<RegularStimulus> p_reg_stim = p_cell->UseCellMLDefaultStimulus(); if (rModelName!="aslanidi_model_2009") // Even before recent changes aslanidi model has stimulus of -400 ! { // Stimulus magnitude should be approximately between -5 and -81 uA/cm^2 TS_ASSERT_LESS_THAN(p_reg_stim->GetMagnitude(),-5); TS_ASSERT_LESS_THAN(-81,p_reg_stim->GetMagnitude()); } // Stimulus duration should be approximately between 0.1 and 5 ms. TS_ASSERT_LESS_THAN(p_reg_stim->GetDuration(),6.01); TS_ASSERT_LESS_THAN(0.1,p_reg_stim->GetDuration()); // Stimulus period should be approximately between 70 (for bondarenko - seems fast! - would expect 8-10 beats per second for mouse) and 2000ms. TS_ASSERT_LESS_THAN(p_reg_stim->GetPeriod(),2000); TS_ASSERT_LESS_THAN(70,p_reg_stim->GetPeriod()); p_cell->SetIntracellularStimulusFunction(original_stim); } // Check lookup tables exist if they should if (testLookupTables && rModelName != "hodgkin_huxley_squid_axon_model_1952_modified") { double v = p_cell->GetVoltage(); p_cell->SetVoltage(tableTestV); TS_ASSERT_THROWS_CONTAINS(p_cell->GetIIonic(), "outside lookup table range"); p_cell->SetVoltage(v); } Simulate(rOutputDirName, rModelName, p_cell); }
void TestSolvePdeAndWriteResultsToFileAndGetPDESolutionAtPointWithoutCoarsePdeMeshDirichlet() throw(Exception) { EXIT_IF_PARALLEL; // Set up SimulationTime SimulationTime::Instance()->SetEndTimeAndNumberOfTimeSteps(0.5, 6); // Set up mesh MutableMesh<2,2> mesh; TrianglesMeshReader<2,2> mesh_reader("mesh/test/data/disk_522_elements"); mesh.ConstructFromMeshReader(mesh_reader); // Set up cells std::vector<CellPtr> cells; CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 2> cells_generator; cells_generator.GenerateBasic(cells, mesh.GetNumNodes()); // Set up cell population MeshBasedCellPopulation<2> cell_population(mesh, cells); // Create a PDE handler object using this cell population CellBasedPdeHandler<2> pde_handler(&cell_population); // Create a single PDE and pass to the handler SimplePdeForTesting pde; ConstBoundaryCondition<2> bc(1.0); PdeAndBoundaryConditions<2> pde_and_bc(&pde, &bc, false); pde_and_bc.SetDependentVariableName("variable"); // For coverage, provide an initial guess for the solution std::vector<double> data(mesh.GetNumNodes()); for (unsigned i=0; i<mesh.GetNumNodes(); i++) { data[i] = 1.0; } Vec vector = PetscTools::CreateVec(data); pde_and_bc.SetSolution(vector); pde_handler.AddPdeAndBc(&pde_and_bc); // Open result file ourselves OutputFileHandler output_file_handler("TestWritePdeSolution", false); pde_handler.mpVizPdeSolutionResultsFile = output_file_handler.OpenOutputFile("results.vizpdesolution"); // Solve PDE (set sampling timestep multiple to be large doesn't do anything as always output on 1st timestep) pde_handler.SolvePdeAndWriteResultsToFile(10); // Close result file ourselves pde_handler.mpVizPdeSolutionResultsFile->close(); // Test that this is correct by comparing with an existing results file std::string results_dir = output_file_handler.GetOutputDirectoryFullPath(); NumericFileComparison comparison(results_dir + "results.vizpdesolution", "cell_based/test/data/TestCellBasedPdeHandler/results.vizpdesolution"); TS_ASSERT(comparison.CompareFiles()); // Check the correct solution was obtained for (AbstractCellPopulation<2>::Iterator cell_iter = cell_population.Begin(); cell_iter != cell_population.End(); ++cell_iter) { double radius = norm_2(cell_population.GetLocationOfCellCentre(*cell_iter)); double analytic_solution = 1.0 - 0.25*(1 - pow(radius,2.0)); // Test that PDE solver is working correctly TS_ASSERT_DELTA(cell_iter->GetCellData()->GetItem("variable"), analytic_solution, 0.02); } // Now check the GetPdeSolutionAtPoint method // First loop over nodes and check it works // Check the correct solution was obtained for (AbstractCellPopulation<2>::Iterator cell_iter = cell_population.Begin(); cell_iter != cell_population.End(); ++cell_iter) { double cell_data_solution(cell_iter->GetCellData()->GetItem("variable")); c_vector<double,2> cell_location = cell_population.GetLocationOfCellCentre(*cell_iter); TS_ASSERT_DELTA(pde_handler.GetPdeSolutionAtPoint(cell_location,"variable"), cell_data_solution, 1e-6); } // Now choose some other points // Centre c_vector<double,2> point; point(0) = 0.0; point(1) = 0.0; TS_ASSERT_DELTA(pde_handler.GetPdeSolutionAtPoint(point,"variable"), 0.75, 0.01); // Cover exception TS_ASSERT_THROWS_CONTAINS(pde_handler.GetPdeSolutionAtPoint(point, "not_a_var"), "There is no PDE with that variable."); // Random point point(0) = 0.5; point(1) = 0.5; TS_ASSERT_DELTA(pde_handler.GetPdeSolutionAtPoint(point,"variable"), 1.0 - (1.0-2.0*0.5*0.5)/4.0, 0.01); // Point on the boundary point(0) = 1.0; point(1) = 0.0; TS_ASSERT_DELTA(pde_handler.GetPdeSolutionAtPoint(point,"variable"), 1.0, 1e-6); }
// These tests are older than the above tests.. void TestImplicitNhs2dOneMechanicsElement() throw(Exception) { PlaneStimulusCellFactory<CellLuoRudy1991FromCellML, 2> cell_factory(-1000*1000); HeartConfig::Instance()->SetSimulationDuration(10.0); CardiacElectroMechProbRegularGeom<2> problem(INCOMPRESSIBLE, 0.05, /* width (cm) */ 1, /* mech mesh size*/ 5, /* elec elem each dir */ &cell_factory, NHS, 1.0, /* mechanics solve timestep */ 0.01, /* contraction model ode timestep */ "TestCardiacElectroMechOneElement"); c_vector<double,2> pos; pos(0) = 0.05; pos(1) = 0.0; problem.SetWatchedPosition(pos); TS_ASSERT_THROWS_CONTAINS(problem.SetOutputDeformationGradientsAndStress(3.4),"not a multiple"); problem.SetOutputDeformationGradientsAndStress(3.0); problem.Solve(); // test by checking the length of the tissue against hardcoded value std::vector<c_vector<double,2> >& r_deformed_position = problem.rGetDeformedPosition(); TS_ASSERT_DELTA(r_deformed_position[1](0), 0.0497, 1e-4); OutputFileHandler handler("TestCardiacElectroMechOneElement",false); NumericFileComparison comparer(handler.GetOutputDirectoryFullPath() + "watched.txt","heart/test/data/good_watched.txt"); TS_ASSERT(comparer.CompareFiles(1e-2)); FileFinder electrics_dir = handler.FindFile("electrics"); TS_ASSERT(electrics_dir.IsDir()); // check electrics output was written TS_ASSERT(handler.FindFile("deformation/deformation_gradient_0.strain").Exists()); TS_ASSERT(handler.FindFile("deformation/deformation_gradient_3.strain").Exists()); TS_ASSERT(handler.FindFile("deformation/deformation_gradient_6.strain").Exists()); TS_ASSERT(handler.FindFile("deformation/second_PK_0.stress").Exists()); TS_ASSERT(handler.FindFile("deformation/second_PK_3.stress").Exists()); TS_ASSERT(handler.FindFile("deformation/second_PK_6.stress").Exists()); // coverage HeartConfig::Instance()->SetSimulationDuration(10.0); // has to be reset after a solve, it seems.. // We can now #2370 put any model anywhere, so these checks don't make sense... // CardiacElectroMechProbRegularGeom<2> prob_with_bad_model(INCOMPRESSIBLE,0.05,1,5,&cell_factory,NONPHYSIOL1,1,0.01,""); // TS_ASSERT_THROWS_CONTAINS(prob_with_bad_model.Solve(),"Invalid contraction model"); // // CardiacElectroMechProbRegularGeom<2> prob_with_bad_model_comp(COMPRESSIBLE,0.05,1,5,&cell_factory,NONPHYSIOL1,1,0.01,""); // TS_ASSERT_THROWS_CONTAINS(prob_with_bad_model_comp.Solve(),"Invalid contraction model"); CardiacElectroMechProbRegularGeom<2> prob_with_bad_timesteps(INCOMPRESSIBLE,0.05,1,5,&cell_factory,NHS,0.025,0.01,""); TS_ASSERT_THROWS_CONTAINS(prob_with_bad_timesteps.Initialise(),"does not divide"); MechanicsEventHandler::Headings(); MechanicsEventHandler::Report(); }
void TestHandler() throw(Exception) { // Test that CHASTE_TEST_OUTPUT always has a trailing slash even before // a class object is instantiated const std::string chaste_test_output(OutputFileHandler::GetChasteTestOutputDirectory()); TS_ASSERT_EQUALS( *(chaste_test_output.end()-1), '/'); // Make a handler that points straight to the CHASTE_TEST_OUTPUT directory. OutputFileHandler handler(""); const std::string handler_path(handler.GetOutputDirectoryFullPath()); TS_ASSERT(handler_path.length() > 0); TS_ASSERT_EQUALS(handler_path, handler.GetChasteTestOutputDirectory()); TS_ASSERT_EQUALS(handler.GetRelativePath(), ""); // Test that CHASTE_TEST_OUTPUT always has a trailing slash TS_ASSERT_EQUALS( *(handler_path.end()-1), '/'); // Make a handler that points to a sub-directory. std::string dir = "testhandler"; OutputFileHandler handler2(dir); std::string full_dir = handler2.GetOutputDirectoryFullPath(); TS_ASSERT_EQUALS(full_dir.substr(full_dir.length()-dir.length()-1), dir+"/"); TS_ASSERT_EQUALS(full_dir.substr(0, full_dir.length()-dir.length()-1), handler_path); TS_ASSERT_EQUALS(handler2.GetRelativePath(), dir); // We can also create handlers from a FileFinder (provided it points to a location in CHASTE_TEST_OUTPUT) OutputFileHandler handler3(handler.FindFile("testhandler2")); full_dir = handler3.GetOutputDirectoryFullPath(); TS_ASSERT_EQUALS(full_dir.substr(full_dir.length()-dir.length()-2), dir+"2/"); TS_ASSERT_EQUALS(full_dir.substr(0, full_dir.length()-dir.length()-2), handler_path); TS_ASSERT_EQUALS(handler3.GetRelativePath(), "testhandler2"); // Check that all three handlers can create files out_stream p_file_stream; p_file_stream = handler.OpenOutputFile("test_file", std::ios::out); TS_ASSERT(FileFinder(handler_path + "test_file").Exists()); p_file_stream = handler.OpenOutputFile("test_file2"); TS_ASSERT(FileFinder(handler_path + "test_file2").Exists()); p_file_stream = handler2.OpenOutputFile("test_file"); TS_ASSERT(FileFinder(handler2.GetOutputDirectoryFullPath() + "test_file").Exists()); p_file_stream = handler2.OpenOutputFile("test_", 34, ".txt"); TS_ASSERT(FileFinder(handler2.GetOutputDirectoryFullPath() + "test_34.txt").Exists()); p_file_stream = handler3.OpenOutputFile("test_file"); TS_ASSERT(FileFinder(handler3.GetOutputDirectoryFullPath() + "test_file").Exists()); // This should try to write files to /, which isn't allowed (we hope!) TS_ASSERT_THROWS_CONTAINS(OutputFileHandler bad_handler("../../../../../../../../../../../../../../../", false), "due to it potentially being above, and cleaning, CHASTE_TEST_OUTPUT."); TS_ASSERT_THROWS_CONTAINS(OutputFileHandler bad_handler("/", false), "The constructor argument to OutputFileHandler must be a relative path"); TS_ASSERT_THROWS_CONTAINS(OutputFileHandler bad_handler(FileFinder("/"), false), "The location provided to OutputFileHandler must be inside CHASTE_TEST_OUTPUT"); // Check the CopyFileTo method FileFinder source_file("global/test/TestOutputFileHandler.hpp", RelativeTo::ChasteSourceRoot); TS_ASSERT(!handler2.FindFile("TestOutputFileHandler.hpp").Exists()); PetscTools::Barrier("TestOutputFileHandler-0"); FileFinder dest_file = handler2.CopyFileTo(source_file); TS_ASSERT(dest_file.Exists()); FileFinder missing_file("global/no_file", RelativeTo::ChasteSourceRoot); TS_ASSERT_THROWS_CONTAINS(handler2.CopyFileTo(missing_file), "Can only copy single files"); FileFinder global_dir("global", RelativeTo::ChasteSourceRoot); TS_ASSERT_THROWS_CONTAINS(handler2.CopyFileTo(global_dir), "Can only copy single files"); // We don't want other people using CHASTE_TEST_OUTPUT whilst we are messing with it! PetscTools::Barrier("TestOutputFileHandler-1"); // Test that the environment variable actually influences the location of files { setenv("CHASTE_TEST_OUTPUT", "", 1/*Overwrite*/); // Check this folder is not present FileFinder test_folder("testoutput/whatever", RelativeTo::ChasteSourceRoot); TS_ASSERT(!test_folder.Exists()); PetscTools::Barrier("TestOutputFileHandler-2"); // Make a folder and erase it - NB only master can erase files and check it is successful! OutputFileHandler handler4("whatever"); TS_ASSERT(test_folder.Exists()); PetscTools::Barrier("TestOutputFileHandler-2b"); if (PetscTools::AmMaster()) { test_folder.Remove(); // If we've not written anything else to the testoutput folder, remove that too // rather than leaving an empty folder lieing around in the source tree! FileFinder output_root("", RelativeTo::ChasteTestOutput); if (output_root.IsEmpty()) { output_root.DangerousRemove(); } } PetscTools::Barrier("TestOutputFileHandler-2c"); } { setenv("CHASTE_TEST_OUTPUT", "config__cyborg__T800__cooper", 1/*Overwrite*/); // Test that CHASTE_TEST_OUTPUT always has a trailing slash even before // a class object is instantiated and when the directory does not exist const std::string nonexistent_test_path(OutputFileHandler::GetChasteTestOutputDirectory()); TS_ASSERT_EQUALS( *(nonexistent_test_path.end()-1), '/'); } { // Check this folder is not present std::string test_folder("somewhere_without_trailing_forward_slash"); TS_ASSERT(!FileFinder(test_folder, RelativeTo::CWD).Exists()); PetscTools::Barrier("TestOutputFileHandler-3"); setenv("CHASTE_TEST_OUTPUT", test_folder.c_str(), 1/*Overwrite*/); // Make a folder using a FileFinder, for coverage of the case where the root output folder doesn't exist FileFinder sub_folder("test_folder", RelativeTo::ChasteTestOutput); TS_ASSERT(!sub_folder.Exists()); PetscTools::Barrier("TestOutputFileHandler-3a"); OutputFileHandler creating_handler(sub_folder); TS_ASSERT(sub_folder.Exists()); // Make a folder OutputFileHandler handler5("whatever"); TS_ASSERT(FileFinder(test_folder, RelativeTo::CWD).Exists()); PetscTools::Barrier("TestOutputFileHandler-3b"); // Erase it if (PetscTools::AmMaster()) { FileFinder(test_folder).DangerousRemove(); } } // Reset the location of CHASTE_TEST_OUTPUT setenv("CHASTE_TEST_OUTPUT", chaste_test_output.c_str(), 1/*Overwrite*/); // We don't want other people using CHASTE_TEST_OUTPUT while we are messing with it! PetscTools::Barrier("TestOutputFileHandler-4"); // Coverage of the case where we can't open a file for writing OutputFileHandler handler6("no_write_access"); if (PetscTools::AmMaster()) { std::string dir_path = handler6.GetOutputDirectoryFullPath(); #ifndef _MSC_VER // This test can never pass on modern Windows OS! See: http://support.microsoft.com/kb/326549 // You can't change DIRECTORY attributes chmod(dir_path.c_str(), CHASTE_READONLY); TS_ASSERT_THROWS_CONTAINS(p_file_stream = handler6.OpenOutputFile("test_file"), "Could not open file"); #endif chmod(dir_path.c_str(), CHASTE_READ_WRITE_EXECUTE); fs::remove(dir_path + ".chaste_deletable_folder"); fs::remove(dir_path); } // Check behaviour of FindFile("") FileFinder handler_self = handler.FindFile(""); TS_ASSERT_EQUALS(handler_self.GetAbsolutePath(), handler.GetOutputDirectoryFullPath()); }
void TestWeCanOnlyDeleteFoldersWeHaveMadeOurselves() throw(Exception, std::exception) { std::string test_folder = "cannot_delete_me"; if (PetscTools::AmMaster()) { ABORT_IF_THROWS(fs::create_directories(OutputFileHandler::GetChasteTestOutputDirectory() + test_folder)); } // Wait until directory has been created, and check it exists PetscTools::Barrier("TestWeCanOnlyDeleteFoldersWeHaveMadeOurselves-1"); FileFinder cannot_delete(test_folder, RelativeTo::ChasteTestOutput); TS_ASSERT(cannot_delete.IsDir()); // Try to use it as an output folder TS_ASSERT_THROWS_CONTAINS(OutputFileHandler bad_handler(test_folder), "because signature file \".chaste_deletable_folder\" is not present"); // Tidy up if (PetscTools::AmMaster()) { TS_ASSERT(cannot_delete.Exists()); cannot_delete.DangerousRemove(); TS_ASSERT(!cannot_delete.Exists()); } // Now create a folder the proper way test_folder = "can_delete_me"; OutputFileHandler handler(test_folder); out_stream p_file_stream = handler.OpenOutputFile("test_file"); p_file_stream->close(); // Windows does not like deleting open files // Test file is present FileFinder test_file = handler.FindFile("test_file"); TS_ASSERT(test_file.Exists()); PetscTools::Barrier("TestWeCanOnlyDeleteFoldersWeHaveMadeOurselves-2"); OutputFileHandler handler2(test_folder, false /* don't clean */); // Test file is still present TS_ASSERT(test_file.Exists()); PetscTools::Barrier("TestWeCanOnlyDeleteFoldersWeHaveMadeOurselves-3"); OutputFileHandler handler3(test_folder, true /* do clean */); // Test file is deleted TS_ASSERT(!test_file.Exists()); PetscTools::Barrier("TestWeCanOnlyDeleteFoldersWeHaveMadeOurselves-4"); // Check we can delete the test_folder too if (PetscTools::AmMaster()) { FileFinder folder = handler.FindFile(""); TS_ASSERT(folder.Exists()); folder.Remove(); TS_ASSERT(!folder.Exists()); } // Test we can make a directory of folders and delete them all OutputFileHandler handler4("what_about_me/and_me/and_me/and_da_da_da", true); // Check we have made a subdirectory FileFinder sub_folder("what_about_me/and_me", RelativeTo::ChasteTestOutput); TS_ASSERT(sub_folder.IsDir()); PetscTools::Barrier("TestWeCanOnlyDeleteFoldersWeHaveMadeOurselves-5"); OutputFileHandler handler5("what_about_me", true); // Check we have wiped the sub-directories TS_ASSERT(!sub_folder.Exists()); PetscTools::Barrier("TestWeCanOnlyDeleteFoldersWeHaveMadeOurselves-6"); // Check we can delete the main directory too if (PetscTools::AmMaster()) { FileFinder folder = handler5.FindFile(""); TS_ASSERT(folder.Exists()); folder.Remove(); TS_ASSERT(!folder.Exists()); } }
void TestPottsBasedWithCoarseMeshTwoEquations() throw(Exception) { EXIT_IF_PARALLEL; // Create a simple 2D PottsMesh PottsMeshGenerator<2> generator(6, 2, 2, 6, 2, 2); PottsMesh<2>* p_mesh = generator.GetMesh(); // Create cells std::vector<CellPtr> cells; MAKE_PTR(DifferentiatedCellProliferativeType, p_diff_type); CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 2> cells_generator; cells_generator.GenerateBasicRandom(cells, p_mesh->GetNumElements(), p_diff_type); // Create cell population PottsBasedCellPopulation<2> cell_population(*p_mesh, cells); // Set up cell-based simulation OnLatticeSimulation<2> simulator(cell_population); simulator.SetOutputDirectory("TestPottsBasedCellPopulationWithTwoPdes"); simulator.SetEndTime(0.1); // Set up PDE and pass to simulation via handler (zero uptake to check analytic solution) AveragedSourcePde<2> pde_1(cell_population, 0.0); ConstBoundaryCondition<2> bc_1(1.0); PdeAndBoundaryConditions<2> pde_and_bc_1(&pde_1, &bc_1, false); pde_and_bc_1.SetDependentVariableName("quantity 1"); AveragedSourcePde<2> pde_2(cell_population, 0.0); ConstBoundaryCondition<2> bc_2(1.0); PdeAndBoundaryConditions<2> pde_and_bc_2(&pde_2, &bc_2, false); pde_and_bc_2.SetDependentVariableName("quantity 2"); CellBasedPdeHandler<2> pde_handler(&cell_population); pde_handler.AddPdeAndBc(&pde_and_bc_1); pde_handler.AddPdeAndBc(&pde_and_bc_2); ChastePoint<2> lower(0.0, 0.0); ChastePoint<2> upper(50.0, 50.0); ChasteCuboid<2> cuboid(lower, upper); pde_handler.UseCoarsePdeMesh(10.0, cuboid, true); pde_handler.SetImposeBcsOnCoarseBoundary(true); simulator.SetCellBasedPdeHandler(&pde_handler); // Create update rules and pass to the simulation MAKE_PTR(VolumeConstraintPottsUpdateRule<2>, p_volume_constraint_update_rule); simulator.AddPottsUpdateRule(p_volume_constraint_update_rule); MAKE_PTR(AdhesionPottsUpdateRule<2>, p_adhesion_update_rule); simulator.AddPottsUpdateRule(p_adhesion_update_rule); // Solve the system simulator.Solve(); // Test solution is constant for (AbstractCellPopulation<2>::Iterator cell_iter = cell_population.Begin(); cell_iter != cell_population.End(); ++cell_iter) { double analytic_solution = 1.0; // Test that PDE solver is working correctly on both pdes TS_ASSERT_DELTA(cell_iter->GetCellData()->GetItem("quantity 1"), analytic_solution, 1e-2); TS_ASSERT_DELTA(cell_iter->GetCellData()->GetItem("quantity 2"), analytic_solution, 1e-2); } #ifdef CHASTE_VTK //First file exists FileFinder vtk_file("TestPottsBasedCellPopulationWithTwoPdes/results_from_time_0/pde_results_1.vtu", RelativeTo::ChasteTestOutput); TS_ASSERT(vtk_file.Exists()); // Check that the second VTK file for the solution has the dependent quantities OutputFileHandler handler("TestPottsBasedCellPopulationWithTwoPdes", false); VtkMeshReader<3,3> vtk_reader(handler.GetOutputDirectoryFullPath()+"results_from_time_0/pde_results_2.vtu"); std::vector<double> data1; //There is no Oxygen TS_ASSERT_THROWS_CONTAINS(vtk_reader.GetPointData("Oxygen", data1), "No point data"); TS_ASSERT(data1.empty()); vtk_reader.GetPointData("quantity 1", data1); TS_ASSERT_EQUALS(data1.size(), 6u*6u); std::vector<double> data2; vtk_reader.GetPointData("quantity 2", data2); TS_ASSERT_EQUALS(data1.size(), data2.size()); #endif //CHASTE_VTK }
void TestArchiving() throw(Exception) { OutputFileHandler archive_dir_("mixed_mesh_archive"); // Clear folder FileFinder main_archive_dir("mixed_mesh_archive", RelativeTo::ChasteTestOutput); std::string archive_file = "mixed_dimension_mesh.arch"; ArchiveLocationInfo::SetMeshFilename("mixed_dimension_mesh"); MixedDimensionMesh<2,2>* p_mesh = new MixedDimensionMesh<2,2>(DistributedTetrahedralMeshPartitionType::DUMB); unsigned num_nodes; unsigned local_num_nodes; unsigned num_elements; unsigned num_cable_elements; unsigned num_local_cable_elements; // archive { TrianglesMeshReader<2,2> mesh_reader("mesh/test/data/mixed_dimension_meshes/2D_0_to_1mm_200_elements"); p_mesh->ConstructFromMeshReader(mesh_reader); num_nodes = p_mesh->GetNumNodes(); local_num_nodes = p_mesh->GetNumLocalNodes(); num_elements = p_mesh->GetNumElements(); num_cable_elements = p_mesh->GetNumCableElements(); num_local_cable_elements = p_mesh->GetNumLocalCableElements(); ArchiveOpener<boost::archive::text_oarchive, std::ofstream> arch_opener(main_archive_dir, archive_file); boost::archive::text_oarchive* p_arch = arch_opener.GetCommonArchive(); AbstractTetrahedralMesh<2,2>* const p_mesh_abstract = static_cast<AbstractTetrahedralMesh<2,2>* >(p_mesh); (*p_arch) << p_mesh_abstract; } FileFinder ncl_file("mixed_dimension_mesh.ncl", main_archive_dir); TS_ASSERT(ncl_file.Exists()); // restore { // Should archive the most abstract class you can to check boost knows what individual classes are. // (but here AbstractMesh doesn't have the methods below). AbstractTetrahedralMesh<2,2>* p_mesh_abstract2; // Create an input archive ArchiveOpener<boost::archive::text_iarchive, std::ifstream> arch_opener(main_archive_dir, archive_file); boost::archive::text_iarchive* p_arch = arch_opener.GetCommonArchive(); // restore from the archive (*p_arch) >> p_mesh_abstract2; // Check we have the right number of nodes & elements MixedDimensionMesh<2,2>* p_mesh2 = static_cast<MixedDimensionMesh<2,2>*>(p_mesh_abstract2); TS_ASSERT_EQUALS(p_mesh2->GetNumNodes(), num_nodes); TS_ASSERT_EQUALS(p_mesh2->GetNumLocalNodes(), local_num_nodes); TS_ASSERT_EQUALS(p_mesh2->GetNumElements(), num_elements); TS_ASSERT_EQUALS(p_mesh2->GetNumCableElements(), num_cable_elements); TS_ASSERT_EQUALS(p_mesh2->GetNumLocalCableElements(), num_local_cable_elements); // Check elements have the right nodes for (unsigned i=0; i<num_cable_elements; i++) { try { Element<1,2>* p_element = p_mesh->GetCableElement(i); Element<1,2>* p_element2 = p_mesh2->GetCableElement(i); TS_ASSERT_EQUALS(p_element->GetNodeGlobalIndex(0), p_element2->GetNodeGlobalIndex(0)); } catch(Exception& e) { TS_ASSERT_DIFFERS((int)e.GetShortMessage().find("does not belong to processor"),-1); } } delete p_mesh2; } // restore from a single processor archive { FileFinder archive_dir("mesh/test/data/mixed_mesh_archive", RelativeTo::ChasteSourceRoot); if ( PetscTools::IsSequential() ) { ArchiveOpener<boost::archive::text_iarchive, std::ifstream> arch_opener(archive_dir, archive_file); boost::archive::text_iarchive* p_arch = arch_opener.GetCommonArchive(); AbstractTetrahedralMesh<2,2>* p_mesh_abstract3 = NULL; (*p_arch) >> p_mesh_abstract3; //Double check that the cables are intact MixedDimensionMesh<2,2>* p_mesh3 = static_cast<MixedDimensionMesh<2,2>*>(p_mesh_abstract3); Element<1,2>* p_element = p_mesh3->GetCableElement(9); TS_ASSERT_EQUALS(p_element->GetNodeGlobalIndex(0), 64u); TS_ASSERT_EQUALS(p_element->GetNodeGlobalIndex(1), 65u); TS_ASSERT_DELTA(p_element->GetAttribute(), 10.5, 1e-8); delete p_mesh_abstract3; } else { typedef ArchiveOpener<boost::archive::text_iarchive, std::ifstream> InputArchiveOpener; if (PetscTools::GetMyRank() > 0) { // Should not read this archive because none exists here. TS_ASSERT_THROWS_CONTAINS(InputArchiveOpener arch_opener(archive_dir, archive_file), "Cannot load secondary archive file:"); } else { // Should not read this archive because there are two or more processes and // this archive was written on one process. InputArchiveOpener arch_opener(archive_dir, archive_file); boost::archive::text_iarchive* p_arch = arch_opener.GetCommonArchive(); AbstractTetrahedralMesh<2,2>* p_mesh3 = NULL; TS_ASSERT_THROWS_THIS((*p_arch) >> p_mesh3, "This archive was written for a different number of processors"); } } }
void TestColemanDynamicVentilationThreeBifurcations() throw(Exception) { FileFinder mesh_finder("lung/test/data/three_bifurcations", RelativeTo::ChasteSourceRoot); //The three bifurcation mesh defines a fully symmetric three bifurcation airway tree. //The composite ventilation problem is then equivalent to a trumpet problem connected //to an acinus with compliance equal to the total compliance of all the acini. double total_compliance = 0.1/98.0665/1e3; //in m^3 / pa. Converted from 0.1 L/cmH2O per lung to four acinar compartments double acinar_compliance = total_compliance/4.0; SimpleAcinarUnitFactory factory(acinar_compliance, 2400.0); TS_ASSERT_THROWS_CONTAINS(factory.GetMesh(), "The mesh object has not been set in the acinar unit factory"); double viscosity = 1.92e-5; //Pa s double terminal_airway_radius = 0.00005; //m double resistance_per_unit_length = 8*viscosity/(M_PI*SmallPow(terminal_airway_radius, 4)); //All airways in the mesh have radius 0.05 mm. The first branch is 3mm long, the others are 5mm. double total_airway_resistance = (0.003 + 0.005/2 + 0.005/4)*resistance_per_unit_length; double ode_volume = 0.0; //Setup a simulation iterating between the flow solver and the acinar balloon. DynamicVentilationProblem problem(&factory, mesh_finder.GetAbsolutePath(), 0u); problem.rGetMatrixVentilationProblem().SetOutflowPressure(0.0); problem.rGetMatrixVentilationProblem().SetMeshInMilliMetres(); problem.SetTimeStep(0.01); factory.GetNumberOfAcini(); TimeStepper time_stepper(0.0, 1.0, 0.01); while (!time_stepper.IsTimeAtEnd()) { //Solve corresponding backward Euler problem for testing double pleural_pressure = factory.GetPleuralPressureForNode(time_stepper.GetNextTime(), NULL); double dt = time_stepper.GetNextTimeStep(); ode_volume = (ode_volume - dt*pleural_pressure/total_airway_resistance)/(1 + dt/(total_airway_resistance*total_compliance)); //Solve using DynamicVentilationProblem problem.SetEndTime(time_stepper.GetNextTime()); problem.Solve(); std::map<unsigned, AbstractAcinarUnit*>& r_acinar_map = problem.rGetAcinarUnitMap(); TS_ASSERT_DELTA(ode_volume, r_acinar_map[5]->GetVolume(), 1e-6); time_stepper.AdvanceOneTimeStep(); } //Solve for longer and write output to VTK problem.SetSamplingTimeStepMultiple(10u); problem.SetOutputDirectory("TestDynamicVentilation"); problem.SetOutputFilenamePrefix("three_bifurcations"); problem.SetWriteVtkOutput(); problem.SetEndTime(1.5); problem.Solve(); #ifdef CHASTE_VTK std::string filepath = OutputFileHandler::GetChasteTestOutputDirectory() + "TestDynamicVentilation/"; std::string basename = filepath + "three_bifurcations"; FileFinder vtu_file(basename + ".vtu", RelativeTo::Absolute); TS_ASSERT(vtu_file.Exists()); #endif }
void TestInterpolatorTimesAndGenerateReferenceTrace() throw(Exception) { #ifdef CHASTE_CVODE OutputFileHandler handler("CvodeCellsWithDataClamp"); boost::shared_ptr<AbstractIvpOdeSolver> p_empty_solver; boost::shared_ptr<AbstractStimulusFunction> p_empty_stimulus; // N.B. Because we use the Shannon model as a lot of examples, // here it is actually a Shannon->WithModifiers->WithDataClamp->CvodeCell // (the WithModifiers doesn't need to be there to use the data clamp!) mpModel.reset(new CellShannon2004FromCellMLCvodeDataClamp(p_empty_solver,p_empty_stimulus)); TS_ASSERT_EQUALS(mpModel->HasParameter("membrane_data_clamp_current_conductance"), true); mpModel->SetMaxSteps(5000); mpModel->UseCellMLDefaultStimulus(); // Run a simulation without clamping switched on Timer::Reset(); double end_time = 400.0; OdeSolution solution = mpModel->Compute(0, end_time, 0.2); Timer::Print("OdeSolution"); std::vector<double> expt_times = solution.rGetTimes(); std::vector<double> expt_data = solution.GetAnyVariable("membrane_voltage"); solution.WriteToFile("CvodeCellsWithDataClamp","shannon_original_no_clamp", "ms", 1, false); // false to clean TS_ASSERT_THROWS_THIS(mpModel->TurnOnDataClamp(), "Before calling TurnOnDataClamp(), please provide experimental data via the SetExperimentalData() method."); // Test the interpolation methods. { mpModel->SetExperimentalData(expt_times, expt_data); // Note - unless the data clamp is switched on the below method just returns DOUBLE_UNSET to save time interpolating. double time = 100.0; TS_ASSERT_EQUALS(mpModel->GetExperimentalVoltageAtTimeT(time), DOUBLE_UNSET); // So now turn on the data clamp mpModel->TurnOnDataClamp(); # if CHASTE_SUNDIALS_VERSION >= 20400 double tol = 5e-3; // mV #else double tol = 0.2; // mV #endif TS_ASSERT_DELTA(mpModel->GetExperimentalVoltageAtTimeT(time), -8.55863245e+01, tol); // So turn it off again mpModel->TurnOffDataClamp(); TS_ASSERT_DELTA(mpModel->GetParameter("membrane_data_clamp_current_conductance"), 0.0, 1e-12); mpModel->TurnOnDataClamp(200.0); TS_ASSERT_DELTA(mpModel->GetParameter("membrane_data_clamp_current_conductance"), 200.0, 1e-12); mpModel->TurnOffDataClamp(); TS_ASSERT_DELTA(mpModel->GetParameter("membrane_data_clamp_current_conductance"), 0.0, 1e-12); mpModel->TurnOnDataClamp(); TS_ASSERT_DELTA(mpModel->GetParameter("membrane_data_clamp_current_conductance"), 100.0, 1e-12); // the default // Test a couple of times where no interpolation is needed (on data points). time = 116.0; double v_at_116 = 1.53670634e+01; TS_ASSERT_DELTA(mpModel->GetExperimentalVoltageAtTimeT(time), v_at_116, tol); time = 116.2; double v_at_116_2 = 1.50089546e+01; TS_ASSERT_DELTA(mpModel->GetExperimentalVoltageAtTimeT(time), v_at_116_2, tol); // Now test a time where interpolation is required. time = 116.1; TS_ASSERT_DELTA(mpModel->GetExperimentalVoltageAtTimeT(time), 0.5*(v_at_116 + v_at_116_2), tol); // Test ends TS_ASSERT_DELTA(mpModel->GetExperimentalVoltageAtTimeT(0.0), expt_data[0], 1e-4); TS_ASSERT_DELTA(mpModel->GetExperimentalVoltageAtTimeT(end_time), expt_data.back(), 1e-4); // Test exceptions TS_ASSERT_THROWS_CONTAINS(mpModel->GetExperimentalVoltageAtTimeT(-1e-12), "is outside the times stored in the data clamp"); TS_ASSERT_THROWS_CONTAINS(mpModel->GetExperimentalVoltageAtTimeT(end_time+1e-12), "is outside the times stored in the data clamp"); //std::cout << "membrane_data_clamp_current_conductance = " << mpModel->GetParameter("membrane_data_clamp_current_conductance") << std::endl << std::flush; //std::cout << "mpModel->GetExperimentalVoltageAtTimeT(time) = " << mpModel->GetExperimentalVoltageAtTimeT(time) << std::endl << std::flush; unsigned how_many = 10000u; Timer::Reset(); for (unsigned i=0; i<how_many; i++) { mpModel->GetExperimentalVoltageAtTimeT(time); } Timer::PrintAndReset("GetExperimentalVoltageAtTimeT"); } // Generate some noisier data - more like a real cell. out_stream experimental_voltage_results_file = handler.OpenOutputFile("Shannon_noisy_data.dat"); double experimental_noise_sd = 0.25; // directly from Teun's AP data trace of a stationary-looking bit for (unsigned i=0; i<expt_data.size(); i++) { double random_number = RandomNumberGenerator::Instance()->StandardNormalRandomDeviate(); expt_data[i] += (10+experimental_noise_sd*random_number); // make experimental data very different to see if clamp works *experimental_voltage_results_file << expt_times[i] << "\t" << expt_data[i] << std::endl; } experimental_voltage_results_file->close(); // In this half of the test, try running simulations with the clamp. { // Now solve with data clamp to the noisy data mpModel->SetExperimentalData(expt_times, expt_data); mpModel->ResetToInitialConditions(); mpModel->TurnOnDataClamp(); mpModel->SetParameter("membrane_data_clamp_current_conductance",0.001); std::vector<double> data_clamp_times; std::vector<double> data_clamp_voltage; for (int i = -4; i < 3; i++) { double clamp_conductance = pow(10,i); std::cout << "clamp_conductance = " << clamp_conductance << std::endl << std::flush; std::stringstream output_file; output_file << "Shannon_test_solution_with_data_clamp_conductance_exponent_" << i << ".dat"; mpModel->ResetToInitialConditions(); mpModel->SetParameter("membrane_data_clamp_current_conductance",clamp_conductance); solution = mpModel->Compute(0, 400, 0.2); data_clamp_times = solution.rGetTimes(); data_clamp_voltage = solution.GetAnyVariable("membrane_voltage"); out_stream data_clamp_voltage_results_file = handler.OpenOutputFile(output_file.str()); for (unsigned j=0; j<data_clamp_voltage.size(); j++) { *data_clamp_voltage_results_file << data_clamp_times[j] << "\t" << data_clamp_voltage[j] << "\n"; } data_clamp_voltage_results_file->close(); } } #else std::cout << "Cvode is not enabled.\n"; #endif }
void TestAdvance() { const double smidge = 1e-10; double start_time = 0.0; double end_time = 2.0; double timestep = 3.7e-05; // This is how a time stepper is normally used TimeStepper my_stepper(start_time, end_time, timestep); while ( !my_stepper.IsTimeAtEnd() ) { // do something my_stepper.AdvanceOneTimeStep(); } // Tests TS_ASSERT_THROWS_THIS(TimeStepper(end_time, start_time, timestep), "The simulation duration must be positive, not -2"); // Note that the timestep in this test does not divide whole time interval nicely, therefore we can't enforce a constant timestep. bool enforce_constant_timestep = true; TS_ASSERT_THROWS_CONTAINS(TimeStepper(start_time, end_time, timestep, enforce_constant_timestep), "TimeStepper estimates non-constant timesteps will need to be used"); TimeStepper stepper(start_time, end_time, timestep); TS_ASSERT_EQUALS(stepper.EstimateTimeSteps(), (unsigned) floor((end_time - start_time)/timestep) ); double real_time_step = timestep; unsigned time_step_number = 0; double current_time = start_time; /* * We'll trap for stopping times that are close to the end time * in order to avoid having a timestep of 1e-14 (or whatever) at * the end in the case of rounding errors. */ double close_to_end_time = end_time - smidge*timestep; while (current_time < end_time) { TS_ASSERT(!stepper.IsTimeAtEnd()); time_step_number++; // Determine what the value time step should really be like double to_time = start_time+time_step_number*timestep; if (to_time >= close_to_end_time) { real_time_step = end_time - current_time; //std::cout<<"TImes: " << timestep << " " << stepper.GetNextTimeStep() <<", difference = " << timestep - stepper.GetNextTimeStep() << "\n"; to_time = end_time; // Note that with non-constant timesteps, the final timestep can vary a lot (but not more than a normal sized timestep!). TS_ASSERT_DELTA(stepper.GetNextTimeStep(), timestep, timestep); } else { // Otherwise the GetNextTimeStep() returns the stored timestep, TS_ASSERT_EQUALS(stepper.GetNextTimeStep(), timestep); } TS_ASSERT_DELTA(stepper.GetNextTimeStep(), real_time_step, DBL_EPSILON); TS_ASSERT_EQUALS(stepper.GetIdealTimeStep(), timestep); TS_ASSERT_EQUALS(stepper.GetTime(), current_time); TS_ASSERT_EQUALS(stepper.GetNextTime(), to_time); // Determine the new current time current_time = to_time; stepper.AdvanceOneTimeStep(); TS_ASSERT_EQUALS(current_time, stepper.GetTime()); } TS_ASSERT(stepper.IsTimeAtEnd()); TS_ASSERT(stepper.GetTotalTimeStepsTaken()==time_step_number); //Stepper no longer allows increments beyond the end to be silently ignored TS_ASSERT_THROWS_THIS(stepper.AdvanceOneTimeStep(), "TimeStepper incremented beyond end time."); }
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); } }
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(); }