Nektar++
BidomainRoth.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: BidomainRoth.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: Bidomain cardiac electrophysiology model - Roth formulation.
32//
33///////////////////////////////////////////////////////////////////////////////
34
35#include <iostream>
36
39
40using namespace std;
41
42namespace Nektar
43{
44
45/**
46 * Registers the class with the Factory.
47 */
50 "BidomainRoth", BidomainRoth::create,
51 "Bidomain Roth model of cardiac electrophysiology.");
52
53/**
54 *
55 */
58 : UnsteadySystem(pSession, pGraph)
59{
60}
61
62/**
63 *
64 */
65void BidomainRoth::v_InitObject(bool DeclareField)
66{
67 UnsteadySystem::v_InitObject(DeclareField);
68
69 m_session->LoadParameter("Chi", m_chi);
70 m_session->LoadParameter("Cm", m_capMembrane);
71
72 std::string vCellModel;
73 m_session->LoadSolverInfo("CELLMODEL", vCellModel, "");
74
75 ASSERTL0(vCellModel != "", "Cell Model not specified.");
76
78 m_fields[0]);
79
80 m_intVariables.push_back(0);
81
82 // Load variable coefficients
83 StdRegions::VarCoeffType varCoeffEnum[6] = {
87 std::string varCoeffString[6] = {"xx", "xy", "yy", "xz", "yz", "zz"};
88 std::string aniso_var[3] = {"fx", "fy", "fz"};
89
90 const int nq = m_fields[0]->GetNpoints();
91
92 // Allocate storage for variable coeffs and initialize to 1.
93 for (int i = 0, k = 0; i < m_spacedim; ++i)
94 {
95 for (int j = 0; j < i + 1; ++j)
96 {
97 if (i == j)
98 {
99 m_vardiffi[varCoeffEnum[k]] = Array<OneD, NekDouble>(nq, 1.0);
100 m_vardiffe[varCoeffEnum[k]] = Array<OneD, NekDouble>(nq, 1.0);
101 m_vardiffie[varCoeffEnum[k]] = Array<OneD, NekDouble>(nq, 1.0);
102 }
103 else
104 {
105 m_vardiffi[varCoeffEnum[k]] = Array<OneD, NekDouble>(nq, 0.0);
106 m_vardiffe[varCoeffEnum[k]] = Array<OneD, NekDouble>(nq, 0.0);
107 m_vardiffie[varCoeffEnum[k]] = Array<OneD, NekDouble>(nq, 0.0);
108 }
109 ++k;
110 }
111 }
112
113 // Apply fibre map f \in [0,1], scale to conductivity range
114 // [o_min,o_max], specified by the session parameters o_min and o_max
115 if (m_session->DefinesFunction("ExtracellularAnisotropicConductivity"))
116 {
117 if (m_session->DefinesCmdLineArgument("verbose"))
118 {
119 cout << "Loading Extracellular Anisotropic Fibre map." << endl;
120 }
121
122 NekDouble o_min = m_session->GetParameter("o_min");
123 NekDouble o_max = m_session->GetParameter("o_max");
124 int k = 0;
125
128
129 /*
130 * Diffusivity matrix D is upper triangular and defined as
131 * d_00 d_01 d_02
132 * d_11 d_12
133 * d_22
134 *
135 * Given a principle fibre direction _f_ the diffusivity is given
136 * by
137 * d_ij = { D_2 + (D_1 - D_2) f_i f_j if i==j
138 * { (D_1 - D_2) f_i f_j if i!=j
139 *
140 * The vector _f_ is given in terms of the variables fx,fy,fz in the
141 * function AnisotropicConductivity. The values of D_1 and D_2 are
142 * the parameters o_max and o_min, respectively.
143 */
144
145 // Loop through columns of D
146 for (int j = 0; j < m_spacedim; ++j)
147 {
148 ASSERTL0(m_session->DefinesFunction(
149 "ExtracellularAnisotropicConductivity", aniso_var[j]),
150 "Function 'AnisotropicConductivity' not correctly "
151 "defined.");
152
153 GetFunction("ExtracellularAnisotropicConductivity")
154 ->Evaluate(aniso_var[j], vTemp_j);
155
156 // Loop through rows of D
157 for (int i = 0; i < j + 1; ++i)
158 {
159 ASSERTL0(
160 m_session->DefinesFunction(
161 "ExtracellularAnisotropicConductivity", aniso_var[i]),
162 "Function 'ExtracellularAnisotropicConductivity' not "
163 "correctly defined.");
164
165 GetFunction("ExtracellularAnisotropicConductivity")
166 ->Evaluate(aniso_var[i], vTemp_i);
168 m_vardiffe[varCoeffEnum[k]].GetValue();
169
170 Vmath::Vmul(nq, vTemp_i, 1, vTemp_j, 1, tmp, 1);
171
172 Vmath::Smul(nq, o_max - o_min, tmp, 1, tmp, 1);
173
174 if (i == j)
175 {
176 Vmath::Sadd(nq, o_min, tmp, 1, tmp, 1);
177 }
178
179 m_vardiffe[varCoeffEnum[k]] = tmp;
180 }
181 }
182 }
183
184 // Apply fibre map f \in [0,1], scale to conductivity range
185 // [o_min,o_max], specified by the session parameters o_min and o_max
186 if (m_session->DefinesFunction("IntracellularAnisotropicConductivity"))
187 {
188 if (m_session->DefinesCmdLineArgument("verbose"))
189 {
190 cout << "Loading Anisotropic Fibre map." << endl;
191 }
192
193 NekDouble o_min = m_session->GetParameter("o_min");
194 NekDouble o_max = m_session->GetParameter("o_max");
195 int k = 0;
196
199
200 /*
201 * Diffusivity matrix D is upper triangular and defined as
202 * d_00 d_01 d_02
203 * d_11 d_12
204 * d_22
205 *
206 * Given a principle fibre direction _f_ the diffusivity is given
207 * by
208 * d_ij = { D_2 + (D_1 - D_2) f_i f_j if i==j
209 * { (D_1 - D_2) f_i f_j if i!=j
210 *
211 * The vector _f_ is given in terms of the variables fx,fy,fz in the
212 * function AnisotropicConductivity. The values of D_1 and D_2 are
213 * the parameters o_max and o_min, respectively.
214 */
215
216 // Loop through columns of D
217 for (int j = 0; j < m_spacedim; ++j)
218 {
219 ASSERTL0(m_session->DefinesFunction(
220 "IntracellularAnisotropicConductivity", aniso_var[j]),
221 "Function 'IntracellularAnisotropicConductivity' not "
222 "correctly defined.");
223
224 GetFunction("IntracellularAnisotropicConductivity")
225 ->Evaluate(aniso_var[j], vTemp_j);
226
227 // Loop through rows of D
228 for (int i = 0; i < j + 1; ++i)
229 {
230 ASSERTL0(
231 m_session->DefinesFunction(
232 "IntracellularAnisotropicConductivity", aniso_var[i]),
233 "Function 'IntracellularAnisotropicConductivity' not "
234 "correctly defined.");
235 GetFunction("IntracellularAnisotropicConductivity")
236 ->Evaluate(aniso_var[i], vTemp_i);
237
239 m_vardiffi[varCoeffEnum[k]].GetValue();
241 m_vardiffe[varCoeffEnum[k]].GetValue();
242 Vmath::Vmul(nq, vTemp_i, 1, vTemp_j, 1, tmp, 1);
243
244 Vmath::Smul(nq, o_max - o_min, tmp, 1, tmp, 1);
245
246 if (i == j)
247 {
248 Vmath::Sadd(nq, o_min, tmp, 1, tmp, 1);
249 }
250
251 Vmath::Vadd(nq, tmp2, 1, tmp, 1, tmp2, 1);
252
253 m_vardiffi[varCoeffEnum[k]] = tmp;
254 m_vardiffe[varCoeffEnum[k]] = tmp2;
255
256 ++k;
257 }
258 }
259 }
260
261 // Write out conductivity values
262 for (int j = 0, k = 0; j < m_spacedim; ++j)
263 {
264 // Loop through rows of D
265 for (int i = 0; i < j + 1; ++i)
266 {
267 // Transform variable coefficient and write out to file.
268 m_fields[0]->FwdTransLocalElmt(
269 m_vardiffi[varCoeffEnum[k]].GetValue(),
270 m_fields[0]->UpdateCoeffs());
271 std::stringstream filenamei;
272 filenamei << "IConductivity_" << varCoeffString[k] << ".fld";
273 WriteFld(filenamei.str());
274
275 // Transform variable coefficient and write out to file.
276 m_fields[0]->FwdTransLocalElmt(
277 m_vardiffe[varCoeffEnum[k]].GetValue(),
278 m_fields[0]->UpdateCoeffs());
279 std::stringstream filenamee;
280 filenamee << "EConductivity_" << varCoeffString[k] << ".fld";
281 WriteFld(filenamee.str());
282
283 ++k;
284 }
285 }
286
287 // Search through the loaded filters and pass the cell model to any
288 // CheckpointCellModel filters loaded.
289 for (auto &x : m_filters)
290 {
291 if (x.first == "CheckpointCellModel")
292 {
293 std::shared_ptr<FilterCheckpointCellModel> c =
294 std::dynamic_pointer_cast<FilterCheckpointCellModel>(x.second);
295 c->SetCellModel(m_cell);
296 }
297 }
298 // Load stimuli
300
302 {
304 }
307}
308
309/**
310 *
311 */
313{
314}
315
316/**
317 * @param inarray Input array.
318 * @param outarray Output array.
319 * @param time Current simulation time.
320 * @param lambda Timestep.
321 */
323 const Array<OneD, const Array<OneD, NekDouble>> &inarray,
325 [[maybe_unused]] const NekDouble time, const NekDouble lambda)
326{
327 int nq = m_fields[0]->GetNpoints();
328
329 StdRegions::ConstFactorMap factorsHelmholtz;
330 // lambda = \Delta t
331 factorsHelmholtz[StdRegions::eFactorLambda] =
332 1.0 / lambda * m_chi * m_capMembrane;
333
334 // ------------------------------
335 // Solve Helmholtz problem for Vm
336 // ------------------------------
337 // Multiply 1.0/timestep
338 // Vmath::Vadd(nq, inarray[0], 1, ggrad, 1, m_fields[0]->UpdatePhys(), 1);
339 Vmath::Smul(nq, -factorsHelmholtz[StdRegions::eFactorLambda], inarray[0], 1,
340 m_fields[0]->UpdatePhys(), 1);
341
342 // Solve a system of equations with Helmholtz solver and transform
343 // back into physical space.
344 m_fields[0]->HelmSolve(m_fields[0]->GetPhys(), m_fields[0]->UpdateCoeffs(),
345 factorsHelmholtz, m_vardiffe);
346
347 m_fields[0]->BwdTrans(m_fields[0]->GetCoeffs(), m_fields[0]->UpdatePhys());
348 m_fields[0]->SetPhysState(true);
349
350 // Copy the solution vector (required as m_fields must be set).
351 outarray[0] = m_fields[0]->GetPhys();
352}
353
354/**
355 *
356 */
358 const Array<OneD, const Array<OneD, NekDouble>> &inarray,
359 Array<OneD, Array<OneD, NekDouble>> &outarray, const NekDouble time)
360{
361 int nq = m_fields[0]->GetNpoints();
362
363 // Compute I_ion
364 m_cell->TimeIntegrate(inarray, outarray, time);
365
366 // Compute I_stim
367 for (unsigned int i = 0; i < m_stimulus.size(); ++i)
368 {
369 m_stimulus[i]->Update(outarray, time);
370 }
371
372 Array<OneD, NekDouble> ggrad0(nq), ggrad1(nq), ggrad2(nq), ggrad(nq);
373 StdRegions::ConstFactorMap factorsPoisson;
374 factorsPoisson[StdRegions::eFactorLambda] = 0.0;
375
376 // ----------------------------
377 // Compute \nabla g_i \nabla Vm
378 // ----------------------------
379 m_fields[0]->PhysDeriv(inarray[0], ggrad0, ggrad1, ggrad2);
380 m_fields[0]->PhysDeriv(0, ggrad0, ggrad0);
381 m_fields[0]->PhysDeriv(1, ggrad1, ggrad1);
382 m_fields[0]->PhysDeriv(2, ggrad2, ggrad2);
383 if (m_session->DefinesFunction("IntracellularAnisotropicConductivity") &&
384 m_session->DefinesFunction("ExtracellularAnisotropicConductivity"))
385 {
386 Vmath::Vmul(nq, &m_vardiffi[StdRegions::eVarCoeffD00][0], 1, &ggrad0[0],
387 1, &ggrad0[0], 1);
388 Vmath::Vmul(nq, &m_vardiffi[StdRegions::eVarCoeffD11][0], 1, &ggrad1[0],
389 1, &ggrad1[0], 1);
390 Vmath::Vmul(nq, &m_vardiffi[StdRegions::eVarCoeffD22][0], 1, &ggrad2[0],
391 1, &ggrad2[0], 1);
392 }
393 // Add partial derivatives together
394 Vmath::Vadd(nq, ggrad0, 1, ggrad1, 1, ggrad, 1);
395 Vmath::Vadd(nq, ggrad2, 1, ggrad, 1, ggrad, 1);
396
397 Vmath::Smul(nq, -1.0, ggrad, 1, m_fields[1]->UpdatePhys(), 1);
398
399 // ----------------------------
400 // Solve Poisson problem for Ve
401 // ----------------------------
402 m_fields[1]->HelmSolve(m_fields[1]->GetPhys(), m_fields[1]->UpdateCoeffs(),
403 factorsPoisson, m_vardiffie);
404 m_fields[1]->BwdTrans(m_fields[1]->GetCoeffs(), m_fields[1]->UpdatePhys());
405 m_fields[1]->SetPhysState(true);
406
407 // ------------------------------
408 // Compute Laplacian of Ve (forcing term)
409 // ------------------------------
410 m_fields[1]->PhysDeriv(m_fields[1]->GetPhys(), ggrad0, ggrad1, ggrad2);
411 m_fields[1]->PhysDeriv(0, ggrad0, ggrad0);
412 m_fields[1]->PhysDeriv(1, ggrad1, ggrad1);
413 m_fields[1]->PhysDeriv(2, ggrad2, ggrad2);
414 if (m_session->DefinesFunction("IntracellularAnisotropicConductivity") &&
415 m_session->DefinesFunction("ExtracellularAnisotropicConductivity"))
416 {
417 Vmath::Vmul(nq, &m_vardiffi[StdRegions::eVarCoeffD00][0], 1, &ggrad0[0],
418 1, &ggrad0[0], 1);
419 Vmath::Vmul(nq, &m_vardiffi[StdRegions::eVarCoeffD11][0], 1, &ggrad1[0],
420 1, &ggrad1[0], 1);
421 Vmath::Vmul(nq, &m_vardiffi[StdRegions::eVarCoeffD22][0], 1, &ggrad2[0],
422 1, &ggrad2[0], 1);
423 }
424 // Add partial derivatives together
425 Vmath::Vadd(nq, ggrad0, 1, ggrad1, 1, ggrad, 1);
426 Vmath::Vadd(nq, ggrad2, 1, ggrad, 1, ggrad, 1);
427
428 Vmath::Vadd(nq, ggrad, 1, outarray[0], 1, outarray[0], 1);
429}
430
431/**
432 *
433 */
435 bool dumpInitialConditions,
436 const int domain)
437{
438 EquationSystem::v_SetInitialConditions(initialtime, dumpInitialConditions,
439 domain);
440 m_cell->Initialise();
441}
442
443/**
444 *
445 */
447{
449 m_cell->GenerateSummary(s);
450}
451
452} // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:208
void v_GenerateSummary(SummaryList &s) override
Prints a summary of the model parameters.
void DoOdeRhs(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble time)
Computes the reaction terms and .
StdRegions::VarCoeffMap m_vardiffi
Definition: BidomainRoth.h:100
std::vector< StimulusSharedPtr > m_stimulus
Definition: BidomainRoth.h:98
void v_InitObject(bool DeclareField=true) override
Init object for UnsteadySystem class.
static std::string className
Name of class.
Definition: BidomainRoth.h:63
static SolverUtils::EquationSystemSharedPtr create(const LibUtilities::SessionReaderSharedPtr &pSession, const SpatialDomains::MeshGraphSharedPtr &pGraph)
Creates an instance of this class.
Definition: BidomainRoth.h:52
BidomainRoth(const LibUtilities::SessionReaderSharedPtr &pSession, const SpatialDomains::MeshGraphSharedPtr &pGraph)
Constructor.
void DoImplicitSolve(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray, NekDouble time, NekDouble lambda)
Solve for the diffusion term.
CellModelSharedPtr m_cell
Cell model.
Definition: BidomainRoth.h:96
void v_SetInitialConditions(NekDouble initialtime, bool dumpInitialConditions, const int domain) override
Sets a custom initial condition.
StdRegions::VarCoeffMap m_vardiffie
Definition: BidomainRoth.h:102
~BidomainRoth() override
Desctructor.
StdRegions::VarCoeffMap m_vardiffe
Definition: BidomainRoth.h:101
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
void DefineProjection(FuncPointerT func, ObjectPointerT obj)
void DefineOdeRhs(FuncPointerT func, ObjectPointerT obj)
void DefineImplicitSolve(FuncPointerT func, ObjectPointerT obj)
int m_spacedim
Spatial dimension (>= expansion dim).
virtual SOLVER_UTILS_EXPORT void v_SetInitialConditions(NekDouble initialtime=0.0, bool dumpInitialConditions=true, const int domain=0)
Array< OneD, MultiRegions::ExpListSharedPtr > m_fields
Array holding all dependent variables.
SOLVER_UTILS_EXPORT void WriteFld(const std::string &outname)
Write field data to the given filename.
LibUtilities::SessionReaderSharedPtr m_session
The session reader.
SOLVER_UTILS_EXPORT SessionFunctionSharedPtr GetFunction(std::string name, const MultiRegions::ExpListSharedPtr &field=MultiRegions::NullExpListSharedPtr, bool cache=false)
Get a SessionFunction by name.
Base class for unsteady solvers.
LibUtilities::TimeIntegrationSchemeOperators m_ode
The time integration scheme operators to use.
std::vector< std::pair< std::string, FilterSharedPtr > > m_filters
SOLVER_UTILS_EXPORT void DoDummyProjection(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble time)
Perform dummy projection.
bool m_explicitDiffusion
Indicates if explicit or implicit treatment of diffusion is used.
SOLVER_UTILS_EXPORT void v_GenerateSummary(SummaryList &s) override
Print a summary of time stepping parameters.
SOLVER_UTILS_EXPORT void v_InitObject(bool DeclareField=true) override
Init object for UnsteadySystem class.
static std::vector< StimulusSharedPtr > LoadStimuli(const LibUtilities::SessionReaderSharedPtr &pSession, const MultiRegions::ExpListSharedPtr &pField)
Definition: Stimulus.cpp:89
std::shared_ptr< SessionReader > SessionReaderSharedPtr
std::vector< std::pair< std::string, std::string > > SummaryList
Definition: Misc.h:46
EquationSystemFactory & GetEquationSystemFactory()
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:174
std::map< ConstFactorType, NekDouble > ConstFactorMap
Definition: StdRegions.hpp:430
CellModelFactory & GetCellModelFactory()
Definition: CellModel.cpp:46
double NekDouble
void Vmul(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Multiply vector z = x*y.
Definition: Vmath.hpp:72
void Vadd(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Add vector z = x+y.
Definition: Vmath.hpp:180
void Smul(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha*x.
Definition: Vmath.hpp:100
void Sadd(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Add vector y = alpha + x.
Definition: Vmath.hpp:194
STL namespace.