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