/*** ^^A -*-C++-*- ******************************************************/ /* pshift_no_convdta 06 August 2014 */ /************************************************************************/ /* 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. Conversion of the data from digital to analog format */ /* is circumvented in this version by carrying on the group delay at */ /* the beginning of the FID from the first time increment. */ /* 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)*/ /* 08AUG2014 Circumvent the need to convert to "analog" data by reading */ /* the data left shift required from GRPDLY. This only works */ /* properly, if this parameter is well defined, either in the */ /* acqus file, or in the approximate lists available for */ /* systems using DSPFVS 10, 11 or 12. (LK) */ /* 23SEP2014 Replaced use of malloc with calloc in version detection(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; double grpdly, decim; /*, dz; Added additional double variables needed. grpdly is the Group delay status parameter read out from acqus. It contains 1) The width of the group delay is given as floor(grpdly) as multiples of the complex dwell time point length 2) the remaining 1st order phase correction that has to be applied to the raw data after circular shifting as the broken number after the point as multiples of 360deg This parameter may be well defined in the acquisition status parameter, for recent hardware. However, for older analog-to-digital converters, it is necessary to read them from a list, which is defined in the decim is the Oversampling dwell time status parameter read out from acqus. lk20140806 */ int dspfvs, pnts_in_grpdly, intital_expno; /* Added additional integer variables needed. dspfvs is the DSP firmware version status parameter read out from acqus. pnts_in_grpdly is the number of data points of the group delay (=2*(floor(grpdly)+1)). initial_expno is the experiment number of the source data set (used in 3D conversion). lk20140806 */ 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=0; /*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"); } } /* store current experiment number to intital_expno. lk20140808 */ intital_expno=expno; /*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*) calloc(6,1); 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; } /* Determine the number of points within group delay of the digital filter */ FETCHPARS("GRPDLY", &grpdly) if(debug == 1){(void)printf("Read out: grpdly = %f\n", grpdly);} if(grpdly<0) { FETCHPARS("DECIM", &decim) FETCHPARS("DSPFVS", &dspfvs) if(debug == 1){(void)printf("Group delay not well defined in acquisition status parameters. Determine length of group delay according to values listed in grpdly_from_list\nRead out: decim = %f, dspfvs = %d\n", decim, dspfvs);} double grpdly_from_list(double *decim, int *dspfvs) /* Reads the group delay resulting from the digital filter settings from a list. */ /* This should be used on hardware, where the variable grpdly is not properly set by the hardware (grpdly=-1) */ /* For further information see the comment at the end of the macro. */ /* If the grpldy corresponding to the input values of decim and dspfvs is not defined in this function, -1 is returned. */ { int vers=*dspfvs, dcim=*decim; switch(vers) { case 10: switch(dcim) { case 2: return 44.7500; case 3: return 33.5000; case 4: return 66.6250; case 6: return 59.0833; case 8: return 68.5625; case 12: return 60.3750; case 16: return 69.5313; case 24: return 61.0208; case 32: return 70.0156; case 48: return 61.3438; case 64: return 70.2578; case 96: return 61.5052; case 128: return 70.3789; case 192: return 61.5859; case 256: return 70.4395; case 384: return 61.6263; case 512: return 70.4697; case 768: return 61.6465; case 1024: return 70.4849; case 1536: return 61.6566; case 2048: return 70.4924; } break; case 11: switch(dcim) { case 2: return 46.0000; case 3: return 36.5000; case 4: return 48.0000; case 6: return 50.1667; case 8: return 53.2500; case 12: return 69.5000; case 16: return 72.2500; case 24: return 70.1667; case 32: return 72.7500; case 48: return 70.5000; case 64: return 73.0000; case 96: return 70.6667; case 128: return 72.5000; case 192: return 71.3333; case 256: return 72.2500; case 384: return 71.6667; case 512: return 72.1250; case 768: return 71.8333; case 1024: return 72.0625; case 1536: return 71.9167; case 2048: return 72.0313; } break; case 12: switch(dcim) { case 2: return 46.311; case 3: return 36.530; case 4: return 47.870; case 6: return 50.229; case 8: return 53.289; case 12: return 69.551; case 16: return 71.600; case 24: return 70.184; case 32: return 72.138; case 48: return 70.528; case 64: return 72.348; case 96: return 70.700; case 128: return 72.524; } break; } return -1; } grpdly=grpdly_from_list(&decim, &dspfvs); if(grpdly<0){STOPMSG("Lacking value for the group delay length valid on this hardware setup. Data rearrangement aborted.")} } if(debug == 1){(void)printf("value of grpdly: %f\n", grpdly);} pnts_in_grpdly=2*(floor(grpdly)+1); if(debug == 1){(void)printf("length of group delay (in dwell time points): %d\n", pnts_in_grpdly);} /* 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 */ /* Skipping CONVDTA statement and subsequent experiment folder change. No need for aexpno after full macro rearrangement?, lk20140806 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); 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); /* Deleted CONVDTA statement writing to aexpno. Deleting this data later on therefore is not necessary any more. lk20140807 */ /* 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")} /* Write data points in Group delay to output FID. Writing the number of complex points during the group delay (=floor(grpdly)) plus the first complex point lk20140807 */ i2=0; while(i2