Nektar++
FilterElectrogram.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: FilterElectrogram.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: Outputs virtual electrograms at specific locations.
32//
33///////////////////////////////////////////////////////////////////////////////
34
37#include <iomanip>
38
39using namespace std;
40
41namespace Nektar
42{
45 "Electrogram", FilterElectrogram::create);
46
47/**
48 *
49 */
52 const std::shared_ptr<SolverUtils::EquationSystem> &pEquation,
53 const ParamMap &pParams)
54 : Filter(pSession, pEquation)
55{
56 // OutputFile
57 auto it = pParams.find("OutputFile");
58 if (it == pParams.end())
59 {
60 m_outputFile = m_session->GetSessionName();
61 }
62 else
63 {
64 ASSERTL0(it->second.length() > 0, "Missing parameter 'OutputFile'.");
65 m_outputFile = it->second;
66 }
67 if (!(m_outputFile.length() >= 4 &&
68 m_outputFile.substr(m_outputFile.length() - 4) == ".ecg"))
69 {
70 m_outputFile += ".ecg";
71 }
72
73 // OutputFrequency
74 it = pParams.find("OutputFrequency");
75 if (it == pParams.end())
76 {
78 }
79 else
80 {
81 LibUtilities::Equation equ(m_session->GetInterpreter(), it->second);
82 m_outputFrequency = floor(equ.Evaluate());
83 }
84
85 // Points
86 it = pParams.find("Points");
87 ASSERTL0(it != pParams.end(), "Missing parameter 'Points'.");
88 m_electrogramStream.str(it->second);
89 m_index = 0;
90}
91
92/**
93 *
94 */
96{
97}
98
99/**
100 *
101 */
104 const NekDouble &time)
105{
106 ASSERTL0(!m_electrogramStream.fail(), "No history points in stream.");
107
108 m_index = 0;
109 Array<OneD, NekDouble> gloCoord(3, 0.0);
110 LibUtilities::CommSharedPtr vComm = pFields[0]->GetComm();
111
112 // Read electrogram points
113 // Always use dim = 3 to allow electrode to be above surface
114 const size_t dim = 3;
115 size_t i = 0;
116
117 while (!m_electrogramStream.fail())
118 {
119 m_electrogramStream >> gloCoord[0] >> gloCoord[1] >> gloCoord[2];
120 if (!m_electrogramStream.fail())
121 {
124 dim, i, gloCoord[0], gloCoord[1], gloCoord[2]);
125
126 m_electrogramPoints.push_back(vert);
127 ++i;
128 }
129 }
130
131 if (vComm->GetRank() == 0)
132 {
133 // Open output stream
134 m_outputStream.open(m_outputFile.c_str());
135 m_outputStream << "# Electrogram data for variables (:";
136
137 for (size_t i = 0; i < pFields.size(); ++i)
138 {
139 m_outputStream << m_session->GetVariable(i) << ",";
140 }
141
142 m_outputStream << ") at points:" << endl;
143
144 for (size_t i = 0; i < m_electrogramPoints.size(); ++i)
145 {
146 m_electrogramPoints[i]->GetCoords(gloCoord[0], gloCoord[1],
147 gloCoord[2]);
148
149 m_outputStream << "# \t" << i;
150 m_outputStream.width(8);
151 m_outputStream << gloCoord[0];
152 m_outputStream.width(8);
153 m_outputStream << gloCoord[1];
154 m_outputStream.width(8);
155 m_outputStream << gloCoord[2];
156 m_outputStream << endl;
157 }
158 }
159
160 // Compute the distance function for each electrogram point
161 const size_t nq = pFields[0]->GetNpoints();
162 const size_t npts = m_electrogramPoints.size();
163 NekDouble px, py, pz;
167
168 Array<OneD, NekDouble> oneOverR(nq, 0.0);
169
170 for (size_t i = 0; i < npts; ++i)
171 {
175
176 Array<OneD, NekDouble> x(nq, 0.0);
177 Array<OneD, NekDouble> y(nq, 0.0);
178 Array<OneD, NekDouble> z(nq, 0.0);
179
180 // Compute 1/R
181 m_electrogramPoints[i]->GetCoords(px, py, pz);
182 pFields[0]->GetCoords(x, y, z);
183
184 Vmath::Sadd(nq, -px, x, 1, x, 1);
185 Vmath::Sadd(nq, -py, y, 1, y, 1);
186 Vmath::Sadd(nq, -pz, z, 1, z, 1);
187 Vmath::Vvtvvtp(nq, x, 1, x, 1, y, 1, y, 1, oneOverR, 1);
188 Vmath::Vvtvp(nq, z, 1, z, 1, oneOverR, 1, oneOverR, 1);
189 Vmath::Vsqrt(nq, oneOverR, 1, oneOverR, 1);
190 Vmath::Sdiv(nq, 1.0, oneOverR, 1, oneOverR, 1);
191
192 // Compute grad 1/R
193 pFields[0]->PhysDeriv(oneOverR, m_grad_R_x[i], m_grad_R_y[i],
194 m_grad_R_z[i]);
195 }
196
197 // Compute electrogram point for initial condition
198 v_Update(pFields, time);
199}
200
201/**
202 *
203 */
206 const NekDouble &time)
207{
208 // Only output every m_outputFrequency.
209 if ((m_index++) % m_outputFrequency)
210 {
211 return;
212 }
213
214 const size_t nq = pFields[0]->GetNpoints();
215 const size_t npoints = m_electrogramPoints.size();
216 LibUtilities::CommSharedPtr vComm = pFields[0]->GetComm();
217
218 size_t i = 0;
219 Array<OneD, NekDouble> e(npoints);
220
221 // Compute grad V
222 Array<OneD, NekDouble> grad_V_x(nq), grad_V_y(nq), grad_V_z(nq);
223 pFields[0]->PhysDeriv(pFields[0]->GetPhys(), grad_V_x, grad_V_y, grad_V_z);
224
225 for (i = 0; i < npoints; ++i)
226 {
227 // Multiply together
228 Array<OneD, NekDouble> output(nq);
229 Vmath::Vvtvvtp(nq, m_grad_R_x[i], 1, grad_V_x, 1, m_grad_R_y[i], 1,
230 grad_V_y, 1, output, 1);
231 Vmath::Vvtvp(nq, m_grad_R_z[i], 1, grad_V_z, 1, output, 1, output, 1);
232
233 e[i] = pFields[0]->Integral(output);
234 }
235
236 // Exchange history data
237 // This could be improved to reduce communication but works for now
238 vComm->AllReduce(e, LibUtilities::ReduceSum);
239
240 // Only the root process writes out electrogram data
241 if (vComm->GetRank() == 0)
242 {
243 m_outputStream.width(8);
244 m_outputStream << setprecision(6) << time;
245
246 // Write data values point by point
247 for (i = 0; i < m_electrogramPoints.size(); ++i)
248 {
249 m_outputStream.width(25);
250 m_outputStream << setprecision(16) << e[i];
251 }
252 m_outputStream << endl;
253 }
254}
255
256/**
257 *
258 */
261 [[maybe_unused]] const NekDouble &time)
262{
263 if (pFields[0]->GetComm()->GetRank() == 0)
264 {
265 m_outputStream.close();
266 }
267}
268
269/**
270 *
271 */
273{
274 return true;
275}
276} // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:208
Array< OneD, Array< OneD, NekDouble > > m_grad_R_z
Gradient of the radius from each electrogram point in z-direction.
Array< OneD, Array< OneD, NekDouble > > m_grad_R_x
Gradient of the radius from each electrogram point in x-direction.
std::ofstream m_outputStream
Output file stream for electrogram data.
static SolverUtils::FilterSharedPtr create(const LibUtilities::SessionReaderSharedPtr &pSession, const std::shared_ptr< SolverUtils::EquationSystem > &pEquation, const ParamMap &pParams)
Creates an instance of this class.
std::string m_outputFile
Filename to output electrogram data to.
Array< OneD, Array< OneD, NekDouble > > m_grad_R_y
Gradient of the radius from each electrogram point in y-direction.
unsigned int m_outputFrequency
Number of timesteps between outputs.
~FilterElectrogram() override
Electrogram filter destructor.
FilterElectrogram(const LibUtilities::SessionReaderSharedPtr &pSession, const std::shared_ptr< SolverUtils::EquationSystem > &pEquation, const ParamMap &pParams)
Electrogram filter constructor.
bool v_IsTimeDependent() override
Filter is time-dependent and should be called at each time-step.
unsigned int m_index
Counts number of calls to update (number of timesteps)
SpatialDomains::PointGeomVector m_electrogramPoints
List of electrogram points.
void v_Update(const Array< OneD, const MultiRegions::ExpListSharedPtr > &pFields, const NekDouble &time) override
Compute extracellular potential at egm points at current time.
std::stringstream m_electrogramStream
Point coordinate input string.
static std::string className
Name of the class.
void v_Initialise(const Array< OneD, const MultiRegions::ExpListSharedPtr > &pFields, const NekDouble &time) override
Initialises the electrogram filter and open output file.
void v_Finalise(const Array< OneD, const MultiRegions::ExpListSharedPtr > &pFields, const NekDouble &time) override
Finalise the electrogram filter and close output file.
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
LibUtilities::SessionReaderSharedPtr m_session
Definition: Filter.h:83
std::map< std::string, std::string > ParamMap
Definition: Filter.h:65
std::shared_ptr< SessionReader > SessionReaderSharedPtr
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:55
FilterFactory & GetFilterFactory()
std::shared_ptr< PointGeom > PointGeomSharedPtr
Definition: Geometry.h:57
std::vector< double > z(NPUPPER)
double NekDouble
void Vsqrt(int n, const T *x, const int incx, T *y, const int incy)
sqrt y = sqrt(x)
Definition: Vmath.hpp:340
void Vvtvp(int n, const T *w, const int incw, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
vvtvp (vector times vector plus vector): z = w*x + y
Definition: Vmath.hpp:366
void Sdiv(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha/x.
Definition: Vmath.hpp:154
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
void Vvtvvtp(int n, const T *v, int incv, const T *w, int incw, const T *x, int incx, const T *y, int incy, T *z, int incz)
vvtvvtp (vector times vector plus vector times vector):
Definition: Vmath.hpp:439
STL namespace.