36 #include "LinearSystem.hpp" 37 #include "ReplicatableVector.hpp" 38 #include "VesselSegment.hpp" 39 #include "FiniteDifferenceSolver.hpp" 40 #include "LinearSteadyStateDiffusionReactionPde.hpp" 41 #include "SimplePetscNonlinearSolver.hpp" 42 #include "BaseUnits.hpp" 45 template<
unsigned DIM>
46 PetscErrorCode HyrbidFiniteDifference_ComputeResidual(SNES snes, Vec solution_guess, Vec residual,
void* pContext);
47 #if ( PETSC_VERSION_MAJOR==3 && PETSC_VERSION_MINOR>=5 ) 48 template<
unsigned DIM>
49 PetscErrorCode HyrbidFiniteDifference_ComputeJacobian(SNES snes, Vec input, Mat jacobian, Mat preconditioner,
void* pContext);
51 template<
unsigned DIM>
52 PetscErrorCode HyrbidFiniteDifference_ComputeJacobian(SNES snes,Vec input,Mat* pJacobian ,Mat* pPreconditioner,MatStructure* pMatStructure ,
void* pContext);
55 template<
unsigned DIM>
58 mpBoundaryConditions(),
59 mUpdateBoundaryConditionsEachSolve(true),
60 mBoundaryConditionsSet(false)
65 template<
unsigned DIM>
72 template<
unsigned DIM>
78 template<
unsigned DIM>
84 template<
unsigned DIM>
90 template<
unsigned DIM>
96 EXCEPTION(
"This solver needs a regular grid to be set before calling Setup.");
101 EXCEPTION(
"This solver needs a PDE to be set before calling Setup.");
124 mpBoundaryConditions = boost::shared_ptr<std::vector<std::pair<bool, units::quantity<unit::concentration> > > > (
new std::vector<std::pair<bool, units::quantity<unit::concentration> > >(this->
mpRegularGrid->GetNumberOfPoints()));
125 for(
unsigned idx=0; idx<this->
mpRegularGrid->GetNumberOfPoints(); idx++)
127 (*mpBoundaryConditions)[idx] = std::pair<bool, units::quantity<unit::concentration> >(
false, 0.0*this->
mReferenceConcentration);
143 template<
unsigned DIM>
149 this->
mpPde->UpdateDiscreteSourceStrengths();
167 template<
unsigned DIM>
171 unsigned number_of_points = this->
mpRegularGrid->GetNumberOfPoints();
177 units::quantity<unit::length> spacing = this->
mpRegularGrid->GetSpacing();
179 double diffusion_term = 0.0;
182 diffusion_term = (this->
mpPde->ComputeIsotropicDiffusionTerm() / (spacing * spacing))*reference_time;
186 diffusion_term = (this->
mpNonLinearPde->ComputeIsotropicDiffusionTerm() / (spacing * spacing))*reference_time;
189 LinearSystem linear_system(number_of_points, 7);
190 for (
unsigned i = 0; i < extents_z; i++)
192 for (
unsigned j = 0; j < extents_y; j++)
194 for (
unsigned k = 0; k < extents_x; k++)
196 unsigned grid_index = this->
mpRegularGrid->Get1dGridIndex(k, j, i);
198 linear_system.AddToMatrixElement(grid_index, grid_index, this->
mpPde->ComputeLinearInUCoeffInSourceTerm(grid_index)*reference_time - 6.0 * diffusion_term);
204 linear_system.AddToMatrixElement(grid_index, grid_index - 1, diffusion_term);
208 linear_system.AddToMatrixElement(grid_index, grid_index, diffusion_term);
212 if (k < extents_x - 1)
214 linear_system.AddToMatrixElement(grid_index, grid_index + 1, diffusion_term);
218 linear_system.AddToMatrixElement(grid_index, grid_index, diffusion_term);
224 linear_system.AddToMatrixElement(grid_index, grid_index - extents_x, diffusion_term);
228 linear_system.AddToMatrixElement(grid_index, grid_index, diffusion_term);
232 if (j < extents_y - 1)
234 linear_system.AddToMatrixElement(grid_index, grid_index + extents_x, diffusion_term);
238 linear_system.AddToMatrixElement(grid_index, grid_index, diffusion_term);
244 linear_system.AddToMatrixElement(grid_index, grid_index - extents_x * extents_y, diffusion_term);
248 linear_system.AddToMatrixElement(grid_index, grid_index, diffusion_term);
252 if (i < extents_z - 1)
254 linear_system.AddToMatrixElement(grid_index, grid_index + extents_x * extents_y, diffusion_term);
258 linear_system.AddToMatrixElement(grid_index, grid_index, diffusion_term);
260 linear_system.SetRhsVectorElement(grid_index, -this->
mpPde->ComputeConstantInUSourceTerm(grid_index)*(reference_time/this->
mReferenceConcentration));
266 std::vector<unsigned> bc_indices;
267 for(
unsigned idx=0; idx<this->
mpRegularGrid->GetNumberOfPoints(); idx++)
271 bc_indices.push_back(idx);
275 linear_system.ZeroMatrixRowsWithValueOnDiagonal(bc_indices, 1.0);
278 linear_system.AssembleFinalLinearSystem();
279 ReplicatableVector soln_repl(linear_system.Solve());
282 std::vector<units::quantity<unit::concentration> > concs = std::vector<units::quantity<unit::concentration> >(number_of_points,
284 for (
unsigned row = 0; row < number_of_points; row++)
297 template<
unsigned DIM>
312 unsigned number_of_points = this->
mpRegularGrid->GetNumberOfPoints();
313 Vec initial_guess=PetscTools::CreateAndSetVec(number_of_points, 1.0);
315 SimplePetscNonlinearSolver solver_petsc;
317 Vec answer_petsc = solver_petsc.Solve(&HyrbidFiniteDifference_ComputeResidual<DIM>,
318 &HyrbidFiniteDifference_ComputeJacobian<DIM>, initial_guess, length,
this);
320 ReplicatableVector soln_repl(answer_petsc);
323 this->
mConcentrations = std::vector<units::quantity<unit::concentration> >(number_of_points,
325 for (
unsigned row = 0; row < number_of_points; row++)
339 template<
unsigned DIM>
340 PetscErrorCode HyrbidFiniteDifference_ComputeResidual(SNES snes, Vec solution_guess, Vec residual,
void* pContext)
344 unsigned extents_x = solver->
GetGrid()->GetExtents()[0];
345 unsigned extents_y = solver->
GetGrid()->GetExtents()[1];
346 unsigned extents_z = solver->
GetGrid()->GetExtents()[2];
349 units::quantity<unit::length> spacing = solver->
GetGrid()->GetSpacing();
350 double diffusion_term = (solver->
GetNonLinearPde()->ComputeIsotropicDiffusionTerm() / (spacing * spacing))*reference_time;
354 ReplicatableVector soln_guess_repl(solution_guess);
357 PetscVecTools::Zero(residual);
358 for (
unsigned i = 0; i < extents_z; i++)
360 for (
unsigned j = 0; j < extents_y; j++)
362 for (
unsigned k = 0; k < extents_x; k++)
364 unsigned grid_index = solver->
GetGrid()->Get1dGridIndex(k, j, i);
365 double grid_guess = soln_guess_repl[grid_index];
368 PetscVecTools::AddToElement(residual, grid_index, grid_guess * (- 6.0 * diffusion_term) +
375 double neighbour_guess = soln_guess_repl[grid_index-1];
376 PetscVecTools::AddToElement(residual, grid_index, neighbour_guess * diffusion_term);
380 PetscVecTools::AddToElement(residual, grid_index, diffusion_term * grid_guess);
384 if (k < extents_x - 1)
386 double neighbour_guess = soln_guess_repl[grid_index+1];
387 PetscVecTools::AddToElement(residual, grid_index, diffusion_term * neighbour_guess);
391 PetscVecTools::AddToElement(residual, grid_index, diffusion_term * grid_guess);
397 double neighbour_guess = soln_guess_repl[grid_index-extents_x];
398 PetscVecTools::AddToElement(residual, grid_index, diffusion_term* neighbour_guess);
402 PetscVecTools::AddToElement(residual, grid_index, diffusion_term * grid_guess);
406 if (j < extents_y - 1)
408 double neighbour_guess = soln_guess_repl[grid_index+extents_x];
409 PetscVecTools::AddToElement(residual, grid_index, diffusion_term* neighbour_guess);
413 PetscVecTools::AddToElement(residual, grid_index, diffusion_term * grid_guess);
419 double neighbour_guess = soln_guess_repl[grid_index - extents_x * extents_y];
420 PetscVecTools::AddToElement(residual, grid_index, diffusion_term*neighbour_guess);
424 PetscVecTools::AddToElement(residual, grid_index, diffusion_term * grid_guess);
428 if (i < extents_z - 1)
430 double neighbour_guess = soln_guess_repl[grid_index + extents_x * extents_y];
431 PetscVecTools::AddToElement(residual, grid_index, diffusion_term * neighbour_guess);
435 PetscVecTools::AddToElement(residual, grid_index, diffusion_term * grid_guess);
441 PetscVecTools::Finalise(residual);
444 std::vector<unsigned> bc_indices;
445 for(
unsigned idx=0; idx<solver->
GetGrid()->GetNumberOfPoints(); idx++)
449 PetscVecTools::SetElement(residual, idx, 0.0);
452 PetscVecTools::Finalise(residual);
457 #if ( PETSC_VERSION_MAJOR==3 && PETSC_VERSION_MINOR>=5 ) 458 template<
unsigned DIM>
459 PetscErrorCode HyrbidFiniteDifference_ComputeJacobian(SNES snes, Vec input, Mat jacobian, Mat preconditioner,
void* pContext)
462 template<
unsigned DIM>
463 PetscErrorCode HyrbidFiniteDifference_ComputeJacobian(SNES snes, Vec input, Mat* pJacobian, Mat* pPreconditioner, MatStructure* pMatStructure,
void* pContext)
465 Mat jacobian = *pJacobian;
468 PetscMatTools::Zero(jacobian);
469 PetscMatTools::SwitchWriteMode(jacobian);
471 ReplicatableVector input_repl(input);
473 unsigned extents_x = solver->
GetGrid()->GetExtents()[0];
474 unsigned extents_y = solver->
GetGrid()->GetExtents()[1];
475 unsigned extents_z = solver->
GetGrid()->GetExtents()[2];
478 units::quantity<unit::length> spacing = solver->
GetGrid()->GetSpacing();
480 double diffusion_term = (solver->
GetNonLinearPde()->ComputeIsotropicDiffusionTerm() / (spacing * spacing))*reference_time;
483 for (
unsigned i = 0; i < extents_z; i++)
485 for (
unsigned j = 0; j < extents_y; j++)
487 for (
unsigned k = 0; k < extents_x; k++)
489 unsigned grid_index = solver->
GetGrid()->Get1dGridIndex(k, j, i);
490 double grid_guess = input_repl[grid_index];
493 PetscMatTools::AddToElement(jacobian, grid_index, grid_index, - 6.0 * diffusion_term +
494 solver->
GetNonLinearPde()->ComputeNonlinearSourceTermPrime(grid_index, scale_grid_guess)*reference_time);
500 PetscMatTools::AddToElement(jacobian, grid_index, grid_index - 1, diffusion_term);
504 PetscMatTools::AddToElement(jacobian, grid_index, grid_index, diffusion_term);
508 if (k < extents_x - 1)
510 PetscMatTools::AddToElement(jacobian, grid_index, grid_index + 1, diffusion_term);
514 PetscMatTools::AddToElement(jacobian, grid_index, grid_index, diffusion_term);
520 PetscMatTools::AddToElement(jacobian, grid_index, grid_index - extents_x, diffusion_term);
524 PetscMatTools::AddToElement(jacobian, grid_index, grid_index, diffusion_term);
528 if (j < extents_y - 1)
530 PetscMatTools::AddToElement(jacobian, grid_index, grid_index + extents_x, diffusion_term);
534 PetscMatTools::AddToElement(jacobian, grid_index, grid_index, diffusion_term);
540 PetscMatTools::AddToElement(jacobian, grid_index, grid_index - extents_x * extents_y, diffusion_term);
544 PetscMatTools::AddToElement(jacobian, grid_index,grid_index, diffusion_term);
548 if (i < extents_z - 1)
550 PetscMatTools::AddToElement(jacobian, grid_index, grid_index + extents_x * extents_y, diffusion_term);
554 PetscMatTools::AddToElement(jacobian, grid_index, grid_index, diffusion_term);
561 std::vector<unsigned> bc_indices;
562 for(
unsigned idx=0; idx<solver->
GetGrid()->GetNumberOfPoints(); idx++)
566 bc_indices.push_back(idx);
570 PetscMatTools::ZeroRowsWithValueOnDiagonal(jacobian, bc_indices, 1.0);
572 PetscMatTools::Finalise(jacobian);
boost::shared_ptr< std::vector< std::pair< bool, units::quantity< unit::concentration > > > > GetRGBoundaryConditions()
boost::shared_ptr< std::vector< std::pair< bool, units::quantity< unit::concentration > > > > mpBoundaryConditions
boost::shared_ptr< AbstractDiscreteContinuumLinearEllipticPde< DIM, DIM > > mpPde
boost::shared_ptr< RegularGrid< DIM > > mpRegularGrid
units::quantity< unit::time > GetReferenceTimeScale()
bool mBoundaryConditionsSet
void UpdateBoundaryConditionsEachSolve(bool doUpdate)
bool mUpdateBoundaryConditionsEachSolve
static boost::shared_ptr< FiniteDifferenceSolver< DIM > > Create()
AbstractCellPopulation< DIM > * mpCellPopulation
boost::shared_ptr< RegularGrid< DIM > > GetGrid()
std::vector< units::quantity< unit::concentration > > mConcentrations
std::vector< boost::shared_ptr< DiscreteContinuumBoundaryCondition< DIM > > > mBoundaryConditions
virtual void UpdateSolution(std::vector< double > &rData)
boost::shared_ptr< AbstractDiscreteContinuumNonLinearEllipticPde< DIM, DIM > > GetNonLinearPde()
boost::shared_ptr< AbstractDiscreteContinuumNonLinearEllipticPde< DIM, DIM > > mpNonLinearPde
static BaseUnits * Instance()
boost::shared_ptr< VesselNetwork< DIM > > mpNetwork
bool CellPopulationIsSet()
units::quantity< unit::concentration > mReferenceConcentration
units::quantity< unit::concentration > GetReferenceConcentration()
virtual ~FiniteDifferenceSolver()
units::quantity< unit::length > mCellPopulationReferenceLength