Chaste  Build::
FiniteElementSolver.cpp
1 /*
2 
3 Copyright (c) 2005-2016, University of Oxford.
4  All rights reserved.
5 
6  University of Oxford means the Chancellor, Masters and Scholars of the
7  University of Oxford, having an administrative office at Wellington
8  Square, Oxford OX1 2JD, UK.
9 
10  This file is part of Chaste.
11 
12  Redistribution and use in source and binary forms, with or without
13  modification, are permitted provided that the following conditions are met:
14  * Redistributions of source code must retain the above copyright notice,
15  this list of conditions and the following disclaimer.
16  * Redistributions in binary form must reproduce the above copyright notice,
17  this list of conditions and the following disclaimer in the documentation
18  and/or other materials provided with the distribution.
19  * Neither the name of the University of Oxford nor the names of its
20  contributors may be used to endorse or promote products derived from this
21  software without specific prior written permission.
22 
23  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34  */
35 
36 #include <math.h>
37 #include "SimpleLinearEllipticSolver.hpp"
38 #include "SimpleNonlinearEllipticSolver.hpp"
39 #include "SimpleNewtonNonlinearSolver.hpp"
40 #include "FiniteElementSolver.hpp"
41 
42 template<unsigned DIM>
45  mUseNewton(false),
46  mUseLinearSolveForGuess(false),
47  mGuess()
48 {
49 
50 }
51 
52 template<unsigned DIM>
54 {
55 
56 }
57 
58 template <unsigned DIM>
59 boost::shared_ptr<FiniteElementSolver<DIM> > FiniteElementSolver<DIM>::Create()
60 {
61  MAKE_PTR(FiniteElementSolver<DIM>, pSelf);
62  return pSelf;
63 }
64 
65 template<unsigned DIM>
67 {
68  if(this->mpPde)
69  {
70  this->mpPde->UpdateDiscreteSourceStrengths();
71  }
72  else
73  {
74  this->mpNonLinearPde->UpdateDiscreteSourceStrengths();
75  }
76 }
77 
78 template<unsigned DIM>
79 void FiniteElementSolver<DIM>::SetGuess(const std::vector<double>& guess)
80 {
81  mGuess = guess;
82 }
83 
84 template<unsigned DIM>
86 {
87  mUseNewton = useNewton;
88 }
89 
90 template<unsigned DIM>
92 {
93  mUseLinearSolveForGuess = useLinearSolve;
94 }
95 
96 template<unsigned DIM>
98 {
99  if(!this->IsSetupForSolve)
100  {
101  this->Setup();
102  }
103 
104  // Set up the boundary conditions in the Chaste format
105  boost::shared_ptr<BoundaryConditionsContainer<DIM, DIM, 1> > p_bcc =
106  boost::shared_ptr<BoundaryConditionsContainer<DIM, DIM, 1> >(new BoundaryConditionsContainer<DIM, DIM, 1> );
107 
108  for(unsigned idx=0; idx<this->mBoundaryConditions.size(); idx++)
109  {
110  this->mBoundaryConditions[idx]->SetMesh(this->mpMesh);
111  this->mBoundaryConditions[idx]->UpdateBoundaryConditionContainer(p_bcc);
112  }
113 
114  // Do the solve
115  // Check the type of pde
116  if(this->mpPde and !this->mpNonLinearPde)
117  {
118  this->mpPde->SetUseRegularGrid(false);
119  this->mpPde->SetMesh(this->mpMesh);
120  this->mpPde->UpdateDiscreteSourceStrengths();
121 
122  SimpleLinearEllipticSolver<DIM, DIM> static_solver(this->mpMesh.get(), this->mpPde.get(), p_bcc.get());
123  ReplicatableVector solution_repl(static_solver.Solve());
124 
125  this->mSolution = std::vector<double>(solution_repl.GetSize());
126  this->mConcentrations = std::vector<units::quantity<unit::concentration> >(solution_repl.GetSize());
127  for(unsigned idx = 0; idx < solution_repl.GetSize(); idx++)
128  {
129  this->mSolution[idx] = solution_repl[idx];
130  this->mConcentrations[idx] = solution_repl[idx]*this->mReferenceConcentration;
131  }
132  this->UpdateSolution(this->mSolution);
133  }
134  else if(this->mpNonLinearPde)
135  {
136  this->mpNonLinearPde->SetUseRegularGrid(false);
137  this->mpNonLinearPde->SetMesh(this->mpMesh);
138  this->mpNonLinearPde->UpdateDiscreteSourceStrengths();
139 
140  if (this->mpPde)
141  {
142  this->mpPde->SetUseRegularGrid(false);
143  this->mpPde->SetMesh(this->mpMesh);
144  this->mpPde->UpdateDiscreteSourceStrengths();
145 
146  SimpleLinearEllipticSolver<DIM, DIM> static_solver(this->mpMesh.get(), this->mpPde.get(), p_bcc.get());
147  ReplicatableVector static_solution_repl(static_solver.Solve());
148 
149  std::vector<double> solution = std::vector<double>(static_solution_repl.GetSize());
150  for(unsigned idx = 0; idx < static_solution_repl.GetSize(); idx++)
151  {
152  solution[idx]= static_solution_repl[idx];
153  // Dont want negative solutions going into the initial guess
154  if(solution[idx]<0.0)
155  {
156  solution[idx] = 0.0;
157  }
158  }
159 
160  Vec initial_guess = PetscTools::CreateVec(this->mpMesh->GetNumNodes());
161  for(unsigned idx=0; idx<solution.size();idx++)
162  {
163  PetscVecTools::SetElement(initial_guess, idx, solution[idx]);
164  }
165  PetscVecTools::Finalise(initial_guess);
166 
167  SimpleNonlinearEllipticSolver<DIM, DIM> solver(this->mpMesh.get(), this->mpNonLinearPde.get(), p_bcc.get());
168  SimpleNewtonNonlinearSolver newton_solver;
169  if(mUseNewton)
170  {
171  solver.SetNonlinearSolver(&newton_solver);
172  newton_solver.SetTolerance(1e-5);
173  newton_solver.SetWriteStats();
174  }
175 
176  ReplicatableVector solution_repl(solver.Solve(initial_guess));
177  this->mSolution = std::vector<double>(solution_repl.GetSize());
178  this->mConcentrations = std::vector<units::quantity<unit::concentration> >(solution_repl.GetSize());
179  for(unsigned idx = 0; idx < solution_repl.GetSize(); idx++)
180  {
181  this->mSolution[idx] = solution_repl[idx];
182  this->mConcentrations[idx] = solution_repl[idx]*this->mReferenceConcentration;
183  }
184  this->UpdateSolution(this->mSolution);
185  PetscTools::Destroy(initial_guess);
186  }
187  else
188  {
189  Vec initial_guess = PetscTools::CreateAndSetVec(this->mpMesh->GetNumNodes(), this->mBoundaryConditions[0]->GetValue()/this->mReferenceConcentration);
190  SimpleNonlinearEllipticSolver<DIM, DIM> solver(this->mpMesh.get(), this->mpNonLinearPde.get(), p_bcc.get());
191  SimpleNewtonNonlinearSolver newton_solver;
192  if(mUseNewton)
193  {
194  solver.SetNonlinearSolver(&newton_solver);
195  newton_solver.SetTolerance(1e-5);
196  newton_solver.SetWriteStats();
197  }
198 
199  ReplicatableVector solution_repl(solver.Solve(initial_guess));
200  this->mSolution = std::vector<double>(solution_repl.GetSize());
201  this->mConcentrations = std::vector<units::quantity<unit::concentration> >(solution_repl.GetSize());
202  for(unsigned idx = 0; idx < solution_repl.GetSize(); idx++)
203  {
204  this->mSolution[idx] = solution_repl[idx];
205  this->mConcentrations[idx] = solution_repl[idx]*this->mReferenceConcentration;
206  }
207  this->UpdateSolution(this->mSolution);
208  PetscTools::Destroy(initial_guess);
209  }
210  }
211  else
212  {
213  EXCEPTION("PDE Type could not be identified, did you set a PDE?");
214  }
215 
216  if(this->mWriteSolution)
217  {
218  this->Write();
219  }
220 }
221 
222 // Explicit instantiation
223 template class FiniteElementSolver<2> ;
224 template class FiniteElementSolver<3> ;
boost::shared_ptr< AbstractDiscreteContinuumLinearEllipticPde< DIM, DIM > > mpPde
void SetUseSimpleNetonSolver(bool useNewton)
std::vector< units::quantity< unit::concentration > > mConcentrations
void SetUseLinearSolveForGuess(bool useLinearSolve)
static boost::shared_ptr< FiniteElementSolver< DIM > > Create()
std::vector< boost::shared_ptr< DiscreteContinuumBoundaryCondition< DIM > > > mBoundaryConditions
boost::shared_ptr< AbstractDiscreteContinuumNonLinearEllipticPde< DIM, DIM > > mpNonLinearPde
void SetGuess(const std::vector< double > &guess)
units::quantity< unit::concentration > mReferenceConcentration
boost::shared_ptr< DiscreteContinuumMesh< DIM, DIM > > mpMesh
std::vector< double > mGuess