openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
IGBops.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 
52 #include<stdlib.h>
53 #include<stdio.h>
54 #include<unistd.h>
55 #include<iostream>
56 #include "IGBheader.h"
57 #include <assert.h>
58 #include "ops_cmdline.h"
59 #include <vector>
60 #include "muParser.h"
61 #ifdef _OPENMP
62 #include <omp.h>
63 #endif
64 
65 const int MAX_NC=4;
66 
67 using namespace std;
68 
70 
74 class Interp {
75  public:
76  Interp( char *ind, char *weight );
77  int size() { return ind.size(); }
78  vector<float*>w;
79  vector<int*>ind;
80  int n=0;
81 };
82 
89 Interp::Interp( char *indf, char *wf )
90 {
91  char buf[8192];
92  FILE *iin = fopen( indf, "r" );
93  while( fgets( buf, 8192, iin )!=NULL ) {
94  if( !n ) {
95  char *l1 = strdup(buf);
96  char *ptr = strtok( l1, " " );
97  while((ptr=strtok( NULL, " " ))) n++;
98  free(l1);
99  }
100  int *ip = new int[n];
101  istringstream oss( buf );
102  for( int i=0; i<n; i++ )
103  oss>>ip[i];
104  ind.push_back(ip);
105  }
106  FILE *win = fopen( wf, "r" );
107  for( int i=0; i<ind.size(); i++ ) {
108  fgets( buf, 8192, win );
109  float *wp = new float[n];
110  istringstream oss( buf );
111  for( int j=0; j<n; j++ )
112  oss >> wp[j];
113  w.push_back( wp );
114  }
115 }
116 
117 
118 
119 #define data_t float
121 
122 void output_scratch( data_t* s, FILE *out, int n, bool bin );
123 void output_scratch( vector<data_t>& s, FILE *out, bool bin );
124 
125 
126 bool overlap(IGBheader *first, IGBheader *second )
127 {
128  return fabs(second->org_t() - (first->org_t()+(first->t()-1)*first->inc_t()) ) < first->inc_t()/2.;
129 }
130 
131 
132 // concatenate X and Y in time
133 void joinXY( IGBheader *h1, IGBheader *h2, IGBheader *hout )
134 {
135  if( h2==NULL ) {
136  fprintf( stderr, "Y must be an IGB file\n\n" );
137  exit(1);
138  }
139 
140  gzFile in1 = (gzFile)(h1->fileptr());
141  gzFile in2 = (gzFile)(h2->fileptr());
142  FILE* out = (FILE *)(hout->fileptr());
143 
144  std::vector<data_t> dat1(hout->slice_sz() * hout->num_components());
145  for( int i=0; i<h1->t(); i++ ) {
146  h1->read_data( dat1.data() );
147  fwrite( dat1.data(), sizeof(data_t), hout->slice_sz() * hout->num_components(), out );
148  }
149 
150  bool skip_second_torg = overlap( h1, h2 );
151  for( int i=0; i<h2->t(); i++ ) {
152  h2->read_data( dat1.data() );
153  if(skip_second_torg)
154  skip_second_torg = false;
155  else
156  fwrite( dat1.data(), sizeof(data_t), hout->slice_sz() * hout->num_components(), out );
157  }
158  fclose(out);
159 }
160 
161 // put Y beside X
162 void join_space( data_t *x, int nx, data_t *y, int ny, FILE *out )
163 {
164  fwrite( x, sizeof(data_t), nx, out );
165  fwrite( y, sizeof(data_t), ny, out );
166 }
167 
168 
169 // evaluate arbitrary expression for one file
170 void eval_expr( data_t *x, int n, char *expr, FILE *out, data_t *result )
171 {
172  using namespace mu;
173 
174  static Parser hParser;
175  static bool init=false;
176 
177  if( !init ) {
178  hParser.DefineVar( "X", x );
179  hParser.SetExpr(expr);
180  init = true;
181  }
182  try {
183  hParser.Eval(result, n);
184  }
185  catch (Parser::exception_type &e)
186  {
187  std::cerr << e.GetMsg() << std::endl;
188  exit(1);
189  }
190  output_scratch( result, out, n, true );
191 }
192 
193 
194 // evaluate arbitrary expression as function of two files
195 // nc>0 means that x1 is a point
206 template<class T>
207 void eval_expr( data_t *x0, T* x1, int n, char *expr, FILE *out, int nc=0 )
208 {
209  using namespace mu;
210 
211  Parser hParser;
212  data_t a, b;
213  hParser.DefineVar( "X", &a );
214  hParser.DefineVar( "Y", &b );
215  hParser.SetExpr(expr);
216 
217  data_t *y = new data_t[n];
218 
219  for( int i=0; i<n; i++ ) {
220  try {
221  a = x0[i];
222  b = x1[nc>0 ? i%nc : i];
223  y[i] = hParser.Eval();
224  }
225  catch (Parser::exception_type &e)
226  {
227  std::cerr << e.GetMsg() << std::endl;
228  exit(1);
229  }
230  }
231  output_scratch( y, out, n, true );
232  delete[] y;
233 }
234 
235 
236 // central difference
237 void center_diff( data_t* x, int slsz, vector<data_t>& odat, int t, float dt, FILE *out)
238 {
239  int older= (t%2) ? 0 : slsz;
240  int old = older ? 0 : slsz;
241 
242  if( t==1 ) { // forward difference for first frame
243  for(int i=0;i<slsz;i++){
244  data_t d = (x[i]-odat[old+i])/dt;
245  fwrite( &d, sizeof(data_t), 1, out );
246  }
247  } else if( t>1 ) {
248  for(int i=0;i<slsz;i++){
249  data_t d = (x[i]-odat[older+i])/dt/2.;
250  fwrite( &d, sizeof(data_t), 1, out );
251  }
252  }
253  for(int i=0;i<slsz;i++)
254  odat[older+i] = x[i];
255 }
256 
257 
258 // forward difference
259 void forward_diff( data_t* x, int slsz, vector<data_t>& old, int t, float dt, FILE *out)
260 {
261  for(int i=0;i<slsz;i++){
262  if( t ) {
263  data_t d = (x[i]-old[i])/dt;
264  fwrite( &d, sizeof(data_t), 1, out );
265  }
266  old[i] = x[i];
267  }
268 }
269 
270 
271 // aX[i] + bY[i%nc]
272 void aXPLUS_bY( data_t* x, data_t *y, data_t a, data_t b, int slsz, int nc, FILE *out)
273 {
274  for(int i=0;i<slsz;i++){
275  data_t datum = x[i]*a + b*y[i%nc];
276  fwrite( &datum, sizeof(data_t), 1, out );
277  }
278 }
279 
280 // aX[i] + bY[i]
281 template<class T>
282 void aXPLUS_bY( data_t* x, T* y, data_t a, data_t b, int slsz, FILE *out)
283 {
284  for(int i=0;i<slsz;i++){
285  data_t datum = x[i]*a + b*y[i];
286  fwrite( &datum, sizeof(data_t), 1, out );
287  }
288 }
289 
290 // avgX[*,t]
291 void avgXt( data_t* x, int slsz, int nc, float t, FILE *out)
292 {
293  data_t sumf[MAX_NC];
294  for( int c=0; c<nc; c++ ) {
295  double s=0;
296 #pragma omp parallel for reduction( +:s )
297  for(int i=c;i<slsz;i+=nc)
298  s += x[i];
299  sumf[c] = s/double(slsz);
300  }
301  fwrite( &sumf, sizeof(sumf[0]), nc, out );
302 }
303 
304 
305 // avgX[i,*]
306 void avgXi( data_t* x, vector<data_t>& sum, const data_t fac)
307 {
308 #pragma omp parallel for
309  for(int i=0; i<sum.size(); i++){
310  sum[i] += fac * x[i];
311  }
312 }
313 
314 void varXi( data_t* x, data_t* mean, vector<data_t>& sum, const data_t fac)
315 {
316 #pragma omp parallel for
317  for(int i=0; i<sum.size(); i++){
318  sum[i] += fac * (x[i] - mean[i]) * (x[i] - mean[i]);
319  }
320 }
321 
322 // aX[i,t]+b
323 void aXPLUS_b( data_t* x, data_t a, data_t b, int slsz, FILE *out)
324 {
325  for(int i=0;i<slsz;i++){
326  data_t datum = x[i]*a+b;
327  fwrite( &datum, sizeof(data_t), 1, out );
328  }
329 }
330 
331 // X[i]/Y[i]
332 void XdivY( data_t* x, data_t* y, int slsz, FILE *out)
333 {
334  bool NAN_FLAG = 0;
335  bool INF_FLAG = 0;
336 
337  for(int i=0;i<slsz;i++){
338  data_t datum = x[i]/y[i];
339  if (std::isinf(datum)) {
340  datum = 0.; // handle infinite numbers
341  INF_FLAG = 1;
342  }
343  if (std::isnan(datum)){
344  datum = 0.; // handle not a number
345  NAN_FLAG = 1;
346  }
347  fwrite( &datum, sizeof(data_t), 1, out );
348  }
349  if (INF_FLAG) std::cout << "Infinite number(s) detected (and set to zero)" << endl;
350  if (NAN_FLAG) std::cout << "NaN(s) detected (and set to zero)" << endl;
351 }
352 
353 
354 // X[i]/Y[0]
355 void XdivY( data_t* x, data_t* y, int slsz, int nc, FILE *out)
356 {
357  bool NAN_FLAG = 0;
358  bool INF_FLAG = 0;
359 
360  for(int i=0;i<slsz;i++){
361  data_t datum = x[i]/y[i%nc];
362  if (std::isinf(datum)) {
363  datum = 0.; // handle infinite numbers
364  INF_FLAG = 1;
365  }
366  if (std::isnan(datum)){
367  datum = 0.; // handle not a number
368  NAN_FLAG = 1;
369  }
370  fwrite( &datum, sizeof(datum), 1, out );
371  }
372  if (INF_FLAG) std::cout << "Infinite number(s) detected (and set to zero)" << endl;
373  if (NAN_FLAG) std::cout << "NaN(s) detected (and set to zero)" << endl;
374 }
375 
376 // X[i]*Y[i]
377 void XmulY( data_t* x, data_t* y, int slsz, FILE *out)
378 {
379  for(int i=0;i<slsz;i++){
380  data_t datum = x[i]*y[i];
381  fwrite( &datum, sizeof(data_t), 1, out );
382  }
383 }
384 
385 // X[i]*Y[0]
386 void XmulY( data_t* x, data_t* y, int slsz, int nc, FILE *out)
387 {
388  for(int i=0;i<slsz;i++){
389  data_t datum = x[i]*y[i%nc];
390  fwrite( &datum, sizeof(datum), 1, out );
391  }
392 }
393 
394 // MIN_i( X[i,t] )
395 void minXt( data_t* x, int slsz, int nc, float t, FILE *out )
396 {
397  data_t min[MAX_NC];
398  for( int i=0; i<nc; i++ ) min[i]=x[i];
399 #pragma omp parallel for
400  for(int i=nc;i<slsz*nc;i++){
401  if( x[i]<min[i%nc] )
402  min[i%nc] = x[i];
403  }
404  fwrite( min, sizeof(data_t), nc, out );
405 }
406 
407 
408 // MAX_t( X[i,t] )
409 void maxXi( data_t* x, data_t* mx, size_t n )
410 {
411 #pragma omp parallel for
412  for( int i=0; i<n; i++ ){
413  if( x[i]>mx[i] )
414  mx[i] = x[i];
415  }
416 }
417 
418 
419 // MIN_t( X[i,t] )
420 void minXi( data_t* x, data_t* mn, size_t n )
421 {
422 #pragma omp parallel for
423  for( int i=0; i<n; i++ ){
424  if( x[i]<mn[i] )
425  mn[i] = x[i];
426  }
427 }
428 
429 
430 // MAX_i( X[i,t] )
431 void maxXt( data_t* x, int slsz, int nc, float t, FILE *out )
432 {
433  data_t max[MAX_NC];
434  for( int i=0; i<nc; i++ ) max[i]=x[i];
435 #pragma omp parallel for
436  for(int i=nc;i<slsz*nc;i++){
437  if( x[i]>max[i%nc] )
438  max[i%nc] = x[i];
439  }
440  fwrite( max, sizeof(data_t), nc, out );
441 }
442 
443 // X[i,t]+a
444 void XPLUS_a( data_t* x, data_t a, int slsz, FILE *out )
445 {
446  for(int i=0;i<slsz;i++){
447  data_t datum = x[i]+a;
448  fwrite( &datum, sizeof(data_t), 1, out );
449  }
450 }
451 
452 
453 // apply a simple box filter to the xXy grid where the center pixel
454 // is the average of the enclosing dXd square, do not filter edges
455 void Xbox( data_t *dat, int x, int y, FILE *out, int d, int nc )
456 {
457  assert(nc==1);
458 
459  int fm = d/2,
460  fp = d - 1 - fm;
461  float area = d*d;
462  for( int j=0; j<y; j++ )
463  for( int i=0; i<x; i++ ) {
464  data_t datum = 0;
465  if( j<fm || j>y-fp-1 || i<fm || i>x-fp-1 )
466  datum = dat[j*x+i];
467  else {
468  for( int m=j-fm; m<=j+fp; m++ )
469  for( int n=i-fm; n<=i+fp; n++ )
470  datum += dat[m*x+n];
471  datum /= area;
472  }
473  fwrite( &datum, sizeof(data_t), 1, out );
474  }
475 }
476 
477 
478 // soft clipping: remove offending point and interpolate
479 void sclip_ab( data_t *dat, int sz, data_t upper, data_t lower, vector<data_t>& scr, int t,
480  int tfinal, FILE *out )
481 {
482  unsigned int curr = (t%3)*sz;
483  unsigned int old = (curr+2*sz)%(3*sz);
484  unsigned int older = (curr+sz)%(3*sz);
485 
486  memcpy( scr.data()+curr, dat, sizeof(data_t)*sz );
487 
488  if( !t )
489  fwrite( dat, sizeof(data_t), sz, out );
490 
491  if( t>1 ) {
492  for( int i=0; i<sz; i++ )
493  if( scr[old+i]>upper || scr[old+i]<lower ) {
494  if( scr[curr+i]>upper || scr[curr+i]<lower )
495  scr[old+i] = scr[older+i];
496  else
497  scr[old+i] = (scr[older+i]+scr[curr+i])/2.;
498  }
499  fwrite( scr.data()+old, sizeof(data_t), sz, out );
500  }
501 
502  if( t==tfinal-1 )
503  fwrite( dat, sizeof(data_t), sz, out );
504 }
505 
506 
514 void
515 magnitude( data_t* x, int n, int nc, FILE *out)
516 {
517  for(int i=0; i<n; i+=nc){
518  data_t mag = 0;
519  for( int j=0; j<nc; j++ )
520  mag += x[i+j]*x[i+j];
521  mag = sqrt( mag );
522  fwrite( &mag, sizeof(mag), 1, out );
523  }
524 }
525 
535 void
536 dot( data_t* x, data_t *y, int n, int nc, FILE *out, bool pt)
537 {
538  int k = !pt;
539  for(int i=0; i<n; i+=nc){
540  data_t dot = 0;
541  for( int j=0; j<nc; j++ )
542  dot += x[i+j]*y[k*i+j];
543  fwrite( &dot, sizeof(dot), 1, out );
544  }
545 }
546 
555 template<class T>
556 void
557 simp38( T *x, int n, int t, data_t *runInt )
558 {
559  int s=t%3;
560  T scale;
561 
562  if( t<0 )
563  scale = 3./8.;
564  else if( s==0 )
565  scale = 3./4.;
566  else if( s==1 || s==2 )
567  scale = 9./8.;
568 
569 #pragma omp parallel for
570  for( int i=0; i<n; i++ )
571  runInt[i] += x[i]*scale;
572 }
573 
574 
577 template<class T>
578 void
579 midpt( T *x, int n, bool end, data_t *reduce )
580 {
581 #pragma omp parallel for
582  for( int i=0; i<n; i++ )
583  if( end )
584  reduce[i] += x[i]/2.;
585  else
586  reduce[i] += x[i];
587 }
588 
589 
600 void
601 interpolate( data_t *dat, vector<int*>&idx, vector<float*>& w, int n, FILE *out )
602 {
603  for( int i=0; i<idx.size(); i++ ) {
604  data_t datum=0.;
605  for( int j=0; j<n; j++ )
606  datum += dat[idx[i][j]]*w[i][j];
607  fwrite( &datum, sizeof(data_t), 1, out );
608  }
609 }
610 
611 
620 template<class T>
621 void
622 normalize( IGBheader *h, FILE *out, T *min, T* max )
623 {
624  size_t slice_mem = h->slice_sz()*h->num_components();
625  h->go2slice(0);
626  vector<data_t> slice( slice_mem );
627 
628  for( int t=0; t< h->t(); t++ ) {
629  h->read_data( slice.data() );
630  for( int j=0; j<slice_mem; j++ ){
631  data_t datum = (slice[j]-min[j])/(max[j]-min[j]);
632  fwrite( &datum, sizeof(data_t), 1, out );
633  }
634  }
635 }
636 
637 
652 void
653 maxP2P( data_t* dat, data_t* big, data_t* maxpp, int sz, int t )
654 {
655  data_t *old = big;
656  data_t *change = big+sz;
657  data_t *extrem = big+2*sz;
658 
659  if( !t ) memcpy( old, dat, sizeof(data_t)*sz );
660 
661 #pragma omp parallel for
662  for( int i=0; i<sz; i++ ) {
663  data_t dV = dat[i] - old[i];
664  if( dV*change[i] < 0 ) {
665  data_t pp = fabs( extrem[i]-old[i] );
666  if( pp > maxpp[i] ) maxpp[i] = pp;
667  change[i] = copysign( 1., dV );
668  extrem[i] = old[i];
669  } else if( change[i]==0. && dV != 0 ) {
670  change[i] = copysign( 1., dV );
671  }
672  }
673  memcpy( old, dat, sizeof(data_t)*sz );
674 }
675 
676 
677 //output scratch vector
678 void
679 output_scratch( data_t* s, FILE *out, int n, bool bin )
680 {
681  for( int i=0; i<n; i++ )
682  if( bin ) {
683  fwrite( s+i, sizeof(data_t), 1, out );
684  }else
685  fprintf( out, "%g\n", s[i] );
686 }
687 
688 //output scratch vector
689 void
690 output_scratch( vector<data_t>& s, FILE *out, bool bin=false )
691 {
692  for( auto i : s )
693  if( bin ) {
694  data_t datum = i;
695  fwrite( &datum, sizeof(data_t), 1, out );
696  }else
697  fprintf( out, "%g\n", i );
698 }
699 
700 
701 
702 // temporal running average
703 void ravgX_ta( data_t *dat1, int sz, int t, int a, vector<data_t>& tmp, FILE *out )
704 {
705  vector <data_t> sum( sz, 0 );
706 
707 #pragma omp parallel for
708  for( int i=0; i<sz; i++ ) {
709 
710  tmp[i+(t%a)*sz] = dat1[i];
711 
712  for( int j=0; j<a; j++ ) {
713  sum[i] += tmp[i+j*sz];
714  }
715  sum[i] /= (float)a;
716  }
717 
718  if( t<a-1 )
719  return;
720 
721  output_scratch( sum, out, true );
722 }
723 
724 
725 //read in an ascii vector file
726 void
727 read_vector( vector<data_t> &y, gzFile in, int nc )
728 {
729  assert( nc<=MAX_NC );
730  char buf[1024];
731  float datum[MAX_NC];
732  while( gzgets( in, buf, 1024 ) != Z_NULL &&
733  sscanf( buf, "%f %f %f %f", datum, datum+1, datum+2, datum+3 )==nc )
734  for( int i=0; i<nc; i++ ) y.push_back( datum[i] );
735 }
736 
737 
743 std::string
744 cmdline_str( int n, char *w[] )
745 {
746  std::string cl;
747  for( int i=0; i<n; i++ ) {
748  cl += w[i];
749  cl += " ";
750  }
751  return cl;
752 }
753 
754 
755 int
756 main( int argc, char *argv[] )
757 {
758 #ifdef _OPENMP
759  if( !getenv("OMP_NUM_THREADS") )
760  omp_set_num_threads(1);
761 #endif
762 
763  gengetopt_args_info opts;
764 
765  std::string cmdline = cmdline_str( argc, argv );
766 
767  // let's call our cmdline parser
768  if (cmdline_parser (argc, argv, &opts) != 0)
769  exit(1);
770 
771  if( !opts.inputs_num ) {
772  cerr << "Must specify one or two IGB files" << endl;
773  exit(1);
774  }
775 
776  // the last arg must be a file name
777  gzFile in1 = !strcmp(opts.inputs[0],"-" ) ?
778  gzdopen( dup(0), "r" ): // duplicate stdin
779  gzopen( opts.inputs[0], "r" );
780  if( in1 == NULL ) {
781  cerr << "File not found: " << opts.inputs[0] << endl;
782  exit(1);
783  }
784  // make sure we can open X which must be an IGB file
785  IGBheader* h1= new IGBheader( in1 );
786  if( h1->read(true) & 0xff ) {
787  cerr << "File 1 is not a proper IGB file: "<< opts.inputs[0] << endl;
788  exit(1);
789  }
790 
791  Interp *interp=NULL;
792  if( opts.interpolate_flag )
793  interp = new Interp( opts.inputs[1], opts.inputs[2] );
794 
795  // is a second file necessary?
796  int numf=1;
797  if( opts.op_given )
798  switch( opts.op_arg ) {
799  case op_arg_aXPLUS_bY:
800  case op_arg_XdivY:
801  case op_arg_XmulY:
802  case op_arg_joinXY_t:
803  case op_arg_joinXY_i:
804  case op_arg_dotXY:
805  numf = 2;
806  break;
807  default: // do nothing;
808  break;
809  }
810  else if( opts.expression_given )
811  if( strchr( opts.expression_arg, 'Y' ) )
812  numf =2;
813 
814  // read header and determine size of second file if necessary
815  gzFile in2;
816  IGBheader *h2 = NULL;
817  vector<float> Y;
818  Data_file_t Ytype = NONE;
819  bool Yigb=false;
820 
821  if( numf==2 ) {
822  if( opts.inputs_num<2 ) {
823  cerr << "A 2nd file is needed : " << endl;
824  exit(1);
825  }
826  if( (in2=gzopen( opts.inputs[1], "r" ))==NULL ) {
827  cerr << "file 2 not found : " << opts.inputs[1] << endl;
828  exit(1);
829  }
830  // check file type
831  h2 = new IGBheader( in2 );
832  if( h2->read(true) & 0xff ) {
833  gzrewind( in2 );
834  read_vector( Y, in2, h1->num_components() );
835  if( Y.size()==h1->slice_sz()*h1->num_components() )
836  Ytype = SPACE;
837  else if( Y.size()==h1->t()*h1->num_components() )
838  Ytype = PT_TIME;
839  else if( Y.size()==h1->num_components() )
840  Ytype = PT;
841  else {
842  cerr << "incompatile file sizes! Y must have " << h1->t()*h1->num_components()
843  << " or " << h1->slice_sz()*h1->num_components() << " or " << h1->num_components()
844  << " entries" << endl;
845  exit(1);
846  }
847  } else {
848  Yigb = true;
849  if( h2->num_components() != h1->num_components() ) {
850  cerr << "Number of data components do not match" << endl;
851  exit(1);
852  }
853  if( h2->slice_sz()==h1->slice_sz() && h2->t()==h1->t() )
854  Ytype = SPACE_TIME;
855  else if( h2->slice_sz()==h1->slice_sz() ) {
856  Ytype = SPACE;
857  if( h2->t()!=1 && opts.op_arg != op_arg_joinXY_t ) {
858  cerr << "Second IGB file time does not match" << endl;
859  exit(1);
860  }
861  Y.resize(h1->slice_sz()*h1->num_components());
862  } else if( h2->slice_sz()==1 && h2->t()==h1->t() )
863  Ytype = PT_TIME;
864  else if ( h2->t()==h1->t() )
865  Ytype = TIME;
866  else if ( h2->slice_sz()==1 && h2->t()==1 )
867  Ytype = PT;
868  else {
869  cerr << "incompatile IGB file sizes!" << endl;
870  exit(1);
871  }
872  }
873  }
874 
875  // determine the output file size
876  IGBheader *hout;
877  FILE *out;
878  string fname = opts.output_file_arg;
879  if( fname=="-" )
880  out= stdout;
881  else{
882  if( fname.length()<5 || fname.substr(fname.length()-4,4)!=".igb" )
883  fname += opts.extension_arg;
884  out = fopen( fname.c_str(), "w" );
885  }
886  hout = new IGBheader;
887  *hout = *h1;
888  hout->type(IGB_DATA_T[h1->num_components()]);
889  switch( opts.op_arg ) {
890  case op_arg_ravgX_ta:
891  hout->t(h1->t()-opts.a_arg+1);
892  break;
893  case op_arg_joinXY_i:
894  if( Yigb )
895  hout->x(h1->slice_sz()+h2->slice_sz());
896  else
897  hout->x(h1->slice_sz()+Y.size());
898  hout->y(1);
899  hout->z(1);
900  break;
901  case op_arg_joinXY_t:
902  hout->type(h1->type());
903  hout->t(h1->t()+h2->t()-overlap(h1,h2));
904  break;
905  case op_arg_diff_f:
906  case op_arg_diff_c:
907  hout->t(h1->t()-1);
908  break;
909  case op_arg_minX_i:
910  case op_arg_maxX_i:
911  case op_arg_avgX_i:
912  case op_arg_stdD_i:
913  case op_arg_intX_i:
914  case op_arg_maxP2P:
915  hout->t(1);
916  hout->type(IGB_DATA_T[1]);
917  break;
918  case op_arg_minX_t:
919  case op_arg_maxX_t:
920  case op_arg_avgX_t:
921  case op_arg_stdD_t:
922  hout->x(1);
923  hout->y(1);
924  hout->z(1);
925  break;
926  case op_arg_magX:
927  case op_arg_dotXY:
928  hout->type(IGB_DATA_T[1]);
929  break;
930  default: // do nothing;
931  break;
932  }
933  if( opts.interpolate_flag ) {
934  hout->x( interp->size() );
935  hout->y(1);
936  hout->z(1);
937  }
938  //hout->comment( cmdline.c_str() );
939  hout->fileptr( out );
940  hout->write();
941 
942  if( opts.op_arg == op_arg_joinXY_t ) {
943  joinXY( h1, h2, hout );
944  exit(0);
945  }
946 
947  // allocate some input memory
948  std::vector<float> dat1(h1->slice_sz() * h1->num_components());
949  std::vector<std::vector<float>> dat3;
950  if( Yigb )
951  Y.assign(h2->slice_sz()*h2->num_components(), 0.0f);
952 
953  // initialize if we need scratch data
954  int h1_slice_comps = h1->slice_sz()*h1->num_components();
955  std::vector<data_t> t_reduce; // automatically output at the end for a temporal reduction
956  std::vector<data_t> big_scratch;
957  switch( opts.op_arg ) {
958  case op_arg_minX_i:
959  case op_arg_maxX_i:
960  case op_arg_avgX_i:
961  case op_arg_stdD_i:
962  case op_arg_intX_i :
963  t_reduce.assign( h1_slice_comps, 0 );
964  break;
965  case op_arg_ravgX_ta :
966  big_scratch.assign( h1_slice_comps*opts.a_arg, 0 );
967  break;
968  case op_arg_sclip_ab :
969  big_scratch.assign( h1_slice_comps*3, 0 );
970  break;
971  case op_arg_diff_f :
972  big_scratch.assign( h1_slice_comps, 0 );
973  break;
974  case op_arg_diff_c :
975  case op_arg_norm_i :
976  big_scratch.assign( h1_slice_comps*3, 0 );
977  break;
978  case op_arg_maxP2P :
979  big_scratch.assign( h1_slice_comps*3, 0 );
980  t_reduce.assign( h1_slice_comps, 0 );
981  break;
982  default: // do nothing;
983  break;
984  }
985  if( opts.expression_given )
986  big_scratch.assign( h1_slice_comps*opts.a_arg, 0 );
987 
988  // loop through the data
989  for( int t=0; t<h1->t(); t++ ) {
990 
991  float tm = h1->org_t() + t*h1->inc_t();
992 
993  h1->read_data( dat1.data() );
994 
995  if(opts.op_arg == op_arg_stdD_i)
996  dat3.push_back(dat1);
997 
998  if( Yigb && (Ytype==SPACE_TIME || Ytype==PT_TIME || !t) )
999  h2->read_data( Y.data() );
1000 
1001  float *Yptr = Y.data();
1002  if( !Yigb && Ytype==PT_TIME )
1003  Yptr += h1->num_components()*t;
1004 
1005  if( !t && (opts.op_arg==op_arg_minX_i ||
1006  opts.op_arg==op_arg_maxX_i ))
1007  t_reduce = dat1;
1008 
1009  if( !t && (opts.op_arg==op_arg_norm_i) ) {
1010  copy( dat1.begin(), dat1.end(), big_scratch.begin() );
1011  copy( dat1.begin(), dat1.end(), big_scratch.begin()+h1_slice_comps );
1012  }
1013 
1014  if( opts.expression_given ){
1015  if( Ytype==NONE )
1016  eval_expr( dat1.data(), h1_slice_comps, opts.expression_arg, out, big_scratch.data() );
1017  else {
1018  bool space = Ytype==SPACE_TIME || Ytype==SPACE;
1019  eval_expr( dat1.data(), Yptr, h1_slice_comps, opts.expression_arg,
1020  out, space? 0 : h1->num_components() );
1021  }
1022  }
1023 
1024  if( opts.interpolate_given )
1025  interpolate( dat1.data(), interp->ind, interp->w, interp->n, out );
1026 
1027  switch( opts.op_arg ) {
1028  case op_arg_aXPLUS_bY:
1029  if( Ytype==SPACE_TIME || Ytype==SPACE )
1030  aXPLUS_bY(dat1.data(), Yptr, opts.a_arg, opts.b_arg,
1031  h1_slice_comps,out);
1032  else
1033  aXPLUS_bY(dat1.data(), Yptr, opts.a_arg, opts.b_arg,
1034  h1_slice_comps,h1->num_components(), out);
1035  break;
1036  case op_arg_aXPLUS_b:
1037  aXPLUS_b(dat1.data(),opts.a_arg,opts.b_arg,h1_slice_comps,out);
1038  break;
1039  case op_arg_XdivY:
1040  if( Ytype==SPACE_TIME || Ytype==SPACE )
1041  XdivY(dat1.data(), Yptr, h1_slice_comps, out);
1042  else
1043  XdivY(dat1.data(), Yptr, h1_slice_comps, h1->num_components(), out);
1044  break;
1045  case op_arg_XmulY:
1046  if( Ytype==SPACE_TIME || Ytype==SPACE )
1047  XmulY( dat1.data(), Yptr, h1_slice_comps, out);
1048  else
1049  XmulY( dat1.data(), Yptr, h1_slice_comps, h1->num_components(), out);
1050  break;
1051  case op_arg_minX_t:
1052  minXt( dat1.data(), h1->slice_sz(), h1->num_components(), tm, out );
1053  break;
1054  case op_arg_maxX_t:
1055  maxXt( dat1.data(), h1->slice_sz(), h1->num_components(), tm, out );
1056  break;
1057  case op_arg_avgX_t:
1058  avgXt( dat1.data(), h1->slice_sz(), h1->num_components(), tm, out );
1059  break;
1060  case op_arg_minX_i:
1061  minXi( dat1.data(), t_reduce.data(), t_reduce.size() );
1062  break;
1063  case op_arg_maxX_i:
1064  maxXi( dat1.data(), t_reduce.data(), t_reduce.size() );
1065  break;
1066  case op_arg_avgX_i:
1067  case op_arg_stdD_i:
1068  avgXi( dat1.data(), t_reduce, 1.0f);
1069  break;
1070  case op_arg_ravgX_ta :
1071  ravgX_ta( dat1.data(), h1_slice_comps, t, opts.a_arg, big_scratch, out );
1072  break;
1073  case op_arg_Xbox :
1074  Xbox( dat1.data(), h1->x(), h1->y(), out, opts.a_arg, h1->num_components() );
1075  break;
1076  case op_arg_sclip_ab :
1077  sclip_ab( dat1.data(), h1_slice_comps, opts.a_arg, opts.b_arg, big_scratch, t, h1->t(), out );
1078  break;
1079  case op_arg_diff_f :
1080  forward_diff( dat1.data(), h1_slice_comps, big_scratch, t, h1->inc_t(), out );
1081  break;
1082  case op_arg_diff_c :
1083  center_diff( dat1.data(), h1_slice_comps, big_scratch, t, h1->inc_t(), out );
1084  break;
1085  case op_arg_joinXY_i:
1086  if( Yigb )
1087  join_space( dat1.data(), h1_slice_comps, Yptr,
1088  h2->slice_sz()*h2->num_components(), out);
1089  else
1090  join_space( dat1.data(), h1_slice_comps, Y.data(), Y.size(), out);
1091  break;
1092  case op_arg_magX:
1093  magnitude( dat1.data(), h1_slice_comps, h1->num_components(), out );
1094  break;
1095  case op_arg_dotXY:
1096  dot( dat1.data(), Yptr, h1_slice_comps, h1->num_components(), out,
1097  Ytype==PT_TIME|| Ytype==PT );
1098  break;
1099  case op_arg_intX_i :
1100  {
1101  int lastT = h1->t()-1;
1102  int lastSimp = lastT - (lastT%3);
1103  if( t<=lastSimp && lastSimp!=0 )
1104  simp38( dat1.data(), h1_slice_comps, t==0||t==lastSimp?-1:t, t_reduce.data() );
1105  if( t>=lastSimp && lastSimp!=lastT )
1106  midpt( dat1.data(), h1_slice_comps, t==lastSimp||t==lastT, t_reduce.data() );
1107  }
1108  break;
1109  case op_arg_norm_i:
1110  minXi( dat1.data(), big_scratch.data(), h1_slice_comps );
1111  maxXi( dat1.data(), big_scratch.data()+h1_slice_comps, h1_slice_comps );
1112  break;
1113  case op_arg_maxP2P:
1114  maxP2P( dat1.data(), big_scratch.data(), t_reduce.data(), h1_slice_comps, t );
1115  break;
1116  case op_arg_NOP:
1117  break;
1118  default: // do nothing;
1119  break;
1120  }
1121  }
1122 
1123  // post process
1124  switch( opts.op_arg ) {
1125  case op_arg_avgX_i:
1126  for( int i=0; i<h1->slice_sz()*h1->num_components(); i++ )
1127  t_reduce[i] /= (data_t)(h1->t());
1128  break;
1129  case op_arg_stdD_i:
1130  {
1131  for( int i=0; i<h1->slice_sz()*h1->num_components(); i++ )
1132  t_reduce[i] /= (data_t)(h1->t());
1133  std::vector<data_t> mean;
1134  mean.assign(t_reduce.begin(), t_reduce.end());
1135  std::fill(t_reduce.begin(), t_reduce.end(), 0);
1136  for( int t=0; t<h1->t(); t++ ) {
1137  float tm = h1->org_t() + t*h1->inc_t();
1138  varXi( dat3[t].data(), mean.data(), t_reduce, 1.0f);
1139  }
1140  for( int i=0; i<h1->slice_sz()*h1->num_components(); i++ )
1141  t_reduce[i] = std::sqrt(t_reduce[i] / ((data_t)(h1->t() - 1)));
1142  break;
1143  }
1144  case op_arg_intX_i:
1145  for( int i=0; i<h1->slice_sz()*h1->num_components(); i++ )
1146  t_reduce[i] *= h1->inc_t();
1147  break;
1148  case op_arg_norm_i:
1149  normalize( h1, out, big_scratch.data(), big_scratch.data()+h1_slice_comps );
1150  break;
1151  default: // do nothing
1152  break;
1153  }
1154 
1155  if( t_reduce.size() )
1156  output_scratch( t_reduce, out, true );
1157 
1158  return 0;
1159 }
void dot(data_t *x, data_t *y, int n, int nc, FILE *out, bool pt)
perform dot product
Definition: IGBops.cc:536
void midpt(T *x, int n, bool end, data_t *reduce)
Definition: IGBops.cc:579
int main(int argc, char *argv[])
Definition: IGBops.cc:756
const int MAX_NC
Definition: IGBops.cc:65
void minXt(data_t *x, int slsz, int nc, float t, FILE *out)
Definition: IGBops.cc:395
void forward_diff(data_t *x, int slsz, vector< data_t > &old, int t, float dt, FILE *out)
Definition: IGBops.cc:259
void aXPLUS_b(data_t *x, data_t a, data_t b, int slsz, FILE *out)
Definition: IGBops.cc:323
bool overlap(IGBheader *first, IGBheader *second)
Definition: IGBops.cc:126
Data_file_t
Definition: IGBops.cc:69
@ SPACE_TIME
Definition: IGBops.cc:69
@ PT
Definition: IGBops.cc:69
@ SPACE
Definition: IGBops.cc:69
@ NONE
Definition: IGBops.cc:69
@ TIME
Definition: IGBops.cc:69
@ PT_TIME
Definition: IGBops.cc:69
void maxXt(data_t *x, int slsz, int nc, float t, FILE *out)
Definition: IGBops.cc:431
void XmulY(data_t *x, data_t *y, int slsz, FILE *out)
Definition: IGBops.cc:377
void eval_expr(data_t *x, int n, char *expr, FILE *out, data_t *result)
Definition: IGBops.cc:170
void maxP2P(data_t *dat, data_t *big, data_t *maxpp, int sz, int t)
find the maximum peak-to-peak value at each point
Definition: IGBops.cc:653
#define data_t
Definition: IGBops.cc:119
void read_vector(vector< data_t > &y, gzFile in, int nc)
Definition: IGBops.cc:727
void minXi(data_t *x, data_t *mn, size_t n)
Definition: IGBops.cc:420
void interpolate(data_t *dat, vector< int * > &idx, vector< float * > &w, int n, FILE *out)
interpolate within points
Definition: IGBops.cc:601
void avgXi(data_t *x, vector< data_t > &sum, const data_t fac)
Definition: IGBops.cc:306
void output_scratch(data_t *s, FILE *out, int n, bool bin)
Definition: IGBops.cc:679
void ravgX_ta(data_t *dat1, int sz, int t, int a, vector< data_t > &tmp, FILE *out)
Definition: IGBops.cc:703
void maxXi(data_t *x, data_t *mx, size_t n)
Definition: IGBops.cc:409
void simp38(T *x, int n, int t, data_t *runInt)
Simpson's 3/8 rule.
Definition: IGBops.cc:557
void normalize(IGBheader *h, FILE *out, T *min, T *max)
normalize pixels over all time
Definition: IGBops.cc:622
int IGB_DATA_T[5]
Definition: IGBops.cc:120
void XPLUS_a(data_t *x, data_t a, int slsz, FILE *out)
Definition: IGBops.cc:444
void sclip_ab(data_t *dat, int sz, data_t upper, data_t lower, vector< data_t > &scr, int t, int tfinal, FILE *out)
Definition: IGBops.cc:479
void varXi(data_t *x, data_t *mean, vector< data_t > &sum, const data_t fac)
Definition: IGBops.cc:314
void join_space(data_t *x, int nx, data_t *y, int ny, FILE *out)
Definition: IGBops.cc:162
std::string cmdline_str(int n, char *w[])
Definition: IGBops.cc:744
void avgXt(data_t *x, int slsz, int nc, float t, FILE *out)
Definition: IGBops.cc:291
void XdivY(data_t *x, data_t *y, int slsz, FILE *out)
Definition: IGBops.cc:332
void joinXY(IGBheader *h1, IGBheader *h2, IGBheader *hout)
Definition: IGBops.cc:133
void Xbox(data_t *dat, int x, int y, FILE *out, int d, int nc)
Definition: IGBops.cc:455
void aXPLUS_bY(data_t *x, data_t *y, data_t a, data_t b, int slsz, int nc, FILE *out)
Definition: IGBops.cc:272
void center_diff(data_t *x, int slsz, vector< data_t > &odat, int t, float dt, FILE *out)
Definition: IGBops.cc:237
void magnitude(data_t *x, int n, int nc, FILE *out)
determine magnitude at each point
Definition: IGBops.cc:515
int read(bool quiet=false)
Definition: IGBheader.cc:757
float org_t(void)
Definition: IGBheader.h:317
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:431
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
Interpolate class.
Definition: IGBops.cc:74
int size()
Definition: IGBops.cc:77
Interp(char *ind, char *weight)
constructor
Definition: IGBops.cc:89
vector< float * > w
Definition: IGBops.cc:78
int n
Definition: IGBops.cc:80
vector< int * > ind
Definition: IGBops.cc:79
double mag(const Point &vect)
vector magnitude
Definition: SF_container.h:112
T sum(const vector< T > &vec)
Compute sum of a vector's entries.
Definition: SF_vector.h:340
@ Y
Definition: kdpart.hpp:64
constexpr T min(T a, T b)
Definition: ion_type.h:33
constexpr T max(T a, T b)
Definition: ion_type.h:31
#define IGB_COMPLEX
Definition: IGBheader.h:62
#define IGB_VEC3_f
Definition: IGBheader.h:71
#define IGB_FLOAT
Definition: IGBheader.h:60
#define IGB_VEC4_f
Definition: IGBheader.h:73