openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
restitute.cc
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // openCARP is an open cardiac electrophysiology simulator.
3 //
4 // Copyright (C) 2020 openCARP project
5 //
6 // This program is licensed under the openCARP Academic Public License (APL)
7 // v1.0: You can use and redistribute it and/or modify it in non-commercial
8 // academic environments under the terms of APL as published by the openCARP
9 // project v1.0, or (at your option) any later version. Commercial use requires
10 // a commercial license (info@opencarp.org).
11 //
12 // This program is distributed without any warranty; see the openCARP APL for
13 // more details.
14 //
15 // You should have received a copy of the openCARP APL along with this program
16 // and can find it online: http://www.opencarp.org/license
17 // ----------------------------------------------------------------------------
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include "restitute.h"
23 #include "ap_analyzer.h"
24 #include "sv_init.h"
25 
26 namespace limpet {
27 
29 
30 void get_protocol_definition(char *r_file, restitution *r, bool useS1S2);
31 int read_restitution_protocol_def(char *r_file, restitution *r);
32 
45 void restitution_trigger_list(char *r_file, restitution *r, char *protocol, int *n_dop, double **t_dop) {
46  // define protocol
47  get_protocol_definition(r_file, r, !strncmp("S1S2", protocol, 4));
48  if (!strcmp(protocol, "S1S2f") ) r->prtcl = S1S2_fast;
49  *n_dop = 0;
50 
51  // compute dependent parameters based on protocol definition
52  if (r->prtcl == S1S2) {
53  // S1-S2 protocol
54  int num_decs = (r->rtype.S1S2.S2_start-r->rtype.S1S2.S2_end)/r->rtype.S1S2.S2_dec;
55  int num_stim = r->numppBeats+num_decs*(r->rtype.S1S2.beats_per_S2+1);
56  r->trigs.lst = (double *)calloc(num_stim, sizeof(double));
57  if (r->trigs.lst == NULL) {
58  /* Memory could not be allocated, so print an error and exit. */
59  fprintf(stderr, "Couldn't allocate memory\n");
60  exit(EXIT_FAILURE);
61  }
62  r->trigs.pmat = (bool *)calloc(num_stim, sizeof(bool));
63 
64  // build trigger list for saving state vectors
65  r->saveState.lst = (double *)calloc(num_decs, sizeof(double));
66  r->saveState.pmat = NULL;
67 
68  int trgIdx = 0;
69  double trgTime = 1.0;
70  r->trigs.pmat[trgIdx] = false;
71  r->trigs.lst[trgIdx++] = trgTime;
72  for (int i = 1; i < r->numppBeats; i++) {
73  trgTime += r->rtype.S1S2.bcl;
74  r->trigs.pmat[trgIdx] = false;
75  r->trigs.lst[trgIdx++] = trgTime;
76  }
77 
78  for (int i = 0; i < num_decs; i++) {
79  for (int j = 0; j < r->rtype.S1S2.beats_per_S2; j++) {
80  trgTime += r->rtype.S1S2.bcl;
81  r->trigs.pmat[trgIdx] = false;
82  r->trigs.lst[trgIdx++] = trgTime;
83  }
84  trgTime += r->rtype.S1S2.S2_start-(i+1)*r->rtype.S1S2.S2_dec;
85  r->trigs.pmat[trgIdx] = true;
86  r->trigs.lst[trgIdx++] = trgTime;
87  r->saveState.lst[i] = trgTime;
88  }
89  r->trigs.n = trgIdx;
90  r->dur = trgTime + r->rtype.S1S2.bcl;
91  r->saveState.n = num_decs;
92  } else if (r->prtcl == S1S2_fast) {
93  // fast S1-S2 protocol, we save the state after S1's and only apply S2's
94  int num_decs = (r->rtype.S1S2.S2_start-r->rtype.S1S2.S2_end)/r->rtype.S1S2.S2_dec;
95  int num_stim = r->numppBeats-1+2*num_decs;
96  r->trigs.lst = (double *)calloc(num_stim, sizeof(double));
97  r->trigs.pmat = (bool *)calloc(num_stim, sizeof(bool) );
98 
99  // build trigger list for saving state vectors
100  r->saveState.lst = (double *)calloc(num_decs, sizeof(double));
101  r->saveState.pmat = NULL;
102 
103  int trgIdx = 0;
104  double trgTime = 1.0;
105  r->trigs.pmat[trgIdx] = false;
106  r->trigs.lst[trgIdx++] = trgTime;
107  for (int i = 1; i < r->numppBeats-1; i++) {
108  trgTime += r->rtype.S1S2.bcl;
109  r->trigs.pmat[trgIdx] = false;
110  r->trigs.lst[trgIdx++] = trgTime;
111  }
112 
113  for (int i = 0; i < num_decs; i++) {
114  trgTime += r->rtype.S1S2.bcl;
115  r->trigs.pmat[trgIdx] = false;
116  r->trigs.lst[trgIdx++] = trgTime;
117  trgTime += r->rtype.S1S2.S2_start-(i+1)*r->rtype.S1S2.S2_dec;
118  r->trigs.pmat[trgIdx] = true;
119  r->trigs.lst[trgIdx++] = trgTime;
120  r->saveState.lst[i] = trgTime;
121  }
122  r->trigs.n = trgIdx;
123  r->dur = trgTime + r->rtype.S1S2.bcl;
124  r->saveState.n = num_decs;
125 
126  *n_dop = num_decs;
127  *t_dop = static_cast<double *>(malloc(num_decs*sizeof(double)));
128  trgIdx = r->numppBeats-1;
129  for (int i = 0; i < num_decs; i++, trgIdx += 2)
130  (*t_dop)[i] = r->trigs.lst[trgIdx] - 1;
131  } else {
132  // dynamic protocol
133  int num_decs = (r->rtype.dyn.bcl_start-r->rtype.dyn.bcl_end)/r->rtype.dyn.bcl_dec;
134  int num_stim = r->numppBeats+num_decs*r->rtype.dyn.beats_per_bcl;
135  r->trigs.lst = (double *)calloc(num_stim, sizeof(double));
136  r->trigs.pmat = (bool *)calloc(num_stim, sizeof(bool));
137 
138  // build trigger list for saving state vectors
139  r->saveState.lst = (double *)calloc(num_decs, sizeof(double));
140  r->saveState.pmat = NULL;
141 
142  int trgIdx = 0;
143  double trgTime = 1.0;
144  r->trigs.pmat[trgIdx] = false;
145  r->trigs.lst[trgIdx++] = trgTime;
146  for (int i = 1; i < r->numppBeats; i++) {
147  trgTime += r->rtype.dyn.bcl_start;
148  r->trigs.pmat[trgIdx] = false;
149  r->trigs.lst[trgIdx++] = trgTime;
150  }
151 
152  for (int i = 0; i < num_decs; i++) {
153  for (int j = 0; j < r->rtype.dyn.beats_per_bcl; j++) {
154  trgTime += r->rtype.dyn.bcl_start-i*r->rtype.dyn.bcl_dec;
155  if ((i > 0) && (j == 0))
156  r->trigs.pmat[trgIdx] = true;
157  else
158  r->trigs.pmat[trgIdx] = false;
159  r->trigs.lst[trgIdx++] = trgTime;
160  }
161  r->saveState.lst[i] = trgTime;
162  }
163  r->trigs.n = trgIdx;
164  r->dur = trgTime + r->rtype.dyn.bcl_end;
165  r->saveState.n = num_decs;
166  }
167 } // restitution_trigger_list
168 
169 void get_protocol_definition(char *r_file, restitution *r, bool useS1S2) {
170  // file based
171  if (strcmp(r_file, "")) {
172  if (read_restitution_protocol_def(r_file, r)) {
173  log_msg(NULL, 0, 0, "\n\nError reading protocol definition from %s",r_file);
174  }
175  else {
176  // if specified protocol matches protocol in file we are done
177  if( (useS1S2&&r->prtcl==S1S2) || (!useS1S2&&r->prtcl==DYNAMIC) )
178  return;
179 
180  // file does not match, we don't use the protocol file and revert to defaults
181  log_msg(NULL, 3, 0, "Restitution protocol definition file does not match.\n");
182  log_msg(NULL, 3, 0, "Using default protocol definitions.\n");
183 
184  r->numppBeats = 20;
185  if (useS1S2) {
186  r->prtcl = S1S2;
187  r->rtype.S1S2.bcl = 1000;
188  r->rtype.S1S2.S2_start = 500;
189  r->rtype.S1S2.S2_end = 200;
190  r->rtype.S1S2.beats_per_S2 = 12;
191  r->rtype.S1S2.S2_dec = 10;
192  } else {
193  r->prtcl = DYNAMIC;
194  r->rtype.dyn.bcl_start = 400;
195  r->rtype.dyn.bcl_end = 200;
196  r->rtype.dyn.beats_per_bcl = 10;
197  r->rtype.dyn.bcl_dec = 10;
198  }
199  }
200  }
201 } // get_protocol_definition
202 
223  const int BUFSIZE = 256;
224  char buf[256];
225 
226  FILE *pdef = fopen(r_file, "rt");
227 
228  if (!pdef) return -1;
229 
230  // skip possible empty or comment lines
231  do {
232  fgets(buf, BUFSIZE, pdef);
233  } while ((*buf == '\n') || (*buf == '#'));
234 
235  int useS1S2;
236  sscanf(buf, "%d", &useS1S2);
237 
238  if (useS1S2) {
239  r->prtcl = S1S2;
240  sscanf(fgets(buf, BUFSIZE, pdef), "%d", &r->numppBeats);
241  if (r->numppBeats < CALIBRATION_BEAT) {
242  log_msg(NULL, 2, 0, "#prepacing beats %d < #calibration beats %d.",
244  log_msg(NULL, 2, 0, "This may bias the calibration of AP statistics parameters.");
245  }
246 
247  sscanf(fgets(buf, BUFSIZE, pdef), "%f", &r->rtype.S1S2.bcl);
248  sscanf(fgets(buf, BUFSIZE, pdef), "%f", &r->rtype.S1S2.S2_start);
249  sscanf(fgets(buf, BUFSIZE, pdef), "%f", &r->rtype.S1S2.S2_end);
250  sscanf(fgets(buf, BUFSIZE, pdef), "%d", &r->rtype.S1S2.beats_per_S2);
251  sscanf(fgets(buf, BUFSIZE, pdef), "%f", &r->rtype.S1S2.S2_dec);
252  } else {
253  r->prtcl = DYNAMIC;
254  sscanf(fgets(buf, BUFSIZE, pdef), "%d", &r->numppBeats);
255  sscanf(fgets(buf, BUFSIZE, pdef), "%f", &r->rtype.dyn.bcl_start);
256  sscanf(fgets(buf, BUFSIZE, pdef), "%f", &r->rtype.dyn.bcl_end);
257  sscanf(fgets(buf, BUFSIZE, pdef), "%d", &r->rtype.dyn.beats_per_bcl);
258  sscanf(fgets(buf, BUFSIZE, pdef), "%f", &r->rtype.dyn.bcl_dec);
259  }
260 
261  fclose(pdef);
262 
263  return 0;
264 } // read_restitution_protocol_def
265 
276  char save_name[1024];
277  static int cnt = 0;
278 
279  snprintf(save_name, sizeof save_name, "test_%d.sv", cnt++);
280  save_sv(miif, R1, save_name);
281 }
282 
283 } // namespace limpet
void restitution_trigger_list(char *r_file, restitution *r, char *protocol, int *n_dop, double **t_dop)
Definition: restitute.cc:45
TrgList trigs
trigger list for defining stim sequence
Definition: restitute.h:50
float bcl_dec
decrement in bcl
Definition: restitute.h:46
r_prtcl prtcl
protocol type
Definition: restitute.h:53
float S2_dec
decrement for S2 beats
Definition: restitute.h:39
void save_sv(MULTI_IF *, int, const char *)
#define BUFSIZE
void get_protocol_definition(char *r_file, restitution *r, bool useS1S2)
Definition: restitute.cc:169
TrgList saveState
instants at wich we save state vectors
Definition: restitute.h:51
int n
number of pulses required for protocol
Definition: restitute.h:29
union limpet::restitution::@0 rtype
int read_restitution_protocol_def(char *r_file, restitution *r)
Definition: restitute.cc:222
float bcl
basic cycle length
Definition: restitute.h:35
float bcl_end
final basic cycle length
Definition: restitute.h:44
#define CALIBRATION_BEAT
Definition: ap_analyzer.h:29
double * lst
store instants of pulse delivery
Definition: restitute.h:30
int beats_per_bcl
number of beats for a particular bcl
Definition: restitute.h:45
float S2_end
bcl of last premature beat
Definition: restitute.h:37
void restitution_save_sv(MULTI_IF *miif, int R1, restitution *r, action_potential *AP)
Definition: restitute.cc:275
float S2_start
bcl of first premature beat
Definition: restitute.h:36
restitute_S1S2 S1S2
Definition: restitute.h:56
restitute_dynamic dyn
Definition: restitute.h:57
void log_msg(FILE_SPEC out, int level, unsigned char flag, const char *fmt,...)
Definition: basics.cc:72
float bcl_start
initial basic cycle length
Definition: restitute.h:43
double dur
total duration of protocol
Definition: restitute.h:52
int beats_per_S2
number of beats before S2
Definition: restitute.h:38
bool * pmat
store flag to indicate prematurity
Definition: restitute.h:31
int numppBeats
number of prepaced beats before protocol
Definition: restitute.h:54