Nektar++
PulseWavePropagation.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File PulseWavePropagation.cpp
4 //
5 // For more information, please see: http://www.nektar.info
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: Pulse Wave Propagation solve routines based on the weak
32 // formulation (1):
33 //
34 ///////////////////////////////////////////////////////////////////////////////
35 
36 #include <iostream>
37 
39 
40 using namespace std;
41 
42 namespace Nektar
43 {
44 string PulseWavePropagation::className =
46  "PulseWavePropagation", PulseWavePropagation::create,
47  "Pulse Wave Propagation equation.");
48 /**
49  * @class PulseWavePropagation
50  *
51  * Set up the routines based on the weak formulation from
52  * "Computational Modelling of 1D blood flow with variable
53  * mechanical properties" by S. J. Sherwin et al. The weak
54  * formulation (1) reads:
55  * \f$ \sum_{e=1}^{N_{el}} \left[ \left( \frac{\partial \mathbf{U}^{\delta}
56  * }{\partial t} , \mathbf{\psi}^{\delta} \right)_{\Omega_e} - \left(
57  * \frac{\partial \mathbf{F(\mathbf{U})}^{\delta} }
58  * {\partial x}, \mathbf{\psi}^{\delta} \right)_{\Omega_e} + \left[
59  * \mathbf{\psi}^{\delta} \cdot \{ \mathbf{F}^u -
60  * \mathbf{F}(\mathbf{U}^{\delta}) \} \right]_{x_e^l}^{x_eû} \right] = 0 \f$
61  */
62 PulseWavePropagation::PulseWavePropagation(
65  : PulseWaveSystem(pSession, pGraph)
66 {
67 }
68 
70 {
72 
74  "Lymphatic", m_vessels, m_session);
75  m_pressureArea->DoPressure();
76 
78  {
81  }
82  else
83  {
84  ASSERTL0(false, "Implicit Pulse Wave Propagation not set up.");
85  }
86 
87  // Create advection object
88  string advName;
89  string riemName;
90  switch (m_upwindTypePulse)
91  {
92  case eUpwindPulse:
93  {
94  advName = "WeakDG";
95  riemName = "UpwindPulse";
96  }
97  break;
98  default:
99  {
100  ASSERTL0(false, "populate switch statement for upwind flux");
101  }
102  break;
103  }
104  m_advObject =
106  m_advObject->SetFluxVector(&PulseWavePropagation::GetFluxVector, this);
108  riemName, m_session);
109  m_riemannSolver->SetScalar("A0", &PulseWavePropagation::GetA0, this);
110  m_riemannSolver->SetScalar("beta", &PulseWavePropagation::GetBeta, this);
111  m_riemannSolver->SetScalar("N", &PulseWavePropagation::GetN, this);
112  m_riemannSolver->SetParam("rho", &PulseWavePropagation::GetRho, this);
113  m_riemannSolver->SetParam("pext", &PulseWavePropagation::GetPext, this);
114 
115  m_advObject->SetRiemannSolver(m_riemannSolver);
116  m_advObject->InitObject(m_session, m_fields);
117 }
118 
120 {
121 }
122 
123 /**
124  * Computes the right hand side of (1). The RHS is everything
125  * except the term that contains the time derivative
126  * \f$\frac{\partial \mathbf{U}}{\partial t}\f$. In case of a
127  * Discontinuous Galerkin projection, m_advObject->Advect
128  * will be called
129  *
130  */
132  const Array<OneD, const Array<OneD, NekDouble>> &inarray,
133  Array<OneD, Array<OneD, NekDouble>> &outarray, const NekDouble time)
134 {
135  int i;
136 
138 
139  // Dummy array for WeakDG advection
141 
142  // Output array for advection
144 
145  int cnt = 0;
146 
147  // Set up Inflow and Outflow boundary conditions.
148  SetPulseWaveBoundaryConditions(inarray, outarray, time);
149 
150  // Set up any interface conditions and write into boundary condition
152 
153  // do advection evauation in all domains
154  for (int omega = 0; omega < m_nDomains; ++omega)
155  {
156  m_currentDomain = omega;
157  int nq = m_vessels[omega * m_nVariables]->GetTotPoints();
158 
159  for (i = 0; i < m_nVariables; ++i)
160  {
161  physarray[i] = inarray[i] + cnt;
162  out[i] = outarray[i] + cnt;
163  }
164 
165  for (i = 0; i < m_nVariables; ++i)
166  {
167  m_fields[i] = m_vessels[omega * m_nVariables + i];
168  }
169 
170  m_advObject->Advect(m_nVariables, m_fields, advVel, physarray, out,
171  time);
172  for (i = 0; i < m_nVariables; ++i)
173  {
174  Vmath::Neg(nq, out[i], 1);
175  }
176 
177  cnt += nq;
178  }
179 }
180 
182  const Array<OneD, const Array<OneD, NekDouble>> &inarray,
183  Array<OneD, Array<OneD, NekDouble>> &outarray, const NekDouble time)
184 {
185  // Just copy over array
186  for (int i = 0; i < m_nVariables; ++i)
187  {
188  Vmath::Vcopy(inarray[i].num_elements(), inarray[i], 1, outarray[i], 1);
189  }
190 }
191 
192 /**
193  * Does the projection between ... space and the ... space. Also checks for
194  *Q-inflow boundary conditions at the inflow of the current arterial segment and
195  *applies the Q-inflow if specified
196  */
198  const Array<OneD, const Array<OneD, NekDouble>> &inarray,
199  Array<OneD, Array<OneD, NekDouble>> &outarray, const NekDouble time)
200 
201 {
202  int omega;
203 
205 
206  int offset = 0;
207 
208  // This will be moved to the RCR boundary condition once factory is setup
209  if (time == 0)
210  {
212 
213  for (omega = 0; omega < m_nDomains; ++omega)
214  {
215  vessel[0] = m_vessels[2 * omega];
216  vessel[1] = m_vessels[2 * omega + 1];
217 
218  for (int j = 0; j < 2; ++j)
219  {
220  std::string BCType =
221  vessel[0]->GetBndConditions()[j]->GetUserDefined();
222  if (BCType.empty()) // if not condition given define it to be
223  // NoUserDefined
224  {
225  BCType = "NoUserDefined";
226  }
227 
228  m_Boundary[2 * omega + j] = GetBoundaryFactory().CreateInstance(
230 
231  // turn on time depedent BCs
232  if (BCType == "Q-inflow")
233  {
234  vessel[0]->GetBndConditions()[j]->SetIsTimeDependent(true);
235  }
236  if (BCType == "A-inflow")
237  {
238  vessel[0]->GetBndConditions()[j]->SetIsTimeDependent(true);
239  }
240  if (BCType == "U-inflow")
241  {
242  vessel[1]->GetBndConditions()[j]->SetIsTimeDependent(true);
243  }
244  else if (BCType == "RCR-terminal")
245  {
246  vessel[0]->GetBndConditions()[j]->SetIsTimeDependent(true);
247  }
248  }
249  }
250  }
251 
252  SetBoundaryConditions(time);
253 
254  // Loop over all vessesls and set boundary conditions
255  for (omega = 0; omega < m_nDomains; ++omega)
256  {
257  for (int n = 0; n < 2; ++n)
258  {
259  m_Boundary[2 * omega + n]->DoBoundary(inarray, m_A_0, m_beta, time,
260  omega, offset, n);
261  }
262  offset += m_vessels[2 * omega]->GetTotPoints();
263  }
264 }
265 
266 /**
267  * Calculates the second term of the weak form (1): \f$
268  * \left( \frac{\partial \mathbf{F(\mathbf{U})}^{\delta}
269  * }{\partial x}, \mathbf{\psi}^{\delta} \right)_{\Omega_e}
270  * \f$
271  * The variables of the system are $\mathbf{U} = [A,u]^T$
272  * physfield[0] = A physfield[1] = u
273  * flux[0] = F[0] = A*u flux[1] = F[1] = u^2/2 + p/rho
274  * p-A-relationship: p = p_ext + beta*(sqrt(A)-sqrt(A_0))
275  */
277  const Array<OneD, Array<OneD, NekDouble>> &physfield,
279 {
280  int nq = m_vessels[m_currentDomain * m_nVariables]->GetTotPoints();
281  NekDouble p = 0.0;
282  NekDouble p_t = 0.0;
283 
284  for (int j = 0; j < nq; j++)
285  {
286  flux[0][0][j] = physfield[0][j] * physfield[1][j];
287 
288  ASSERTL0(physfield[0][j] >= 0, "Negative A not allowed.");
289 
290  p = m_pext +
291  m_beta[m_currentDomain][j] *
292  (sqrt(physfield[0][j]) - sqrt(m_A_0[m_currentDomain][j]));
293 
294  p_t = (physfield[1][j] * physfield[1][j]) / 2 + p / m_rho;
295  flux[1][0][j] = p_t;
296  }
297 }
298 
300 {
302 }
303 
305 {
307 }
308 
310 {
312 }
313 
315 {
316  return m_rho;
317 }
318 
320 {
321  return m_pext;
322 }
323 
324 /**
325  * Print summary routine, calls virtual routine reimplemented in
326  * UnsteadySystem
327  */
329 {
331 }
332 } // namespace Nektar
Array< OneD, Array< OneD, NekDouble > > m_beta_trace
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
UpwindTypePulse m_upwindTypePulse
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:163
Array< OneD, NekDouble > & GetA0()
void SetPulseWaveBoundaryConditions(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble time)
LibUtilities::TimeIntegrationSchemeOperators m_ode
The time integration scheme operators to use.
std::vector< std::pair< std::string, std::string > > SummaryList
Definition: Misc.h:46
SolverUtils::RiemannSolverSharedPtr m_riemannSolver
Array< OneD, Array< OneD, NekDouble > > m_trace_fwd_normal
STL namespace.
SolverUtils::AdvectionSharedPtr m_advObject
void GetFluxVector(const Array< OneD, Array< OneD, NekDouble > > &physfield, Array< OneD, Array< OneD, Array< OneD, NekDouble > > > &flux)
DG Pulse Wave Propagation routines:
void EnforceInterfaceConditions(const Array< OneD, const Array< OneD, NekDouble > > &fields)
virtual void v_GenerateSummary(SolverUtils::SummaryList &s)
BoundaryFactory & GetBoundaryFactory()
Array< OneD, Array< OneD, NekDouble > > m_A_0_trace
void DoOdeRhs(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble time)
Array< OneD, NekDouble > & GetN()
Base class for unsteady solvers.
void DefineProjection(FuncPointerT func, ObjectPointerT obj)
virtual SOLVER_UTILS_EXPORT void v_GenerateSummary(SummaryList &s)
Print a summary of time stepping parameters.
void DoOdeProjection(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble time)
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:144
bool m_explicitAdvection
Indicates if explicit or implicit treatment of advection is used.
void DefineOdeRhs(FuncPointerT func, ObjectPointerT obj)
Array< OneD, Array< OneD, NekDouble > > m_A_0
RiemannSolverFactory & GetRiemannSolverFactory()
Array< OneD, NekDouble > & GetBeta()
int m_spacedim
Spatial dimension (>= expansion dim).
AdvectionFactory & GetAdvectionFactory()
Gets the factory for initialising advection objects.
Definition: Advection.cpp:47
void Neg(int n, T *x, const int incx)
Negate x = -x.
Definition: Vmath.cpp:399
double NekDouble
EquationSystemFactory & GetEquationSystemFactory()
SOLVER_UTILS_EXPORT void SetBoundaryConditions(NekDouble time)
Evaluates the boundary conditions at the given time.
Array< OneD, Array< OneD, NekDouble > > m_beta
Array< OneD, MultiRegions::ExpListSharedPtr > m_fields
Array holding all dependent variables.
LibUtilities::SessionReaderSharedPtr m_session
The session reader.
PressureAreaFactory & GetPressureAreaFactory()
Array< OneD, PulseWaveBoundarySharedPtr > m_Boundary
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:199
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1064
Array< OneD, MultiRegions::ExpListSharedPtr > m_vessels
PulseWavePressureAreaSharedPtr m_pressureArea
std::shared_ptr< SessionReader > SessionReaderSharedPtr
simple upwinding scheme