/** * Solve the Field-Noyes system. * This is a stiff ODE so Runge-Kutta won't work - program hangs if * end time > 0.01 and variables go out of bounds. * Can be solved ok with backward Euler. */ void TestFieldNoyesReactionSystem() { FieldNoyesReactionSystem ode_system; RungeKutta4IvpOdeSolver rk4_solver; OdeSolution ode_solution; std::vector<double> ode_state_variables = ode_system.GetInitialConditions(); // note small end time ode_solution = rk4_solver.Solve(&ode_system, ode_state_variables, 0.0, 0.01, 0.001, 0.001); int last = ode_solution.GetNumberOfTimeSteps(); for (int i=0; i<=last; i++) { double x = ode_solution.rGetSolutions()[i][0]; TS_ASSERT_LESS_THAN(x, 9.7e3); TS_ASSERT_LESS_THAN(0.99, x); } BackwardEulerIvpOdeSolver backward_euler_solver(ode_system.GetNumberOfStateVariables()); OdeSolution ode_solution2; std::vector<double> ode_state_variables2 = ode_system.GetInitialConditions(); ode_solution2 = backward_euler_solver.Solve(&ode_system, ode_state_variables2, 0.0, 0.1, 0.001, 0.001); last = ode_solution2.GetNumberOfTimeSteps(); for (int i=0; i<=last; i++) { double x = ode_solution2.rGetSolutions()[i][0]; TS_ASSERT_LESS_THAN(x, 9.7e3); TS_ASSERT_LESS_THAN(0.99, x); } }
void compare_interval_in_range(struct timeval start, struct timeval finish, suseconds_t tmin, suseconds_t tmax) { time_t sec = finish.tv_sec - start.tv_sec; suseconds_t actual = sec * 1000000 - start.tv_usec + finish.tv_usec; TS_ASSERT_LESS_THAN(tmin, actual); TS_ASSERT_LESS_THAN(actual,tmax); }
void TestBackwardEulerSystemOf3EquationsWithEvents() { OdeThirdOrderWithEvents ode_system_with_events; double h_value = 0.01; // Euler solver solution worked out BackwardEulerIvpOdeSolver backward_euler_solver(ode_system_with_events.GetNumberOfStateVariables()); OdeSolution solutions; std::vector<double> state_variables = ode_system_with_events.GetInitialConditions(); solutions = backward_euler_solver.Solve(&ode_system_with_events, state_variables, 0.0, 2.0, h_value, h_value); unsigned last = solutions.GetNumberOfTimeSteps(); // Final time should be pi/6 (?) TS_ASSERT_DELTA( solutions.rGetTimes()[last], 0.5236, 0.01); // Penultimate y0 should be greater than -0.5 TS_ASSERT_LESS_THAN(-0.5,solutions.rGetSolutions()[last-1][0]); // Final y0 should be less than -0.5 TS_ASSERT_LESS_THAN( solutions.rGetSolutions()[last][0], -0.5); // Solver should correctly state the stopping event occurred TS_ASSERT_EQUALS(backward_euler_solver.StoppingEventOccurred(), true); }
// Test a given solver on an ODE which has a stopping event defined void MyTestSolverOnOdesWithEvents(AbstractIvpOdeSolver& rSolver) { // ODE which has solution y0 = cos(t), and stopping event y0<0, // ie should stop when t = pi/2; OdeSecondOrderWithEvents ode_with_events; OdeSolution solutions; std::vector<double> state_variables = ode_with_events.GetInitialConditions(); solutions = rSolver.Solve(&ode_with_events, state_variables, 0.0, 2.0, 0.001, 0.001); unsigned num_timesteps = solutions.GetNumberOfTimeSteps(); // Final time should be around pi/2 TS_ASSERT_DELTA( solutions.rGetTimes()[num_timesteps], M_PI_2, 0.01); // Penultimate y0 should be greater than zero TS_ASSERT_LESS_THAN( 0, solutions.rGetSolutions()[num_timesteps-1][0]); // Final y0 should be less than zero TS_ASSERT_LESS_THAN( solutions.rGetSolutions()[num_timesteps][0], 0); // Solver should correctly state the stopping event occurred TS_ASSERT_EQUALS(rSolver.StoppingEventOccurred(), true); // This is to cover the exception when a stopping event occurs before the first timestep. TS_ASSERT_THROWS_ANYTHING(rSolver.Solve(&ode_with_events, state_variables, 2.0, 3.0, 0.001)); /////////////////////////////////////////////// // Repeat with sampling time larger than dt /////////////////////////////////////////////// state_variables = ode_with_events.GetInitialConditions(); solutions = rSolver.Solve(&ode_with_events, state_variables, 0.0, 2.0, 0.001, 0.01); num_timesteps = solutions.GetNumberOfTimeSteps(); // Final time should be around pi/2 TS_ASSERT_DELTA( solutions.rGetTimes()[num_timesteps], M_PI_2, 0.01); // Penultimate y0 should be greater than zero TS_ASSERT_LESS_THAN( 0, solutions.rGetSolutions()[num_timesteps-1][0]); // Final y0 should be less than zero TS_ASSERT_LESS_THAN( solutions.rGetSolutions()[num_timesteps][0], 0); // Solver should correctly state the stopping event occurred TS_ASSERT_EQUALS(rSolver.StoppingEventOccurred(), true); // Cover the check event isn't initially true exception std::vector<double> bad_init_cond; bad_init_cond.push_back(-1); //y0 < 0 so stopping event true bad_init_cond.push_back(0.0); TS_ASSERT_THROWS_ANYTHING(rSolver.Solve(&ode_with_events, bad_init_cond, 0.0, 2.0, 0.001, 0.01)); }
void TestWithCoarseSlightlyOutsideFine() throw(Exception) { // Fine mesh is has h=0.1, on unit cube (so 6000 elements) TetrahedralMesh<3,3> fine_mesh; fine_mesh.ConstructRegularSlabMesh(0.1, 1.0,1.0,1.0); // Coarse mesh is slightly bigger than in previous test QuadraticMesh<3> coarse_mesh(1.0, 1.0, 1.0, 1.0); // xmax > 1.0 coarse_mesh.Scale(1.03, 1.0, 1.0); FineCoarseMeshPair<3> mesh_pair(fine_mesh,coarse_mesh); GaussianQuadratureRule<3> quad_rule(3); // Need to call SetUpBoxesOnFineMesh first TS_ASSERT_THROWS_CONTAINS(mesh_pair.ComputeFineElementsAndWeightsForCoarseQuadPoints(quad_rule, true), "Call"); mesh_pair.SetUpBoxesOnFineMesh(0.3); TS_ASSERT_EQUALS(mesh_pair.mpFineMeshBoxCollection->GetNumBoxes(), 4*4*4u); mesh_pair.ComputeFineElementsAndWeightsForCoarseQuadPoints(quad_rule, true); TS_ASSERT_EQUALS(mesh_pair.mNotInMesh.size(), 2u); // hardcoded TS_ASSERT_EQUALS(mesh_pair.mNotInMeshNearestElementWeights.size(), 2u); TS_ASSERT_EQUALS(mesh_pair.rGetElementsAndWeights().size(), 6*8u); for (unsigned i=0; i<mesh_pair.rGetElementsAndWeights().size(); i++) { TS_ASSERT_LESS_THAN(mesh_pair.rGetElementsAndWeights()[i].ElementNum, fine_mesh.GetNumElements()); // comment out this test as now some of the weights are negative/greater than one //for (unsigned j=0; j<4; j++) //{ // TS_ASSERT_LESS_THAN(-1e14, mesh_pair.rGetElementsAndWeights()[i].Weights(j)); // TS_ASSERT_LESS_THAN(mesh_pair.rGetElementsAndWeights()[i].Weights(j), 1.0+1e-14); //} } /* * For each quadrature point that was not found in the fine mesh, check * that its x-value is greater than one - this is the only way it could * be outside the fine mesh. */ QuadraturePointsGroup<3> quad_point_posns(coarse_mesh, quad_rule); for (unsigned i=0; i<mesh_pair.mNotInMesh.size(); i++) { double x = quad_point_posns.rGet(mesh_pair.mNotInMesh[i])(0); TS_ASSERT_LESS_THAN(1.0, x); } mesh_pair.PrintStatistics(); TS_ASSERT_EQUALS( Warnings::Instance()->GetNumWarnings(), 1u); Warnings::Instance()->QuietDestroy(); }
/** * Test for Tyson & Novak self-cycling cells without having their * initial conditions reset. When using CVODE, the cell-cycle model * resets itself by halving the mass of the cell. * When not using CVODE, the cell-cycle model resets its initial * conditions, since the oscillatory solution computed using the Chaste * ODE solver is not stable. */ void TestTysonNovakCellCycleModelSolver() throw(Exception) { // Set up simulation time unsigned num_timesteps = 100000; double standard_divide_time = 75.19/60.0; SimulationTime::Instance()->SetEndTimeAndNumberOfTimeSteps(100.1*standard_divide_time, num_timesteps); // Create cell-cycle model and associated cell TysonNovakCellCycleModel* p_repeating_cell_model = new TysonNovakCellCycleModel; MAKE_PTR(ApcOneHitCellMutationState, p_mutation); MAKE_PTR(StemCellProliferativeType, p_stem_type); CellPtr p_tyson_novak_cell(new Cell(p_mutation, p_repeating_cell_model)); p_tyson_novak_cell->SetCellProliferativeType(p_stem_type); p_tyson_novak_cell->InitialiseCellCycleModel(); // Run through the cell-cycle model for a certain duration // and test how many times it has stopped for division unsigned num_divisions = 0; for (unsigned i=0; i<num_timesteps; i++) { SimulationTime::Instance()->IncrementTimeOneStep(); bool result = p_repeating_cell_model->ReadyToDivide(); // std::vector<double> proteins = p_repeating_cell_model->GetProteinConcentrations(); // out << SimulationTime::Instance()->GetTime() << "\t"; // for (unsigned j=0; j<proteins.size(); j++) // { // out << proteins[j] << "\t"; // } // out << "\n" << std::flush; if (result) { p_repeating_cell_model->ResetForDivision(); p_repeating_cell_model->SetBirthTime(SimulationTime::Instance()->GetTime()); num_divisions++; } } TS_ASSERT_LESS_THAN(num_divisions, 102u); TS_ASSERT_LESS_THAN(99u, num_divisions); // out.close(); /* * Matlab code for plotting the output commented above: * cdchaste * data = load('TN_output.txt'); * figure * for i=1:6 * subplot(3,2,i) * plot(data(:,1),data(:,1+i)) * end */ }
void TestImposeBoundaryConditionWithNoWntButWithJiggling() throw(Exception) { // Create a cell population CylindricalHoneycombMeshGenerator generator(4, 4, 0, 1.0); Cylindrical2dMesh* p_mesh = generator.GetCylindricalMesh(); std::vector<unsigned> location_indices = generator.GetCellLocationIndices(); std::vector<CellPtr> cells; MAKE_PTR(TransitCellProliferativeType, p_transit_type); CryptCellsGenerator<FixedDurationGenerationBasedCellCycleModel> cells_generator; cells_generator.Generate(cells, p_mesh, std::vector<unsigned>(), true); MeshBasedCellPopulationWithGhostNodes<2> crypt(*p_mesh, cells, location_indices); // Store the node locations std::map<Node<2>*, c_vector<double, 2> > node_locations_before; for (unsigned node_index=0; node_index<p_mesh->GetNumNodes(); node_index++) { node_locations_before[crypt.GetNode(node_index)] = crypt.GetNode(node_index)->rGetLocation(); } // Move the first cell (which should be on y=0, and is a stem cell) down a bit AbstractCellPopulation<2>::Iterator cell_iter = crypt.Begin(); crypt.GetNode(0)->rGetModifiableLocation()[1] = -0.1; // Also move the second cell (which should be on y=0, and we make a transit cell) ++cell_iter; TS_ASSERT_EQUALS(cell_iter->GetCellProliferativeType()->IsType<StemCellProliferativeType>(), true); cell_iter->SetCellProliferativeType(p_transit_type); TS_ASSERT_EQUALS(cell_iter->GetCellProliferativeType()->IsType<TransitCellProliferativeType>(), true); TS_ASSERT_DELTA(crypt.GetLocationOfCellCentre(*cell_iter)[1], 0.0, 1e-6); crypt.GetNode(1)->rGetModifiableLocation()[1] = -0.1; TS_ASSERT_LESS_THAN(crypt.GetLocationOfCellCentre(*cell_iter)[1], 0.0); // Create a boundary condition object CryptSimulationBoundaryCondition<2> boundary_condition(&crypt); boundary_condition.SetUseJiggledBottomCells(true); // Impose the boundary condition without a Wnt stimulus but with jiggled bottom cells boundary_condition.ImposeBoundaryCondition(node_locations_before); /* * The first cell should have been pulled up to y=0 since it is a stem cell and * there is no Wnt stimulus. It should then be unaffected by the jiggling. The * second cell should not have been pulled up since it is a stem cell, but should * then have been moved to above y=0 by the jiggling. */ AbstractCellPopulation<2>::Iterator cell_iter2 = crypt.Begin(); TS_ASSERT_DELTA(0.0, crypt.GetLocationOfCellCentre(*cell_iter2)[1], 1e-3); ++cell_iter2; TS_ASSERT_LESS_THAN(0.0, crypt.GetLocationOfCellCentre(*cell_iter2)[1]); }
/* * Test when calling ComputeFineElementsAndWeightsForCoarseQuadPoints() * in non-safe mode, but using the default value of box width. It is * difficult to get the class to run incorrectly (ie fail without an * assertion failing) in non-safe mode (ie we can't just specify boxes * that are too small), so we just test we get the same results as in * safe mode. */ void TestNonSafeMode() throw(Exception) { // Fine mesh is has h=0.1, on unit cube (so 6000 elements) TetrahedralMesh<3,3> fine_mesh; fine_mesh.ConstructRegularSlabMesh(0.1, 1.0, 1.0, 1.0); QuadraticMesh<3> coarse_mesh(1.0, 1.0, 1.0, 1.0); // xmax > 1.0 coarse_mesh.Scale(1.03, 1.0, 1.0); FineCoarseMeshPair<3> mesh_pair(fine_mesh,coarse_mesh); GaussianQuadratureRule<3> quad_rule(3); // Call SetUpBoxesOnFineMesh() without providing a width mesh_pair.SetUpBoxesOnFineMesh(); /* * Whereas before 4 by 4 by 4 boxes were explicitly chosen, here it * has been determined that 6 by 6 by 6 are needed. */ TS_ASSERT_EQUALS(mesh_pair.mpFineMeshBoxCollection->GetNumBoxes(), 6*6*6u); mesh_pair.ComputeFineElementsAndWeightsForCoarseQuadPoints(quad_rule, false /* non-safe mode*/); TS_ASSERT_EQUALS(mesh_pair.mNotInMesh.size(), 2u); // hardcoded TS_ASSERT_EQUALS(mesh_pair.mNotInMeshNearestElementWeights.size(), 2u); TS_ASSERT_EQUALS(mesh_pair.rGetElementsAndWeights().size(), 6*8u); for (unsigned i=0; i<mesh_pair.rGetElementsAndWeights().size(); i++) { TS_ASSERT_LESS_THAN(mesh_pair.rGetElementsAndWeights()[i].ElementNum, fine_mesh.GetNumElements()); } /* * For each quadrature point that was not found in the fine mesh, check * that its x-value is greater than one - this is the only way it could * be outside the fine mesh. */ QuadraturePointsGroup<3> quad_point_posns(coarse_mesh, quad_rule); for (unsigned i=0; i<mesh_pair.mNotInMesh.size(); i++) { double x = quad_point_posns.rGet(mesh_pair.mNotInMesh[i])(0); TS_ASSERT_LESS_THAN(1.0, x); } mesh_pair.PrintStatistics(); TS_ASSERT_EQUALS( Warnings::Instance()->GetNumWarnings(), 1u); Warnings::Instance()->QuietDestroy(); }
void TestGetLocationOfCellCentre() throw (Exception) { // Create a Potts-based cell population PottsMeshGenerator<2> generator(4, 2, 2, 4, 2, 2); PottsMesh<2>* p_mesh = generator.GetMesh(); std::vector<CellPtr> cells; CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 2> cells_generator; cells_generator.GenerateBasic(cells, p_mesh->GetNumElements()); PottsBasedCellPopulation<2> cell_population(*p_mesh, cells); // Test GetLocationOfCellCentre() AbstractCellPopulation<2>::Iterator cell_iter = cell_population.Begin(); for (unsigned i=0; i<4; i++) { c_vector<double, 2> cell_location = cell_population.GetLocationOfCellCentre(*cell_iter); c_vector<double, 2> expected; expected(0) = 0.5 + 2*(i%2 != 0); expected(1) = 0.5 + 2*(i > 1); double drift = norm_2(cell_location-expected); TS_ASSERT_LESS_THAN(drift, 1e-6); ++cell_iter; } }
/* * Note only solves one PDE */ void TestMultipleCaBasedWithoutCoarseMeshUsingPdeHandlerOnCuboid() throw(Exception) { EXIT_IF_PARALLEL; // Create a simple 2D PottsMesh PottsMeshGenerator<2> generator(10, 0, 0, 10, 0, 0); PottsMesh<2>* p_mesh = generator.GetMesh(); // Create cells std::vector<CellPtr> cells; CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 2> cells_generator; cells_generator.GenerateBasic(cells, 100); std::vector<unsigned> location_indices; for (unsigned i=0; i<100; i++) { location_indices.push_back(i); } // Create cell population MultipleCaBasedCellPopulation<2> cell_population(*p_mesh, cells, location_indices); // Set up cell-based simulation OnLatticeSimulation<2> simulator(cell_population); simulator.SetOutputDirectory("TestMultipleCaBasedCellPopulationWithPdesOnCuboid"); simulator.SetDt(0.1); simulator.SetEndTime(1); // Set up a PDE with mixed boundary conditions (use zero uptake to check analytic solution) AveragedSourcePde<2> pde(cell_population, 0.0); ConstBoundaryCondition<2> bc(1.0); PdeAndBoundaryConditions<2> pde_and_bc(&pde, &bc, false); pde_and_bc.SetDependentVariableName("nutrient"); // Pass this to the simulation object via a PDE handler CellBasedPdeHandlerOnCuboid<2> pde_handler(&cell_population); pde_handler.AddPdeAndBc(&pde_and_bc); pde_handler.SetImposeBcsOnCoarseBoundary(false); simulator.SetCellBasedPdeHandler(&pde_handler); // Solve the system simulator.Solve(); // Test that PDE solver is working correctly for (AbstractCellPopulation<2>::Iterator cell_iter = cell_population.Begin(); cell_iter != cell_population.End(); ++cell_iter) { c_vector<double, 2> cell_location = simulator.rGetCellPopulation().GetLocationOfCellCentre(*cell_iter); if (cell_location[1] < 1e-6 || cell_location[1] > 9 - 1e-6) { TS_ASSERT_DELTA(cell_iter->GetCellData()->GetItem("nutrient"),1.0, 1e-2); } else { TS_ASSERT_LESS_THAN(1.0,cell_iter->GetCellData()->GetItem("nutrient")); } } }
void TestComputeFineElemsAndWeightsForCoarseNodes() throw(Exception) { TetrahedralMesh<2,2> fine_mesh; TrianglesMeshReader<2,2> mesh_reader("mesh/test/data/square_4_elements"); fine_mesh.ConstructFromMeshReader(mesh_reader); QuadraticMesh<2> coarse_mesh(0.5, 0.5, 0.5); coarse_mesh.Translate(0.2,0.1); FineCoarseMeshPair<2> mesh_pair(fine_mesh,coarse_mesh); // Need to call SetUpBoxesOnFineMesh first TS_ASSERT_THROWS_CONTAINS(mesh_pair.ComputeFineElementsAndWeightsForCoarseNodes(true), "Call"); mesh_pair.SetUpBoxesOnFineMesh(); mesh_pair.ComputeFineElementsAndWeightsForCoarseNodes(true); // All coarse quadrature points should have been found in the fine mesh TS_ASSERT_EQUALS(mesh_pair.mNotInMesh.size(), 0u); TS_ASSERT_EQUALS(mesh_pair.mNotInMeshNearestElementWeights.size(), 0u); // Check the elements and weights have been set up correctly TS_ASSERT_EQUALS(mesh_pair.rGetElementsAndWeights().size(), 9u); // Check the first four nodes against what they should be TS_ASSERT_EQUALS(mesh_pair.rGetElementsAndWeights()[0].ElementNum, 1u); TS_ASSERT_EQUALS(mesh_pair.rGetElementsAndWeights()[1].ElementNum, 1u); TS_ASSERT_EQUALS(mesh_pair.rGetElementsAndWeights()[2].ElementNum, 0u); TS_ASSERT_EQUALS(mesh_pair.rGetElementsAndWeights()[3].ElementNum, 2u); for (unsigned i=0; i<mesh_pair.rGetElementsAndWeights().size(); i++) { TS_ASSERT_LESS_THAN(mesh_pair.rGetElementsAndWeights()[i].ElementNum, fine_mesh.GetNumElements()); // All the weights should be between 0 and 1 as no coarse nodes are // Note weights = (1-psi_x-psi_y-psi_z, psi_x, psi_y, psi_z), where psi is the position of the // point in that element when transformed to the canonical element for (unsigned j=0; j<3; j++) { TS_ASSERT_LESS_THAN(-1e14, mesh_pair.rGetElementsAndWeights()[i].Weights(j)); TS_ASSERT_LESS_THAN(mesh_pair.rGetElementsAndWeights()[i].Weights(j), 1.0+1e-14); } } TS_ASSERT_EQUALS(mesh_pair.mStatisticsCounters[0], 9u); TS_ASSERT_EQUALS(mesh_pair.mStatisticsCounters[1], 0u); }
void TestImposeBoundaryConditionWithNoWnt1d() throw(Exception) { // Create 1D cell population unsigned num_cells = 5; MutableMesh<1,1> mesh; mesh.ConstructLinearMesh(num_cells-1); std::vector<CellPtr> cells; CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 2> cells_generator; cells_generator.GenerateBasic(cells, mesh.GetNumNodes()); MeshBasedCellPopulation<1> crypt(mesh, cells); // Store the node locations std::map<Node<1>*, c_vector<double, 1> > node_locations_before; for (unsigned node_index=0; node_index<mesh.GetNumNodes(); node_index++) { node_locations_before[crypt.GetNode(node_index)] = crypt.GetNode(node_index)->rGetLocation(); } // Now move the first cell (which should be on x=0, and a stem cell) to the left a bit AbstractCellPopulation<1>::Iterator cell_iter = crypt.Begin(); // Check is a stem cell TS_ASSERT_EQUALS(cell_iter->GetCellProliferativeType()->IsType<StemCellProliferativeType>(), true); // Check initially at x=0 TS_ASSERT_DELTA(crypt.GetLocationOfCellCentre(*cell_iter)[0], 0.0, 1e-6); // Now move to the left a bit crypt.GetNode(0)->rGetModifiableLocation()[0] = -0.1; TS_ASSERT_LESS_THAN(crypt.GetLocationOfCellCentre(*cell_iter)[0], 0.0); // Pass this cell population to a boundary condition object CryptSimulationBoundaryCondition<1> boundary_condition(&crypt); // Impose the boundary condition without a Wnt stimulus boundary_condition.ImposeBoundaryCondition(node_locations_before); /* * The first cell should have been pulled back to x=0 since it is a stem cell and * there is no Wnt stimulus. It should be unaffected by jiggling, which is not imposed * in 1D. */ TS_ASSERT_DELTA(0.0, crypt.GetLocationOfCellCentre(*cell_iter)[0], 1e-3); // The nodes should all now be at their original locations std::map<Node<1>*, c_vector<double, 1> > node_locations_after; for (unsigned node_index=0; node_index<mesh.GetNumNodes(); node_index++) { node_locations_after[crypt.GetNode(node_index)] = crypt.GetNode(node_index)->rGetLocation(); } for (unsigned node_index=0; node_index<mesh.GetNumNodes(); node_index++) { TS_ASSERT_DELTA(node_locations_before[crypt.GetNode(node_index)](0), node_locations_after[crypt.GetNode(node_index)](0), 1e-3); } }
void TestSplitPointCloud() throw(Exception) { #if defined(CHASTE_VTK) && ( (VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION >= 6) || VTK_MAJOR_VERSION >= 6) EXIT_IF_PARALLEL; vtkSmartPointer<vtkPolyData> sphere = CreateSphere(); AirwayGenerator generator(sphere); vtkSmartPointer<vtkPolyData> point_cloud = generator.CreatePointCloudUsingTargetPoints(50); double normal[3] = {0.0, 1.0, 0.0 }; double origin[3] = {0.0, 0.0, 0.0}; vtkSmartPointer<vtkPolyData> top_half_sphere = generator.SplitPointCloud(point_cloud, normal, origin, false); TS_ASSERT_EQUALS(top_half_sphere->GetNumberOfPoints(), 21); for (int i = 0; i < top_half_sphere->GetNumberOfPoints(); ++i) { double coords[3]; top_half_sphere->GetPoint(i, coords); TS_ASSERT_LESS_THAN(0.0, coords[1]); } top_half_sphere = generator.SplitPointCloud(point_cloud, normal, origin, true); TS_ASSERT_EQUALS(top_half_sphere->GetNumberOfPoints(), 28); for (int i = 0; i < top_half_sphere->GetNumberOfPoints(); ++i) { double coords[3]; top_half_sphere->GetPoint(i, coords); TS_ASSERT_LESS_THAN(coords[1], 0.0); } #endif }
void TestNodeAndMeshMethods() throw(Exception) { // Create a Potts-based cell population PottsMeshGenerator<2> generator(4, 2, 2, 4, 2, 2); PottsMesh<2>* p_mesh = generator.GetMesh(); std::vector<CellPtr> cells; CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 2> cells_generator; cells_generator.GenerateBasic(cells, p_mesh->GetNumElements()); PottsBasedCellPopulation<2> cell_population(*p_mesh, cells); // Test GetNumNodes() TS_ASSERT_EQUALS(cell_population.GetNumNodes(), 16u); // Test GetNode() for (unsigned index=0; index<cell_population.GetNumNodes(); index++) { Node<2>* p_node = cell_population.GetNode(index); TS_ASSERT_EQUALS(p_node->GetIndex(), index); c_vector<double, 2> node_location = p_node->rGetLocation(); c_vector<double, 2> expected; expected(0) = (double)(index%4); expected(1) = (double)(index>3) + (double)(index>7) + (double)(index>11); double drift = norm_2(node_location-expected); TS_ASSERT_LESS_THAN(drift, 1e-6); } // Test GetElement() for (unsigned index=0; index<cell_population.GetNumElements(); index++) { PottsElement<2>* p_element = cell_population.GetElement(index); TS_ASSERT_EQUALS(p_element->GetIndex(), index); TS_ASSERT_EQUALS(p_element->GetNumNodes(), 4u); } // Test SetNode() ChastePoint<2> unused_point; TS_ASSERT_THROWS_THIS(cell_population.SetNode(0, unused_point), "SetNode() cannot be called on a subclass of AbstractOnLatticeCellPopulation."); // Test GetWidth() method double width_x = cell_population.GetWidth(0); TS_ASSERT_DELTA(width_x, 3.0, 1e-4); double width_y = cell_population.GetWidth(1); TS_ASSERT_DELTA(width_y, 3.0, 1e-4); // Test GetNeighbouringNodeIndices() method TS_ASSERT_THROWS_THIS(cell_population.GetNeighbouringNodeIndices(10), "Cannot call GetNeighbouringNodeIndices() on a subclass of AbstractOnLatticeCellPopulation, need to go through the PottsMesh instead"); }
/** * Initializes a matrix with the specified id. * Global matrices are set to the corresponding values, * local matrices initialized with random values. * * @param i_id id of the matrix {0, .., 51} -> flux matrix, {52} -> jacobian (flux solver), {53, 54, 55} -> stiffness matrices, {56, 57, 58} -> transposed stiffness matrices, {59} -> jacobian (star matrix) * @param i_numberOfRows number of rows. * @param i_numberOfColumns number of columns. * @param o_matrix matrix, which is initialized. **/ void initializeMatrix( unsigned int i_id, unsigned int i_numberOfRows, unsigned int i_numberOfColumns, real* o_matrix ) { // assert the matrices have been read assert( m_matrixIds.size() > 0 ); // get the position of our matrix unsigned int l_position; for( l_position = 0; l_position < m_matrixIds.size(); l_position++ ) { if( i_id == m_matrixIds[l_position] ) { break; } else { // matrix with the given id couldn't be found TS_ASSERT_DIFFERS( l_position, m_matrixIds.size() -1 ); } } // flux solver -> random values if( i_id == 52 ) { // assert correct matrix id TS_ASSERT_EQUALS( m_matrixIds[l_position], 52 ); setRandomValues( i_numberOfRows * i_numberOfColumns, o_matrix ); } // flux matrix, stiffness matrix or star matrix else { std::fill( o_matrix, o_matrix + i_numberOfRows * i_numberOfColumns, 0 ); for( unsigned int l_element = 0; l_element < m_matrixRows[l_position].size(); l_element++ ) { // assert that we can save the non-zero element TS_ASSERT_LESS_THAN_EQUALS( m_matrixRows[l_position][l_element], i_numberOfRows); TS_ASSERT_LESS_THAN_EQUALS( m_matrixColumns[l_position][l_element], i_numberOfColumns); unsigned int l_denseIndex = (m_matrixColumns[l_position][l_element]-1) * i_numberOfRows + (m_matrixRows[l_position][l_element]-1); // assert this a valid index TS_ASSERT_LESS_THAN( l_denseIndex, i_numberOfRows*i_numberOfColumns ); if( i_id == 59 ) { // star matrix o_matrix[ l_denseIndex ] = ((real)rand()/(real)RAND_MAX)*10.0; } else if( i_id >= 56 && i_id <= 58 ) { // add minus-sign for time kernel o_matrix[ l_denseIndex ] = -m_matrixValues[l_position][l_element]; } else{ // flux or stiffness matrix o_matrix[ l_denseIndex ] = m_matrixValues[l_position][l_element]; } } } }
void TestOn3dNonlinearProblem() throw (Exception) { SimplePetscNonlinearSolver solver_petsc; SimpleNewtonNonlinearSolver solver_newton; // Set up solution guess for residuals int length = 3; // Set up initial Guess Vec initial_guess=PetscTools::CreateVec(length); PetscVecTools::SetElement(initial_guess, 0, 1); PetscVecTools::SetElement(initial_guess, 1, 1); PetscVecTools::SetElement(initial_guess, 2, 1); PetscVecTools::Finalise(initial_guess); // Solve using petsc solver Vec answer_petsc = solver_petsc.Solve(&ComputeTestResidual3d, &ComputeTestJacobian3d, initial_guess, length, NULL); // Solve using newton method solver_newton.SetTolerance(1e-10); // to cover this method solver_newton.SetWriteStats(); // to cover this method Vec answer_newton = solver_newton.Solve(&ComputeTestResidual3d, &ComputeTestJacobian3d, initial_guess, length, NULL); // Replicate the answers so we can access them without worrying about parallel stuff ReplicatableVector answer_petsc_repl(answer_petsc); ReplicatableVector answer_newton_repl(answer_newton); double tol = 1e-6; for (int i=0; i<3; i++) { // the solution is x = 1/sqrt(3.0), y = 1/sqrt(3.0), z = 1/sqrt(3.0) TS_ASSERT_DELTA(answer_petsc_repl[i] ,1/sqrt(3.0),tol); TS_ASSERT_DELTA(answer_newton_repl[i],1/sqrt(3.0),tol); } // Check the residual really did have scaled norm within the tolerance Vec residual; VecDuplicate(answer_newton, &residual); ComputeTestResidual3d(NULL, answer_newton, residual, NULL); double norm; VecNorm(residual, NORM_2, &norm); TS_ASSERT_LESS_THAN(norm/length, 1e-10); PetscTools::Destroy(residual); PetscTools::Destroy(initial_guess); PetscTools::Destroy(answer_petsc); PetscTools::Destroy(answer_newton); }
void TestInitialiseCellPdeElementMapAndFindCoarseElementContainingCell() throw(Exception) { EXIT_IF_PARALLEL; // Create a cell population HoneycombMeshGenerator generator(4, 4, 0); MutableMesh<2,2>* p_generating_mesh = generator.GetMesh(); NodesOnlyMesh<2> mesh; mesh.ConstructNodesWithoutMesh(*p_generating_mesh, 1.5); std::vector<CellPtr> cells; CellsGenerator<FixedDurationGenerationBasedCellCycleModel, 2> cells_generator; cells_generator.GenerateBasic(cells, mesh.GetNumNodes()); NodeBasedCellPopulation<2> cell_population(mesh, cells); // Create a PDE handler object using this cell population CellBasedPdeHandler<2> pde_handler(&cell_population); TS_ASSERT_EQUALS(pde_handler.mCellPdeElementMap.size(), 0u); // Test that InitialiseCellPdeElementMap() throws an exception if mpCoarsePdeMesh is not set up TS_ASSERT_THROWS_THIS(pde_handler.InitialiseCellPdeElementMap(), "InitialiseCellPdeElementMap() should only be called if mpCoarsePdeMesh is set up."); // Set up PDE and pass to handler AveragedSourcePde<2> pde(cell_population, -0.1); ConstBoundaryCondition<2> bc(1.0); PdeAndBoundaryConditions<2> pde_and_bc(&pde, &bc, false); pde_handler.AddPdeAndBc(&pde_and_bc); // Use a coarse PDE mesh ChastePoint<2> lower(0.0, 0.0); ChastePoint<2> upper(9.0, 9.0); ChasteCuboid<2> cuboid(lower, upper); pde_handler.UseCoarsePdeMesh(3.0, cuboid, true); // Test that mCellPdeElementMap is initialised correctly pde_handler.InitialiseCellPdeElementMap(); TS_ASSERT_EQUALS(pde_handler.mCellPdeElementMap.size(), cell_population.GetNumRealCells()); for (AbstractCellPopulation<2>::Iterator cell_iter = cell_population.Begin(); cell_iter != cell_population.End(); ++cell_iter) { unsigned containing_element_index = pde_handler.mCellPdeElementMap[*cell_iter]; TS_ASSERT_LESS_THAN(containing_element_index, pde_handler.GetCoarsePdeMesh()->GetNumElements()); TS_ASSERT_EQUALS(containing_element_index, pde_handler.FindCoarseElementContainingCell(*cell_iter)); } }
void TestRKFehlbergSystemOf3EquationsWithEvents() throw(Exception) { OdeThirdOrderWithEvents ode_system_with_events; double h_value = 0.1; // Euler solver solution worked out RungeKuttaFehlbergIvpOdeSolver rkf_solver; OdeSolution solutions; std::vector<double> state_variables = ode_system_with_events.GetInitialConditions(); solutions = rkf_solver.Solve(&ode_system_with_events, state_variables, 0.0, 2.0, h_value, 1e-5); unsigned last = solutions.GetNumberOfTimeSteps(); // for (unsigned i=0; i<last+1; i++) // { // std::cout << "Time = " << solutions.rGetTimes()[i] << // " x = " << solutions.rGetSolutions()[i][0] << "\n" << std::flush; // } // Final time should be pi/6 (?) TS_ASSERT_DELTA( solutions.rGetTimes()[last], M_PI/6.0, h_value); // Penultimate y0 should be greater than -0.5 TS_ASSERT_LESS_THAN(-0.5,solutions.rGetSolutions()[last-1][0]); // Final y0 should be less than -0.5 TS_ASSERT_LESS_THAN( solutions.rGetSolutions()[last][0], -0.5); // Solver should correctly state the stopping event occurred TS_ASSERT_EQUALS(rkf_solver.StoppingEventOccurred(), true); // Coverage of exceptions TS_ASSERT_THROWS_THIS(rkf_solver.Solve(&ode_system_with_events, solutions.rGetSolutions()[last], M_PI/6.0, 2.0, 0.1, 1e-5), "(Solve with sampling) Stopping event is true for initial condition"); TS_ASSERT_THROWS_THIS(rkf_solver.Solve(&ode_system_with_events, solutions.rGetSolutions()[last], M_PI/6.0, 2.0, 0.1), "(Solve without sampling) Stopping event is true for initial condition"); }
void TestImposeBoundaryConditionWithNoWntOrJiggling2d() throw(Exception) { // Create a cell population CylindricalHoneycombMeshGenerator generator(4, 4, 0, 1.0); Cylindrical2dMesh* p_mesh = generator.GetCylindricalMesh(); std::vector<unsigned> location_indices = generator.GetCellLocationIndices(); std::vector<CellPtr> cells; CryptCellsGenerator<FixedDurationGenerationBasedCellCycleModel> cells_generator; cells_generator.Generate(cells, p_mesh, std::vector<unsigned>(), true); MeshBasedCellPopulationWithGhostNodes<2> crypt(*p_mesh, cells, location_indices); // Store the node locations std::map<Node<2>*, c_vector<double, 2> > node_locations_before; for (unsigned node_index=0; node_index<p_mesh->GetNumNodes(); node_index++) { node_locations_before[crypt.GetNode(node_index)] = crypt.GetNode(node_index)->rGetLocation(); } // Now move the first cell (which should be on y=0) down a bit AbstractCellPopulation<2>::Iterator cell_iter = crypt.Begin(); TS_ASSERT_DELTA(crypt.GetLocationOfCellCentre(*cell_iter)[1], 0.0, 1e-6); crypt.GetNode(0)->rGetModifiableLocation()[1] = -0.1; TS_ASSERT_LESS_THAN(crypt.GetLocationOfCellCentre(*cell_iter)[1], 0.0); // Create a boundary condition object CryptSimulationBoundaryCondition<2> boundary_condition(&crypt); boundary_condition.SetUseJiggledBottomCells(false); // Impose the boundary condition without a Wnt stimulus or jiggled bottom cells boundary_condition.ImposeBoundaryCondition(node_locations_before); // The first cell should have been moved back by the boundary condition object TS_ASSERT_DELTA(crypt.GetLocationOfCellCentre(*cell_iter)[1], 0.0, 1e-4); // The nodes should all now be at their original locations std::map<Node<2>*, c_vector<double, 2> > node_locations_after; for (unsigned node_index=0; node_index<p_mesh->GetNumNodes(); node_index++) { node_locations_after[crypt.GetNode(node_index)] = crypt.GetNode(node_index)->rGetLocation(); } for (unsigned node_index=0; node_index<p_mesh->GetNumNodes(); node_index++) { TS_ASSERT_DELTA(node_locations_before[crypt.GetNode(node_index)](0), node_locations_after[crypt.GetNode(node_index)](0), 1e-3); TS_ASSERT_DELTA(node_locations_before[crypt.GetNode(node_index)](1), node_locations_after[crypt.GetNode(node_index)](1), 1e-3); } }
//Experiments with ksp_atol follow. //This first one has to be done with GMRES as 1D are known to be a bit flakey void TestSpaceConvergencein1DWithAtol() { HeartConfig::Instance()->SetKSPSolver("gmres"); HeartConfig::Instance()->SetKSPPreconditioner("jacobi"); SpaceConvergenceTester<CellLuoRudy1991FromCellMLBackwardEuler, BidomainProblem<1>, 1, 2> tester; HeartConfig::Instance()->SetUseAbsoluteTolerance(1e-5); //tester.SetKspAbsoluteTolerance(1e-5); tester.Converge(__FUNCTION__); TS_ASSERT(tester.Converged); TS_ASSERT_EQUALS(tester.MeshNum, 5u); TS_ASSERT_LESS_THAN(tester.LastDifference, 0.0041039); //Has to be at least as good as the 1D with Rtol=1e-7 //Note the final line fails with ksp_atol=1e-4 HeartConfig::Instance()->Reset(); }
/* == Sliding boundary conditions == * * It is common to require a Dirichlet boundary condition where the displacement/position in one dimension * is fixed, but the displacement/position in the others are free. This can be easily done when * collecting the new locations for the fixed nodes, as shown in the following example. Here, we * take a unit square, apply gravity downward, and suppose the Y=0 surface is like a frictionless boundary, * so that, for the nodes on Y=0, we specify y=0 but leave x free (Here (X,Y)=old position, (x,y)=new position). * (Note though that this wouldn't be enough to uniquely specify the final solution - an arbitrary * translation in the Y direction could be added a solution to obtain another valid solution, so we * fully fix the node at the origin.) */ void TestWithSlidingDirichletBoundaryConditions() throw(Exception) { QuadraticMesh<2> mesh; mesh.ConstructRegularSlabMesh(0.1 /*stepsize*/, 1.0 /*width*/, 1.0 /*height*/); ExponentialMaterialLaw<2> law(1.0, 0.5); // First parameter is 'a', second 'b', in W=a*exp(b(I1-3)) /* Create fixed nodes and locations... */ std::vector<unsigned> fixed_nodes; std::vector<c_vector<double,2> > locations; /* Fix node 0 (the node at the origin) */ fixed_nodes.push_back(0); locations.push_back(zero_vector<double>(2)); /* For the rest, if the node is on the Y=0 surface.. */ for (unsigned i=1; i<mesh.GetNumNodes(); i++) { if ( fabs(mesh.GetNode(i)->rGetLocation()[1])<1e-6) { /* ..add it to the list of fixed nodes.. */ fixed_nodes.push_back(i); /* ..and define y to be 0 but x is fixed */ c_vector<double,2> new_location; new_location(0) = SolidMechanicsProblemDefinition<2>::FREE; new_location(1) = 0.0; locations.push_back(new_location); } } /* Set the material law and fixed nodes, add some gravity, and solve */ SolidMechanicsProblemDefinition<2> problem_defn(mesh); problem_defn.SetMaterialLaw(INCOMPRESSIBLE,&law); problem_defn.SetFixedNodes(fixed_nodes, locations); c_vector<double,2> gravity = zero_vector<double>(2); gravity(1) = -0.5; problem_defn.SetBodyForce(gravity); IncompressibleNonlinearElasticitySolver<2> solver(mesh, problem_defn, "ElasticitySlidingBcsExample"); solver.Solve(); solver.CreateCmguiOutput(); /* Check the node at (1,0) has moved but has stayed on Y=0 */ TS_ASSERT_LESS_THAN(1.0, solver.rGetDeformedPosition()[10](0)); TS_ASSERT_DELTA(solver.rGetDeformedPosition()[10](1), 0.0, 1e-3); }
//More experiments with ksp_atol follow. void TestSpaceConvergencein2DWithAtol() { HeartConfig::Instance()->SetKSPSolver("symmlq"); HeartConfig::Instance()->SetKSPPreconditioner("bjacobi"); SpaceConvergenceTester<CellLuoRudy1991FromCellMLBackwardEuler, BidomainProblem<2>, 2, 2> tester; //tester.SetKspAbsoluteTolerance(1e-5); HeartConfig::Instance()->SetUseAbsoluteTolerance(1e-5); tester.Converge(__FUNCTION__); TS_ASSERT(tester.Converged); TS_ASSERT_EQUALS(tester.MeshNum, 5u); TS_ASSERT_LESS_THAN(tester.LastDifference, 0.0081583); //Comes in at 1.17118e-5 //Has to be at least as good as the 2D with Rtol=5e-8 HeartConfig::Instance()->Reset(); }
void TestCreatePointCloud() throw(Exception) { #if defined(CHASTE_VTK) && ( (VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION >= 6) || VTK_MAJOR_VERSION >= 6) EXIT_IF_PARALLEL; vtkSmartPointer<vtkPolyData> sphere = CreateSphere(50); AirwayGenerator generator(sphere); double test_point[3]; test_point[0] = 1.0; test_point[1] = 1.0; test_point[2] = 0.0; TS_ASSERT(!generator.IsInsideLobeSurface(test_point)); TS_ASSERT_DELTA(generator.DistanceFromLobeSurface(test_point), sqrt(2.0) - 1, 5e-3); vtkSmartPointer<vtkPolyData> point_data = generator.CreatePointCloud(std::pow(4*M_PI/3/50, 1.0/3.0)); //Gives spacing for ~50 points //Check that all points created are inside the sphere std::cout << point_data->GetNumberOfPoints() << std::endl; TS_ASSERT_EQUALS(point_data->GetNumberOfPoints(), 51); for (int i = 0; i < point_data->GetNumberOfPoints(); ++i) { double coords[3]; point_data->GetPoint(i, coords); TS_ASSERT_LESS_THAN(std::sqrt(coords[0]*coords[0] + coords[1]*coords[1] + coords[2]*coords[2]), 1.0); } //Check that the centre of mass is close to zero double centre[3]; generator.GetCentreOfMass(point_data, centre); TS_ASSERT_DELTA(centre[0], 0.0, 5e-2); TS_ASSERT_DELTA(centre[1], 0.0, 5e-2); TS_ASSERT_DELTA(centre[2], 0.0, 5e-2); std::set<unsigned>& invalid_ids = generator.GetInvalidIds(); TS_ASSERT_EQUALS(invalid_ids.size(), 0u); #endif }
/** * Check that the faces are read correctly. Checks that the output vector * for a given input file is the correct length and that if the input file * is corrupted (missing faces) then an exception is thrown. */ void TestFacesDataReadWithAttributes() throw(Exception) { TrianglesMeshReader<3,3> mesh_reader("heart/test/data/box_shaped_heart/box_heart_nonnegative_flags"); TS_ASSERT_EQUALS( mesh_reader.GetNumFaces(), 92u); // just boundary faces are read TS_ASSERT_EQUALS( mesh_reader.GetNumFaceAttributes(), 1u); bool read_zero_attribute = false; for (unsigned i=0; i<mesh_reader.GetNumFaces(); i++) { ElementData data = mesh_reader.GetNextFaceData(); // Attributes are 0, 1, 2, or 3. TS_ASSERT_LESS_THAN(data.AttributeValue, 4u); if (data.AttributeValue == 0u) { read_zero_attribute = true; } TS_ASSERT(read_zero_attribute); } }
// Test the functionality specific to SolidMechanicsProblemDefinition void TestSolidMechanicsProblemDefinition() throw(Exception) { TS_ASSERT_EQUALS(SolidMechanicsProblemDefinition<2>::FREE, DBL_MAX); TS_ASSERT_LESS_THAN(0, SolidMechanicsProblemDefinition<2>::FREE); QuadraticMesh<2> mesh(0.5, 1.0, 1.0); SolidMechanicsProblemDefinition<2> problem_defn(mesh); ////////////////////////////////// // Fixed nodes ////////////////////////////////// std::vector<unsigned> fixed_nodes; fixed_nodes.push_back(0); fixed_nodes.push_back(4); problem_defn.SetZeroDisplacementNodes(fixed_nodes); TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodes().size(), 2u); TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodes()[0], 0u); TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodes()[1], 4u); TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodeValues().size(), 2u); TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[0](0), 0.0, 1e-12); TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[0](1), 0.0, 1e-12); TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[1](0), 0.0, 1e-12); TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[1](1), 0.0, 1e-12); fixed_nodes.push_back(8); fixed_nodes.push_back(9); fixed_nodes.push_back(10); std::vector<c_vector<double,2> > locations; c_vector<double,2> location = zero_vector<double>(2); // Node 0 is to be placed at (0,0) locations.push_back(location); // Node 4 is to be placed at (0,0.1) location(1)=0.1; locations.push_back(location); // Node 8 is to be placed at (0.1,0.1) location(0)=0.1; locations.push_back(location); // Node 9 is to be placed at (0.5,FREE) location(0) = 0.5; location(1) = SolidMechanicsProblemDefinition<2>::FREE; locations.push_back(location); // Node 9 is to be placed at (FREE,1.5) location(0) = SolidMechanicsProblemDefinition<2>::FREE; location(1) = 1.5; locations.push_back(location); problem_defn.SetFixedNodes(fixed_nodes, locations); TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodes().size(), 5u); TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodeValues().size(), 5u); // the fully fixed nodes TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodes()[0], 0u); TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodes()[1], 4u); TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodes()[2], 8u); TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[0](0), 0.0 - mesh.GetNode(0)->rGetLocation()[0], 1e-12); TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[0](1), 0.0 - mesh.GetNode(0)->rGetLocation()[1], 1e-12); TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[1](0), 0.0 - mesh.GetNode(4)->rGetLocation()[0], 1e-12); TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[1](1), 0.1 - mesh.GetNode(4)->rGetLocation()[1], 1e-12); TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[2](0), 0.1 - mesh.GetNode(8)->rGetLocation()[0], 1e-12); TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[2](1), 0.1 - mesh.GetNode(8)->rGetLocation()[1], 1e-12); // the partial fixed nodes TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodes()[3], 9u); TS_ASSERT_EQUALS(problem_defn.rGetDirichletNodes()[4], 10u); TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[3](0), 0.5 - mesh.GetNode(9)->rGetLocation()[0], 1e-12); TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[3](1), SolidMechanicsProblemDefinition<2>::FREE, 1e-12); TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[4](0), SolidMechanicsProblemDefinition<2>::FREE, 1e-12); TS_ASSERT_DELTA(problem_defn.rGetDirichletNodeValues()[4](1), 1.5 - mesh.GetNode(10)->rGetLocation()[1], 1e-12); /////////////////////////////////////// // Set an incompressible material law /////////////////////////////////////// TS_ASSERT_THROWS_THIS(problem_defn.Validate(), "No material law has been set"); // set a homogeneous law MooneyRivlinMaterialLaw<2> incomp_mooney_rivlin_law(1.0); problem_defn.SetMaterialLaw(INCOMPRESSIBLE,&incomp_mooney_rivlin_law); TS_ASSERT_EQUALS(problem_defn.IsHomogeneousMaterial(), true); TS_ASSERT_EQUALS(problem_defn.GetCompressibilityType(), INCOMPRESSIBLE); TS_ASSERT_EQUALS(problem_defn.GetIncompressibleMaterialLaw(0), &incomp_mooney_rivlin_law); // set a heterogeneous law MooneyRivlinMaterialLaw<2> incomp_mooney_rivlin_law_2(2.0); std::vector<AbstractMaterialLaw<2>*> laws; for(unsigned i=0; i<mesh.GetNumElements()/2; i++) { laws.push_back(&incomp_mooney_rivlin_law); } for(unsigned i=mesh.GetNumElements()/2; i<mesh.GetNumElements(); i++) { laws.push_back(&incomp_mooney_rivlin_law_2); } problem_defn.SetMaterialLaw(INCOMPRESSIBLE,laws); TS_ASSERT_EQUALS(problem_defn.IsHomogeneousMaterial(), false); for(unsigned i=0; i<mesh.GetNumElements()/2; i++) { TS_ASSERT_EQUALS(problem_defn.GetIncompressibleMaterialLaw(i), &incomp_mooney_rivlin_law); } for(unsigned i=mesh.GetNumElements()/2; i<mesh.GetNumElements(); i++) { TS_ASSERT_EQUALS(problem_defn.GetIncompressibleMaterialLaw(i), &incomp_mooney_rivlin_law_2); } ///////////////////////////////////////////////////////////////////////// // Set a compressible material law (clears the incompressible laws) ///////////////////////////////////////////////////////////////////////// CompressibleMooneyRivlinMaterialLaw<2> comp_mooney_rivlin_law(2.0, 1.0); problem_defn.SetMaterialLaw(COMPRESSIBLE,&comp_mooney_rivlin_law); TS_ASSERT_EQUALS(problem_defn.IsHomogeneousMaterial(), true); TS_ASSERT_EQUALS(problem_defn.GetCompressibilityType(), COMPRESSIBLE); TS_ASSERT_EQUALS(problem_defn.GetCompressibleMaterialLaw(0), &comp_mooney_rivlin_law); // set a heterogeneous law CompressibleMooneyRivlinMaterialLaw<2> comp_mooney_rivlin_law_2(4.0, 1.0); std::vector<AbstractMaterialLaw<2>*> comp_laws; for(unsigned i=0; i<mesh.GetNumElements()/2; i++) { comp_laws.push_back(&comp_mooney_rivlin_law); } for(unsigned i=mesh.GetNumElements()/2; i<mesh.GetNumElements(); i++) { comp_laws.push_back(&comp_mooney_rivlin_law_2); } problem_defn.SetMaterialLaw(COMPRESSIBLE,comp_laws); TS_ASSERT_EQUALS(problem_defn.IsHomogeneousMaterial(), false); for(unsigned i=0; i<mesh.GetNumElements()/2; i++) { TS_ASSERT_EQUALS(problem_defn.GetCompressibleMaterialLaw(i), &comp_mooney_rivlin_law); } for(unsigned i=mesh.GetNumElements()/2; i<mesh.GetNumElements(); i++) { TS_ASSERT_EQUALS(problem_defn.GetCompressibleMaterialLaw(i), &comp_mooney_rivlin_law_2); } // should not throw anything problem_defn.Validate(); TS_ASSERT_THROWS_THIS(problem_defn.SetMaterialLaw(INCOMPRESSIBLE,&comp_mooney_rivlin_law),"Compressibility type was declared as INCOMPRESSIBLE but a compressible material law was given"); TS_ASSERT_THROWS_THIS(problem_defn.SetMaterialLaw(COMPRESSIBLE,&incomp_mooney_rivlin_law),"Incompressibility type was declared as COMPRESSIBLE but an incompressible material law was given"); /////////////////////////////// // solver stuff /////////////////////////////// TS_ASSERT_EQUALS(problem_defn.GetSolveUsingSnes(), false); TS_ASSERT_EQUALS(problem_defn.GetVerboseDuringSolve(), false); problem_defn.SetSolveUsingSnes(); problem_defn.SetVerboseDuringSolve(); TS_ASSERT_EQUALS(problem_defn.GetSolveUsingSnes(), true); TS_ASSERT_EQUALS(problem_defn.GetVerboseDuringSolve(), true); problem_defn.SetSolveUsingSnes(false); problem_defn.SetVerboseDuringSolve(false); TS_ASSERT_EQUALS(problem_defn.GetSolveUsingSnes(), false); TS_ASSERT_EQUALS(problem_defn.GetVerboseDuringSolve(), false); }
/* HOW_TO_TAG Cardiac/Electro-mechanics * Run electro-mechanical simulations using bidomain instead of monodomain * * This test is the same as above but with bidomain instead of monodomain. * Extracellular conductivities are set very high so the results should be the same. */ void TestWithHomogeneousEverythingCompressibleBidomain() throw(Exception) { EntirelyStimulatedTissueCellFactory cell_factory; TetrahedralMesh<2,2> electrics_mesh; electrics_mesh.ConstructRegularSlabMesh(0.01, 0.05, 0.05); QuadraticMesh<2> mechanics_mesh; mechanics_mesh.ConstructRegularSlabMesh(0.025, 0.05, 0.05); std::vector<unsigned> fixed_nodes; std::vector<c_vector<double,2> > fixed_node_locations; // fix the node at the origin so that the solution is well-defined (ie unique) fixed_nodes.push_back(0); fixed_node_locations.push_back(zero_vector<double>(2)); // for the rest of the nodes, if they lie on X=0, fix x=0 but leave y free. for(unsigned i=1 /*not 0*/; i<mechanics_mesh.GetNumNodes(); i++) { if(fabs(mechanics_mesh.GetNode(i)->rGetLocation()[0])<1e-6) { c_vector<double,2> new_position; new_position(0) = 0.0; new_position(1) = SolidMechanicsProblemDefinition<2>::FREE; fixed_nodes.push_back(i); fixed_node_locations.push_back(new_position); } } ElectroMechanicsProblemDefinition<2> problem_defn(mechanics_mesh); problem_defn.SetContractionModel(KERCHOFFS2003,1.0); problem_defn.SetUseDefaultCardiacMaterialLaw(COMPRESSIBLE); problem_defn.SetFixedNodes(fixed_nodes, fixed_node_locations); problem_defn.SetMechanicsSolveTimestep(1.0); // the following is just for coverage - applying a zero pressure so has no effect on deformation std::vector<BoundaryElement<1,2>*> boundary_elems; boundary_elems.push_back(* (mechanics_mesh.GetBoundaryElementIteratorBegin())); problem_defn.SetApplyNormalPressureOnDeformedSurface(boundary_elems, 0.0); HeartConfig::Instance()->SetSimulationDuration(10.0); HeartConfig::Instance()->SetExtracellularConductivities(Create_c_vector(1500,1500,1500)); //creates the EM problem with ELEC_PROB_DIM=2 CardiacElectroMechanicsProblem<2,2> problem(COMPRESSIBLE, BIDOMAIN, &electrics_mesh, &mechanics_mesh, &cell_factory, &problem_defn, "TestCardiacEmHomogeneousEverythingCompressibleBidomain"); problem.Solve(); std::vector<c_vector<double,2> >& r_deformed_position = problem.rGetDeformedPosition(); // not sure how easy is would be determine what the deformation should be // exactly, but it certainly should be constant squash in X direction, constant // stretch in Y. // first, check node 8 starts is the far corner assert(fabs(mechanics_mesh.GetNode(8)->rGetLocation()[0] - 0.05)<1e-8); assert(fabs(mechanics_mesh.GetNode(8)->rGetLocation()[1] - 0.05)<1e-8); double X_scale_factor = r_deformed_position[8](0)/0.05; double Y_scale_factor = r_deformed_position[8](1)/0.05; std::cout << "Scale_factors = " << X_scale_factor << " " << Y_scale_factor << ", product = " << X_scale_factor*Y_scale_factor<<"\n"; for(unsigned i=0; i<mechanics_mesh.GetNumNodes(); i++) { double X = mechanics_mesh.GetNode(i)->rGetLocation()[0]; double Y = mechanics_mesh.GetNode(i)->rGetLocation()[1]; TS_ASSERT_DELTA( r_deformed_position[i](0), X * X_scale_factor, 1e-6); TS_ASSERT_DELTA( r_deformed_position[i](1), Y * Y_scale_factor, 1e-6); } //check interpolated voltages and calcium unsigned quad_points = problem.mpCardiacMechSolver->GetTotalNumQuadPoints(); TS_ASSERT_EQUALS(problem.mInterpolatedVoltages.size(), quad_points); TS_ASSERT_EQUALS(problem.mInterpolatedCalciumConcs.size(), quad_points); //two hardcoded values TS_ASSERT_DELTA(problem.mInterpolatedVoltages[0],9.267,1e-3); TS_ASSERT_DELTA(problem.mInterpolatedCalciumConcs[0],0.001464,1e-6); //for the rest, we check that, at the end of this simulation, all quad nodes have V and Ca above a certain threshold for(unsigned i = 0; i < quad_points; i++) { TS_ASSERT_LESS_THAN(9.2,problem.mInterpolatedVoltages[i]); TS_ASSERT_LESS_THAN(0.0014,problem.mInterpolatedCalciumConcs[i]); } //check default value of whether there is a bath or not TS_ASSERT_EQUALS(problem.mpElectricsProblem->GetHasBath(), false); //test the functionality of having phi_e on the mechanics mesh (values are tested somewhere else) Hdf5DataReader data_reader("TestCardiacEmHomogeneousEverythingCompressibleBidomain/electrics","voltage_mechanics_mesh"); TS_ASSERT_THROWS_NOTHING(data_reader.GetVariableOverTime("Phi_e",0u)); }
void TestSteadyStateRunnerConverges(void) throw(Exception) { #ifdef CHASTE_CVODE //////////// DEFINE PARAMETERS /////////////// // Get the frequency double hertz = 1.0; ///////// END DEFINE PARAMETERS //////////////////////// // Setup a CVODE model that has empty solver and stimulus boost::shared_ptr<RegularStimulus> p_stimulus; boost::shared_ptr<AbstractIvpOdeSolver> p_solver; boost::shared_ptr<AbstractCvodeCell> p_model(new CellShannon2004FromCellMLCvode(p_solver, p_stimulus)); // Get it to use the default stimulus from CellML boost::shared_ptr<RegularStimulus> p_reg_stim = p_model->UseCellMLDefaultStimulus(); { // Test that the steady state analysis throws a nice error if we try to run it with a non-RegularStimulus boost::shared_ptr<ZeroStimulus> p_stim(new ZeroStimulus()); p_model->SetStimulusFunction(p_stim); SteadyStateRunner bad_steady_runner(p_model); TS_ASSERT_THROWS_THIS(bad_steady_runner.RunToSteadyState(), "Steady State approximations only work for models with RegularStimulus objects."); // Reset to a sensible stimulus function. p_model->SetStimulusFunction(p_reg_stim); } p_reg_stim->SetPeriod(1000.0/hertz); // Note that increasing the strictness of the tolerances here (default is 1e-5, 1e-7) // actually leads to a faster convergence to steady state, as a model solved in // a sloppy way might never actually get close to its true limit cycle! p_model->SetTolerances(1e-6,1e-8); /** * STEADY STATE PACING EXPERIMENT */ /* * HOW_TO_TAG Cardiac/Cell Models * Get a cardiac cell model to (roughly) a steady state, given a regular stimulus, using the `SteadyStateRunner` class. */ SteadyStateRunner steady_runner(p_model); bool result; // Here we don't reach steady state by max num paces steady_runner.SetMaxNumPaces(1u); result = steady_runner.RunToSteadyState(); TS_ASSERT_EQUALS(result,false); // Here we do reach the steady state OK. steady_runner.SetMaxNumPaces(10000u); result = steady_runner.RunToSteadyState(); TS_ASSERT_EQUALS(result,true); // Your mileage may vary. 32-bit machine, default build gives 520 evaluations, 484 on recent 64-bit CVODE. TS_ASSERT_LESS_THAN(steady_runner.GetNumEvaluations(),550u); // For coverage TS_ASSERT_THROWS_THIS(steady_runner.SetMaxNumPaces(0u), "Please set a maximum number of paces that is positive"); #else std::cout << "CVODE must be enabled for the steady state runner to work." << std::endl; #endif //_CHASTE_CVODE }
void TestPerformRosetteRankIncrease() throw (Exception) { // Create the standard five-cell rosette MutableVertexMesh<2,2>* p_mesh = ConstructFiveCellRosette(); /** * Modify the mesh to incorporate an additional element which will go on to increase the rosette rank */ // One new node will be needed unsigned new_node_idx = p_mesh->AddNode(new Node<2>(11, false, 0.5, 0.0)); // One new element will be needed, consisting of four nodes std::vector<Node<2>* > nodes_new_elem; nodes_new_elem.push_back(p_mesh->GetNode(new_node_idx)); nodes_new_elem.push_back(p_mesh->GetNode(10)); nodes_new_elem.push_back(p_mesh->GetNode(1)); nodes_new_elem.push_back(p_mesh->GetNode(2)); unsigned new_elem_idx = p_mesh->AddElement(new VertexElement<2,2>(5, nodes_new_elem)); p_mesh->GetElement(new_elem_idx)->RegisterWithNodes(); // Add new node in to elements 0 and 4, and remove node with global index 1 from elements 0 and 4 VertexElement<2,2>* p_elem_0 = p_mesh->GetElement(0); VertexElement<2,2>* p_elem_4 = p_mesh->GetElement(4); VertexElement<2,2>* p_elem_n = p_mesh->GetElement(new_elem_idx); p_elem_0->AddNode(p_mesh->GetNode(new_node_idx), p_elem_0->GetNodeLocalIndex(0)); p_elem_4->AddNode(p_mesh->GetNode(new_node_idx), p_elem_4->GetNodeLocalIndex(1)); p_elem_0->DeleteNode(p_elem_0->GetNodeLocalIndex(1)); p_elem_4->DeleteNode(p_elem_4->GetNodeLocalIndex(1)); /** * Now the mesh is as desired, we can get the necessary numbers, perform the rosette rank increase, and assert * that everything is as intended after the operation */ unsigned num_nodes_before = p_mesh->GetNumNodes(); assert(num_nodes_before == 12); unsigned num_nodes_elem_0_before = p_elem_0->GetNumNodes(); assert(num_nodes_elem_0_before == 4); unsigned num_nodes_elem_4_before = p_elem_4->GetNumNodes(); assert(num_nodes_elem_4_before == 4); unsigned num_nodes_new_elem_before = p_elem_n->GetNumNodes(); assert(num_nodes_new_elem_before == 4); c_vector<double, 2> node_0_location_before = p_mesh->GetNode(0)->rGetLocation(); // Perform the rosette rank increase p_mesh->PerformRosetteRankIncrease(p_mesh->GetNode(0), p_mesh->GetNode(new_node_idx)); // The mesh should have lost one node TS_ASSERT_EQUALS(num_nodes_before - 1, p_mesh->GetNumNodes()); // Elements 0 and 4 should have lost a node, but the new element should not have lost any TS_ASSERT_EQUALS(num_nodes_elem_0_before - 1, p_elem_0->GetNumNodes()); TS_ASSERT_EQUALS(num_nodes_elem_4_before - 1, p_elem_4->GetNumNodes()); TS_ASSERT_EQUALS(num_nodes_new_elem_before, p_elem_n->GetNumNodes()); // The node with global index 0 should remain in the same location TS_ASSERT_DELTA(node_0_location_before[0], p_mesh->GetNode(0)->rGetLocation()[0], 1e-10); TS_ASSERT_DELTA(node_0_location_before[1], p_mesh->GetNode(0)->rGetLocation()[1], 1e-10); // The node with global index 0 should now be included in the new element TS_ASSERT_LESS_THAN(p_elem_n->GetNodeLocalIndex(0), UINT_MAX); delete p_mesh; }
void TestChebyshevAdaptiveVsNoAdaptive() throw (Exception) { unsigned num_nodes = 1331; DistributedVectorFactory factory(num_nodes); Vec parallel_layout = factory.CreateVec(2); // Solving with zero guess for coverage Vec zero_guess = factory.CreateVec(2); double zero = 0.0; #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) VecSet(&zero, zero_guess); #else VecSet(zero_guess, zero); #endif Mat system_matrix; // Note that this test deadlocks if the file's not on the disk PetscTools::ReadPetscObject(system_matrix, "linalg/test/data/matrices/cube_6000elems_half_activated.mat", parallel_layout); Vec system_rhs; // Note that this test deadlocks if the file's not on the disk PetscTools::ReadPetscObject(system_rhs, "linalg/test/data/matrices/cube_6000elems_half_activated.vec", parallel_layout); // Make sure we are not inheriting a non-default number of iterations from previous test std::stringstream num_it_str; num_it_str << 1000; PetscOptionsSetValue("-ksp_max_it", num_it_str.str().c_str()); try { LinearSystem ls = LinearSystem(system_rhs, system_matrix); ls.SetMatrixIsSymmetric(); // Solve to relative convergence for coverage ls.SetRelativeTolerance(1e-6); ls.SetPcType("jacobi"); ls.SetKspType("chebychev"); ls.SetUseFixedNumberIterations(true, 64); // Solving with zero guess for coverage. Vec solution = ls.Solve(zero_guess); unsigned chebyshev_adaptive_its = ls.GetNumIterations(); TS_ASSERT_EQUALS(chebyshev_adaptive_its, 40u); TS_ASSERT_DELTA(ls.mEigMin, 0.0124, 1e-4); TS_ASSERT_DELTA(ls.mEigMax, 1.8810, 1e-4); PetscTools::Destroy(solution); } catch (Exception& e) { if (e.GetShortMessage() == "Chebyshev with fixed number of iterations is known to be broken in PETSc <= 2.3.2") { WARNING(e.GetShortMessage()); } else { TS_FAIL(e.GetShortMessage()); } } // Make sure we are not inheriting a non-default number of iterations from previous test PetscOptionsSetValue("-ksp_max_it", num_it_str.str().c_str()); { LinearSystem ls = LinearSystem(system_rhs, system_matrix); ls.SetMatrixIsSymmetric(); ls.SetRelativeTolerance(1e-6); ls.SetPcType("jacobi"); ls.SetKspType("chebychev"); Vec solution = ls.Solve(zero_guess); unsigned chebyshev_no_adaptive_its = ls.GetNumIterations(); TS_ASSERT_LESS_THAN(chebyshev_no_adaptive_its, 100u); // Normally 88, but 99 on maverick & natty TS_ASSERT_DELTA(ls.mEigMin, 0.0124, 1e-4); TS_ASSERT_DELTA(ls.mEigMax, 1.8841, 1e-4); PetscTools::Destroy(solution); } // Make sure we are not inheriting a non-default number of iterations from previous test PetscOptionsSetValue("-ksp_max_it", num_it_str.str().c_str()); { LinearSystem ls = LinearSystem(system_rhs, system_matrix); ls.SetMatrixIsSymmetric(); ls.SetRelativeTolerance(1e-6); ls.SetPcType("jacobi"); ls.SetKspType("cg"); Vec solution = ls.Solve(zero_guess); unsigned cg_its = ls.GetNumIterations(); TS_ASSERT_EQUALS(cg_its, 40u); TS_ASSERT_EQUALS(ls.mEigMin, DBL_MAX); TS_ASSERT_EQUALS(ls.mEigMax, DBL_MIN); PetscTools::Destroy(solution); } PetscTools::Destroy(system_matrix); PetscTools::Destroy(system_rhs); PetscTools::Destroy(parallel_layout); PetscTools::Destroy(zero_guess); }
void TestChebyshevVsCG() throw (Exception) { unsigned num_nodes = 1331; DistributedVectorFactory factory(num_nodes); Vec parallel_layout = factory.CreateVec(2); unsigned cg_its; unsigned chebyshev_its; Timer::Reset(); { Mat system_matrix; // Note that this test deadlocks if the file's not on the disk PetscTools::ReadPetscObject(system_matrix, "linalg/test/data/matrices/cube_6000elems_half_activated.mat", parallel_layout); Vec system_rhs; // Note that this test deadlocks if the file's not on the disk PetscTools::ReadPetscObject(system_rhs, "linalg/test/data/matrices/cube_6000elems_half_activated.vec", parallel_layout); LinearSystem ls = LinearSystem(system_rhs, system_matrix); ls.SetMatrixIsSymmetric(); ls.SetAbsoluteTolerance(1e-9); ls.SetKspType("cg"); ls.SetPcType("bjacobi"); Vec solution = ls.Solve(); cg_its = ls.GetNumIterations(); PetscTools::Destroy(system_matrix); PetscTools::Destroy(system_rhs); PetscTools::Destroy(solution); } Timer::PrintAndReset("CG"); { Mat system_matrix; // Note that this test deadlocks if the file's not on the disk PetscTools::ReadPetscObject(system_matrix, "linalg/test/data/matrices/cube_6000elems_half_activated.mat", parallel_layout); Vec system_rhs; // Note that this test deadlocks if the file's not on the disk PetscTools::ReadPetscObject(system_rhs, "linalg/test/data/matrices/cube_6000elems_half_activated.vec", parallel_layout); LinearSystem ls = LinearSystem(system_rhs, system_matrix); ls.SetMatrixIsSymmetric(); ls.SetAbsoluteTolerance(1e-9); ls.SetKspType("chebychev"); ls.SetPcType("bjacobi"); Vec solution = ls.Solve(); chebyshev_its = ls.GetNumIterations(); PetscTools::Destroy(system_matrix); PetscTools::Destroy(system_rhs); PetscTools::Destroy(solution); } Timer::Print("Chebyshev"); TS_ASSERT_LESS_THAN(cg_its, 15u); // Takes 14 iterations with 16 cores TS_ASSERT_LESS_THAN(chebyshev_its, 17u); // Takes 16 iterations with 16 cores PetscTools::Destroy(parallel_layout); }