openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
restitute.cc
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (c) NumeriCor GmbH
2 // SPDX-License-Identifier: LicenseRef-APL-1.1
3 
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include "restitute.h"
8 #include "ap_analyzer.h"
9 #include "sv_init.h"
10 
11 namespace limpet {
12 
14 
15 void get_protocol_definition(char *r_file, restitution *r, bool useS1S2);
16 int read_restitution_protocol_def(char *r_file, restitution *r);
17 
30 void restitution_trigger_list(char *r_file, restitution *r, char *protocol, int *n_dop, double **t_dop) {
31  // define protocol
32  get_protocol_definition(r_file, r, !strncmp("S1S2", protocol, 4));
33  if (!strcmp(protocol, "S1S2f") ) r->prtcl = S1S2_fast;
34  *n_dop = 0;
35 
36  // compute dependent parameters based on protocol definition
37  if (r->prtcl == S1S2) {
38  // S1-S2 protocol
39  int num_decs = (r->rtype.S1S2.S2_start-r->rtype.S1S2.S2_end)/r->rtype.S1S2.S2_dec;
40  int num_stim = r->numppBeats+num_decs*(r->rtype.S1S2.beats_per_S2+1);
41  r->trigs.lst = (double *)calloc(num_stim, sizeof(double));
42  if (r->trigs.lst == NULL) {
43  /* Memory could not be allocated, so print an error and exit. */
44  fprintf(stderr, "Couldn't allocate memory\n");
45  exit(EXIT_FAILURE);
46  }
47  r->trigs.pmat = (bool *)calloc(num_stim, sizeof(bool));
48 
49  // build trigger list for saving state vectors
50  r->saveState.lst = (double *)calloc(num_decs, sizeof(double));
51  r->saveState.pmat = NULL;
52 
53  int trgIdx = 0;
54  double trgTime = 1.0;
55  r->trigs.pmat[trgIdx] = false;
56  r->trigs.lst[trgIdx++] = trgTime;
57  for (int i = 1; i < r->numppBeats; i++) {
58  trgTime += r->rtype.S1S2.bcl;
59  r->trigs.pmat[trgIdx] = false;
60  r->trigs.lst[trgIdx++] = trgTime;
61  }
62 
63  for (int i = 0; i < num_decs; i++) {
64  for (int j = 0; j < r->rtype.S1S2.beats_per_S2; j++) {
65  trgTime += r->rtype.S1S2.bcl;
66  r->trigs.pmat[trgIdx] = false;
67  r->trigs.lst[trgIdx++] = trgTime;
68  }
69  trgTime += r->rtype.S1S2.S2_start-(i+1)*r->rtype.S1S2.S2_dec;
70  r->trigs.pmat[trgIdx] = true;
71  r->trigs.lst[trgIdx++] = trgTime;
72  r->saveState.lst[i] = trgTime;
73  }
74  r->trigs.n = trgIdx;
75  r->dur = trgTime + r->rtype.S1S2.bcl;
76  r->saveState.n = num_decs;
77  } else if (r->prtcl == S1S2_fast) {
78  // fast S1-S2 protocol, we save the state after S1's and only apply S2's
79  int num_decs = (r->rtype.S1S2.S2_start-r->rtype.S1S2.S2_end)/r->rtype.S1S2.S2_dec;
80  int num_stim = r->numppBeats-1+2*num_decs;
81  r->trigs.lst = (double *)calloc(num_stim, sizeof(double));
82  r->trigs.pmat = (bool *)calloc(num_stim, sizeof(bool) );
83 
84  // build trigger list for saving state vectors
85  r->saveState.lst = (double *)calloc(num_decs, sizeof(double));
86  r->saveState.pmat = NULL;
87 
88  int trgIdx = 0;
89  double trgTime = 1.0;
90  r->trigs.pmat[trgIdx] = false;
91  r->trigs.lst[trgIdx++] = trgTime;
92  for (int i = 1; i < r->numppBeats-1; i++) {
93  trgTime += r->rtype.S1S2.bcl;
94  r->trigs.pmat[trgIdx] = false;
95  r->trigs.lst[trgIdx++] = trgTime;
96  }
97 
98  for (int i = 0; i < num_decs; i++) {
99  trgTime += r->rtype.S1S2.bcl;
100  r->trigs.pmat[trgIdx] = false;
101  r->trigs.lst[trgIdx++] = trgTime;
102  trgTime += r->rtype.S1S2.S2_start-(i+1)*r->rtype.S1S2.S2_dec;
103  r->trigs.pmat[trgIdx] = true;
104  r->trigs.lst[trgIdx++] = trgTime;
105  r->saveState.lst[i] = trgTime;
106  }
107  r->trigs.n = trgIdx;
108  r->dur = trgTime + r->rtype.S1S2.bcl;
109  r->saveState.n = num_decs;
110 
111  *n_dop = num_decs;
112  *t_dop = static_cast<double *>(malloc(num_decs*sizeof(double)));
113  trgIdx = r->numppBeats-1;
114  for (int i = 0; i < num_decs; i++, trgIdx += 2)
115  (*t_dop)[i] = r->trigs.lst[trgIdx] - 1;
116  } else {
117  // dynamic protocol
118  int num_decs = (r->rtype.dyn.bcl_start-r->rtype.dyn.bcl_end)/r->rtype.dyn.bcl_dec;
119  int num_stim = r->numppBeats+num_decs*r->rtype.dyn.beats_per_bcl;
120  r->trigs.lst = (double *)calloc(num_stim, sizeof(double));
121  r->trigs.pmat = (bool *)calloc(num_stim, sizeof(bool));
122 
123  // build trigger list for saving state vectors
124  r->saveState.lst = (double *)calloc(num_decs, sizeof(double));
125  r->saveState.pmat = NULL;
126 
127  int trgIdx = 0;
128  double trgTime = 1.0;
129  r->trigs.pmat[trgIdx] = false;
130  r->trigs.lst[trgIdx++] = trgTime;
131  for (int i = 1; i < r->numppBeats; i++) {
132  trgTime += r->rtype.dyn.bcl_start;
133  r->trigs.pmat[trgIdx] = false;
134  r->trigs.lst[trgIdx++] = trgTime;
135  }
136 
137  for (int i = 0; i < num_decs; i++) {
138  for (int j = 0; j < r->rtype.dyn.beats_per_bcl; j++) {
139  trgTime += r->rtype.dyn.bcl_start-i*r->rtype.dyn.bcl_dec;
140  if ((i > 0) && (j == 0))
141  r->trigs.pmat[trgIdx] = true;
142  else
143  r->trigs.pmat[trgIdx] = false;
144  r->trigs.lst[trgIdx++] = trgTime;
145  }
146  r->saveState.lst[i] = trgTime;
147  }
148  r->trigs.n = trgIdx;
149  r->dur = trgTime + r->rtype.dyn.bcl_end;
150  r->saveState.n = num_decs;
151  }
152 } // restitution_trigger_list
153 
154 void get_protocol_definition(char *r_file, restitution *r, bool useS1S2) {
155  // file based
156  if (strcmp(r_file, "")) {
157  if (read_restitution_protocol_def(r_file, r)) {
158  log_msg(NULL, 0, 0, "\n\nError reading protocol definition from %s",r_file);
159  }
160  else {
161  // if specified protocol matches protocol in file we are done
162  if( (useS1S2&&r->prtcl==S1S2) || (!useS1S2&&r->prtcl==DYNAMIC) )
163  return;
164 
165  // file does not match, we don't use the protocol file and revert to defaults
166  log_msg(NULL, 3, 0, "Restitution protocol definition file does not match.\n");
167  log_msg(NULL, 3, 0, "Using default protocol definitions.\n");
168 
169  r->numppBeats = 20;
170  if (useS1S2) {
171  r->prtcl = S1S2;
172  r->rtype.S1S2.bcl = 1000;
173  r->rtype.S1S2.S2_start = 500;
174  r->rtype.S1S2.S2_end = 200;
175  r->rtype.S1S2.beats_per_S2 = 12;
176  r->rtype.S1S2.S2_dec = 10;
177  } else {
178  r->prtcl = DYNAMIC;
179  r->rtype.dyn.bcl_start = 400;
180  r->rtype.dyn.bcl_end = 200;
181  r->rtype.dyn.beats_per_bcl = 10;
182  r->rtype.dyn.bcl_dec = 10;
183  }
184  }
185  }
186 } // get_protocol_definition
187 
208  const int BUFSIZE = 256;
209  char buf[256];
210 
211  FILE *pdef = fopen(r_file, "rt");
212 
213  if (!pdef) return -1;
214 
215  // skip possible empty or comment lines
216  do {
217  fgets(buf, BUFSIZE, pdef);
218  } while ((*buf == '\n') || (*buf == '#'));
219 
220  int useS1S2;
221  sscanf(buf, "%d", &useS1S2);
222 
223  if (useS1S2) {
224  r->prtcl = S1S2;
225  sscanf(fgets(buf, BUFSIZE, pdef), "%d", &r->numppBeats);
226  if (r->numppBeats < CALIBRATION_BEAT) {
227  log_msg(NULL, 2, 0, "#prepacing beats %d < #calibration beats %d.",
229  log_msg(NULL, 2, 0, "This may bias the calibration of AP statistics parameters.");
230  }
231 
232  sscanf(fgets(buf, BUFSIZE, pdef), "%f", &r->rtype.S1S2.bcl);
233  sscanf(fgets(buf, BUFSIZE, pdef), "%f", &r->rtype.S1S2.S2_start);
234  sscanf(fgets(buf, BUFSIZE, pdef), "%f", &r->rtype.S1S2.S2_end);
235  sscanf(fgets(buf, BUFSIZE, pdef), "%d", &r->rtype.S1S2.beats_per_S2);
236  sscanf(fgets(buf, BUFSIZE, pdef), "%f", &r->rtype.S1S2.S2_dec);
237  } else {
238  r->prtcl = DYNAMIC;
239  sscanf(fgets(buf, BUFSIZE, pdef), "%d", &r->numppBeats);
240  sscanf(fgets(buf, BUFSIZE, pdef), "%f", &r->rtype.dyn.bcl_start);
241  sscanf(fgets(buf, BUFSIZE, pdef), "%f", &r->rtype.dyn.bcl_end);
242  sscanf(fgets(buf, BUFSIZE, pdef), "%d", &r->rtype.dyn.beats_per_bcl);
243  sscanf(fgets(buf, BUFSIZE, pdef), "%f", &r->rtype.dyn.bcl_dec);
244  }
245 
246  fclose(pdef);
247 
248  return 0;
249 } // read_restitution_protocol_def
250 
261  char save_name[1024];
262  static int cnt = 0;
263 
264  snprintf(save_name, sizeof save_name, "test_%d.sv", cnt++);
265  save_sv(miif, R1, save_name);
266 }
267 
268 } // namespace limpet
#define BUFSIZE
#define CALIBRATION_BEAT
Definition: ap_analyzer.h:14
#define log_msg(F, L, O,...)
Definition: filament.h:8
@ S1S2_fast
Definition: restitute.h:12
@ S1S2
Definition: restitute.h:12
@ DYNAMIC
Definition: restitute.h:12
int read_restitution_protocol_def(char *r_file, restitution *r)
Definition: restitute.cc:207
void get_protocol_definition(char *r_file, restitution *r, bool useS1S2)
Definition: restitute.cc:154
void restitution_trigger_list(char *r_file, restitution *r, char *protocol, int *n_dop, double **t_dop)
Definition: restitute.cc:30
void save_sv(MULTI_IF *, int, const char *)
void restitution_save_sv(MULTI_IF *miif, int R1, restitution *r, action_potential *AP)
Definition: restitute.cc:260
int n
number of pulses required for protocol
Definition: restitute.h:14
double * lst
store instants of pulse delivery
Definition: restitute.h:15
bool * pmat
store flag to indicate prematurity
Definition: restitute.h:16
float S2_start
bcl of first premature beat
Definition: restitute.h:21
float bcl
basic cycle length
Definition: restitute.h:20
float S2_end
bcl of last premature beat
Definition: restitute.h:22
float S2_dec
decrement for S2 beats
Definition: restitute.h:24
int beats_per_S2
number of beats before S2
Definition: restitute.h:23
int beats_per_bcl
number of beats for a particular bcl
Definition: restitute.h:30
float bcl_start
initial basic cycle length
Definition: restitute.h:28
float bcl_dec
decrement in bcl
Definition: restitute.h:31
float bcl_end
final basic cycle length
Definition: restitute.h:29
union limpet::restitution::@0 rtype
TrgList saveState
instants at wich we save state vectors
Definition: restitute.h:36
double dur
total duration of protocol
Definition: restitute.h:37
restitute_S1S2 S1S2
Definition: restitute.h:41
TrgList trigs
trigger list for defining stim sequence
Definition: restitute.h:35
r_prtcl prtcl
protocol type
Definition: restitute.h:38
restitute_dynamic dyn
Definition: restitute.h:42
int numppBeats
number of prepaced beats before protocol
Definition: restitute.h:39