openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
IGBextract.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 free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program. If not, see <https://www.gnu.org/licenses/>.
18 // ----------------------------------------------------------------------------
19 
20 
23 #include<stdlib.h>
24 #include<stdio.h>
25 #include<iostream>
26 #include "IGBheader.h"
27 #include <assert.h>
28 #include "ext_cmdline.h"
29 #include <vector>
30 #include <algorithm>
31 
32 using namespace std;
33 
50 bool
51 process_specifier( char *sp, vector<int> &nodes, int max )
52 {
53  int inc = 1;
54  if( strchr( sp, ':' ) ){
55  char *colptr = strchr( sp, ':' );
56  int consumed;
57  sscanf( colptr+1, "%d%n", &inc, &consumed );
58  if( !consumed || consumed!=strlen(colptr+1) ) {
59  fprintf( stderr, "Illegal range specified: %s\n", sp );
60  exit(1);
61  }
62  *colptr = '\0';
63  }
64 
65  if( !strcmp( "*", sp ) ) {
66  nodes.clear();
67  for( int i=0; i<max; i+=inc )
68  nodes.push_back(i);
69  return inc==1;
70  }
71 
72  if( strchr( sp, '-' ) ){
73  int s;
74  char fs[100];
75  int nr = sscanf( sp, "%d-%s", &s, fs );
76  if( nr<2 ) {
77  fprintf( stderr, "Illegal range specified: %s\n", sp );
78  exit(1);
79  }
80 
81  int f;
82  if( !strcmp(fs, "*") )
83  f = max-1;
84  else {
85  int consumed;
86  sscanf( fs, "%d%n", &f, &consumed );
87  if( consumed != strlen(fs) ) {
88  fprintf( stderr, "Illegal range specified: %s\n", sp );
89  exit(1);
90  }
91  }
92 
93  if( s<0 || f<s ) {
94  fprintf( stderr, "Illegal range specified: %s\n", sp );
95  exit(1);
96  }
97  for( int i=s; i<=f; i+=inc )
98  nodes.push_back( i );
99 
100  } else {
101 
102  int num;
103  sscanf( sp, "%d", &num );
104 
105  if( !sscanf( sp, "%d", &num ) || num<0 ) {
106  fprintf( stderr, "Illegal node number specified in list\n" );
107  exit(1);
108  }
109  nodes.push_back( num );
110  }
111  return false;
112 }
113 
114 
115 void
116 extract_nodes( const char *list, vector<int> &nodes, int max )
117 {
118  char *lc = strdup( list );
119  char *sp = strtok( lc, "," );
120  while( sp != NULL ) {
121 
122  if( process_specifier( sp, nodes, max ) ) return;
123 
124  sp = strtok( NULL, "," );
125  }
126  free( lc );
127 }
128 
129 
130 void
131 read_nodes( char *file, vector<int> &nodes, int max )
132 {
133  FILE *in = fopen( file, "r" );
134  if( in == NULL ) {
135  fprintf( stderr, "cannot open node list file\n" );
136  exit(1);
137  }
138 #define BUFSIZE 1024
139  char buf[BUFSIZE];
140  while( fgets( buf, BUFSIZE, in ) != NULL ) {
141  if( process_specifier( buf, nodes, max ) )
142  return;
143  }
144  fclose( in );
145 }
146 
147 
156 string
157 outfile( string specified, enum_format format, int s=-1 )
158 {
159  if( specified=="-" )
160  return specified.c_str();
161 
162  string ext;
163  switch( format ) {
164  case format_arg_binary:
165  case format_arg_asciiTm:
166  case format_arg_ascii:
167  case format_arg_ascii_1cpL:
168  case format_arg_ascii_1pL:
169  case format_arg_ascii_1pLn:
170  // no standard extension
171  break;
172  case format_arg_dat_t:
173  ext = ".dat_t";
174  break;
175  case format_arg_IGB:
176  ext = ".igb";
177  break;
178  default:
179  fprintf(stderr, "Unknown format '%d'\n", format);
180  }
181 
182  string slice;
183  if( s>=0 ) {
184  char paddedS[10];
185  snprintf(paddedS, sizeof paddedS, "_%05d", s);
186  slice = paddedS;
187  }
188 
189  // remove possible extension
190  if( specified.length()>ext.length() &&
191  specified.substr(specified.length()-ext.length()) == ext )
192  specified = specified.substr(0,specified.length()-ext.length());
193 
194  return specified + slice + ext;
195 }
196 
197 
209 void
210 output( vector<int> nodes, IGBheader *h, char *ofname,
211  enum_format of, int t0, int t1, int stride, bool explode, float scale)
212 {
213  IGBheader hout = *h;
214  FILE *out=NULL;
215  if( !strcmp(ofname, "-") )
216  out = stdout;
217  else if( !explode ) {
218  string out_fname = outfile(ofname, of);
219  out = fopen(out_fname.c_str(), "w");
220  if (!out) {
221  fprintf(stderr, "Can't open output file '%s'\n", out_fname.c_str());
222  exit(1);
223  }
224  }
225 
226  if (t1 >= h->t()) t1 = h->t()-1;
227  int tend = t1==-1? h->t()-1 : t1;
228 
229  hout.x( nodes.size() );
230  hout.y(1);
231  hout.z(1);
232  hout.t( explode ? 1 : (tend-t0)/stride+1 );
233  hout.org_t( h->org_t()+t0*h->inc_t() );
234  hout.inc_t(h->inc_t()*stride);
235  hout.dim_t( (t1-t0)*hout.inc_t() );
236  if( h->num_components()==3 )
237  hout.type( IGB_VEC3_f );
238  else if( h->num_components()==4 )
239  hout.type( IGB_VEC4_f );
240  else if( h->num_components()==9 )
241  hout.type( IGB_VEC9_f );
242  else
243  hout.type(IGB_FLOAT);
244 
245  if( of==format_arg_IGB ) {
246  hout.fileptr( out );
247  if( !explode ) hout.write();
248  }
249  const bool lessnodes = nodes.size() != (size_t) h->x();
250  std::vector<float> slice(h->slice_sz() * hout.num_components());
251  std::vector<float> slice_cropped(lessnodes ? nodes.size() * hout.num_components() : 0);
252  float * slice_ptr = slice.data();
253  float *output_slice = lessnodes ? slice_cropped.data() : slice_ptr;
254 
255  if( of==format_arg_dat_t )
256  fprintf( out, "%d\n", (tend-t0)/stride+1 );
257  else if( of==format_arg_ascii_1pLn )
258  fprintf( out, "%d\n", int(nodes.size()) );
259 
260  for( int t=t0; t<=tend; t+=stride ) {
261 
262  if( explode && out!=stdout ) {
263  string out_fname = outfile(ofname, of, t);
264  out = fopen(out_fname.c_str(), "w");
265  if( of==format_arg_IGB ) {
266  hout.fileptr(out);
267  hout.write();
268  }
269  }
270 
271  if( of==format_arg_dat_t )
272  fprintf(out, "%d\n", int(nodes.size()));
273 
274  h->go2slice(t);
275  h->read_data( slice_ptr );
276 
277  if( of== format_arg_asciiTm )
278  fprintf( out, "%f", h->org_t()+h->inc_t()*t );
279 
280  if(lessnodes) {
281  size_t cnt = 0;
282  for(const auto p : nodes)
283  for(size_t k=0; k < hout.num_components(); k++)
284  slice_cropped[cnt++] = slice[hout.num_components() * p + k];
285  }
286  std::for_each(output_slice, output_slice + nodes.size() * hout.num_components(), [scale](float & c){ c *= scale; });
287  switch(of) {
288  case format_arg_IGB:
289  case format_arg_binary:
290  fwrite(output_slice, sizeof(float), hout.slice_sz() * hout.num_components(), out );
291  break;
292  case format_arg_asciiTm:
293  {
294  size_t cnt=0;
295  for(size_t i = 0; i < nodes.size(); i++)
296  for(size_t k=0; k < hout.num_components(); k++)
297  fprintf(out, " %g", output_slice[cnt++]);
298  break;
299  }
300  case format_arg_ascii_1cpL:
301  {
302  size_t cnt=0;
303  for(size_t i = 0; i < nodes.size(); i++)
304  for(size_t k=0; k < hout.num_components(); k++)
305  fprintf(out, " %g\n", output_slice[cnt++]);
306  break;
307  }
308  case format_arg_ascii_1pL:
309  case format_arg_ascii_1pLn:
310  {
311  size_t cnt=0;
312  for(size_t i = 0; i < nodes.size(); i++) {
313  for(size_t k=0; k < hout.num_components(); k++)
314  fprintf(out, " %g", output_slice[cnt++]);
315  fputs("\n", out);
316  }
317  break;
318  }
319  case format_arg_ascii:
320  {
321  size_t cnt=0;
322  for(size_t i=0; i < nodes.size(); i++)
323  for(size_t k=0; k < hout.num_components(); k++)
324  fprintf(out, "%g ", output_slice[cnt++]);
325  break;
326  }
327  case format_arg_dat_t:
328  {
329  size_t cnt=0;
330  for(size_t i=0; i < nodes.size(); i++)
331  for(size_t k=0; k < hout.num_components(); k++)
332  fprintf(out, "%g\n", output_slice[cnt++]);
333  break;
334  }
335  default:
336  fprintf(stderr, "Unknown format '%d'\n", of);
337  }
338  if( of==format_arg_ascii || of==format_arg_asciiTm )
339  fprintf( out, "\n" );
340  if( explode && out!=stdout )
341  fclose(out);
342  }
343 
344  if( !explode && out != stdout )
345  fclose( out );
346 }
347 
348 
349 int
350 main( int argc, char *argv[] )
351 {
352  gengetopt_args_info args;
353 
354  // let's call our cmdline parser
355  if (cmdline_parser (argc, argv, &args) != 0)
356  exit(1);
357 
358  // the last arg must be a file name
359  gzFile in = ( !args.inputs_num || !strcmp(args.inputs[0],"-") ) ?
360  gzdopen( dup(0), "r" ): // duplicate stdin
361  gzopen( args.inputs[0], "r" );
362  if( in == NULL ) {
363  cerr << "File not found: " << args.inputs[0] << endl;
364  exit(1);
365  }
366  IGBheader header(in);
367  header.read(true);
368 
369  if( args.explode_flag && args.format_arg==format_arg_dat_t ) {
370  cerr << "Cannot explode into dat_t format" << endl;
371  exit(1);
372  }
373 
374  vector<int> nodes;
375  if( args.list_given )
376  extract_nodes( args.list_arg, nodes, header.slice_sz() );
377  else if( args.input_file_given )
378  read_nodes( args.input_file_arg, nodes, header.slice_sz() );
379  else // read them all
380  extract_nodes( "*", nodes, header.slice_sz() );
381 
382  for( auto p : nodes )
383  if( header.slice_sz() <= p ) {
384  cerr << "Error: out of range nodes requested" << endl;
385  exit(1);
386  }
387 
388  int f0=args.f0_arg, f1=args.f1_arg;
389  if( args.t0_given )
390  f0 = std::round((args.t0_arg-header.org_t())/header.inc_t());
391  if( f0<0 || f0>=header.t() ) {
392  cerr << "Illegal ending frame specified: "<<f0<<" not in [0,"<<header.t()<<")"<< endl;
393  exit(1);
394  }
395  if( args.t1_given )
396  f1 = args.t1_arg==-1 ? header.t()-1 : std::round((args.t1_arg-header.org_t())/header.inc_t());
397  if( f1>=0 && f1<f0 ) {
398  cerr << "Illegal ending frame specified: "<<f1<<" not in ["<<f0<<","<<header.t()<<")"<< endl;
399  exit(1);
400  }
401 
402  output(nodes, &header, args.output_file_arg,args.format_arg,
403  f0, f1, args.df_arg, args.explode_flag, args.scale_arg );
404 
405  cmdline_parser_free(&args);
406 }
void extract_nodes(const char *list, vector< int > &nodes, int max)
Definition: IGBextract.cc:116
int main(int argc, char *argv[])
Definition: IGBextract.cc:350
string outfile(string specified, enum_format format, int s=-1)
Definition: IGBextract.cc:157
bool process_specifier(char *sp, vector< int > &nodes, int max)
Definition: IGBextract.cc:51
void read_nodes(char *file, vector< int > &nodes, int max)
Definition: IGBextract.cc:131
#define BUFSIZE
void output(vector< int > nodes, IGBheader *h, char *ofname, enum_format of, int t0, int t1, int stride, bool explode, float scale)
Definition: IGBextract.cc:210
int read(bool quiet=false)
Definition: IGBheader.cc:757
float org_t(void)
Definition: IGBheader.h:317
void dim_t(float a)
Definition: IGBheader.h:341
size_t x(void)
Definition: IGBheader.h:268
int type(void)
Definition: IGBheader.h:280
unsigned short num_components()
Definition: IGBheader.h:378
size_t t(void)
Definition: IGBheader.h:277
int read_data(T *dp, size_t numt=1, char *buf=NULL)
Definition: IGBheader.h:432
size_t y(void)
Definition: IGBheader.h:271
void fileptr(gzFile f)
Definition: IGBheader.cc:329
int write()
Definition: IGBheader.cc:343
size_t z(void)
Definition: IGBheader.h:274
size_t slice_sz()
Definition: IGBheader.h:263
void inc_t(float a)
Definition: IGBheader.h:329
int go2slice(size_t s)
go to a slice
Definition: IGBheader.cc:1459
constexpr T max(T a, T b)
Definition: ion_type.h:31
#define IGB_VEC9_f
Definition: IGBheader.h:76
#define IGB_VEC3_f
Definition: IGBheader.h:71
#define IGB_FLOAT
Definition: IGBheader.h:60
#define IGB_VEC4_f
Definition: IGBheader.h:73