/*** ^^A -*-C++-*- ******************************************************/ /* pshift2D3D4D 07 August 2013 */ /************************************************************************/ /* Short Description : */ /* AU program to reconstruct Zangger-Sterk based */ /* 2D, 3D and 4D Pureshift */ /************************************************************************/ /* Keywords : */ /* pureshift, Zangger-Sterk, BIRD, DOSY */ /************************************************************************/ /* Description/Usage : */ /* This AU program reconstructs 2D, 3D Pureshift (aqseq 312), not 4D */ /* Pureshift (aqseq 4123) data */ /* data recorded with Zangger-Sterk based pulse sequences. */ /* Depending on the dimensionality, 2D, 3D or 4D processing is */ /* employed. First, data is converted to analog form into temporary */ /* expno 9999. Further, the user is promted to enter an unused expno */ /* for the output data (default is expno+1). A template for the output */ /* data is then generated using the macros RSER (for 2D) and */ /* RSER2D (for 3D, 4D), respectively. Consequently, the data is read */ /* in (complete ser file for 2D data, 13 plane ser file for 3D data). */ /* After concatenation of the data to a single fid (2D) and */ /* ser file (3D,4D), respectively, the status parameters in the output */ /* dataset are adjusted. */ /************************************************************************/ /* Author(s) : */ /* Name : Ralph Adams */ /* Organisation : University of Manchester, UK */ /* Email : ralph.adams@manchester.ac.uk */ /************************************************************************/ /* Version History, original 2D macro written by Aitor Morreno@Bruker */ /* 01JUN2011 modified to include debugging and correction for non-256 */ /* block sized data. Also added comments. (R. Adams) */ /* 01NOV2011 modified to incorporate TS2 and TS3 compatibility using */ /* precompiler checking with #ifdef and #ifndef and version */ /* checking using getxwinvers() to correct RSER2D (R. Adams) */ /* 21NOV2011 updates td in acquisition as well as status files (RA) */ /* 27JUL2012 modified macro to cope with 2D->1D files larger than */ /* defined MAXSIZE that resulted in a seqmentation fault (RA) */ /* 14SEP2012 modified macro to correct calculation of sw/sw1 (GAM) */ /* 07AUG2013 4D->3D loop added but not operational yet(RA) */ /* 02OCT2013 Added annoying pop up to make sure use is acknowledged (RA)*/ /************************************************************************/ /* For TD = 32 and lower */ #define MAXSIZE 655360 int row[MAXSIZE], temp[MAXSIZE], temp2[256]; int pmod, si1, si2, si3, si12, si13, si12c, drppts, npoints, nzero=0, i4, debug, download, infomsg, twoFiveSixCorr; int aexpno=9999, pexpno=9998, nexpno=expno+1000; double sw1, sw2, sw3; double sfo1, sfo2, sfo3; float l4; char infile[PATH_MAX], outfile[PATH_MAX], statustext[256]; FILE *fpin, *fpout; GETCURDATA /*Flags - set all of them to 0 for an easy life */ /*debug = 1 for on, 0 for off*/ debug=1; /*download = 1 to display pop up, 0 to skip*/ download=1; /*Advice about processing: infomsg = 1 for on, 0 for off*/ infomsg=1; if(download == 1){ i1 = Proc_err(QUESTION_OPT,"By using this macro you agree to acknowledge \n\"http://nmr.chemistry.manchester.ac.uk\" \nin any resulting publication. \n\nClick OK to agree and continue. \nClick cancel to disagree and abort.\n\n This message can be suppressed by setting the variable \n\"download=0;\" in the macro."); if ( i1 == ERR_CANCEL ) { ABORT } else{ } } if(debug == 1){(void)printf("Debugging on\nsuppress debugging by setting debug=0 in macro\n");} if(debug == 1){ if(infomsg == 1){ (void)printf("Information messages will be shown during processing on\n"); } } if(debug == 1){ if(download == 1){ (void)printf("Download agreement will be shown during processing\n"); } } /*Get the version of Topspin that is running so that the appropriate syntax and macros are used*/ char curversion[80]; getxwinvers(curversion); if(debug == 1){(void)printf("Topspin Version: %s\n",curversion);} const char* from = curversion; char *vers = (char*) malloc(6); strncpy(vers, from+7, 1); if(debug == 1){(void)printf("Topspin Version: %s\n",vers);} int versn=atoi(vers); if(debug == 1){ (void)printf("Version detection char to int confirmation:\n"); if(versn==3){(void)printf("Topspin Version: %i Detected Successfully.\n",versn);} if(versn==2){(void)printf("Topspin Version: %i Detected Successfully.\n",versn);} if(versn==1){(void)printf("Topspin Version: %i Detected Successfully.\n",versn);} } #ifdef NEWACQUPATH if(debug == 1){(void)printf("NEWACQUPATH is defined and will be used.\n");} #endif #ifndef NEWACQUPATH if(debug == 1){(void)printf("NEWACQUPATH is not defined, ACQUPATH will be used.\n");} #endif #ifdef ACQUPATH if(debug == 1){(void)printf("ACQUPATH is defined and will be used.\n");} #endif #ifndef ACQUPATH if(debug == 1){(void)printf("ACQUPATH is not defined.\n");} #endif /* Function to round double to integer */ int round_to_int(double d) { return d<0?d-.5:d+.5; } int round_to_int_f(float f) { return f<0?f-.5:f+.5; } /* Check experiment type, 2D or 3D */ FETCHPAR("PARMODE",&pmod) if ( (pmod < 1) || (pmod > 2) ) STOPMSG("Not a 2D or 3D dataset.\nTry changing pparmod in the processing parameters.") /* 2D */ if (pmod == 1){ /*Get status parameters */ if(debug == 1){(void)printf("Starting 2D conversion\n");} FETCHPAR1S("TD",&si1) FETCHPAR("TD",&si2) FETCHPAR1S("SW",&sw1) FETCHPAR1S("SFO1",&sfo1) sw1=sw1*sfo1; FETCHPARS("SW",&sw2) FETCHPARS("SFO1",&sfo2) sw2=sw2*sfo2; si12=si1*si2; twoFiveSixCorr=256-(si2%256); if(twoFiveSixCorr == 256){twoFiveSixCorr = 0;} if(debug == 1){(void)printf("Correction Value for si2 not divisible by 256: %d\n",twoFiveSixCorr);} if(debug == 1){(void)printf("Full si2: %d\n",si2+twoFiveSixCorr);} si12c=si1*(si2+twoFiveSixCorr); if(debug == 1){(void)printf("File size (si12c) calculated as: %d\n",4*si12c);} if(si12c <=MAXSIZE){ /* Digitial to analog conversion, define Topspin input ("ser") and output ("fid") data files */ CONVDTA(aexpno) REXPNO(aexpno) strcpy(infile, ACQUPATH("ser")); GETINT("Enter new expno for 1D pureshift data: ",nexpno) RSER(1,nexpno,1) /*use the precompiler to check if the appropriate Topspin 2 or 3 macros exist*/ #ifdef NEWACQUPATH if(debug == 1){(void)printf("ifdef TS3\n");} strcpy(outfile,NEWACQUPATH(nexpno, "fid")); #endif #ifndef NEWACQUPATH if(debug == 1){(void)printf("ifndef TS2\n");} REXPNO(nexpno) strcpy(outfile,ACQUPATH("fid")); REXPNO(aexpno) #endif /* Define the start position and the number of points to extract for concatenation of the FID */ FETCHPAR("CNST 4",&l4) if(debug == 1){(void)printf("Value of cnst4 passed to macro: %f\n",l4);} drppts=round_to_int_f(l4); if(debug == 1){(void)printf("Value of drppts passed on in macro: %d\n",drppts);} drppts=(drppts*2); /*drppts=2;*/ if(debug == 1){(void)printf("'Complex' points to drop: %d\n",drppts);} npoints=round_to_int(sw2/sw1); /*read and store the entire 2D SER file*/ if((fpin = fopen(infile,"r")) == NULL){STOPMSG("Open of infile failed!\n")} if(fread(row,sizeof(int),si12c,fpin)!=si12c){STOPMSG("Read in of ser file failed!\n")} if(debug == 1){(void)printf("Full file size should be: %d\n",si1*(si2+twoFiveSixCorr));} fclose(fpin); /* Delete the temporary expno 9999 */ DELETEEXPNO(name, aexpno, disk, user) /* extract and concatenate the chunked FID's to single FID */ if((fpout=fopen(outfile,"w")) == NULL){STOPMSG("Open of outfile failed!\n")} i1=0; while(i1 < si1){ if(debug == 1){(void)printf("%d \n",i1);} for (i2=0; i2<2*npoints; i2++){ /*temp[i2]=row[i1*si2+i2+drppts];*/ sprintf(statustext,"%d of %d (%d.%d) ",i1,si1,i1,i2); Show_status(statustext); if(debug == 1){(void)printf("%d.%d(%d) ",i1,i2,i1*(si2+twoFiveSixCorr)+i2+drppts);} temp[i2]=row[i1*(si2+twoFiveSixCorr)+i2+drppts]; /*added correction for the case that si2 is not a multiple of 256*/ } if(fwrite(temp, sizeof(int), 2*npoints, fpout) != 2*npoints) {STOPMSG("writing to outfile failed")} i1++; if(debug == 1){(void)printf("\n",i1);} } fclose(fpout); /* Set status parameter TD in the output dataset according to constructed FID length */ REXPNO(nexpno) SETCURDATA STOREPARS("TD",2*npoints*si1) /*status*/ STOREPAR("TD",2*npoints*si1) /*acq*/ if(debug == 1){(void)printf("Finished 2D conversion\n");} VIEWDATA_SAMEWIN } else{ if(debug == 1){(void)printf("Slow version of macro is being used - multiple writes to disk rather than using just RAM\n");} /* Digitial to analog conversion, define Topspin input ("ser") and output ("fid") data files */ CONVDTA(aexpno) REXPNO(aexpno) strcpy(infile, ACQUPATH("ser")); GETINT("Enter new expno for 1D pureshift data: ",nexpno) RSER(1,nexpno,1) if(infomsg == 1){ Proc_err(INFO_OPT,"The size of the data set is large.\nProcessing may be slow.\nUnless there is a specific reason for acquiring such a big data set reduce the\nnumber of chunks (TD 1) or the number of points acquired per chunk (TD 2).\n\n This message can be suppressed by setting the infomsg flag in the macro."); } /*use the precompiler to check if the appropriate Topspin 2 or 3 macros exist*/ #ifdef NEWACQUPATH if(debug == 1){(void)printf("ifdef TS3\n");} strcpy(outfile,NEWACQUPATH(nexpno, "fid")); #endif #ifndef NEWACQUPATH if(debug == 1){(void)printf("ifndef TS2\n");} REXPNO(nexpno) strcpy(outfile,ACQUPATH("fid")); REXPNO(aexpno) #endif if((fpin = fopen(infile,"r")) == NULL){STOPMSG("Open of infile failed!\n")} /* Define the start position and the number of points to extract for concatenation of the FID */ FETCHPAR("CNST 4",&l4) if(debug == 1){(void)printf("Value of cnst4 passed to macro: %f\n",l4);} drppts=round_to_int_f(l4); if(debug == 1){(void)printf("Value of drppts passed on in macro: %d\n",drppts);} drppts=(drppts*2); /*drppts=2;*/ if(debug == 1){(void)printf("'Complex' points to drop: %d\n",drppts);} npoints=round_to_int(sw2/sw1); /* extract and concatenate the chunked FID's to single FID */ if((fpout=fopen(outfile,"w")) == NULL){STOPMSG("Open of outfile failed!\n")} i1=0; while(i1 < si1){ if(debug == 1){(void)printf("%d \n",i1);} /*read and store each FID from the SER file*/ if(fread(row,sizeof(int),si2+twoFiveSixCorr,fpin)!=si2+twoFiveSixCorr){STOPMSG("Read in of ser file failed!\n")} for (i2=0; i2<2*npoints; i2++){ sprintf(statustext,"%d of %d (%d.%d) ",i1,si1,i1,i2); Show_status(statustext); if(debug == 1){(void)printf("%d.%d(%d) ",i1,i2,i1*(si2+twoFiveSixCorr)+i2+drppts);} temp[i2]=row[i2+drppts]; /*added correction for the case that si2 is not a multiple of 256*/ } if(fwrite(temp, sizeof(int), 2*npoints, fpout) != 2*npoints) {STOPMSG("writing to outfile failed")} i1++; if(debug == 1){(void)printf("\n",i1);} } fclose(fpout); fclose(fpin); /* Delete the temporary expno 9999 */ DELETEEXPNO(name, aexpno, disk, user) /* Set status parameter TD in the output dataset according to constructed FID length */ REXPNO(nexpno) SETCURDATA STOREPARS("TD",2*npoints*si1) /*status*/ STOREPAR("TD",2*npoints*si1) /*acq*/ if(debug == 1){(void)printf("Finished 2D conversion\n");} VIEWDATA_SAMEWIN } } /* 3D */ if (pmod == 2){ /* Get required status parameters for all dimensions */ if(debug == 1){(void)printf("Starting 3D conversion\n");} FETCHPAR3S("TD",&si1) /* zs */ FETCHPARNS(2,"TD",&si2) /* noe/roe/tocsy */ FETCHPAR("TD",&si3) /* fid */ FETCHPAR3S("SW",&sw1) /**/ FETCHPAR3S("SFO1",&sfo1) /**/ FETCHPARNS(2,"SW",&sw2) /**/ FETCHPARNS(2,"SFO1",&sfo2) /**/ FETCHPARS("SW",&sw3) /**/ FETCHPARS("SFO1",&sfo3) /**/ sw1=sw1*sfo1; sw2=sw2*sfo2; sw3=sw3*sfo3; si13=si3*si1; /*STOPMSG("This version of the macro is not compatible with such a large amount of data, \n reduce the number of chunks (TD 1) or the number of points acquired per chunk (TD 2).")*/ if(debug == 1){(void)printf("si1: %d\nsi2: %d\nsi3: %d\nsw1: %d\nsw2: %d\nsw3: %d\n",si1,si2,si3,sw1,sw2,sw3);} if(debug == 1){(void)printf("Data Size for each plane: %d\n",si13);} /*If using Topspin 3, define Topspin input data file */ #ifdef NEWACQUPATH if(debug == 1){(void)printf("ifdef TS3\n");} strcpy(infile,NEWACQUPATH(pexpno, "ser")); if(debug == 1){ sprintf(statustext,"If using Topspin 3, define Topspin input data file pexpno"); Show_status(statustext); } #endif /* digital to analog conversion */ CONVDTA(aexpno) REXPNO(aexpno) if(debug == 1){(void)printf("Converted data to analog\n");} /*If using Topspin 2, define Topspin input data file */ #ifndef NEWACQUPATH if(debug == 1){(void)printf("ifndef TS2\n");} if(debug == 1){(void)printf("RSER2D \"s13\"\n");} if(debug == 1){ sprintf(statustext,"If using Topspin 2, define Topspin input data file pexpno (1)"); Show_status(statustext); } RSER2D("s13",1,pexpno) if(debug == 1){ sprintf(statustext,"If using Topspin 2, define Topspin input data file pexpno (2)"); Show_status(statustext); } REXPNO(pexpno) strcpy(infile,ACQUPATH("ser")); REXPNO(aexpno) #endif /* Define Topspin output data file, create 2D output file using RSER2D */ GETINT("Enter new expno for 2D pureshift data: ",nexpno) /*RSER2D version compatibility*/ if(versn==3){ if(debug == 1){(void)printf("RSER2D 23\n");} RSER2D(23,1,nexpno) } else{ if(debug == 1){(void)printf("RSER2D \"s23\"\n");} RSER2D("s23",1,nexpno) } /*Define Topspin input data file, version dependent */ #ifdef NEWACQUPATH if(debug == 1){(void)printf("ifdef TS3\n");} strcpy(outfile,NEWACQUPATH(nexpno, "ser")); #endif #ifndef NEWACQUPATH if(debug == 1){(void)printf("ifndef TS2\n");} REXPNO(nexpno) strcpy(outfile,ACQUPATH("ser")); REXPNO(aexpno) #endif REXPNO(aexpno) /* Define the start position and the number of points to extract for concatenation of the FID */ FETCHPAR("CNST 4",&l4) if(debug == 1){(void)printf("Value of cnst4 passed to macro: %f\n",l4);} drppts=round_to_int_f(l4); if(debug == 1){(void)printf("Value of drppts passed on in macro: %d\n",drppts);} drppts=(drppts*2); /*drppts=2;*/ if(debug == 1){(void)printf("Real + Imaginary points to drop: %d\n",drppts);} npoints=round_to_int(sw3/sw1); /* Create array filled with zeros to properly process the direct dimension */ /* The data has to be a multiple of 256 due to the way Bruker saves it in blocks*/ nzero=256-(2*npoints*si1)%256; if (nzero!=256) { for(i3=0; i3