Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 // License for the specific language governing rights and limitations under
14 // Permission is hereby granted, free of charge, to any person obtaining a
15 // copy of this software and associated documentation files (the "Software"),
16 // to deal in the Software without restriction, including without limitation
17 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 // and/or sell copies of the Software, and to permit persons to whom the
19 // Software is furnished to do so, subject to the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be included
22 // in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 // DEALINGS IN THE SOFTWARE.
31 //
32 // Description: Outputs virtual electrograms at specific locations.
33 //
34 ///////////////////////////////////////////////////////////////////////////////
35 
37 #include <iomanip>
39 
40 namespace Nektar
41 {
42  std::string FilterElectrogram::className =
44  "Electrogram",
46 
47  /**
48  *
49  */
52  const std::map<std::string, std::string> &pParams) :
53  Filter(pSession)
54  {
55  if (pParams.find("OutputFile") == pParams.end())
56  {
57  m_outputFile = m_session->GetSessionName();
58  }
59  else
60  {
61  ASSERTL0(!(pParams.find("OutputFile")->second.empty()),
62  "Missing parameter 'OutputFile'.");
63  m_outputFile = pParams.find("OutputFile")->second;
64  }
65  if (!(m_outputFile.length() >= 4
66  && m_outputFile.substr(m_outputFile.length() - 4) == ".ecg"))
67  {
68  m_outputFile += ".ecg";
69  }
70 
71  if (pParams.find("OutputFrequency") == pParams.end())
72  {
74  }
75  else
76  {
77  m_outputFrequency = atoi(pParams.find("OutputFrequency")->second.c_str());
78  }
79 
80  ASSERTL0(pParams.find("Points") != pParams.end(),
81  "Missing parameter 'Points'.");
82  m_electrogramStream.str(pParams.find("Points")->second);
83  m_index = 0;
84  }
85 
86 
87  /**
88  *
89  */
91  {
92 
93  }
94 
95 
96  /**
97  *
98  */
99  void FilterElectrogram::v_Initialise(const Array<OneD, const MultiRegions::ExpListSharedPtr> &pFields, const NekDouble &time)
100  {
102  "No history points in stream.");
103 
104  m_index = 0;
105  Array<OneD, NekDouble> gloCoord(3,0.0);
106  LibUtilities::CommSharedPtr vComm = pFields[0]->GetComm();
107 
108  // Read electrogram points
109  // Always use dim = 3 to allow electrode to be above surface
110  const int dim = 3;
111  const NekDouble tol = 1e-06;
112  int i = 0;
113 
114  while (!m_electrogramStream.fail())
115  {
116  m_electrogramStream >> gloCoord[0] >> gloCoord[1] >> gloCoord[2];
117  if (!m_electrogramStream.fail())
118  {
119  ASSERTL0(pFields[0]->GetExpIndex(gloCoord, tol) == -1,
120  "Electrogram point must lie outside of domain: ("
121  + boost::lexical_cast<string>(gloCoord[0]) + ","
122  + boost::lexical_cast<string>(gloCoord[1]) + ","
123  + boost::lexical_cast<string>(gloCoord[2]) + ")");
124 
127  ::AllocateSharedPtr(dim, i, gloCoord[0],
128  gloCoord[1], gloCoord[2]);
129 
130  m_electrogramPoints.push_back(vert);
131  ++i;
132  }
133  }
134 
135  if (vComm->GetRank() == 0)
136  {
137  // Open output stream
138  m_outputStream.open(m_outputFile.c_str());
139  m_outputStream << "# Electrogram data for variables (:";
140 
141  for (i = 0; i < pFields.num_elements(); ++i)
142  {
143  m_outputStream << m_session->GetVariable(i) <<",";
144  }
145 
146  m_outputStream << ") at points:" << endl;
147 
148  for (i = 0; i < m_electrogramPoints.size(); ++i)
149  {
150  m_electrogramPoints[i]->GetCoords( gloCoord[0],
151  gloCoord[1],
152  gloCoord[2]);
153 
154  m_outputStream << "# \t" << i;
155  m_outputStream.width(8);
156  m_outputStream << gloCoord[0];
157  m_outputStream.width(8);
158  m_outputStream << gloCoord[1];
159  m_outputStream.width(8);
160  m_outputStream << gloCoord[2];
161  m_outputStream << endl;
162  }
163  }
164 
165  // Compute the distance function for each electrogram point
166  const unsigned int nq = pFields[0]->GetNpoints();
167  NekDouble px, py, pz;
168  m_grad_R_x = Array<OneD, Array<OneD, NekDouble> >(m_electrogramPoints.size());
169  m_grad_R_y = Array<OneD, Array<OneD, NekDouble> >(m_electrogramPoints.size());
170  m_grad_R_z = Array<OneD, Array<OneD, NekDouble> >(m_electrogramPoints.size());
171 
172  Array<OneD, NekDouble> x(nq);
173  Array<OneD, NekDouble> y(nq);
174  Array<OneD, NekDouble> z(nq);
175 
176  Array<OneD, NekDouble> oneOverR(nq);
177  for (unsigned int i = 0; i < m_electrogramPoints.size(); ++i)
178  {
179  m_grad_R_x[i] = Array<OneD, NekDouble>(nq);
180  m_grad_R_y[i] = Array<OneD, NekDouble>(nq);
181  m_grad_R_z[i] = Array<OneD, NekDouble>(nq);
182 
183  // Compute 1/R
184  m_electrogramPoints[i]->GetCoords(px,py,pz);
185 
186  pFields[0]->GetCoords(x,y,z);
187 
188  Vmath::Sadd (nq, -px, x, 1, x, 1);
189  Vmath::Sadd (nq, -py, y, 1, y, 1);
190  Vmath::Sadd (nq, -pz, z, 1, z, 1);
191  Vmath::Vvtvvtp(nq, x, 1, x, 1, y, 1, y, 1, oneOverR, 1);
192  Vmath::Vvtvp (nq, z, 1, z, 1, oneOverR, 1, oneOverR, 1);
193  Vmath::Vsqrt (nq, oneOverR, 1, oneOverR, 1);
194  Vmath::Sdiv (nq, 1.0, oneOverR, 1, oneOverR, 1);
195 
196  // Compute grad 1/R
197  pFields[0]->PhysDeriv(oneOverR, m_grad_R_x[i], m_grad_R_y[i], m_grad_R_z[i]);
198  }
199 
200  // Compute electrogram point for initial condition
201  v_Update(pFields, time);
202  }
203 
204 
205  /**
206  *
207  */
208  void FilterElectrogram::v_Update(const Array<OneD, const MultiRegions::ExpListSharedPtr> &pFields, const NekDouble &time)
209  {
210  // Only output every m_outputFrequency.
211  if ((m_index++) % m_outputFrequency)
212  {
213  return;
214  }
215 
216  const unsigned int nq = pFields[0]->GetNpoints();
217  const unsigned int npoints = m_electrogramPoints.size();
218  LibUtilities::CommSharedPtr vComm = pFields[0]->GetComm();
219 
220  unsigned int i = 0;
221  Array<OneD, NekDouble> e(npoints);
222 
223  // Compute grad V
224  Array<OneD, NekDouble> grad_V_x(nq), grad_V_y(nq), grad_V_z(nq);
225  pFields[0]->PhysDeriv(pFields[0]->GetPhys(), grad_V_x, grad_V_y, grad_V_z);
226 
227  for (i = 0; i < npoints; ++i)
228  {
229  // Multiply together
230  Array<OneD, NekDouble> output(nq);
231  Vmath::Vvtvvtp(nq, m_grad_R_x[i], 1, grad_V_x, 1, m_grad_R_y[i], 1, grad_V_y, 1, output, 1);
232  Vmath::Vvtvp (nq, m_grad_R_z[i], 1, grad_V_z, 1, output, 1, output, 1);
233 
234  e[i] = pFields[0]->Integral(output);
235  }
236 
237  // Exchange history data
238  // This could be improved to reduce communication but works for now
239  vComm->AllReduce(e, LibUtilities::ReduceSum);
240 
241  // Only the root process writes out electrogram data
242  if (vComm->GetRank() == 0)
243  {
244  m_outputStream.width(8);
245  m_outputStream << setprecision(6) << time;
246 
247  // Write data values point by point
248  for (i = 0; i < m_electrogramPoints.size(); ++i)
249  {
250  m_outputStream.width(25);
251  m_outputStream << setprecision(16) << e[i];
252  }
253  m_outputStream << endl;
254  }
255  }
256 
257 
258  /**
259  *
260  */
261  void FilterElectrogram::v_Finalise(const Array<OneD, const MultiRegions::ExpListSharedPtr> &pFields, const NekDouble &time)
262  {
263  if (pFields[0]->GetComm()->GetRank() == 0)
264  {
265  m_outputStream.close();
266  }
267  }
268 
269 
270  /**
271  *
272  */
274  {
275  return true;
276  }
277 }