#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <signal.h>
#include <limits.h>
#include <float.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "snaphu.h"
extern char dumpresults_global;
extern char requestedstop_global;
extern FILE *sp0, *sp1, *sp2, *sp3;
extern nodeT NONTREEARC[1];
extern void (*CalcCost)(void **, long, long, long, long, long,
paramT *, long *, long *);
extern long (*EvalCost)(void **, short **, long, long, long, paramT *);
static
int IsTrue(char *str);
static
int IsFalse(char *str);
static
double ModDiff(double f1, double f2);
static
int IsTrue(char *str){
if(!strcmp(str,"TRUE") || !strcmp(str,"true") || !strcmp(str,"True")
|| !strcmp(str,"1") || !strcmp(str,"y") || !strcmp(str,"Y")
|| !strcmp(str,"yes") || !strcmp(str,"YES") || !strcmp(str,"Yes")){
return(TRUE);
}else{
return(FALSE);
}
}
static
int IsFalse(char *str){
if(!strcmp(str,"FALSE") || !strcmp(str,"false") || !strcmp(str,"False")
|| !strcmp(str,"0") || !strcmp(str,"n") || !strcmp(str,"N")
|| !strcmp(str,"no") || !strcmp(str,"NO") || !strcmp(str,"No")){
return(TRUE);
}else{
return(FALSE);
}
}
signed char SetBooleanSignedChar(signed char *boolptr, char *str){
if(IsTrue(str)){
(*boolptr)=TRUE;
return(FALSE);
}else if(IsFalse(str)){
(*boolptr)=FALSE;
return(FALSE);
}
return(TRUE);
}
static
double ModDiff(double f1, double f2){
double f3;
f3=f1-f2;
if(f3>PI){
f3-=TWOPI;
}else if(f3<=-PI){
f3+=TWOPI;
}
return(f3);
}
int WrapPhase(float **wrappedphase, long nrow, long ncol){
long row, col;
for(row=0;row<nrow;row++){
for(col=0;col<ncol;col++){
wrappedphase[row][col]-=TWOPI*floor(wrappedphase[row][col]/TWOPI);
}
}
return(0);
}
int CalcWrappedRangeDiffs(float **dpsi, float **avgdpsi, float **wrappedphase,
long kperpdpsi, long kpardpsi,
long nrow, long ncol){
long row, col;
float **paddpsi;
for(row=0;row<nrow;row++){
for(col=0;col<ncol-1;col++){
dpsi[row][col]=(wrappedphase[row][col+1]-wrappedphase[row][col])/TWOPI;
if(dpsi[row][col]>=0.5){
dpsi[row][col]-=1.0;
}else if(dpsi[row][col]<-0.5){
dpsi[row][col]+=1.0;
}
}
}
paddpsi=MirrorPad(dpsi,nrow,ncol-1,(kperpdpsi-1)/2,(kpardpsi-1)/2);
if(paddpsi==dpsi){
fflush(NULL);
fprintf(sp0,"Wrapped-gradient averaging box too large "
"for input array size\nAbort\n");
exit(ABNORMAL_EXIT);
}
BoxCarAvg(avgdpsi,paddpsi,nrow,ncol-1,kperpdpsi,kpardpsi);
Free2DArray((void **)paddpsi,nrow+kperpdpsi-1);
return(0);
}
int CalcWrappedAzDiffs(float **dpsi, float **avgdpsi, float **wrappedphase,
long kperpdpsi, long kpardpsi, long nrow, long ncol){
long row, col;
float **paddpsi;
for(row=0;row<nrow-1;row++){
for(col=0;col<ncol;col++){
dpsi[row][col]=(wrappedphase[row][col]-wrappedphase[row+1][col])/TWOPI;
if(dpsi[row][col]>=0.5){
dpsi[row][col]-=1.0;
}else if(dpsi[row][col]<-0.5){
dpsi[row][col]+=1.0;
}
}
}
paddpsi=MirrorPad(dpsi,nrow-1,ncol,(kpardpsi-1)/2,(kperpdpsi-1)/2);
if(paddpsi==dpsi){
fflush(NULL);
fprintf(sp0,"Wrapped-gradient averaging box too large "
"for input array size\nAbort\n");
exit(ABNORMAL_EXIT);
}
BoxCarAvg(avgdpsi,paddpsi,nrow-1,ncol,kpardpsi,kperpdpsi);
Free2DArray((void **)paddpsi,nrow-1+kpardpsi-1);
return(0);
}
int CycleResidue(float **phase, signed char **residue,
int nrow, int ncol){
int row, col;
float **rowdiff, **coldiff;
rowdiff=(float **)Get2DMem(nrow-1,ncol,sizeof(float *),sizeof(float));
coldiff=(float **)Get2DMem(nrow,ncol-1,sizeof(float *),sizeof(float));
for(row=0;row<nrow-1;row++){
for(col=0;col<ncol;col++){
rowdiff[row][col]=ModDiff(phase[row+1][col],phase[row][col]);
}
}
for(row=0;row<nrow;row++){
for(col=0;col<ncol-1;col++){
coldiff[row][col]=ModDiff(phase[row][col+1],phase[row][col]);
}
}
for(row=0;row<nrow-1;row++){
for(col=0;col<ncol-1;col++){
residue[row][col]=(signed char)LRound((coldiff[row][col]
+rowdiff[row][col+1]
-coldiff[row+1][col]
-rowdiff[row][col])/TWOPI);
}
}
Free2DArray((void **)rowdiff,nrow-1);
Free2DArray((void **)coldiff,nrow);
return(0);
}
int NodeResidue(float **wphase, long row, long col){
int residue;
residue=(int )LRound((ModDiff(wphase[row][col+1],wphase[row][col])
+ModDiff(wphase[row+1][col+1],wphase[row][col+1])
+ModDiff(wphase[row+1][col],wphase[row+1][col+1])
+ModDiff(wphase[row][col],wphase[row+1][col]))/TWOPI);
return(residue);
}
int CalcFlow(float **phase, short ***flowsptr, long nrow, long ncol){
long row, col;
if((*flowsptr)==NULL){
(*flowsptr)=(short **)Get2DRowColMem(nrow,ncol,
sizeof(short *),sizeof(short));
}
for(row=0;row<nrow-1;row++){
for(col=0;col<ncol;col++){
(*flowsptr)[row][col]=(short)LRound((phase[row][col]-phase[row+1][col])
/TWOPI);
}
}
for(row=0;row<nrow;row++){
for(col=0;col<ncol-1;col++){
(*flowsptr)[nrow-1+row][col]=(short)LRound((phase[row][col+1]
-phase[row][col])
/TWOPI);
}
}
return(0);
}
int IntegratePhase(float **psi, float **phi, short **flows,
long nrow, long ncol){
long row, col;
short **rowflow, **colflow;
rowflow=flows;
colflow=&(flows[nrow-1]);
phi[0][0]=psi[0][0];
for(col=1;col<ncol;col++){
phi[0][col]=phi[0][col-1]+(ModDiff(psi[0][col],psi[0][col-1])
+colflow[0][col-1]*TWOPI);
}
for(row=1;row<nrow;row++){
for(col=0;col<ncol;col++){
phi[row][col]=phi[row-1][col]+(ModDiff(psi[row][col],psi[row-1][col])
-rowflow[row-1][col]*TWOPI);
}
}
return(0);
}
float **ExtractFlow(float **unwrappedphase, short ***flowsptr,
long nrow, long ncol){
long row, col;
float **wrappedphase;
wrappedphase=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float));
for(row=0;row<nrow;row++){
for(col=0;col<ncol;col++){
wrappedphase[row][col]=unwrappedphase[row][col]
-TWOPI*floor(unwrappedphase[row][col]/TWOPI);
}
}
CalcFlow(unwrappedphase,flowsptr,nrow,ncol);
return(wrappedphase);
}
int FlipPhaseArraySign(float **arr, paramT *params, long nrow, long ncol){
long row, col;
if(params->flipphasesign){
for(row=0;row<nrow;row++){
for(col=0;col<ncol;col++){
arr[row][col]*=-1;
}
}
}
return(0);
}
int FlipFlowArraySign(short **arr, paramT *params, long nrow, long ncol){
long row, col, maxcol;
if(params->flipphasesign){
for(row=0;row<2*nrow-1;row++){
if(row<nrow-1){
maxcol=ncol;
}else{
maxcol=ncol-1;
}
for(col=0;col<maxcol;col++){
arr[row][col]=-arr[row][col];
}
}
}
return(0);
}
void **Get2DMem(int nrow, int ncol, int psize, size_t size){
long row;
void *baseptr;
void **arr;
if(nrow < 1 || ncol < 1){
return(NULL);
}
baseptr=CAlloc(nrow*ncol,size);
arr=(void **)MAlloc(nrow*sizeof(void *));
for(row=0;row<nrow;row++){
arr[row]=&(((char *)baseptr)[row*ncol*size]);
}
return(arr);
}
void **Get2DRowColMem(long nrow, long ncol, int psize, size_t size){
void **array;
array = Get2DRowColZeroMem(nrow,ncol,psize,size);
return(array);
}
void **Get2DRowColZeroMem(long nrow, long ncol, int psize, size_t size){
long row;
void *baseptr;
void **arr;
if(nrow < 1 || ncol < 1){
return(NULL);
}
baseptr=CAlloc((nrow-1)*ncol+nrow*(ncol-1),size);
arr=(void **)MAlloc((2*nrow-1)*sizeof(void *));
for(row=0;row<nrow-1;row++){
arr[row]=&(((char *)baseptr)[row*ncol*size]);
}
for(row=nrow-1;row<2*nrow-1;row++){
arr[row]=&(((char *)baseptr)[((nrow-1)*ncol+(row-(nrow-1))*(ncol-1))*size]);
}
return(arr);
}
void *MAlloc(size_t size){
void *ptr;
if(size==0){
return(NULL);
}
if((ptr=malloc(size))==NULL){
fflush(NULL);
fprintf(sp0,"Out of memory\n");
exit(ABNORMAL_EXIT);
}
return(ptr);
}
void *CAlloc(size_t nitems, size_t size){
void *ptr;
if(size==0){
return(NULL);
}
if((ptr=calloc(nitems,size))==NULL){
fflush(NULL);
fprintf(sp0,"Out of memory\n");
exit(ABNORMAL_EXIT);
}
return(ptr);
}
void *ReAlloc(void *ptr, size_t size){
void *ptr2;
if(size==0){
if(ptr!=NULL){
free(ptr);
}
return(NULL);
}
if((ptr2=realloc(ptr,size))==NULL){
fflush(NULL);
fprintf(sp0,"Out of memory\n");
exit(ABNORMAL_EXIT);
}
return(ptr2);
}
int Free2DArray(void **array, unsigned int nrow){
if(array != NULL){
if(array[0] != NULL){
free(array[0]);
array[0] = NULL;
}
free(array);
}
return(0);
}
int Set2DShortArray(short **arr, long nrow, long ncol, long value){
long row, col;
for(row=0;row<nrow;row++){
for(col=0;col<ncol;col++){
arr[row][col]=value;
}
}
return(0);
}
signed char ValidDataArray(float **arr, long nrow, long ncol){
long row, col;
for(row=0;row<nrow;row++){
for(col=0;col<ncol;col++){
if(!IsFinite(arr[row][col])){
return(FALSE);
}
}
}
return(TRUE);
}
signed char NonNegDataArray(float **arr, long nrow, long ncol){
long row, col;
for(row=0;row<nrow;row++){
for(col=0;col<ncol;col++){
if(arr[row][col] < 0){
return(FALSE);
}
}
}
return(TRUE);
}
signed char IsFinite(double d){
#ifdef SNAPHU_USE_FINITE
return(finite(d));
#else
return(isfinite(d));
#endif
}
long LRound(double a){
return((long )rint(a));
}
long LMin(long a, long b){
if(a<b){
return(a);
}else{
return(b);
}
}
long LClip(long a, long minval, long maxval){
if(a<minval){
return(minval);
}else if(a>maxval){
return(maxval);
}else{
return(a);
}
}
long Short2DRowColAbsMax(short **arr, long nrow, long ncol){
long row, col, maxval;
maxval=0;
for(row=0;row<nrow-1;row++){
for(col=0;col<ncol;col++){
if(labs(arr[row][col])>maxval){
maxval=labs(arr[row][col]);
}
}
}
for(row=nrow-1;row<2*nrow-1;row++){
for(col=0;col<ncol-1;col++){
if(labs(arr[row][col])>maxval){
maxval=labs(arr[row][col]);
}
}
}
return(maxval);
}
float LinInterp1D(float *arr, double index, long nelem){
long intpart;
double fracpart;
intpart=(long )floor(index);
fracpart=index-intpart;
if(intpart<0){
return(arr[0]);
}else if(intpart>=nelem-1){
return(arr[nelem-1]);
}else{
return(((1-fracpart)*arr[intpart]+fracpart*arr[intpart+1])/2.0);
}
}
float LinInterp2D(float **arr, double rowind, double colind ,
long nrow, long ncol){
long rowintpart;
double rowfracpart;
rowintpart=(long )floor(rowind);
rowfracpart=rowind-rowintpart;
if(rowintpart<0){
return(LinInterp1D(arr[0],colind,ncol));
}else if(rowintpart>=nrow-1){
return(LinInterp1D(arr[nrow-1],colind,ncol));
}else{
return(((1-rowfracpart)*LinInterp1D(arr[rowintpart],colind,ncol)
+rowfracpart*LinInterp1D(arr[rowintpart+1],colind,ncol))/2.0);
}
}
int Despeckle(float **mag, float ***ei, long nrow, long ncol){
float **intensity;
double ratio, ratiomax, wfull, wstick, w[NARMS+1];
long row, col, i, j, k, Irow, Icol;
short jmin[5]={2,2,0,1,2};
short jmax[5]={2,3,4,3,2};
enum{ C=0, T, B, R, L, TR, BL, TL, BR};
if(*ei==NULL){
(*ei)=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float));
}
intensity=MirrorPad(mag,nrow,ncol,ARMLEN,ARMLEN);
if(intensity==mag){
fflush(NULL);
fprintf(sp0,"Despeckling box size too large for input array size\n"
"Abort\n");
exit(ABNORMAL_EXIT);
}
for(row=0;row<nrow;row++){
Irow=row+ARMLEN;
for(col=0;col<ncol;col++){
Icol=col+ARMLEN;
if(intensity[Irow][Icol]==0){
(*ei)[row][col]=0;
}else{
for(k=0;k<NARMS+1;k++){
w[k]=0;
}
for(i=-1;i<=1;i++){
for(j=-1;j<=1;j++){
w[C]+=intensity[Irow+i][Icol+j];
}
}
for(i=-1;i<=1;i++){
for(j=2;j<ARMLEN+1;j++){
w[T]+=intensity[Irow-j][Icol+i];
w[B]+=intensity[Irow+j][Icol+i];
w[L]+=intensity[Irow+i][Icol-j];
w[R]+=intensity[Irow+i][Icol+j];
}
}
for(i=0;i<=4;i++){
for(j=jmin[i];j<=jmax[i];j++){
w[TR]+=intensity[Irow-i][Icol+j];
w[BR]+=intensity[Irow+i][Icol+j];
w[BL]+=intensity[Irow+i][Icol-j];
w[TL]+=intensity[Irow-i][Icol-j];
}
}
wfull=w[C]+w[T]+w[R]+w[B]+w[L];
for(i=2;i<5;i++){
for(j=2;j<7-i;j++){
wfull+=intensity[Irow+i][Icol+j];
wfull+=intensity[Irow-i][Icol+j];
wfull+=intensity[Irow+i][Icol-j];
wfull+=intensity[Irow-i][Icol-j];
}
}
ratiomax=1;
for(k=1;k<=NARMS;k+=2){
wstick=w[0]+w[k]+w[k+1];
if((ratio=wstick/(wfull-wstick))<1){
ratio=1/ratio;
}
if(ratio>ratiomax){
ratiomax=ratio;
(*ei)[row][col]=wstick;
}
}
}
}
}
Free2DArray((void **)intensity,nrow+2*ARMLEN);
return(0);
}
float **MirrorPad(float **array1, long nrow, long ncol, long krow, long kcol){
long row, col;
float **array2;
array2=(float **)Get2DMem(nrow+2*krow,ncol+2*kcol,
sizeof(float *),sizeof(float));
for(row=0;row<nrow;row++){
for(col=0;col<ncol;col++){
array2[row+krow][col+kcol]=array1[row][col];
}
}
if(krow>nrow || kcol>ncol){
return(array1);
}
for(row=0;row<krow;row++){
for(col=0;col<kcol;col++){
array2[row][col]=array2[2*krow-row][2*kcol-col];
array2[row][ncol+kcol+col]
=array2[2*krow-row][ncol+kcol-2-col];
array2[nrow+krow+row][col]
=array2[nrow+krow-2-row][2*kcol-col];
array2[nrow+krow+row][ncol+kcol+col]
=array2[nrow+krow-2-row][ncol+kcol-2-col];
}
}
for(row=krow;row<nrow+krow;row++){
for(col=0;col<kcol;col++){
array2[row][col]=array2[row][2*kcol-col];
array2[row][ncol+kcol+col]
=array2[row][ncol+kcol-2-col];
}
}
for(col=kcol;col<ncol+kcol;col++){
for(row=0;row<krow;row++){
array2[row][col]=array2[2*krow-row][col];
array2[nrow+krow+row][col]
=array2[nrow+krow-2-row][col];
}
}
return(array2);
}
int BoxCarAvg(float **avgarr, float **padarr, long nrow, long ncol,
long krow, long kcol){
long i, row, col, n;
double window;
for(row=0;row<nrow;row++){
window=0;
for(i=row;i<row+krow;i++){
for(col=0;col<kcol;col++){
window+=padarr[i][col];
}
}
avgarr[row][0]=(float )window;
for(col=1;col<ncol;col++){
for(i=row;i<row+krow;i++){
window-=padarr[i][col-1];
window+=padarr[i][col+kcol-1];
}
avgarr[row][col]=(float )window;
}
}
n=krow*kcol;
for(row=0;row<nrow;row++){
for(col=0;col<ncol;col++){
avgarr[row][col]/=n;
}
}
return(0);
}
char *StrNCopy(char *dest, const char *src, size_t n){
char *s;
s=strncpy(dest,src,n-1);
dest[n-1]='\0';
return(s);
}
int FlattenWrappedPhase(float **wrappedphase, float **unwrappedest,
long nrow, long ncol){
long row, col;
for(row=0;row<nrow;row++){
for(col=0;col<ncol;col++){
wrappedphase[row][col]-=unwrappedest[row][col];
wrappedphase[row][col]=fmod(wrappedphase[row][col],TWOPI);
if(wrappedphase[row][col]<0){
wrappedphase[row][col]+=TWOPI;
}
}
}
return(0);
}
int Add2DFloatArrays(float **arr1, float **arr2, long nrow, long ncol){
long row, col;
for(row=0;row<nrow;row++){
for(col=0;col<ncol;col++){
arr1[row][col]+=arr2[row][col];
}
}
return(0);
}
int StringToDouble(char *str, double *d){
double tempdouble;
char *endp;
endp=str;
tempdouble=strtod(str,&endp);
if(strlen(endp) || tempdouble>=HUGE_VAL || tempdouble<=-HUGE_VAL){
return(TRUE);
}else{
*d=tempdouble;
return(FALSE);
}
}
int StringToLong(char *str, long *l){
long templong;
char *endp;
endp=str;
templong=strtol(str,&endp,10);
if(strlen(endp) || templong==LONG_MAX || templong==LONG_MIN){
return(TRUE);
}else{
*l=templong;
return(FALSE);
}
}
int CatchSignals(void (*SigHandler)(int)){
signal(SIGHUP,SigHandler);
signal(SIGINT,SigHandler);
signal(SIGQUIT,SigHandler);
signal(SIGILL,SigHandler);
signal(SIGABRT,SigHandler);
signal(SIGFPE,SigHandler);
signal(SIGSEGV,SigHandler);
signal(SIGPIPE,SigHandler);
signal(SIGALRM,SigHandler);
signal(SIGTERM,SigHandler);
signal(SIGBUS,SigHandler);
return(0);
}
void SetDump(int signum){
if(signum==SIGINT){
signal(SIGINT,exit);
fflush(NULL);
fprintf(sp0,"\n\nSIGINT signal caught. Please wait for graceful exit\n");
fprintf(sp0,"(One more interrupt signal halts job)\n");
dumpresults_global=TRUE;
requestedstop_global=TRUE;
}else if(signum==SIGHUP){
signal(SIGHUP,SetDump);
fflush(NULL);
fprintf(sp0,"\n\nSIGHUP signal caught. Dumping results\n");
dumpresults_global=TRUE;
}else{
fflush(NULL);
fprintf(sp0,"WARNING: Invalid signal (%d) passed to signal handler\n",
signum);
}
return;
}
void KillChildrenExit(int signum){
fflush(NULL);
fprintf(sp0,"Parent received signal %d\nKilling children and exiting\n",
signum);
fflush(NULL);
signal(SIGTERM,SIG_IGN);
kill(0,SIGTERM);
exit(ABNORMAL_EXIT);
return;
}
void SignalExit(int signum){
signal(SIGTERM,SIG_IGN);
fflush(NULL);
fprintf(sp0,"Exiting with status %d on signal %d\n",ABNORMAL_EXIT,signum);
fflush(NULL);
exit(ABNORMAL_EXIT);
return;
}
int StartTimers(time_t *tstart, double *cputimestart){
struct rusage usagebuf;
*tstart=time(NULL);
*cputimestart=-1.0;
if(!getrusage(RUSAGE_SELF,&usagebuf)){
*cputimestart=(double )(usagebuf.ru_utime.tv_sec
+(usagebuf.ru_utime.tv_usec/(double )1000000)
+usagebuf.ru_stime.tv_sec
+(usagebuf.ru_stime.tv_usec/(double )1000000));
if(!getrusage(RUSAGE_CHILDREN,&usagebuf)){
*cputimestart+=(double )(usagebuf.ru_utime.tv_sec
+(usagebuf.ru_utime.tv_usec/(double )1000000)
+usagebuf.ru_stime.tv_sec
+(usagebuf.ru_stime.tv_usec/(double )1000000));
}
}
return(0);
}
int DisplayElapsedTime(time_t tstart, double cputimestart){
double cputime, walltime, seconds;
long hours, minutes;
time_t tstop;
struct rusage usagebuf;
cputime=-1.0;
if(!getrusage(RUSAGE_CHILDREN,&usagebuf)){
cputime=(double )(usagebuf.ru_utime.tv_sec
+(usagebuf.ru_utime.tv_usec/(double )1000000)
+usagebuf.ru_stime.tv_sec
+(usagebuf.ru_stime.tv_usec/(double )1000000));
if(!getrusage(RUSAGE_SELF,&usagebuf)){
cputime+=(double )(usagebuf.ru_utime.tv_sec
+(usagebuf.ru_utime.tv_usec/(double )1000000)
+usagebuf.ru_stime.tv_sec
+(usagebuf.ru_stime.tv_usec/(double )1000000));
}
}
tstop=time(NULL);
if(cputime>0 && cputimestart>=0){
cputime-=cputimestart;
hours=(long )floor(cputime/3600);
minutes=(long )floor((cputime-3600*hours)/60);
seconds=cputime-3600*hours-60*minutes;
fprintf(sp1,"Elapsed processor time: %ld:%02ld:%05.2f\n",
hours,minutes,seconds);
}
if(tstart>0 && tstop>0){
walltime=tstop-tstart;
hours=(long )floor(walltime/3600);
minutes=(long )floor((walltime-3600*hours)/60);
seconds=walltime-3600*hours-60*minutes;
fprintf(sp1,"Elapsed wall clock time: %ld:%02ld:%02ld\n",
hours,minutes,(long )seconds);
}
return(0);
}
int LongCompare(const void *c1, const void *c2){
return((*((long *)c1))-(*((long *)c2)));
}