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 
39 using namespace std;
40 
41 namespace Nektar
42 {
43 std::string FilterElectrogram::className =
45  "Electrogram", FilterElectrogram::create);
46 
47 /**
48  *
49  */
50 FilterElectrogram::FilterElectrogram(
52  const std::weak_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  {
172  m_grad_R_x[i] = Array<OneD, NekDouble>(nq, 0.0);
173  m_grad_R_y[i] = Array<OneD, NekDouble>(nq, 0.0);
174  m_grad_R_z[i] = Array<OneD, NekDouble>(nq, 0.0);
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  const NekDouble &time)
262 {
263  boost::ignore_unused(time);
264 
265  if (pFields[0]->GetComm()->GetRank() == 0)
266  {
267  m_outputStream.close();
268  }
269 }
270 
271 /**
272  *
273  */
275 {
276  return true;
277 }
278 } // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
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.
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.
virtual 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.
virtual 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.
virtual void v_Initialise(const Array< OneD, const MultiRegions::ExpListSharedPtr > &pFields, const NekDouble &time) override
Initialises the electrogram filter and open output file.
virtual void v_Finalise(const Array< OneD, const MultiRegions::ExpListSharedPtr > &pFields, const NekDouble &time) override
Finalise the electrogram filter and close output file.
virtual ~FilterElectrogram()
Electrogram filter destructor.
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:198
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
LibUtilities::SessionReaderSharedPtr m_session
Definition: Filter.h:85
std::map< std::string, std::string > ParamMap
Definition: Filter.h:67
std::shared_ptr< SessionReader > SessionReaderSharedPtr
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:54
FilterFactory & GetFilterFactory()
Definition: Filter.cpp:41
std::shared_ptr< PointGeom > PointGeomSharedPtr
Definition: Geometry.h:59
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
double NekDouble
void Vsqrt(int n, const T *x, const int incx, T *y, const int incy)
sqrt y = sqrt(x)
Definition: Vmath.cpp:534
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.cpp:574
void Sdiv(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha/y.
Definition: Vmath.cpp:324
void Sadd(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Add scalar y = alpha + x.
Definition: Vmath.cpp:384
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.cpp:692