void TestCellKillersOutputParameters() { std::string output_directory = "TestSloughingCellKillersOutputParameters"; OutputFileHandler output_file_handler(output_directory, false); // Test with SloughingCellKiller SloughingCellKiller<2> sloughing_cell_killer(NULL, 20.0, true, 10.0); TS_ASSERT_EQUALS(sloughing_cell_killer.GetIdentifier(), "SloughingCellKiller-2"); out_stream sloughing_cell_killer_parameter_file = output_file_handler.OpenOutputFile("sloughing_results.parameters"); sloughing_cell_killer.OutputCellKillerParameters(sloughing_cell_killer_parameter_file); sloughing_cell_killer_parameter_file->close(); std::string sloughing_cell_killer_results_dir = output_file_handler.GetOutputDirectoryFullPath(); FileComparison( sloughing_cell_killer_results_dir + "sloughing_results.parameters", "crypt/test/data/TestSloughingCellKillers/sloughing_results.parameters").CompareFiles(); // Test with RadialSloughingCellKiller c_vector<double,2> centre(2); centre[0] = 0.1; centre[1] = 0.2; double radius = 0.4; RadialSloughingCellKiller radial_cell_killer(NULL, centre, radius); TS_ASSERT_EQUALS(radial_cell_killer.GetIdentifier(), "RadialSloughingCellKiller"); out_stream radial_cell_killer_parameter_file = output_file_handler.OpenOutputFile("radial_results.parameters"); radial_cell_killer.OutputCellKillerParameters(radial_cell_killer_parameter_file); radial_cell_killer_parameter_file->close(); std::string radial_cell_killer_results_dir = output_file_handler.GetOutputDirectoryFullPath(); FileComparison( radial_cell_killer_results_dir + "radial_results.parameters", "crypt/test/data/TestSloughingCellKillers/radial_results.parameters").CompareFiles(); }
/* * Cellular birth has been tested in TestCaSingleCellWithBirth for one cell per lattice site. * This test adds to the above by further testing cellular birth considering multiple cells per lattice site. * A two-lattice mesh was created and only one lattice had free space to add one daughter cell. */ void TestMultipleCellsPerLatticeSiteWithBirth() throw (Exception) { EXIT_IF_PARALLEL; // Create a simple 2D PottsMesh PottsMeshGenerator<2> generator(2, 0, 0, 1, 0, 0); PottsMesh<2>* p_mesh = generator.GetMesh(); // Create cells std::vector<CellPtr> cells; MAKE_PTR(StemCellProliferativeType, p_stem_type); CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 2> cells_generator; cells_generator.GenerateBasicRandom(cells, 3, p_stem_type); // Specify where cells lie std::vector<unsigned> location_indices; location_indices.push_back(0); location_indices.push_back(0); location_indices.push_back(1); // Create cell population CaBasedCellPopulation<2> cell_population(*p_mesh, cells, location_indices, 2); // Set up cell-based simulation OnLatticeSimulation<2> simulator(cell_population); std::string output_directory = "TestMultipleCellsPerLatticeSiteWithBirth"; simulator.SetOutputDirectory(output_directory); simulator.SetDt(0.1); simulator.SetEndTime(40); // Add update rule MAKE_PTR(DiffusionCaUpdateRule<2u>, p_diffusion_update_rule); p_diffusion_update_rule->SetDiffusionParameter(0.5); simulator.AddCaUpdateRule(p_diffusion_update_rule); // Run simulation simulator.Solve(); // Check the number of cells TS_ASSERT_EQUALS(simulator.rGetCellPopulation().GetNumRealCells(), 4u); // Test no deaths and some births TS_ASSERT_EQUALS(simulator.GetNumBirths(), 1u); TS_ASSERT_EQUALS(simulator.GetNumDeaths(), 0u); #ifdef CHASTE_VTK // Test that VTK writer has produced a file OutputFileHandler output_file_handler(output_directory, false); std::string results_dir = output_file_handler.GetOutputDirectoryFullPath(); // Initial condition file FileFinder vtk_file(results_dir + "results_from_time_0/results_0.vtu", RelativeTo::Absolute); TS_ASSERT(vtk_file.Exists()); // Final file FileFinder vtk_file2(results_dir + "results_from_time_0/results_400.vtu", RelativeTo::Absolute); TS_ASSERT(vtk_file2.Exists()); #endif //CHASTE_VTK }
void TestWriter() throw (Exception) { EXIT_IF_PARALLEL; // Set up a small MeshBasedCellPopulationWithGhostNodes using an appropriate cell-cycle model class CylindricalHoneycombMeshGenerator generator(5, 4, 1); Cylindrical2dMesh* p_mesh = generator.GetCylindricalMesh(); double domain_length_for_wnt = 4.0*(sqrt(3.0)/2); std::vector<unsigned> location_indices = generator.GetCellLocationIndices(); std::vector<CellPtr> cells; CryptCellsGenerator<VanLeeuwen2009WntSwatCellCycleModelHypothesisOne> cells_generator; cells_generator.Generate(cells, p_mesh, location_indices, false); MeshBasedCellPopulationWithGhostNodes<2> cell_population(*p_mesh, cells, location_indices); // Create an instance of a Wnt concentration WntConcentration<2>::Instance()->SetType(LINEAR); WntConcentration<2>::Instance()->SetCellPopulation(cell_population); WntConcentration<2>::Instance()->SetCryptLength(domain_length_for_wnt); // Initialise the cell population to set up the ODE system associated with each cell-cycle model object cell_population.InitialiseCells(); // Create an output directory for the writer std::string output_directory = "TestCellBetaCateninWriter"; OutputFileHandler output_file_handler(output_directory, false); std::string results_dir = output_file_handler.GetOutputDirectoryFullPath(); // Create a CellBetaCateninWriter and test that the correct output is generated CellBetaCateninWriter<2,2> cell_writer; cell_writer.OpenOutputFile(output_file_handler); cell_writer.WriteTimeStamp(); for (AbstractCellPopulation<2,2>::Iterator cell_iter = cell_population.Begin(); cell_iter != cell_population.End(); ++cell_iter) { cell_writer.VisitCell(*cell_iter, &cell_population); } cell_writer.CloseFile(); /* * To verify this test, we can eyeball the results file to check that the correct default * initial conditions are output (see VanLeeuwen2009WntSwatCellCycleOdeSystem.hpp). */ FileComparison(results_dir + "results.vizbetacatenin", "crypt/test/data/TestCellBetaCateninWriter/results.vizbetacatenin").CompareFiles(); // Test the correct data are returned for VTK output for the first cell double vtk_data = cell_writer.GetCellDataForVtkOutput(*(cell_population.Begin()), &cell_population); TS_ASSERT_DELTA(vtk_data, 14.6088, 1e-4); // Avoid memory leak WntConcentration<2>::Destroy(); }
void CellBasedPdeHandler<DIM>::OpenResultsFiles(std::string outputDirectory) { // If appropriate, make a coarse mesh which exactly overlays the lattice sites of a PottsMesh (used for all OnLattice simulations) if ((dynamic_cast<MultipleCaBasedCellPopulation<DIM>*>(mpCellPopulation) != NULL) && mpCoarsePdeMesh==NULL) { assert(DIM ==2); ChasteCuboid<DIM> cuboid = mpCellPopulation->rGetMesh().CalculateBoundingBox(); // Currently only works with square meshes assert(cuboid.GetWidth(0) == cuboid.GetWidth(1)); UseCoarsePdeMesh(1, cuboid, false); } // If using a NodeBasedCellPopulation a VertexBasedCellPopulation, a MultipleCABasedCellPopulation or a PottsBasedCellPopulation, mpCoarsePdeMesh must be set up if (PdeSolveNeedsCoarseMesh() && mpCoarsePdeMesh==NULL) { EXCEPTION("Trying to solve a PDE on a cell population that doesn't have a mesh. Try calling UseCoarsePdeMesh()."); } if (mpCoarsePdeMesh != NULL) { InitialiseCellPdeElementMap(); // Write mesh to file TrianglesMeshWriter<DIM,DIM> mesh_writer(outputDirectory+"/coarse_mesh_output", "coarse_mesh",false); mesh_writer.WriteFilesUsingMesh(*mpCoarsePdeMesh); } if (PetscTools::AmMaster()) { OutputFileHandler output_file_handler(outputDirectory+"/", false); if (mpCoarsePdeMesh != NULL) { mpVizPdeSolutionResultsFile = output_file_handler.OpenOutputFile("results.vizcoarsepdesolution"); } else { mpVizPdeSolutionResultsFile = output_file_handler.OpenOutputFile("results.vizpdesolution"); } if (mWriteAverageRadialPdeSolution) { mpAverageRadialPdeSolutionResultsFile = output_file_handler.OpenOutputFile("radial_dist.dat"); } } mDirPath = outputDirectory; // caching the path to the output directory for VTK //double current_time = SimulationTime::Instance()->GetTime(); //WritePdeSolution(current_time); }
void TestUseInPopulationWriteResultsToFile() { EXIT_IF_PARALLEL; // Set up SimulationTime (needed if VTK is used) SimulationTime::Instance()->SetEndTimeAndNumberOfTimeSteps(1.0, 1); // Create a simple mesh-based cell population, comprising various cell types in various cell cycle phases TrianglesMeshReader<2,2> mesh_reader("mesh/test/data/square_4_elements"); MutableMesh<2,2> mesh; mesh.ConstructFromMeshReader(mesh_reader); std::vector<CellPtr> cells; CellsGenerator<VanLeeuwen2009WntSwatCellCycleModelHypothesisOne, 2> cells_generator; cells_generator.GenerateBasic(cells, mesh.GetNumNodes()); MeshBasedCellPopulation<2> cell_population(mesh, cells); // Create an instance of a Wnt concentration WntConcentration<2>::Instance()->SetType(LINEAR); WntConcentration<2>::Instance()->SetCellPopulation(cell_population); WntConcentration<2>::Instance()->SetCryptLength(1.0); cell_population.InitialiseCells(); // This is where we add the writer cell_population.AddCellWriter<CellBetaCateninWriter>(); // This method is usually called by Update() cell_population.CreateVoronoiTessellation(); std::string output_directory = "TestUseInPopulationWriteResultsToFile"; OutputFileHandler output_file_handler(output_directory, false); cell_population.OpenWritersFiles(output_file_handler); cell_population.WriteResultsToFiles(output_directory); SimulationTime::Instance()->IncrementTimeOneStep(); cell_population.Update(); cell_population.WriteResultsToFiles(output_directory); cell_population.CloseWritersFiles(); // Compare output with saved file of what they should look like std::string results_dir = output_file_handler.GetOutputDirectoryFullPath(); FileComparison comparer(results_dir + "results.vizbetacatenin","crypt/test/data/TestCellBetaCateninWriter/results2.vizbetacatenin"); TS_ASSERT(comparer.CompareFiles()); }
void TestForceOutputParameters() { std::string output_directory = "TestForcesOutputParameters"; OutputFileHandler output_file_handler(output_directory, false); // Test with VertexCryptBoundaryForce VertexCryptBoundaryForce<2> boundary_force; TS_ASSERT_EQUALS(boundary_force.GetIdentifier(), "VertexCryptBoundaryForce-2"); out_stream boundary_force_parameter_file = output_file_handler.OpenOutputFile("boundary_results.parameters"); boundary_force.OutputForceParameters(boundary_force_parameter_file); boundary_force_parameter_file->close(); std::string boundary_force_results_dir = output_file_handler.GetOutputDirectoryFullPath(); FileComparison( boundary_force_results_dir + "boundary_results.parameters", "crypt/test/data/TestForcesForCrypt/boundary_results.parameters").CompareFiles(); }
void TestCellProliferativeTypesCountWriters() throw (Exception) { EXIT_IF_PARALLEL; // Create a simple 3D MeshBasedCellPopulation std::vector<Node<3>*> nodes; nodes.push_back(new Node<3>(0, true, 0.0, 0.0, 0.0)); nodes.push_back(new Node<3>(1, true, 1.0, 1.0, 0.0)); nodes.push_back(new Node<3>(2, true, 1.0, 0.0, 1.0)); nodes.push_back(new Node<3>(3, true, 0.0, 1.0, 1.0)); nodes.push_back(new Node<3>(4, false, 0.5, 0.5, 0.5)); MutableMesh<3,3> mesh(nodes); std::vector<CellPtr> cells; CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 3> cells_generator; cells_generator.GenerateBasic(cells, mesh.GetNumNodes()); MeshBasedCellPopulation<3> cell_population(mesh, cells); cell_population.AddCellPopulationCountWriter<CellProliferativeTypesCountWriter>(); // An ordering must be specified for cell mutation states and cell proliferative types cell_population.SetDefaultCellMutationStateAndProliferativeTypeOrdering(); // Create an output directory for the writer std::string output_directory = "TestCellProliferativeTypesCountWriter"; OutputFileHandler output_file_handler(output_directory, false); std::string results_dir = output_file_handler.GetOutputDirectoryFullPath(); // Create a CellProliferativeTypesCountWriter and test that the correct output is generated CellProliferativeTypesCountWriter<3,3> types_count_writer; types_count_writer.OpenOutputFile(output_file_handler); types_count_writer.WriteTimeStamp(); types_count_writer.Visit(&cell_population); types_count_writer.WriteNewline(); types_count_writer.CloseFile(); FileComparison(results_dir + "celltypes.dat", "cell_based/test/data/TestCellPopulationCountWriters/celltypes.dat").CompareFiles(); // Test that we can append to files types_count_writer.OpenOutputFileForAppend(output_file_handler); types_count_writer.WriteTimeStamp(); types_count_writer.Visit(&cell_population); types_count_writer.WriteNewline(); types_count_writer.CloseFile(); FileComparison(results_dir + "celltypes.dat", "cell_based/test/data/TestCellPopulationCountWriters/celltypes_twice.dat").CompareFiles(); }
void TestCellMutationStatesCountWriter() throw (Exception) { EXIT_IF_PARALLEL; // Create a simple 2D CaBasedCellPopulation PottsMeshGenerator<2> generator(5, 0, 0, 5, 0, 0); PottsMesh<2>* p_mesh = generator.GetMesh(); std::vector<CellPtr> cells; CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 2> cells_generator; cells_generator.GenerateBasic(cells, 5u); std::vector<unsigned> location_indices; location_indices.push_back(7); location_indices.push_back(11); location_indices.push_back(12); location_indices.push_back(13); location_indices.push_back(17); CaBasedCellPopulation<2> cell_population(*p_mesh, cells, location_indices); cell_population.AddCellPopulationCountWriter<CellMutationStatesCountWriter>(); // Create an output directory for the writer std::string output_directory = "TestCellMutationStatesCountWriter"; OutputFileHandler output_file_handler(output_directory, false); std::string results_dir = output_file_handler.GetOutputDirectoryFullPath(); // Create a CellMutationStatesCountWriter and test that the correct output is generated CellMutationStatesCountWriter<2,2> mutation_states_writer; mutation_states_writer.OpenOutputFile(output_file_handler); mutation_states_writer.WriteHeader(&cell_population); mutation_states_writer.WriteTimeStamp(); mutation_states_writer.Visit(&cell_population); mutation_states_writer.WriteNewline(); mutation_states_writer.CloseFile(); FileComparison(results_dir + "cellmutationstates.dat", "cell_based/test/data/TestCellPopulationCountWriters/cellmutationstates.dat").CompareFiles(); // Test that we can append to files mutation_states_writer.OpenOutputFileForAppend(output_file_handler); mutation_states_writer.WriteTimeStamp(); mutation_states_writer.Visit(&cell_population); mutation_states_writer.WriteNewline(); mutation_states_writer.CloseFile(); FileComparison(results_dir + "cellmutationstates.dat", "cell_based/test/data/TestCellPopulationCountWriters/cellmutationstates_twice.dat").CompareFiles(); }
void TestWriteAverageRadialPdeSolution() throw(Exception) { EXIT_IF_PARALLEL; // Create a cell population using a circular mesh HoneycombMeshGenerator generator(5, 5, 0); MutableMesh<2,2>* p_mesh = generator.GetMesh(); std::vector<CellPtr> cells; CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 2> cells_generator; cells_generator.GenerateBasic(cells, p_mesh->GetNumNodes()); MeshBasedCellPopulation<2> cell_population(*p_mesh, cells); // Put random data on the cells for (AbstractCellPopulation<2>::Iterator cell_iter = cell_population.Begin(); cell_iter != cell_population.End(); ++cell_iter) { cell_iter->GetCellData()->SetItem("averaged quantity", RandomNumberGenerator::Instance()->ranf()); } // Create a PDE handler object using this cell population CellBasedPdeHandler<2> pde_handler(&cell_population); pde_handler.SetWriteAverageRadialPdeSolution("averaged quantity", 2); // Open result file ourselves OutputFileHandler output_file_handler("TestWriteAverageRadialPdeSolution", false); pde_handler.mpAverageRadialPdeSolutionResultsFile = output_file_handler.OpenOutputFile("radial_dist.dat"); // Write average radial PDE solution to file pde_handler.WriteAverageRadialPdeSolution(SimulationTime::Instance()->GetTime()); // Test that this is correct by comparing with an existing results file std::string results_dir = output_file_handler.GetOutputDirectoryFullPath(); NumericFileComparison comparison(results_dir + "/radial_dist.dat", "cell_based/test/data/TestCellBasedPdeHandler/radial_dist.dat"); TS_ASSERT(comparison.CompareFiles()); // Close result file ourselves pde_handler.mpAverageRadialPdeSolutionResultsFile->close(); }
void TestUpdateRuleOutputUpdateRuleInfo() { std::string output_directory = "TestCaUpdateRulesOutputParameters"; OutputFileHandler output_file_handler(output_directory, false); // Test with VolumeConstraintPottsUpdateRule DiffusionCaUpdateRule<2> diffusion_update_rule; diffusion_update_rule.SetDiffusionParameter(1.0); TS_ASSERT_EQUALS(diffusion_update_rule.GetIdentifier(), "DiffusionCaUpdateRule-2"); out_stream diffusion_update_rule_parameter_file = output_file_handler.OpenOutputFile("diffusion_update_rule_results.parameters"); diffusion_update_rule.OutputUpdateRuleInfo(diffusion_update_rule_parameter_file); diffusion_update_rule_parameter_file->close(); // Compare the generated file in test output with a reference copy in the source code. FileFinder generated = output_file_handler.FindFile("diffusion_update_rule_results.parameters"); FileFinder reference("cell_based/test/data/TestCaUpdateRules/diffusion_update_rule_results.parameters", RelativeTo::ChasteSourceRoot); FileComparison comparer(generated, reference); TS_ASSERT(comparer.CompareFiles()); }
void TestSwitchingUpdateRuleOutputUpdateRuleInfo() { std::string output_directory = "TestCaSwitchingUpdateRulesOutputParameters"; OutputFileHandler output_file_handler(output_directory, false); // Test with RandomCaSwitchingUpdateRule RandomCaSwitchingUpdateRule<2> random_switching_update_rule; random_switching_update_rule.SetSwitchingParameter(1.0); TS_ASSERT_EQUALS(random_switching_update_rule.GetIdentifier(), "RandomCaSwitchingUpdateRule-2"); out_stream random_switching_update_rule_parameter_file = output_file_handler.OpenOutputFile("random_switching_update_rule_results.parameters"); random_switching_update_rule.OutputUpdateRuleInfo(random_switching_update_rule_parameter_file); random_switching_update_rule_parameter_file->close(); // Compare the generated file in test output with a reference copy in the source code. FileFinder generated = output_file_handler.FindFile("random_switching_update_rule_results.parameters"); FileFinder reference("cell_based/test/data/TestCaUpdateRules/random_switching_update_rule_results.parameters", RelativeTo::ChasteSourceRoot); FileComparison comparer(generated, reference); TS_ASSERT(comparer.CompareFiles()); }
void TestOutputParameters2d() throw(Exception) { std::string output_directory = "TestOutputParameters2d"; OutputFileHandler output_file_handler(output_directory, false); CryptSimulationBoundaryCondition<2> boundary_condition(NULL); TS_ASSERT_EQUALS(boundary_condition.GetIdentifier(), "CryptSimulationBoundaryCondition-2"); out_stream boundary_condition_parameter_file = output_file_handler.OpenOutputFile("results2d.parameters"); boundary_condition.OutputCellPopulationBoundaryConditionParameters(boundary_condition_parameter_file); boundary_condition_parameter_file->close(); std::string boundary_condition_results_dir = output_file_handler.GetOutputDirectoryFullPath(); FileComparison( boundary_condition_results_dir + "results2d.parameters", "crypt/test/data/TestCryptSimulationBoundaryCondition/results2d.parameters").CompareFiles(); // Test OutputCellPopulationBoundaryConditionInfo() method out_stream boundary_condition_info_file = output_file_handler.OpenOutputFile("results2d.info"); boundary_condition.OutputCellPopulationBoundaryConditionInfo(boundary_condition_info_file); boundary_condition_info_file->close(); FileComparison( boundary_condition_results_dir + "results2d.info", "crypt/test/data/TestCryptSimulationBoundaryCondition/results2d.info").CompareFiles(); }
void TestSimpleTargetAreaModifierOutputParameters() { EXIT_IF_PARALLEL; std::string output_directory = "TestSimpleTargetAreaModifierOutputParameters"; OutputFileHandler output_file_handler(output_directory, false); MAKE_PTR(SimpleTargetAreaModifier<2>, p_modifier); TS_ASSERT_EQUALS(p_modifier->GetIdentifier(), "SimpleTargetAreaModifier-2"); out_stream modifier_parameter_file = output_file_handler.OpenOutputFile("SimpleTargetAreaModifier.parameters"); p_modifier->OutputSimulationModifierParameters(modifier_parameter_file); modifier_parameter_file->close(); { // Compare the generated file in test output with a reference copy in the source code FileFinder generated = output_file_handler.FindFile("SimpleTargetAreaModifier.parameters"); FileFinder reference("cell_based/test/data/TestSimulationModifierOutputParameters/SimpleTargetAreaModifier.parameters", RelativeTo::ChasteSourceRoot); FileComparison comparer(generated, reference); TS_ASSERT(comparer.CompareFiles()); } }
void TestCellBasedPdeHandlerOutputParameters() throw(Exception) { EXIT_IF_PARALLEL; std::string output_directory = "TestCellBasedPdeHandlerOutputParameters"; OutputFileHandler output_file_handler(output_directory, false); // Create a cell population HoneycombMeshGenerator generator(2, 2, 0); MutableMesh<2,2>* p_generating_mesh = generator.GetMesh(); NodesOnlyMesh<2> mesh; mesh.ConstructNodesWithoutMesh(*p_generating_mesh, 1.5); std::vector<CellPtr> cells; CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 2> cells_generator; cells_generator.GenerateBasic(cells, mesh.GetNumNodes()); NodeBasedCellPopulation<2> cell_population(mesh, cells); // Create a PDE handler object using this cell population CellBasedPdeHandler<2> pde_handler(&cell_population); // Test output methods TS_ASSERT_EQUALS(pde_handler.GetIdentifier(), "CellBasedPdeHandler-2"); out_stream pde_handler_parameter_file = output_file_handler.OpenOutputFile("CellBasedPdeHandler.parameters"); pde_handler.OutputParameters(pde_handler_parameter_file); pde_handler_parameter_file->close(); { // Compare the generated file in test output with a reference copy in the source code. FileFinder generated = output_file_handler.FindFile("CellBasedPdeHandler.parameters"); FileFinder reference("cell_based/test/data/TestCellBasedPdeHandler/CellBasedPdeHandler.parameters", RelativeTo::ChasteSourceRoot); FileComparison comparer(generated, reference); TS_ASSERT(comparer.CompareFiles()); } }
void PostProcessingWriter<ELEMENT_DIM, SPACE_DIM>::WriteGenericFileToMeshalyzer(std::vector<std::vector<double> >& rDataPayload, const std::string& rFolder, const std::string& rFileName) { OutputFileHandler output_file_handler(HeartConfig::Instance()->GetOutputDirectory() + "/" + rFolder, false); PetscTools::BeginRoundRobin(); { out_stream p_file=out_stream(NULL); //Open file if (PetscTools::AmMaster()) { // Open the file for the first time p_file = output_file_handler.OpenOutputFile(rFileName); } else { // Append data to the existing file opened by master p_file = output_file_handler.OpenOutputFile(rFileName, std::ios::app); } // Write data for (unsigned line_number=0; line_number<rDataPayload.size(); line_number++) { for (unsigned i = 0; i < rDataPayload[line_number].size(); i++) { *p_file << rDataPayload[line_number][i] << "\t"; } *p_file << std::endl; } // Last processor appends comment line if (PetscTools::AmTopMost()) { std::string comment = "# " + ChasteBuildInfo::GetProvenanceString(); *p_file << comment; } p_file->close(); } //There's a barrier included here: Process i+1 waits for process i to close the file PetscTools::EndRoundRobin(); }
void TestCellCycleModelOutputParameters() { std::string output_directory = "TestCellCycleModelOutputParameters"; OutputFileHandler output_file_handler(output_directory, false); // Test with Alarcon2004OxygenBasedCellCycleModel Alarcon2004OxygenBasedCellCycleModel alarcon_oxygen_based_cell_cycle_model; TS_ASSERT_EQUALS(alarcon_oxygen_based_cell_cycle_model.GetIdentifier(), "Alarcon2004OxygenBasedCellCycleModel"); out_stream alarcon_oxygen_based_parameter_file = output_file_handler.OpenOutputFile("alarcon_oxygen_based_results.parameters"); alarcon_oxygen_based_cell_cycle_model.OutputCellCycleModelParameters(alarcon_oxygen_based_parameter_file); alarcon_oxygen_based_parameter_file->close(); { FileFinder generated_file = output_file_handler.FindFile("alarcon_oxygen_based_results.parameters"); FileFinder reference_file("cell_based/test/data/TestCellCycleModels/alarcon_oxygen_based_results.parameters", RelativeTo::ChasteSourceRoot); FileComparison comparer(generated_file,reference_file); TS_ASSERT(comparer.CompareFiles()); } // Test with TysonNovakCellCycleModel TysonNovakCellCycleModel tyson_novak_based_cell_cycle_model; TS_ASSERT_EQUALS(tyson_novak_based_cell_cycle_model.GetIdentifier(), "TysonNovakCellCycleModel"); out_stream tyson_novak_based_parameter_file = output_file_handler.OpenOutputFile("tyson_novak_based_results.parameters"); tyson_novak_based_cell_cycle_model.OutputCellCycleModelParameters(tyson_novak_based_parameter_file); tyson_novak_based_parameter_file->close(); { FileFinder generated_file = output_file_handler.FindFile("tyson_novak_based_results.parameters"); FileFinder reference_file("cell_based/test/data/TestCellCycleModels/tyson_novak_based_results.parameters", RelativeTo::ChasteSourceRoot); FileComparison comparer(generated_file,reference_file); TS_ASSERT(comparer.CompareFiles()); } }
void TestSolvePdeAndWriteResultsToFileWithCoarsePdeMesh() throw(Exception) { EXIT_IF_PARALLEL; // Set up SimulationTime SimulationTime::Instance()->SetEndTimeAndNumberOfTimeSteps(0.05, 6); // Create a cell population HoneycombMeshGenerator generator(5, 5, 0); MutableMesh<2,2>* p_mesh = generator.GetMesh(); std::vector<CellPtr> cells; CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 2> cells_generator; cells_generator.GenerateBasic(cells, p_mesh->GetNumNodes()); MeshBasedCellPopulation<2> cell_population(*p_mesh, cells); // Create a PDE handler object using this cell population CellBasedPdeHandler<2> pde_handler(&cell_population); // Set up PDE and pass to handler AveragedSourcePde<2> pde(cell_population, -0.1); ConstBoundaryCondition<2> bc(1.0); PdeAndBoundaryConditions<2> pde_and_bc(&pde, &bc, false); pde_and_bc.SetDependentVariableName("quantity 1"); pde_handler.AddPdeAndBc(&pde_and_bc); // Set up second PDE and pass to handler AveragedSourcePde<2> pde2(cell_population, -0.5); PdeAndBoundaryConditions<2> pde_and_bc2(&pde2, &bc, false); TS_ASSERT_THROWS_THIS(pde_handler.AddPdeAndBc(&pde_and_bc2), "When adding more than one PDE to CellBasedPdeHandler set the dependent variable name using SetDependentVariableName(name)."); pde_and_bc2.SetDependentVariableName("quantity 1"); TS_ASSERT_THROWS_THIS(pde_handler.AddPdeAndBc(&pde_and_bc2), "The name quantity 1 has already been used in the PDE collection"); pde_and_bc2.SetDependentVariableName("quantity 2"); pde_handler.AddPdeAndBc(&pde_and_bc2); // Solve PDEs on a coarse mesh 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(false); // Open result file ourselves OutputFileHandler output_file_handler("TestSolvePdeAndWriteResultsToFileWithCoarsePdeMesh", false); pde_handler.mpVizPdeSolutionResultsFile = output_file_handler.OpenOutputFile("results.vizpdesolution"); // Solve PDEs and (for coverage) write results to file pde_handler.SolvePdeAndWriteResultsToFile(1); // Close result file ourselves pde_handler.mpVizPdeSolutionResultsFile->close(); TetrahedralMesh<2,2>* p_coarse_mesh = pde_handler.GetCoarsePdeMesh(); TS_ASSERT(p_coarse_mesh != NULL); TS_ASSERT_THROWS_THIS(pde_handler.GetPdeSolution("quantity 3"), "The PDE collection does not contain a PDE named quantity 3"); ReplicatableVector pde_solution0(pde_handler.GetPdeSolution("quantity 1")); ReplicatableVector pde_solution1(pde_handler.GetPdeSolution("quantity 2")); TS_ASSERT_EQUALS(pde_solution0.GetSize(), pde_solution1.GetSize()); // Test that the solution is 1.0 at each coarse mesh node far from the cells for (unsigned i=0; i<pde_solution0.GetSize(); i++) { c_vector<double,2> centre; centre(0) = 2.5; // assuming 5x5 honeycomb mesh centre(1) = 2.5; c_vector<double,2> position = p_coarse_mesh->GetNode(i)->rGetLocation(); double dist = norm_2(centre - position); double u0 = pde_solution0[i]; double u1 = pde_solution1[i]; if (dist > 4.0) { TS_ASSERT_DELTA(u0, 1.0, 1e-5); TS_ASSERT_DELTA(u1, 1.0, 1e-5); } } /* * Loop over cells, find the coarse mesh element containing it, then * check the interpolated PDE solution is between the min and max of * the PDE solution on the nodes of that element. */ for (AbstractCellPopulation<2>::Iterator cell_iter = cell_population.Begin(); cell_iter != cell_population.End(); ++cell_iter) { c_vector<double,2> cell_location = cell_population.GetLocationOfCellCentre(*cell_iter); unsigned elem_index = p_coarse_mesh->GetContainingElementIndex(cell_location); Element<2,2>* p_element = p_coarse_mesh->GetElement(elem_index); unsigned node_0_index = p_element->GetNodeGlobalIndex(0); unsigned node_1_index = p_element->GetNodeGlobalIndex(1); unsigned node_2_index = p_element->GetNodeGlobalIndex(2); double max0 = std::max(pde_solution0[node_0_index], pde_solution0[node_1_index]); max0 = std::max(max0, pde_solution0[node_2_index]); double max1 = std::max(pde_solution1[node_0_index], pde_solution1[node_1_index]); max1 = std::max(max1, pde_solution1[node_2_index]); double min0 = std::min(pde_solution0[node_0_index], pde_solution0[node_1_index]); min0 = std::min(min0, pde_solution0[node_2_index]); double min1 = std::min(pde_solution1[node_0_index], pde_solution1[node_1_index]); min1 = std::min(min1, pde_solution1[node_2_index]); double value0_at_cell = cell_iter->GetCellData()->GetItem("quantity 1"); double value1_at_cell = cell_iter->GetCellData()->GetItem("quantity 2"); TS_ASSERT_LESS_THAN_EQUALS(value1_at_cell, value0_at_cell); TS_ASSERT_LESS_THAN_EQUALS(min0, value0_at_cell + DBL_EPSILON); TS_ASSERT_LESS_THAN_EQUALS(value0_at_cell, max0 + DBL_EPSILON); TS_ASSERT_LESS_THAN_EQUALS(min1, value1_at_cell + DBL_EPSILON); TS_ASSERT_LESS_THAN_EQUALS(value1_at_cell, max1 + DBL_EPSILON); // Now check the GetPdeSolutionAtPoint method matches TS_ASSERT_DELTA(pde_handler.GetPdeSolutionAtPoint(cell_location, "quantity 1"), value0_at_cell, 1e-6); TS_ASSERT_DELTA(pde_handler.GetPdeSolutionAtPoint(cell_location, "quantity 2"), value1_at_cell, 1e-6); } }
/** * Run the same test at different levels of refinement until some convergence criterion is met. * @param nameOfTest The name of the convergence test (typically the name in the suite) for use in naming files. * \todo This is a scarily long method; could do with some parts extracted? */ void Converge(std::string nameOfTest) { // Create the meshes on which the test will be based const std::string mesh_dir = "ConvergenceMesh"; OutputFileHandler output_file_handler(mesh_dir); ReplicatableVector voltage_replicated; unsigned file_num=0; // Create a file for storing conduction velocity and AP data and write the header OutputFileHandler conv_info_handler("ConvergencePlots"+nameOfTest, false); out_stream p_conv_info_file; if (PetscTools::AmMaster()) { std::cout << "=========================== Beginning Test...==================================\n"; p_conv_info_file = conv_info_handler.OpenOutputFile(nameOfTest+"_info.csv"); (*p_conv_info_file) << "#Abcisa\t" << "l2-norm-full\t" << "l2-norm-onset\t" << "Max absolute err\t" << "APD90_1st_quad\t" << "APD90_3rd_quad\t" << "Conduction velocity (relative diffs)" << std::endl; } SetInitialConvergenceParameters(); double prev_apd90_first_qn=0.0; double prev_apd90_third_qn=0.0; double prev_cond_velocity=0.0; std::vector<double> prev_voltage; std::vector<double> prev_times; PopulateStandardResult(prev_voltage, prev_times); do { CuboidMeshConstructor<DIM> constructor; //If the printing time step is too fine, then simulations become I/O bound without much improvement in accuracy double printing_step = this->PdeTimeStep; #define COVERAGE_IGNORE while (printing_step < 1.0e-4) { printing_step *= 2.0; std::cout<<"Warning: PrintingTimeStep increased\n"; } #undef COVERAGE_IGNORE HeartConfig::Instance()->SetOdePdeAndPrintingTimeSteps(this->OdeTimeStep, this->PdeTimeStep, printing_step); #define COVERAGE_IGNORE if (SimulateFullActionPotential) { HeartConfig::Instance()->SetSimulationDuration(400.0); } else { HeartConfig::Instance()->SetSimulationDuration(8.0); } #undef COVERAGE_IGNORE HeartConfig::Instance()->SetOutputDirectory("Convergence"+nameOfTest); HeartConfig::Instance()->SetOutputFilenamePrefix("Results"); DistributedTetrahedralMesh<DIM, DIM> mesh; constructor.Construct(mesh, this->MeshNum, mMeshWidth); unsigned num_ele_across = SmallPow(2u, this->MeshNum+2); // number of elements in each dimension AbstractCardiacCellFactory<DIM>* p_cell_factory=NULL; switch (this->Stimulus) { case NEUMANN: { p_cell_factory = new ZeroStimulusCellFactory<CELL, DIM>(); break; } case PLANE: { if (this->UseAbsoluteStimulus) { #define COVERAGE_IGNORE p_cell_factory = new GeneralPlaneStimulusCellFactory<CELL, DIM>(0, this->AbsoluteStimulus, true); #undef COVERAGE_IGNORE } else { p_cell_factory = new GeneralPlaneStimulusCellFactory<CELL, DIM>(num_ele_across, constructor.GetWidth(), false, this->AbsoluteStimulus); } break; } case QUARTER: { ///\todo consider reducing all stimuli to match this one. p_cell_factory = new RampedQuarterStimulusCellFactory<CELL, DIM>(constructor.GetWidth(), num_ele_across, this->AbsoluteStimulus/10.0); break; } default: NEVER_REACHED; } CARDIAC_PROBLEM cardiac_problem(p_cell_factory); cardiac_problem.SetMesh(&mesh); // Calculate positions of nodes 1/4 and 3/4 through the mesh unsigned third_quadrant_node; unsigned first_quadrant_node; switch(DIM) { case 1: { first_quadrant_node = (unsigned) (0.25*constructor.GetNumElements()); third_quadrant_node = (unsigned) (0.75*constructor.GetNumElements()); break; } case 2: { unsigned n= SmallPow (2u, this->MeshNum+2); first_quadrant_node = (n+1)*(n/2)+ n/4 ; third_quadrant_node = (n+1)*(n/2)+3*n/4 ; break; } case 3: { const unsigned first_quadrant_nodes_3d[5]={61, 362, 2452, 17960, 137296}; const unsigned third_quadrant_nodes_3d[5]={63, 366, 2460, 17976, 137328}; assert(this->PdeTimeStep<5); first_quadrant_node = first_quadrant_nodes_3d[this->MeshNum]; third_quadrant_node = third_quadrant_nodes_3d[this->MeshNum]; break; } default: NEVER_REACHED; } double mesh_width=constructor.GetWidth(); // We only need the output of these two nodes std::vector<unsigned> nodes_to_be_output; nodes_to_be_output.push_back(first_quadrant_node); nodes_to_be_output.push_back(third_quadrant_node); cardiac_problem.SetOutputNodes(nodes_to_be_output); // The results of the tests were originally obtained with the following conductivity // values. After implementing fibre orientation the defaults changed. Here we set // the former ones to be used. SetConductivities(cardiac_problem); cardiac_problem.Initialise(); boost::shared_ptr<BoundaryConditionsContainer<DIM,DIM,PROBLEM_DIM> > p_bcc(new BoundaryConditionsContainer<DIM,DIM,PROBLEM_DIM>); SimpleStimulus stim(NeumannStimulus, 0.5); if (Stimulus==NEUMANN) { StimulusBoundaryCondition<DIM>* p_bc_stim = new StimulusBoundaryCondition<DIM>(&stim); // get mesh AbstractTetrahedralMesh<DIM, DIM> &r_mesh = cardiac_problem.rGetMesh(); // loop over boundary elements typename AbstractTetrahedralMesh<DIM, DIM>::BoundaryElementIterator iter; iter = r_mesh.GetBoundaryElementIteratorBegin(); while (iter != r_mesh.GetBoundaryElementIteratorEnd()) { double x = ((*iter)->CalculateCentroid())[0]; ///\todo remove magic number? (#1884) if (x*x<=1e-10) { p_bcc->AddNeumannBoundaryCondition(*iter, p_bc_stim); } iter++; } // pass the bcc to the problem cardiac_problem.SetBoundaryConditionsContainer(p_bcc); } DisplayRun(); Timer::Reset(); //// use this to get some info printed out //cardiac_problem.SetWriteInfo(); try { cardiac_problem.Solve(); } catch (Exception e) { WARNING("This run threw an exception. Check convergence results\n"); std::cout << e.GetMessage() << std::endl; } if (PetscTools::AmMaster()) { std::cout << "Time to solve = " << Timer::GetElapsedTime() << " seconds\n"; } OutputFileHandler results_handler("Convergence"+nameOfTest, false); Hdf5DataReader results_reader = cardiac_problem.GetDataReader(); { std::vector<double> transmembrane_potential = results_reader.GetVariableOverTime("V", third_quadrant_node); std::vector<double> time_series = results_reader.GetUnlimitedDimensionValues(); OutputFileHandler plot_file_handler("ConvergencePlots"+nameOfTest, false); if (PetscTools::AmMaster()) { // Write out the time series for the node at third quadrant { std::stringstream plot_file_name_stream; plot_file_name_stream<< nameOfTest << "_Third_quadrant_node_run_"<< file_num << ".csv"; out_stream p_plot_file = plot_file_handler.OpenOutputFile(plot_file_name_stream.str()); for (unsigned data_point = 0; data_point<time_series.size(); data_point++) { (*p_plot_file) << time_series[data_point] << "\t" << transmembrane_potential[data_point] << "\n"; } p_plot_file->close(); } // Write time series for first quadrant node { std::vector<double> transmembrane_potential_1qd=results_reader.GetVariableOverTime("V", first_quadrant_node); std::vector<double> time_series_1qd = results_reader.GetUnlimitedDimensionValues(); std::stringstream plot_file_name_stream; plot_file_name_stream<< nameOfTest << "_First_quadrant_node_run_"<< file_num << ".csv"; out_stream p_plot_file = plot_file_handler.OpenOutputFile(plot_file_name_stream.str()); for (unsigned data_point = 0; data_point<time_series.size(); data_point++) { (*p_plot_file) << time_series_1qd[data_point] << "\t" << transmembrane_potential_1qd[data_point] << "\n"; } p_plot_file->close(); } } // calculate conduction velocity and APD90 error PropagationPropertiesCalculator ppc(&results_reader); try { #define COVERAGE_IGNORE if (SimulateFullActionPotential) { Apd90FirstQn = ppc.CalculateActionPotentialDuration(90.0, first_quadrant_node); Apd90ThirdQn = ppc.CalculateActionPotentialDuration(90.0, third_quadrant_node); } #undef COVERAGE_IGNORE ConductionVelocity = ppc.CalculateConductionVelocity(first_quadrant_node,third_quadrant_node,0.5*mesh_width); } catch (Exception e) { #define COVERAGE_IGNORE std::cout << "Warning - this run threw an exception in calculating propagation. Check convergence results\n"; std::cout << e.GetMessage() << std::endl; #undef COVERAGE_IGNORE } double cond_velocity_error = 1e10; double apd90_first_qn_error = 1e10; double apd90_third_qn_error = 1e10; if (this->PopulatedResult) { if (prev_cond_velocity != 0.0) { cond_velocity_error = fabs(ConductionVelocity - prev_cond_velocity) / prev_cond_velocity; } #define COVERAGE_IGNORE if (prev_apd90_first_qn != 0.0) { apd90_first_qn_error = fabs(Apd90FirstQn - prev_apd90_first_qn) / prev_apd90_first_qn; } if (prev_apd90_third_qn != 0.0) { apd90_third_qn_error = fabs(Apd90ThirdQn - prev_apd90_third_qn) / prev_apd90_third_qn; } if (apd90_first_qn_error == 0.0) { apd90_first_qn_error = DBL_EPSILON; //Avoid log zero on plot } if (apd90_third_qn_error == 0.0) { apd90_third_qn_error = DBL_EPSILON; //Avoid log zero on plot } #undef COVERAGE_IGNORE if (cond_velocity_error == 0.0) { cond_velocity_error = DBL_EPSILON; //Avoid log zero on plot } } prev_cond_velocity = ConductionVelocity; prev_apd90_first_qn = Apd90FirstQn; prev_apd90_third_qn = Apd90ThirdQn; // calculate l2norm double max_abs_error = 0; double sum_sq_abs_error =0; double sum_sq_prev_voltage = 0; double sum_sq_abs_error_full =0; double sum_sq_prev_voltage_full = 0; if (this->PopulatedResult) { //If the PDE step is varying then we'll have twice as much data now as we use to have unsigned time_factor=(time_series.size()-1) / (prev_times.size()-1); assert (time_factor == 1 || time_factor == 2 || time_factor == 8); //Iterate over the shorter time series data for (unsigned data_point = 0; data_point<prev_times.size(); data_point++) { unsigned this_data_point=time_factor*data_point; assert(time_series[this_data_point] == prev_times[data_point]); double abs_error = fabs(transmembrane_potential[this_data_point]-prev_voltage[data_point]); max_abs_error = (abs_error > max_abs_error) ? abs_error : max_abs_error; //Only do resolve the upstroke... sum_sq_abs_error_full += abs_error*abs_error; sum_sq_prev_voltage_full += prev_voltage[data_point] * prev_voltage[data_point]; if (time_series[this_data_point] <= 8.0) { //In most regular cases we always do this, since the simulation stops at ms sum_sq_abs_error += abs_error*abs_error; sum_sq_prev_voltage += prev_voltage[data_point] * prev_voltage[data_point]; } } } if (!this->PopulatedResult || !FixedResult) { prev_voltage = transmembrane_potential; prev_times = time_series; } if (this->PopulatedResult) { double l2_norm_upstroke = sqrt(sum_sq_abs_error/sum_sq_prev_voltage); double l2_norm_full = sqrt(sum_sq_abs_error_full/sum_sq_prev_voltage_full); if (PetscTools::AmMaster()) { (*p_conv_info_file) << std::setprecision(8) << Abscissa() << "\t" << l2_norm_full << "\t" << l2_norm_upstroke << "\t" << max_abs_error << "\t" << Apd90FirstQn <<" "<< apd90_first_qn_error <<""<< "\t" << Apd90ThirdQn <<" "<< apd90_third_qn_error <<""<< "\t" << ConductionVelocity <<" "<< cond_velocity_error <<""<< std::endl; } // convergence criterion this->Converged = l2_norm_full < this->RelativeConvergenceCriterion; this->LastDifference = l2_norm_full; #define COVERAGE_IGNORE assert (time_series.size() != 1u); if (time_series.back() == 0.0) { std::cout << "Failed after successful convergence - give up this convergence test\n"; break; } #undef COVERAGE_IGNORE } if ( time_series.back() != 0.0) { // Simulation ran to completion this->PopulatedResult=true; } } // Get ready for the next test by halving the time step if (!this->Converged) { UpdateConvergenceParameters(); file_num++; } delete p_cell_factory; } while (!GiveUpConvergence() && !this->Converged); if (PetscTools::AmMaster()) { p_conv_info_file->close(); std::cout << "Results: " << std::endl; FileFinder info_finder = conv_info_handler.FindFile(nameOfTest + "_info.csv"); std::ifstream info_file(info_finder.GetAbsolutePath().c_str()); if (info_file) { std::cout << info_file.rdbuf(); info_file.close(); } } }
void TestSolvingEllipticPde() throw(Exception) { /* First we declare a mesh reader which reads mesh data files of the 'Triangle' * format. The path given is relative to the main Chaste directory. As we are in 2d, * the reader will look for three datafiles, [name].nodes, [name].ele and [name].edge. * Note that the first template argument here is the spatial dimension of the * elements in the mesh ({{{ELEMENT_DIM}}}), and the second is the dimension of the nodes, * i.e. the dimension of the space the mesh lives in ({{{SPACE_DIM}}}). Usually * {{{ELEMENT_DIM}}} and {{{SPACE_DIM}}} will be equal. */ TrianglesMeshReader<2,2> mesh_reader("mesh/test/data/square_128_elements"); /* Now declare a tetrahedral mesh with the same dimensions... */ TetrahedralMesh<2,2> mesh; /* ... and construct the mesh using the mesh reader. */ mesh.ConstructFromMeshReader(mesh_reader); /* Next we instantiate an instance of our PDE we wish to solve. */ MyPde pde; /* A set of boundary conditions are stored in a {{{BoundaryConditionsContainer}}}. The * three template arguments are ELEMENT_DIM, SPACE_DIM and PROBLEM_DIM, the latter being * the number of unknowns we are solving for. We have one unknown (ie u is a scalar, not * a vector), so in this case {{{PROBLEM_DIM}}}=1. */ BoundaryConditionsContainer<2,2,1> bcc; /* Defining the boundary conditions is the only particularly fiddly part of solving PDEs, * unless they are very simple, such as u=0 on the boundary, which could be done * as follows: */ //bcc.DefineZeroDirichletOnMeshBoundary(&mesh); /* We want to specify u=0 on x=0 and y=0. To do this, we first create the boundary condition * object saying what the value of the condition is at any particular point in space. Here * we use the class `ConstBoundaryCondition`, a subclass of `AbstractBoundaryCondition` that * yields the same constant value (0.0 here) everywhere it is used. * * Note that the object is allocated with `new`. The `BoundaryConditionsContainer` object deals * with deleting its associated boundary condition objects. Note too that we could allocate a * separate condition object for each boundary node, but using the same object where possible is * more memory efficient. */ ConstBoundaryCondition<2>* p_zero_boundary_condition = new ConstBoundaryCondition<2>(0.0); /* We then get a boundary node iterator from the mesh... */ TetrahedralMesh<2,2>::BoundaryNodeIterator iter = mesh.GetBoundaryNodeIteratorBegin(); /* ...and loop over the boundary nodes, getting the x and y values. */ while (iter < mesh.GetBoundaryNodeIteratorEnd()) { double x = (*iter)->GetPoint()[0]; double y = (*iter)->GetPoint()[1]; /* If x=0 or y=0... */ if ((x==0) || (y==0)) { /* ...associate the zero boundary condition created above with this boundary node * ({{{*iter}}} being a pointer to a {{{Node<2>}}}). */ bcc.AddDirichletBoundaryCondition(*iter, p_zero_boundary_condition); } iter++; } /* Now we create Neumann boundary conditions for the ''surface elements'' on x=1 and y=1. Note that * Dirichlet boundary conditions are defined on nodes, whereas Neumann boundary conditions are * defined on surface elements. Note also that the natural boundary condition statement for this * PDE is (D grad u).n = g(x) (where n is the outward-facing surface normal), and g(x) is a prescribed * function, ''not'' something like du/dn=g(x). Hence the boundary condition we are specifying is * (D grad u).n = 0. * * '''Important note for 1D:''' This means that if we were solving 2u,,xx,,=f(x) in 1D, and * wanted to specify du/dx=1 on the LHS boundary, the Neumann boundary value we have to specify is * -2, as n=-1 (outward facing normal) so (D gradu).n = -2 when du/dx=1. * * To define Neumann bcs, we reuse the zero boundary condition object defined above, but apply it * at surface elements. We loop over these using another iterator provided by the mesh class. */ TetrahedralMesh<2,2>::BoundaryElementIterator surf_iter = mesh.GetBoundaryElementIteratorBegin(); while (surf_iter != mesh.GetBoundaryElementIteratorEnd()) { /* Get the x and y values of any node (here, the 0th) in the element. */ unsigned node_index = (*surf_iter)->GetNodeGlobalIndex(0); double x = mesh.GetNode(node_index)->GetPoint()[0]; double y = mesh.GetNode(node_index)->GetPoint()[1]; /* If x=1 or y=1... */ if ( (fabs(x-1.0) < 1e-6) || (fabs(y-1.0) < 1e-6) ) { /* ...associate the boundary condition with the surface element. */ bcc.AddNeumannBoundaryCondition(*surf_iter, p_zero_boundary_condition); } /* Finally increment the iterator. */ surf_iter++; } /* Next we define the solver of the PDE. * To solve an {{{AbstractLinearEllipticPde}}} (which is the type of PDE {{{MyPde}}} is), * we use a {{{SimpleLinearEllipticSolver}}}. The solver, again templated over * {{{ELEMENT_DIM}}} and {{{SPACE_DIM}}}, needs to be given (pointers to) the mesh, * pde and boundary conditions. */ SimpleLinearEllipticSolver<2,2> solver(&mesh, &pde, &bcc); /* To solve, just call {{{Solve()}}}. A PETSc vector is returned. */ Vec result = solver.Solve(); /* It is a pain to access the individual components of a PETSc vector, even when running only on * one process. A helper class called {{{ReplicatableVector}}} has been created. Create * an instance of one of these, using the PETSc {{{Vec}}} as the data. The ''i''th * component of {{{result}}} can now be obtained by simply doing {{{result_repl[i]}}}. */ ReplicatableVector result_repl(result); /* Let us write out the solution to a file. To do this, create an * {{{OutputFileHandler}}}, passing in the directory we want files written to. * This is relative to the directory defined by the CHASTE_TEST_OUTPUT environment * variable - usually `/tmp/$USER/testoutput`. Note by default the output directory * passed in is emptied by this command. To avoid this, {{{false}}} can be passed in as a second * parameter. */ OutputFileHandler output_file_handler("TestSolvingLinearPdeTutorial"); /* Create an {{{out_stream}}}, which is a stream to a particular file. An {{{out_stream}}} * is a smart pointer to a `std::ofstream`. */ out_stream p_file = output_file_handler.OpenOutputFile("linear_solution.txt"); /* Loop over the entries of the solution. */ for (unsigned i=0; i<result_repl.GetSize(); i++) { /* Get the x and y-values of the node corresponding to this entry. The method * {{{GetNode}}} on the mesh class returns a pointer to a {{{Node}}}. */ double x = mesh.GetNode(i)->rGetLocation()[0]; double y = mesh.GetNode(i)->rGetLocation()[1]; /* Get the computed solution at this node from the {{{ReplicatableVector}}}. */ double u = result_repl[i]; /* Finally, write x, y and u to the output file. The solution could then be * visualised in (eg) matlab, using the commands: * {{{sol=load('linear_solution.txt'); plot3(sol(:,1),sol(:,2),sol(:,3),'.');}}}*/ (*p_file) << x << " " << y << " " << u << "\n"; } /* All PETSc {{{Vec}}}s should be destroyed when they are no longer needed, or you will have a memory leak. */ PetscTools::Destroy(result); }
CylindricalHoneycombMeshGenerator::CylindricalHoneycombMeshGenerator(unsigned numNodesAlongWidth, unsigned numNodesAlongLength, unsigned ghosts, double scaleFactor) { mpMesh = NULL; mDomainWidth = numNodesAlongWidth*scaleFactor; mNumCellWidth = numNodesAlongWidth; //*1 because cells are considered to be size one mNumCellLength = numNodesAlongLength; mMeshFilename = "mesh"; mGhostNodeIndices.clear(); // The code below won't work in parallel assert(PetscTools::IsSequential()); // An older version of the constructor might allow the wrong argument through to the scale factor assert(scaleFactor > 0.0); // Get a unique mesh filename std::stringstream pid; pid << getpid(); OutputFileHandler output_file_handler("2D_temporary_honeycomb_mesh_"+ pid.str()); unsigned num_nodes_along_width = mNumCellWidth; unsigned num_nodes_along_length = mNumCellLength; double horizontal_spacing = mDomainWidth / (double)num_nodes_along_width; double vertical_spacing = (sqrt(3.0)/2)*horizontal_spacing; // This line is needed to define ghost nodes later mDomainDepth = (double)(num_nodes_along_length) * vertical_spacing; // Take account of ghost nodes num_nodes_along_length += 2*ghosts; unsigned num_nodes = num_nodes_along_width*num_nodes_along_length; unsigned num_elem_along_width = num_nodes_along_width-1; unsigned num_elem_along_length = num_nodes_along_length-1; unsigned num_elem = 2*num_elem_along_width*num_elem_along_length; unsigned num_edges = 3*num_elem_along_width*num_elem_along_length + num_elem_along_width + num_elem_along_length; double x0 = 0; double y0 = -vertical_spacing*ghosts; mBottom = -vertical_spacing*ghosts; mTop = mBottom + vertical_spacing*(num_nodes_along_length-1); // Write node file out_stream p_node_file = output_file_handler.OpenOutputFile(mMeshFilename+".node"); (*p_node_file) << std::scientific; //(*p_node_file) << std::setprecision(20); (*p_node_file) << num_nodes << "\t2\t0\t1" << std::endl; unsigned node = 0; for (unsigned i=0; i<num_nodes_along_length; i++) { for (unsigned j=0; j<num_nodes_along_width; j++) { if (i<ghosts || i>=(ghosts+mNumCellLength)) { mGhostNodeIndices.insert(node); } unsigned boundary = 0; if ((i==0) || (i==num_nodes_along_length-1)) { boundary = 1; } double x = x0 + horizontal_spacing*((double)j + 0.25*(1.0+ SmallPow(-1.0,i+1))); double y = y0 + vertical_spacing*(double)i; // Avoid floating point errors which upset OffLatticeSimulation if ( (y<0.0) && (y>-1e-12) ) { // Difficult to cover - just corrects floating point errors that have occurred from time to time! #define COVERAGE_IGNORE y = 0.0; #undef COVERAGE_IGNORE } (*p_node_file) << node++ << "\t" << x << "\t" << y << "\t" << boundary << std::endl; } } p_node_file->close(); // Write element file and edge file out_stream p_elem_file = output_file_handler.OpenOutputFile(mMeshFilename+".ele"); (*p_elem_file) << std::scientific; out_stream p_edge_file = output_file_handler.OpenOutputFile(mMeshFilename+".edge"); (*p_node_file) << std::scientific; (*p_elem_file) << num_elem << "\t3\t0" << std::endl; (*p_edge_file) << num_edges << "\t1" << std::endl; unsigned elem = 0; unsigned edge = 0; for (unsigned i=0; i<num_elem_along_length; i++) { for (unsigned j=0; j < num_elem_along_width; j++) { unsigned node0 = i*num_nodes_along_width + j; unsigned node1 = i*num_nodes_along_width + j+1; unsigned node2 = (i+1)*num_nodes_along_width + j; if (i%2 != 0) { node2 = node2 + 1; } (*p_elem_file) << elem++ << "\t" << node0 << "\t" << node1 << "\t" << node2 << std::endl; unsigned horizontal_edge_is_boundary_edge = 0; unsigned vertical_edge_is_boundary_edge = 0; if (i==0) { horizontal_edge_is_boundary_edge = 1; } (*p_edge_file) << edge++ << "\t" << node0 << "\t" << node1 << "\t" << horizontal_edge_is_boundary_edge << std::endl; (*p_edge_file) << edge++ << "\t" << node1 << "\t" << node2 << "\t" << 0 << std::endl; (*p_edge_file) << edge++ << "\t" << node2 << "\t" << node0 << "\t" << vertical_edge_is_boundary_edge << std::endl; node0 = i*num_nodes_along_width + j + 1; if (i%2 != 0) { node0 = node0 - 1; } node1 = (i+1)*num_nodes_along_width + j+1; node2 = (i+1)*num_nodes_along_width + j; (*p_elem_file) << elem++ << "\t" << node0 << "\t" << node1 << "\t" << node2 << std::endl; } } for (unsigned i=0; i<num_elem_along_length; i++) { unsigned node0, node1; if (i%2==0) { node0 = (i+1)*num_nodes_along_width - 1; node1 = (i+2)*num_nodes_along_width - 1; } else { node0 = (i+1)*num_nodes_along_width; node1 = (i)*num_nodes_along_width; } (*p_edge_file) << edge++ << "\t" << node0 << "\t" << node1 << "\t" << 1 << std::endl; } for (unsigned j=0; j<num_elem_along_width; j++) { unsigned node0 = num_nodes_along_width*(num_nodes_along_length-1) + j; unsigned node1 = num_nodes_along_width*(num_nodes_along_length-1) + j+1; (*p_edge_file) << edge++ << "\t" << node1 << "\t" << node0 << "\t" << 1 << std::endl; } p_elem_file->close(); p_edge_file->close(); // Having written the mesh to file, now construct it using TrianglesMeshReader. // Nested scope so the reader closes files before we delete them below. { TrianglesMeshReader<2,2> mesh_reader(output_file_handler.GetOutputDirectoryFullPath() + mMeshFilename); mpMesh = new Cylindrical2dMesh(mDomainWidth); mpMesh->ConstructFromMeshReader(mesh_reader); } // Make the mesh cylindrical (we use Triangle library mode inside this ReMesh call) mpMesh->ReMesh(); // Delete the temporary files output_file_handler.FindFile("").Remove(); // The original files have been deleted, it is better if the mesh object forgets about them mpMesh->SetMeshHasChangedSinceLoading(); }
void TestWriteResultsToFileAndOutputCellPopulationParameters() { EXIT_IF_PARALLEL; // Copying in parallel uses parallel NodesOnlyMesh and will therefore cause unexpected errors. // Resetting the maximum cell ID to zero (to account for previous tests) CellId::ResetMaxCellId(); std::string output_directory = "TestPottsBasedCellPopulationWriters"; OutputFileHandler output_file_handler(output_directory, false); // 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; CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 2> cells_generator; cells_generator.GenerateBasic(cells, p_mesh->GetNumElements()); // Create cell population PottsBasedCellPopulation<2> cell_population(*p_mesh, cells); // For coverage, label one cell boost::shared_ptr<AbstractCellProperty> p_label(cell_population.GetCellPropertyRegistry()->Get<CellLabel>()); cell_population.GetCellUsingLocationIndex(0)->AddCellProperty(p_label); TS_ASSERT_EQUALS(cell_population.GetIdentifier(), "PottsBasedCellPopulation-2"); cell_population.SetCellAncestorsToLocationIndices(); cell_population.AddCellPopulationCountWriter<CellMutationStatesCountWriter>(); cell_population.AddCellPopulationCountWriter<CellProliferativeTypesCountWriter>(); cell_population.AddCellPopulationCountWriter<CellProliferativePhasesCountWriter>(); cell_population.AddCellWriter<CellProliferativePhasesWriter>(); cell_population.AddCellWriter<CellAncestorWriter>(); cell_population.AddCellWriter<CellAgesWriter>(); cell_population.AddCellWriter<CellVolumesWriter>(); cell_population.SetNumSweepsPerTimestep(5); TS_ASSERT_EQUALS(cell_population.GetNumSweepsPerTimestep(), 5u); // VTK writing needs a simulation time SimulationTime::Instance()->SetEndTimeAndNumberOfTimeSteps(1.0, 1); cell_population.OpenWritersFiles(output_file_handler); cell_population.WriteResultsToFiles(output_directory); cell_population.CloseWritersFiles(); // Compare output with saved files of what they should look like std::string results_dir = output_file_handler.GetOutputDirectoryFullPath(); FileComparison(results_dir + "results.viznodes", "cell_based/test/data/TestPottsBasedCellPopulationWriters/results.viznodes").CompareFiles(); FileComparison(results_dir + "results.vizcelltypes", "cell_based/test/data/TestPottsBasedCellPopulationWriters/results.vizcelltypes").CompareFiles(); FileComparison(results_dir + "results.vizancestors", "cell_based/test/data/TestPottsBasedCellPopulationWriters/results.vizancestors").CompareFiles(); FileComparison(results_dir + "cellmutationstates.dat", "cell_based/test/data/TestPottsBasedCellPopulationWriters/cellmutationstates.dat").CompareFiles(); FileComparison(results_dir + "cellages.dat", "cell_based/test/data/TestPottsBasedCellPopulationWriters/cellages.dat").CompareFiles(); FileComparison(results_dir + "cellareas.dat", "cell_based/test/data/TestPottsBasedCellPopulationWriters/cellareas.dat").CompareFiles(); // Test that the cell population parameters are output correctly out_stream parameter_file = output_file_handler.OpenOutputFile("results.parameters"); // Write cell population parameters to file cell_population.OutputCellPopulationParameters(parameter_file); parameter_file->close(); // Compare output with saved files of what they should look like FileComparison( results_dir + "results.parameters", "cell_based/test/data/TestPottsBasedCellPopulationWriters/results.parameters").CompareFiles(); }
void AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::Solve() { CellBasedEventHandler::BeginEvent(CellBasedEventHandler::EVERYTHING); CellBasedEventHandler::BeginEvent(CellBasedEventHandler::SETUP); // Set up the simulation time SimulationTime* p_simulation_time = SimulationTime::Instance(); double current_time = p_simulation_time->GetTime(); assert(mDt != DOUBLE_UNSET); //Subclass constructors take care of this if (mEndTime == DOUBLE_UNSET) { EXCEPTION("SetEndTime has not yet been called."); } /* * Note that mDt is used here for "ideal time step". If this step doesn't divide the time remaining * then a *different* time step will be taken by the time-stepper. The real time-step (used in the * SimulationTime singleton) is currently not available to this class. * * \todo Should we over-write the value of mDt, or change this behaviour? (see #2159) */ unsigned num_time_steps = (unsigned) ((mEndTime-current_time)/mDt+0.5); if (current_time > 0) // use the reset function if necessary { p_simulation_time->ResetEndTimeAndNumberOfTimeSteps(mEndTime, num_time_steps); } else { if (p_simulation_time->IsEndTimeAndNumberOfTimeStepsSetUp()) { EXCEPTION("End time and number of timesteps already setup. You should not use SimulationTime::SetEndTimeAndNumberOfTimeSteps in cell-based tests."); } else { p_simulation_time->SetEndTimeAndNumberOfTimeSteps(mEndTime, num_time_steps); } } if (mOutputDirectory == "") { EXCEPTION("OutputDirectory not set"); } double time_now = p_simulation_time->GetTime(); std::ostringstream time_string; time_string << time_now; std::string results_directory = mOutputDirectory +"/results_from_time_" + time_string.str(); mSimulationOutputDirectory = results_directory; // Set up simulation // Create output files for the visualizer OutputFileHandler output_file_handler(results_directory+"/", true); mrCellPopulation.OpenWritersFiles(results_directory+"/"); if (mOutputDivisionLocations) { mpDivisionLocationFile = output_file_handler.OpenOutputFile("divisions.dat"); } if (PetscTools::AmMaster()) { mpVizSetupFile = output_file_handler.OpenOutputFile("results.vizsetup"); } // If any PDEs have been defined, set up results files to store their solution if (mpCellBasedPdeHandler != NULL) { mpCellBasedPdeHandler->OpenResultsFiles(this->mSimulationOutputDirectory); if (PetscTools::AmMaster()) { *this->mpVizSetupFile << "PDE \n"; } /* * If any PDEs have been defined, solve them here before updating cells and store * their solution in results files. This also initializes the relevant CellData. * NOTE that this works as the PDEs are elliptic. */ CellBasedEventHandler::BeginEvent(CellBasedEventHandler::PDE); mpCellBasedPdeHandler->SolvePdeAndWriteResultsToFile(this->mSamplingTimestepMultiple); CellBasedEventHandler::EndEvent(CellBasedEventHandler::PDE); } SetupSolve(); // Call SetupSolve() on each modifier for (typename std::vector<boost::shared_ptr<AbstractCellBasedSimulationModifier<ELEMENT_DIM, SPACE_DIM> > >::iterator iter = mSimulationModifiers.begin(); iter != mSimulationModifiers.end(); ++iter) { (*iter)->SetupSolve(this->mrCellPopulation,this->mSimulationOutputDirectory); } /* * Age the cells to the correct time. Note that cells are created with * negative birth times so that some are initially almost ready to divide. */ LOG(1, "Setting up cells..."); for (typename AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>::Iterator cell_iter = mrCellPopulation.Begin(); cell_iter != mrCellPopulation.End(); ++cell_iter) { /* * We don't use the result; this call is just to force the cells to age * to the current time running their cell-cycle models to get there. */ cell_iter->ReadyToDivide(); } LOG(1, "\tdone\n"); // Write initial conditions to file for the visualizer WriteVisualizerSetupFile(); if (PetscTools::AmMaster()) { *mpVizSetupFile << std::flush; } mrCellPopulation.WriteResultsToFiles(results_directory+"/"); OutputSimulationSetup(); CellBasedEventHandler::EndEvent(CellBasedEventHandler::SETUP); // Enter main time loop while (!( p_simulation_time->IsFinished() || StoppingEventHasOccurred() ) ) { LOG(1, "--TIME = " << p_simulation_time->GetTime() << "\n"); // This function calls DoCellRemoval(), DoCellBirth() and CellPopulation::Update() UpdateCellPopulation(); // Update cell locations and topology UpdateCellLocationsAndTopology(); // Update the assignment of cells to processes. mrCellPopulation.UpdateCellProcessLocation(); // Increment simulation time here, so results files look sensible p_simulation_time->IncrementTimeOneStep(); // If any PDEs have been defined, solve them and store their solution in results files if (mpCellBasedPdeHandler != NULL) { CellBasedEventHandler::BeginEvent(CellBasedEventHandler::PDE); mpCellBasedPdeHandler->SolvePdeAndWriteResultsToFile(this->mSamplingTimestepMultiple); CellBasedEventHandler::EndEvent(CellBasedEventHandler::PDE); } // Call UpdateAtEndOfTimeStep(), which may be implemented by child classes CellBasedEventHandler::BeginEvent(CellBasedEventHandler::UPDATESIMULATION); UpdateAtEndOfTimeStep(); // Call UpdateAtEndOfTimeStep() on each modifier for (typename std::vector<boost::shared_ptr<AbstractCellBasedSimulationModifier<ELEMENT_DIM, SPACE_DIM> > >::iterator iter = mSimulationModifiers.begin(); iter != mSimulationModifiers.end(); ++iter) { (*iter)->UpdateAtEndOfTimeStep(this->mrCellPopulation); } CellBasedEventHandler::EndEvent(CellBasedEventHandler::UPDATESIMULATION); // Output current results to file CellBasedEventHandler::BeginEvent(CellBasedEventHandler::OUTPUT); if (p_simulation_time->GetTimeStepsElapsed()%mSamplingTimestepMultiple == 0) { mrCellPopulation.WriteResultsToFiles(results_directory+"/"); // Call UpdateAtEndOfOutputTimeStep() on each modifier for (typename std::vector<boost::shared_ptr<AbstractCellBasedSimulationModifier<ELEMENT_DIM, SPACE_DIM> > >::iterator iter = mSimulationModifiers.begin(); iter != mSimulationModifiers.end(); ++iter) { (*iter)->UpdateAtEndOfOutputTimeStep(this->mrCellPopulation); } } CellBasedEventHandler::EndEvent(CellBasedEventHandler::OUTPUT); } LOG(1, "--END TIME = " << p_simulation_time->GetTime() << "\n"); /* * Carry out a final update so that cell population is coherent with new cell positions. * Note that cell birth and death still need to be checked because they may be spatially * dependent. */ UpdateCellPopulation(); // If any PDEs have been defined, close the results files storing their solution if (mpCellBasedPdeHandler != NULL) { mpCellBasedPdeHandler->CloseResultsFiles(); } CellBasedEventHandler::BeginEvent(CellBasedEventHandler::UPDATESIMULATION); UpdateAtEndOfSolve(); // Call UpdateAtEndOfSolve(), on each modifier for (typename std::vector<boost::shared_ptr<AbstractCellBasedSimulationModifier<ELEMENT_DIM, SPACE_DIM> > >::iterator iter = mSimulationModifiers.begin(); iter != mSimulationModifiers.end(); ++iter) { (*iter)->UpdateAtEndOfSolve(this->mrCellPopulation); } CellBasedEventHandler::EndEvent(CellBasedEventHandler::UPDATESIMULATION); CellBasedEventHandler::BeginEvent(CellBasedEventHandler::OUTPUT); mrCellPopulation.CloseOutputFiles(); if (mOutputDivisionLocations) { mpDivisionLocationFile->close(); } if (PetscTools::AmMaster()) { *mpVizSetupFile << "Complete\n"; mpVizSetupFile->close(); } CellBasedEventHandler::EndEvent(CellBasedEventHandler::OUTPUT); CellBasedEventHandler::EndEvent(CellBasedEventHandler::EVERYTHING); }
void TestSolvePdeAndWriteResultsToFileWithoutCoarsePdeMeshNeumann() 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 // Note SimplePdeForTesting wouldnt work as theres no solution with Neuman conditions. // Also note that when using Neuman conditions the only solution that works is u=0 CellwiseSourcePde<2> pde(cell_population, 0.0); ConstBoundaryCondition<2> bc(0.0); PdeAndBoundaryConditions<2> pde_and_bc(&pde, &bc, true); pde_and_bc.SetDependentVariableName("variable"); // For coverage, provide an initial guess for the solution std::vector<double> data(mesh.GetNumNodes()+1); 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(); // Check the correct solution was obtained for (AbstractCellPopulation<2>::Iterator cell_iter = cell_population.Begin(); cell_iter != cell_population.End(); ++cell_iter) { // Test that PDE solver is working correctly TS_ASSERT_DELTA(cell_iter->GetCellData()->GetItem("variable"), 0.0, 0.02); } }
void TestNodeBasedSimulationWithContactInhibition() { EXIT_IF_PARALLEL; // HoneycombMeshGenerator does not work in parallel // Create a simple 2D NodeBasedCellPopulation HoneycombMeshGenerator generator(5, 5, 0); TetrahedralMesh<2,2>* p_generating_mesh = generator.GetMesh(); NodesOnlyMesh<2> mesh; mesh.ConstructNodesWithoutMesh(*p_generating_mesh, 1.5); MAKE_PTR(WildTypeCellMutationState, p_state); MAKE_PTR(TransitCellProliferativeType, p_transit_type); std::vector<CellPtr> cells; for (unsigned i=0; i<mesh.GetNumNodes(); i++) { ContactInhibitionCellCycleModel* p_cycle_model = new ContactInhibitionCellCycleModel(); p_cycle_model->SetDimension(2); p_cycle_model->SetBirthTime(-10.0); p_cycle_model->SetQuiescentVolumeFraction(0.9); p_cycle_model->SetEquilibriumVolume(0.7854); //pi *(0.5)^2 p_cycle_model->SetStemCellG1Duration(0.1); p_cycle_model->SetTransitCellG1Duration(0.1); CellPtr p_cell(new Cell(p_state, p_cycle_model)); p_cell->SetCellProliferativeType(p_transit_type); cells.push_back(p_cell); } NodeBasedCellPopulation<2> cell_population(mesh, cells); cell_population.AddPopulationWriter<CellMutationStatesCountWriter>(); cell_population.AddCellWriter<CellVolumesWriter>(); cell_population.AddPopulationWriter<NodeVelocityWriter>(); // Create a simulation OffLatticeSimulation<2> simulator(cell_population); simulator.SetOutputDirectory("TestNodeBasedSimulationWithVolumeTracked"); TS_ASSERT_EQUALS(simulator.GetDt(), 1.0/120.0); // Default value for off-lattice simulations simulator.SetEndTime(simulator.GetDt()/2.0); // Create a volume-tracking modifier and pass it to the simulation MAKE_PTR(VolumeTrackingModifier<2>, p_modifier); simulator.AddSimulationModifier(p_modifier); // Create a force law and pass it to the simulation MAKE_PTR(GeneralisedLinearSpringForce<2>, p_force); p_force->SetCutOffLength(1.5); simulator.AddForce(p_force); // Run simulation simulator.Solve(); // Test that the node velocities file exists OutputFileHandler output_file_handler("TestNodeBasedSimulationWithVolumeTracked", false); FileFinder generated = output_file_handler.FindFile("results_from_time_0/nodevelocities.dat"); TS_ASSERT(generated.Exists()); // Test that the volumes of the cells are correct in CellData at the first timestep for (AbstractCellPopulation<2>::Iterator cell_iter = cell_population.Begin(); cell_iter != cell_population.End(); ++cell_iter) { TS_ASSERT_DELTA(cell_population.GetVolumeOfCell(*cell_iter), cell_iter->GetCellData()->GetItem("volume"), 1e-4); } simulator.SetEndTime(2.0); // Run simulation simulator.Solve(); // Test that the volumes of the cells are correct in CellData at the end time for (AbstractCellPopulation<2>::Iterator cell_iter = cell_population.Begin(); cell_iter != cell_population.End(); ++cell_iter) { TS_ASSERT_DELTA(cell_population.GetVolumeOfCell(*cell_iter), cell_iter->GetCellData()->GetItem("volume"), 1e-4); } // Check that the correct number of cells are labelled (i.e. experiencing contact inhibition) TS_ASSERT_EQUALS(cell_population.GetCellPropertyRegistry()->Get<CellLabel>()->GetCellCount(), 2u); }
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); }
void TestUpdateRuleOutputUpdateRuleInfo() { EXIT_IF_PARALLEL; std::string output_directory = "TestPottsUpdateRulesOutputParameters"; OutputFileHandler output_file_handler(output_directory, false); // Test with VolumeConstraintPottsUpdateRule VolumeConstraintPottsUpdateRule<2> volume_constraint; volume_constraint.SetDeformationEnergyParameter(0.1); volume_constraint.SetMatureCellTargetVolume(20); TS_ASSERT_EQUALS(volume_constraint.GetIdentifier(), "VolumeConstraintPottsUpdateRule-2"); out_stream volume_constraint_parameter_file = output_file_handler.OpenOutputFile("volume_constraint_results.parameters"); volume_constraint.OutputUpdateRuleInfo(volume_constraint_parameter_file); volume_constraint_parameter_file->close(); std::string volume_constraint_results_dir = output_file_handler.GetOutputDirectoryFullPath(); FileComparison( volume_constraint_results_dir + "volume_constraint_results.parameters", "cell_based/test/data/TestPottsUpdateRules/volume_constraint_results.parameters").CompareFiles(); // Test with SurfaceAreaConstraintPottsUpdateRule SurfaceAreaConstraintPottsUpdateRule<2> surface_area_constraint; surface_area_constraint.SetDeformationEnergyParameter(0.1); surface_area_constraint.SetMatureCellTargetSurfaceArea(20); TS_ASSERT_EQUALS(surface_area_constraint.GetIdentifier(), "SurfaceAreaConstraintPottsUpdateRule-2"); out_stream surface_area_constraint_parameter_file = output_file_handler.OpenOutputFile("surface_area_constraint_results.parameters"); surface_area_constraint.OutputUpdateRuleInfo(surface_area_constraint_parameter_file); surface_area_constraint_parameter_file->close(); std::string surface_area_constraint_results_dir = output_file_handler.GetOutputDirectoryFullPath(); FileComparison( surface_area_constraint_results_dir + "surface_area_constraint_results.parameters", "cell_based/test/data/TestPottsUpdateRules/surface_area_constraint_results.parameters").CompareFiles(); // Test with AdhesionPottsUpdateRule AdhesionPottsUpdateRule<2> adhesion_update; adhesion_update.SetCellCellAdhesionEnergyParameter(0.3); adhesion_update.SetCellBoundaryAdhesionEnergyParameter(0.4); TS_ASSERT_EQUALS(adhesion_update.GetIdentifier(), "AdhesionPottsUpdateRule-2"); out_stream adhesion_update_parameter_file = output_file_handler.OpenOutputFile("adhesion_update_results.parameters"); adhesion_update.OutputUpdateRuleInfo(adhesion_update_parameter_file); adhesion_update_parameter_file->close(); std::string adhesion_update_results_dir = output_file_handler.GetOutputDirectoryFullPath(); FileComparison( adhesion_update_results_dir + "adhesion_update_results.parameters", "cell_based/test/data/TestPottsUpdateRules/adhesion_update_results.parameters").CompareFiles(); // Test with DifferentialAdhesionPottsUpdateRule DifferentialAdhesionPottsUpdateRule<2> differential_adhesion_update; differential_adhesion_update.SetLabelledCellLabelledCellAdhesionEnergyParameter(0.3); differential_adhesion_update.SetLabelledCellCellAdhesionEnergyParameter(0.4); differential_adhesion_update.SetCellCellAdhesionEnergyParameter(0.5); differential_adhesion_update.SetLabelledCellBoundaryAdhesionEnergyParameter(0.6); differential_adhesion_update.SetCellBoundaryAdhesionEnergyParameter(0.7); TS_ASSERT_EQUALS(differential_adhesion_update.GetIdentifier(), "DifferentialAdhesionPottsUpdateRule-2"); out_stream differential_adhesion_update_parameter_file = output_file_handler.OpenOutputFile("differential_adhesion_update_results.parameters"); differential_adhesion_update.OutputUpdateRuleInfo(differential_adhesion_update_parameter_file); differential_adhesion_update_parameter_file->close(); std::string differential_adhesion_update_results_dir = output_file_handler.GetOutputDirectoryFullPath(); FileComparison(differential_adhesion_update_results_dir + "differential_adhesion_update_results.parameters", "cell_based/test/data/TestPottsUpdateRules/differential_adhesion_update_results.parameters").CompareFiles(); // Test with DifferentialAdhesionPottsUpdateRule ChemotaxisPottsUpdateRule<2> chemotaxis_update; TS_ASSERT_EQUALS(chemotaxis_update.GetIdentifier(), "ChemotaxisPottsUpdateRule-2"); out_stream chemotaxis_update_parameter_file = output_file_handler.OpenOutputFile("chemotaxis_update_results.parameters"); chemotaxis_update.OutputUpdateRuleInfo(chemotaxis_update_parameter_file); chemotaxis_update_parameter_file->close(); std::string chemotaxis_update_results_dir = output_file_handler.GetOutputDirectoryFullPath(); FileComparison(chemotaxis_update_results_dir + "chemotaxis_update_results.parameters", "cell_based/test/data/TestPottsUpdateRules/chemotaxis_update_results.parameters").CompareFiles(); }
void TestSolvePdeAndWriteResultsToFileCoarsePdeMeshNeumann() throw(Exception) { EXIT_IF_PARALLEL; // Set up SimulationTime SimulationTime::Instance()->SetEndTimeAndNumberOfTimeSteps(0.05, 6); // Create a cigar-shaped mesh TrianglesMeshReader<2,2> mesh_reader("mesh/test/data/disk_522_elements"); MutableMesh<2,2> mesh; mesh.ConstructFromMeshReader(mesh_reader); mesh.Scale(5.0, 1.0); // Create a cell population std::vector<CellPtr> cells; CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 2> cells_generator; cells_generator.GenerateBasic(cells, mesh.GetNumNodes()); MeshBasedCellPopulation<2> cell_population(mesh, cells); // Create a PDE handler object using this cell population CellBasedPdeHandler<2> pde_handler(&cell_population); // Set up PDE and pass to handler AveragedSourcePde<2> pde(cell_population, -0.01); ConstBoundaryCondition<2> bc(0.0); PdeAndBoundaryConditions<2> pde_and_bc(&pde, &bc, true); // Last boolean specifies Neuman conditions pde_and_bc.SetDependentVariableName("variable"); pde_handler.AddPdeAndBc(&pde_and_bc); // Solve PDEs on a coarse mesh 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(false); // For coverage, provide an initial guess for the solution std::vector<double> data(pde_handler.mpCoarsePdeMesh->GetNumNodes()); for (unsigned i=0; i<pde_handler.mpCoarsePdeMesh->GetNumNodes(); i++) { data[i] = 1.0; } Vec vector = PetscTools::CreateVec(data); pde_and_bc.SetSolution(vector); // 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 boundary cells experience the right boundary condition for (AbstractCellPopulation<2>::Iterator cell_iter = cell_population.Begin(); cell_iter != cell_population.End(); ++cell_iter) { if (cell_population.GetNodeCorrespondingToCell(*cell_iter)->IsBoundaryNode()) { TS_ASSERT_DELTA(cell_iter->GetCellData()->GetItem("variable"), 0.0, 1e-1); } } }
void TestCellPopulationWritersIn3dWithParticles() throw(Exception) { EXIT_IF_PARALLEL; // This test doesn't work in parallel. // Set up SimulationTime (needed if VTK is used) SimulationTime::Instance()->SetEndTimeAndNumberOfTimeSteps(1.0, 1); // Resetting the Maximum cell Id to zero (to account for previous tests) CellId::ResetMaxCellId(); // Create a simple 3D mesh with some particles std::vector<Node<3>*> nodes; nodes.push_back(new Node<3>(0, true, 0.0, 0.0, 0.0)); nodes.push_back(new Node<3>(1, true, 1.0, 1.0, 0.0)); nodes.push_back(new Node<3>(2, true, 1.0, 0.0, 1.0)); nodes.push_back(new Node<3>(3, true, 0.0, 1.0, 1.0)); nodes.push_back(new Node<3>(4, false, 0.5, 0.5, 0.5)); nodes.push_back(new Node<3>(5, false, -1.0, -1.0, -1.0)); nodes.push_back(new Node<3>(6, false, 2.0, -1.0, -1.0)); nodes.push_back(new Node<3>(7, false, 2.0, 2.0, -1.0)); nodes.push_back(new Node<3>(8, false, -1.0, 2.0, -1.0)); nodes.push_back(new Node<3>(9, false, -1.0, -1.0, 2.0)); nodes.push_back(new Node<3>(10, false, 2.0, -1.0, 2.0)); nodes.push_back(new Node<3>(11, false, 2.0, 2.0, 2.0)); nodes.push_back(new Node<3>(12, false, -1.0, 2.0, 2.0)); // Convert this to a NodesOnlyMesh MAKE_PTR(NodesOnlyMesh<3>, p_mesh); p_mesh->ConstructNodesWithoutMesh(nodes, 1.5); // Specify the node indices corresponding to cells (the others correspond to particles) std::vector<unsigned> location_indices; for (unsigned index=0; index<5; index++) { location_indices.push_back(index); } // Set up cells std::vector<CellPtr> cells; CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 3> cells_generator; cells_generator.GenerateGivenLocationIndices(cells, location_indices); cells[4]->AddCellProperty(CellPropertyRegistry::Instance()->Get<ApoptoticCellProperty>()); // coverage TS_ASSERT_EQUALS(cells[4]->HasCellProperty<ApoptoticCellProperty>(), true); // Create cell population NodeBasedCellPopulationWithParticles<3> cell_population(*p_mesh, cells, location_indices); // Coverage of writing CellData to VTK for (NodeBasedCellPopulationWithParticles<3>::Iterator cell_iter = cell_population.Begin(); cell_iter != cell_population.End(); ++cell_iter) { cell_iter->GetCellData()->SetItem("var0", 1.0); cell_iter->GetCellData()->SetItem("var1", 2.0); } cell_population.Update(); // so cell neighbours are calculated when outputting volume TS_ASSERT_EQUALS(cell_population.GetIdentifier(), "NodeBasedCellPopulationWithParticles-3"); // Test writer methods cell_population.AddCellWriter<CellVolumesWriter>(); cell_population.AddCellPopulationCountWriter<CellMutationStatesCountWriter>(); cell_population.AddCellPopulationCountWriter<CellProliferativeTypesCountWriter>(); cell_population.AddCellWriter<CellAgesWriter>(); cell_population.AddCellPopulationCountWriter<CellProliferativePhasesCountWriter>(); cell_population.AddCellWriter<CellProliferativePhasesWriter>(); cell_population.SetCellAncestorsToLocationIndices(); cell_population.AddCellWriter<CellAncestorWriter>(); std::string output_directory = "TestCellPopulationWritersIn3dWithParticles"; OutputFileHandler output_file_handler(output_directory, false); cell_population.OpenWritersFiles(output_file_handler); cell_population.WriteResultsToFiles(output_directory); cell_population.CloseWritersFiles(); // Compare output with saved files of what they should look like std::string results_dir = output_file_handler.GetOutputDirectoryFullPath(); FileComparison(results_dir + "results.viznodes", "cell_based/test/data/TestCellPopulationWritersIn3dWithParticles/results.viznodes").CompareFiles(); FileComparison(results_dir + "results.vizcelltypes", "cell_based/test/data/TestCellPopulationWritersIn3dWithParticles/results.vizcelltypes").CompareFiles(); FileComparison(results_dir + "results.vizancestors", "cell_based/test/data/TestCellPopulationWritersIn3dWithParticles/results.vizancestors").CompareFiles(); // Test the GetCellMutationStateCount function: there should only be healthy cells std::vector<unsigned> cell_mutation_states = cell_population.GetCellMutationStateCount(); TS_ASSERT_EQUALS(cell_mutation_states.size(), 4u); TS_ASSERT_EQUALS(cell_mutation_states[0], 5u); TS_ASSERT_EQUALS(cell_mutation_states[1], 0u); TS_ASSERT_EQUALS(cell_mutation_states[2], 0u); TS_ASSERT_EQUALS(cell_mutation_states[3], 0u); // Test the GetCellProliferativeTypeCount function - we should have 4 stem cells and 1 dead cell (for coverage) std::vector<unsigned> cell_types = cell_population.GetCellProliferativeTypeCount(); TS_ASSERT_EQUALS(cell_types.size(), 4u); TS_ASSERT_EQUALS(cell_types[0], 5u); TS_ASSERT_EQUALS(cell_types[1], 0u); TS_ASSERT_EQUALS(cell_types[2], 0u); TS_ASSERT_EQUALS(cell_types[3], 0u); // Test that the cell population parameters are output correctly out_stream parameter_file = output_file_handler.OpenOutputFile("results.parameters"); // Write cell population parameters to file cell_population.OutputCellPopulationParameters(parameter_file); parameter_file->close(); // Compare output with saved files of what they should look like FileComparison( results_dir + "results.parameters", "cell_based/test/data/TestCellPopulationWritersIn3dWithParticles/results.parameters").CompareFiles(); for (unsigned i=0; i<nodes.size(); i++) { delete nodes[i]; } }
void AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::OutputSimulationSetup() { OutputFileHandler output_file_handler(this->mSimulationOutputDirectory + "/", false); // Output machine information ExecutableSupport::SetOutputDirectory(output_file_handler.GetOutputDirectoryFullPath()); ExecutableSupport::WriteMachineInfoFile("system_info"); if (PetscTools::AmMaster()) { // Output Chaste provenance information out_stream build_info_file = output_file_handler.OpenOutputFile("build.info"); std::string build_info; ExecutableSupport::GetBuildInfo(build_info); *build_info_file << build_info; build_info_file->close(); // Output simulation parameter and setup details out_stream parameter_file = output_file_handler.OpenOutputFile("results.parameters"); // Output simulation details std::string simulation_type = GetIdentifier(); *parameter_file << "<Chaste>\n"; *parameter_file << "\n\t<" << simulation_type << ">\n"; OutputSimulationParameters(parameter_file); *parameter_file << "\t</" << simulation_type << ">\n"; *parameter_file << "\n"; // Output cell population details (includes cell-cycle model details) mrCellPopulation.OutputCellPopulationInfo(parameter_file); // Loop over cell killers *parameter_file << "\n\t<CellKillers>\n"; for (typename std::vector<boost::shared_ptr<AbstractCellKiller<SPACE_DIM> > >::iterator iter = mCellKillers.begin(); iter != mCellKillers.end(); ++iter) { // Output cell killer details (*iter)->OutputCellKillerInfo(parameter_file); } *parameter_file << "\t</CellKillers>\n"; // Iterate over simulationmodifiers *parameter_file << "\n\t<SimulationModifiers>\n"; for (typename std::vector<boost::shared_ptr<AbstractCellBasedSimulationModifier<ELEMENT_DIM, SPACE_DIM> > >::iterator iter = mSimulationModifiers.begin(); iter != mSimulationModifiers.end(); ++iter) { // Output simulation modifier details (*iter)->OutputSimulationModifierInfo(parameter_file); } *parameter_file << "\t</SimulationModifiers>\n"; // This is used to output information about subclasses OutputAdditionalSimulationSetup(parameter_file); *parameter_file << "\n</Chaste>\n"; parameter_file->close(); } }
TetrahedralMesh<DIM, DIM>* VertexBasedCellPopulation<DIM>::GetTetrahedralMeshUsingVertexMesh() { // This method only works in 2D sequential assert(DIM == 2); assert(PetscTools::IsSequential()); unsigned num_vertex_nodes = mpMutableVertexMesh->GetNumNodes(); unsigned num_vertex_elements = mpMutableVertexMesh->GetNumElements(); std::string mesh_file_name = "mesh"; // Get a unique temporary foldername std::stringstream pid; pid << getpid(); OutputFileHandler output_file_handler("2D_temporary_tetrahedral_mesh_" + pid.str()); std::string output_dir = output_file_handler.GetOutputDirectoryFullPath(); // Compute the number of nodes in the TetrahedralMesh unsigned num_tetrahedral_nodes = num_vertex_nodes + num_vertex_elements; // Write node file out_stream p_node_file = output_file_handler.OpenOutputFile(mesh_file_name+".node"); (*p_node_file) << std::scientific; (*p_node_file) << std::setprecision(20); (*p_node_file) << num_tetrahedral_nodes << "\t2\t0\t1" << std::endl; // Begin by writing each node in the VertexMesh for (unsigned node_index=0; node_index<num_vertex_nodes; node_index++) { Node<DIM>* p_node = mpMutableVertexMesh->GetNode(node_index); ///\todo will the nodes in mpMutableVertexMesh always have indices 0,1,2,...? (#2221) unsigned index = p_node->GetIndex(); c_vector<double, DIM> location = p_node->rGetLocation(); unsigned is_boundary_node = p_node->IsBoundaryNode() ? 1 : 0; (*p_node_file) << index << "\t" << location[0] << "\t" << location[1] << "\t" << is_boundary_node << std::endl; } // Now write an additional node at each VertexElement's centroid unsigned num_tetrahedral_elements = 0; for (unsigned vertex_elem_index=0; vertex_elem_index<num_vertex_elements; vertex_elem_index++) { unsigned index = num_vertex_nodes + vertex_elem_index; c_vector<double, DIM> location = mpMutableVertexMesh->GetCentroidOfElement(vertex_elem_index); // Any node located at a VertexElement's centroid will not be a boundary node unsigned is_boundary_node = 0; (*p_node_file) << index << "\t" << location[0] << "\t" << location[1] << "\t" << is_boundary_node << std::endl; // Also keep track of how many tetrahedral elements there will be num_tetrahedral_elements += mpMutableVertexMesh->GetElement(vertex_elem_index)->GetNumNodes(); } p_node_file->close(); // Write element file out_stream p_elem_file = output_file_handler.OpenOutputFile(mesh_file_name+".ele"); (*p_elem_file) << std::scientific; (*p_elem_file) << num_tetrahedral_elements << "\t3\t0" << std::endl; std::set<std::pair<unsigned, unsigned> > tetrahedral_edges; unsigned tetrahedral_elem_index = 0; for (unsigned vertex_elem_index=0; vertex_elem_index<num_vertex_elements; vertex_elem_index++) { VertexElement<DIM, DIM>* p_vertex_element = mpMutableVertexMesh->GetElement(vertex_elem_index); // Iterate over nodes owned by this VertexElement unsigned num_nodes_in_vertex_element = p_vertex_element->GetNumNodes(); for (unsigned local_index=0; local_index<num_nodes_in_vertex_element; local_index++) { unsigned node_0_index = p_vertex_element->GetNodeGlobalIndex(local_index); unsigned node_1_index = p_vertex_element->GetNodeGlobalIndex((local_index+1)%num_nodes_in_vertex_element); unsigned node_2_index = num_vertex_nodes + vertex_elem_index; (*p_elem_file) << tetrahedral_elem_index++ << "\t" << node_0_index << "\t" << node_1_index << "\t" << node_2_index << std::endl; // Add edges to the set if they are not already present std::pair<unsigned, unsigned> edge_0 = this->CreateOrderedPair(node_0_index, node_1_index); std::pair<unsigned, unsigned> edge_1 = this->CreateOrderedPair(node_1_index, node_2_index); std::pair<unsigned, unsigned> edge_2 = this->CreateOrderedPair(node_2_index, node_0_index); tetrahedral_edges.insert(edge_0); tetrahedral_edges.insert(edge_1); tetrahedral_edges.insert(edge_2); } } p_elem_file->close(); // Write edge file out_stream p_edge_file = output_file_handler.OpenOutputFile(mesh_file_name+".edge"); (*p_edge_file) << std::scientific; (*p_edge_file) << tetrahedral_edges.size() << "\t1" << std::endl; unsigned edge_index = 0; for (std::set<std::pair<unsigned, unsigned> >::iterator edge_iter = tetrahedral_edges.begin(); edge_iter != tetrahedral_edges.end(); ++edge_iter) { std::pair<unsigned, unsigned> this_edge = *edge_iter; // To be a boundary edge both nodes need to be boundary nodes. bool is_boundary_edge = false; if (this_edge.first < mpMutableVertexMesh->GetNumNodes() && this_edge.second < mpMutableVertexMesh->GetNumNodes()) { is_boundary_edge = (mpMutableVertexMesh->GetNode(this_edge.first)->IsBoundaryNode() && mpMutableVertexMesh->GetNode(this_edge.second)->IsBoundaryNode() ); } unsigned is_boundary_edge_unsigned = is_boundary_edge ? 1 : 0; (*p_edge_file) << edge_index++ << "\t" << this_edge.first << "\t" << this_edge.second << "\t" << is_boundary_edge_unsigned << std::endl; } p_edge_file->close(); // Having written the mesh to file, now construct it using TrianglesMeshReader TetrahedralMesh<DIM, DIM>* p_mesh = new TetrahedralMesh<DIM, DIM>; // Nested scope so reader is destroyed before we remove the temporary files. { TrianglesMeshReader<DIM, DIM> mesh_reader(output_dir + mesh_file_name); p_mesh->ConstructFromMeshReader(mesh_reader); } // Delete the temporary files output_file_handler.FindFile("").Remove(); // The original files have been deleted, it is better if the mesh object forgets about them p_mesh->SetMeshHasChangedSinceLoading(); return p_mesh; }