ISCE_INSAR/contrib/Snaphu/src/snaphu_util.c

1147 lines
29 KiB
C
Raw Normal View History

2019-01-16 19:40:08 +00:00
/*************************************************************************
snaphu utility function source file
Written by Curtis W. Chen
Copyright 2002 Board of Trustees, Leland Stanford Jr. University
Please see the supporting documentation for terms of use.
No warranty.
*************************************************************************/
#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 <sys/time.h>
#include <sys/resource.h>
#include "snaphu.h"
/* function: IsTrue()
* ------------------
* Returns TRUE if the string input is any of TRUE, True, true, 1,
* y, Y, yes, YES
*/
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);
}
}
/* function: IsFalse()
* ------------------
* Returns FALSE if the string input is any of FALSE, False, false,
* 0, n, N, no, NO
*/
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);
}
}
/* function: SetBoolenaSignedChar()
* --------------------------------
* Sets the value of a signed character based on the string argument passed.
* Returns TRUE if the string was not a valid value, FALSE otherwise.
*/
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);
}
/* function: ModDiff()
* -------------------
* Computes floating point difference between two numbers.
* f1 and f2 should be between [0,2pi). The result is the
* modulo difference between (-pi,pi]. Assumes that
* PI and TWOPI have been defined.
*/
double ModDiff(double f1, double f2){
double f3;
f3=f1-f2;
if(f3>PI){
f3-=TWOPI;
}else if(f3<=-PI){
f3+=TWOPI;
}
return(f3);
}
/* function: WrapPhase()
* ---------------------
* Makes sure the passed float array is properly wrapped into the [0,2pi)
* interval.
*/
void 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);
}
}
}
/* function: CalcWrappedRangeDiffs()
* ---------------------------------
* Computes an array of wrapped phase differences in range (across rows).
* Input wrapped phase array should be in radians. Output is in cycles.
*/
void 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){
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);
}
/* function: CalcWrappedAzDiffs()
* ---------------------------------
* Computes an array of wrapped phase differences in range (across rows).
* Input wrapped phase array should be in radians. Output is in cycles.
*/
void 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){
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);
}
/* function: CycleResidue()
* ------------------------
* Computes the cycle array of a phase 2D phase array. Input arrays
* should be type float ** and signed char ** with memory pre-allocated.
* Numbers of rows and columns in phase array should be passed.
* Residue array will then have size nrow-1 x ncol-1. Residues will
* always be -1, 0, or 1 if wrapped phase is passed in.
*/
void 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);
}
/* function: CalcFlow()
* --------------------
* Calculates flow based on unwrapped phase data in a 2D array.
* Allocates memory for row and column flow arrays.
*/
void CalcFlow(float **phase, short ***flowsptr, long nrow, long ncol){
long row, col;
/* get memory for flow arrays */
if((*flowsptr)==NULL){
(*flowsptr)=(short **)Get2DRowColMem(nrow,ncol,
sizeof(short *),sizeof(short));
}
/* get row flows (vertical phase differences) */
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);
}
}
/* get col flows (horizontal phase differences) */
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);
}
}
}
/* function: IntegratePhase()
* --------------------------
* This function takes row and column flow information and integrates
* wrapped phase to create an unwrapped phase field. The unwrapped
* phase field will be the same size as the wrapped field. The array
* rowflow should have size N-1xM and colflow size NxM-1 where the
* phase fields are NxM. Output is saved to a file.
*/
void IntegratePhase(float **psi, float **phi, short **flows,
long nrow, long ncol){
long row, col;
short **rowflow, **colflow;
rowflow=flows;
colflow=&(flows[nrow-1]);
/* set first element as seed */
phi[0][0]=psi[0][0];
/* integrate over first row */
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);
}
/* integrate over columns */
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);
}
}
}/* end IntegratePhase() */
/* function: ExtractFlow()
* -----------------------
* Given an unwrapped phase array, parse the data and find the flows.
* Assumes only integer numbers of cycles have been added to get the
* unwrapped phase from the wrapped pase. Gets memory and writes
* wrapped phase to passed pointer. Assumes flows fit into short ints.
*/
float **ExtractFlow(float **unwrappedphase, short ***flowsptr,
long nrow, long ncol){
long row, col;
float **wrappedphase;
/* get memory for wrapped phase array */
wrappedphase=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float));
/* calculate wrapped phase */
for(row=0;row<nrow;row++){
for(col=0;col<ncol;col++){
/* fmod() gives wrong results here (maybe because of float argument?) */
/* wrappedphase[row][col]=fmod(unwrappedphase[row][col],TWOPI); */
wrappedphase[row][col]=unwrappedphase[row][col]
-TWOPI*floor(unwrappedphase[row][col]/TWOPI);
}
}
/* calculate flows */
CalcFlow(unwrappedphase,flowsptr,nrow,ncol);
/* return pointer to wrapped phase array */
return(wrappedphase);
}
/* function: FlipPhaseArraySign()
* ------------------------------
* Flips the sign of all values in a passed array if the flip flag is set.
* Otherwise, does nothing.
*/
void 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;
}
}
}
}
/* function: FlipFlowArraySign()
* ------------------------------
* Flips the sign of all values in a row-by-column array if the flip
* flip flag is set. Otherwise, does nothing.
*/
void 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];
}
}
}
}
/* function: Get2DMem()
* --------------------
* Allocates memory for 2D array.
* Dynamically allocates memory and returns pointer of
* type void ** for an array of size nrow x ncol.
* First index is row number: array[row][col]
* size is size of array element, psize is size of pointer
* to array element (eg sizeof(float *)).
*/
void **Get2DMem(int nrow, int ncol, int psize, size_t size){
int row;
void **array;
if((array=malloc(nrow*psize))==NULL){
fprintf(sp0,"Out of memory\n");
exit(ABNORMAL_EXIT);
}
for(row=0; row<nrow; row++){
if((array[row]=malloc(ncol*size))==NULL){
fprintf(sp0,"Out of memory\n");
exit(ABNORMAL_EXIT);
}
}
return(array);
}
/* function: Get2DRowColMem()
* --------------------------
* Allocates memory for 2D array. The array will have 2*nrow-1 rows.
* The first nrow-1 rows will have ncol columns, and the rest will
* have ncol-1 columns.
*/
void **Get2DRowColMem(long nrow, long ncol, int psize, size_t size){
long row;
void **array;
if((array=malloc((2*nrow-1)*psize))==NULL){
fprintf(sp0,"Out of memory\n");
exit(ABNORMAL_EXIT);
}
for(row=0; row<nrow-1; row++){
if((array[row]=malloc(ncol*size))==NULL){
fprintf(sp0,"Out of memory\n");
exit(ABNORMAL_EXIT);
}
}
for(row=nrow-1; row<2*nrow-1; row++){
if((array[row]=malloc((ncol-1)*size))==NULL){
fprintf(sp0,"Out of memory\n");
exit(ABNORMAL_EXIT);
}
}
return(array);
}
/* function: Get2DRowColZeroMem()
* ------------------------------
* Allocates memory for 2D array. The array will have 2*nrow-1 rows.
* The first nrow-1 rows will have ncol columns, and the rest will
* have ncol-1 columns. Memory is initialized to zero.
*/
void **Get2DRowColZeroMem(long nrow, long ncol, int psize, size_t size){
long row;
void **array;
if((array=malloc((2*nrow-1)*psize))==NULL){
fprintf(sp0,"Out of memory\n");
exit(ABNORMAL_EXIT);
}
for(row=0; row<nrow-1; row++){
if((array[row]=calloc(ncol,size))==NULL){
fprintf(sp0,"Out of memory\n");
exit(ABNORMAL_EXIT);
}
}
for(row=nrow-1; row<2*nrow-1; row++){
if((array[row]=calloc((ncol-1),size))==NULL){
fprintf(sp0,"Out of memory\n");
exit(ABNORMAL_EXIT);
}
}
return(array);
}
/* function: MAlloc()
* --------------------
* Has same functionality as malloc(), but exits if out of memory.
*/
void *MAlloc(size_t size){
void *ptr;
if((ptr=malloc(size))==NULL){
fprintf(sp0,"Out of memory\n");
exit(ABNORMAL_EXIT);
}
return(ptr);
}
/* function: CAlloc()
* ------------------
* Has same functionality as calloc(), but exits if out of memory.
*/
void *CAlloc(size_t nitems, size_t size){
void *ptr;
if((ptr=calloc(nitems,size))==NULL){
fprintf(sp0,"Out of memory\n");
exit(ABNORMAL_EXIT);
}
return(ptr);
}
/* function: ReAlloc()
* -------------------
* Has same functionality as realloc(), but exits if out of memory.
*/
void *ReAlloc(void *ptr, size_t size){
void *ptr2;
if((ptr2=realloc(ptr,size))==NULL){
fprintf(sp0,"Out of memory\n");
exit(ABNORMAL_EXIT);
}
return(ptr2);
}
/* function: Free2DArray()
* -----------------------
* This function frees the dynamically allocated memory for a 2D
* array. Pass in a pointer to a pointer cast to a void **.
* The function assumes the array is of the form arr[rows][cols]
* so that nrow is the number of elements in the pointer array.
*/
void Free2DArray(void **array, unsigned int nrow){
int row;
for(row=0; row<nrow; row++){
free(array[row]);
}
free(array);
}
/* function: Set2DShortArray()
* -------------------------
* Sets all entries of a 2D array of shorts to the given value. Assumes
* that memory is already allocated.
*/
void 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;
}
}
}
/* function: ValidDataArray()
* --------------------------
* Given a 2D floating point array, returns FALSE if any elements are NaN
* or infinite, and TRUE otherwise (uses math library finite() function).
*/
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);
}
/* function: IsFinite()
* --------------------
* This function takes a double and returns a nonzero value if
* the arguemnt is finite (not NaN and not infinite), and zero otherwise.
* Different implementations are given here since not all machines have
* these functions available.
*/
signed char IsFinite(double d){
return(finite(d));
/* return(isfinite(d)); */
/* return(!(isnan(d) || isinf(d))); */
/* return(TRUE) */
}
/* function: LRound()
* ------------------
* Rounds a floating point number to the nearest integer.
* The function takes a float and returns a long.
*/
long LRound(double a){
return((long )rint(a));
}
/* function: Short2DRowColAbsMax()
* -------------------------------
* Returns the maximum of the absolute values of element in a
* two-dimensional short array. The number of rows and columns
* should be passed in.
*/
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);
}
/* function: LinInterp1D()
* -----------------------
* Given an array of floats, interpolates at the specified noninteger
* index. Returns first or last array value if index is out of bounds.
*/
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);
}
}
/* function: LinInterp2D()
* -----------------------
* Given a 2-D array of floats, interpolates at the specified noninteger
* indices. Returns first or last array values if index is out of bounds.
*/
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);
}
}
/* function: Despeckle()
* ---------------------
* Filters magnitude/power data with adaptive geometric filter to get rid of
* speckle. Allocates 2D memory for ei. Does not square before averaging.
*/
void 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};
/* get memory for output array */
if(*ei==NULL){
(*ei)=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float));
}
/* pad magnitude and place into new array (don't touch original data) */
intensity=MirrorPad(mag,nrow,ncol,ARMLEN,ARMLEN);
if(intensity==mag){
fprintf(sp0,"Despeckling box size too large for input array size\n"
"Abort\n");
exit(ABNORMAL_EXIT);
}
/* do the filtering */
for(row=0;row<nrow;row++){
Irow=row+ARMLEN;
for(col=0;col<ncol;col++){
Icol=col+ARMLEN;
/* filter only if input is nonzero so we preserve mask info in input */
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;
}
}
}
}
}
/* free memory */
Free2DArray((void **)intensity,nrow+2*ARMLEN);
}
/* function: MirrorPad()
* ---------------------
* Returns pointer to 2D array where passed array is in center and
* edges are padded by mirror reflections. If the pad dimensions are
* too large for the array size, a pointer to the original array is
* returned.
*/
float **MirrorPad(float **array1, long nrow, long ncol, long krow, long kcol){
long row, col;
float **array2;
/* get memory */
array2=(float **)Get2DMem(nrow+2*krow,ncol+2*kcol,
sizeof(float *),sizeof(float));
/* center array1 in new array */
for(row=0;row<nrow;row++){
for(col=0;col<ncol;col++){
array2[row+krow][col+kcol]=array1[row][col];
}
}
/* make sure pad is less than image dimensions */
/* if array is too small for pad dimensions, return original array */
/* requires checking by calling function */
if(krow>nrow || kcol>ncol){
return(array1);
}
/* mirror reflect edges */
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 a pointer to the padded array */
return(array2);
}
/* function: BoxCarAvg()
* ---------------------
* Takes in 2-D array, convolves with boxcar filter of size specified.
* Uses a recursion technique (but the function does not actually call
* itself recursively) to compute the result, so there may be roundoff
* errors.
*/
void BoxCarAvg(float **avgarr, float **padarr, long nrow, long ncol,
long krow, long kcol){
long i, row, col, n;
double window;
/* loop over all rows */
for(row=0;row<nrow;row++){
/* calculate first cell */
window=0;
for(i=row;i<row+krow;i++){
for(col=0;col<kcol;col++){
window+=padarr[i][col];
}
}
avgarr[row][0]=(float )window;
/* convolve window with row, using result of last cell */
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;
}
}
/* normalize */
n=krow*kcol;
for(row=0;row<nrow;row++){
for(col=0;col<ncol;col++){
avgarr[row][col]/=n;
}
}
}
/* function: StrNCopy()
* --------------------
* Just like strncpy(), but terminates string by putting a null
* character at the end (may overwrite last character).
*/
char *StrNCopy(char *dest, const char *src, size_t n){
char *s;
s=strncpy(dest,src,n-1);
dest[n-1]='\0';
return(s);
}
/* function: FlattenWrappedPhase()
* -------------------------------
* Given a wrapped phase array and an unwrapped phase array, subtracts
* the unwrapped data elementwise from the wrapped data and stores
* the result, rewrapped to [0,2pi), in the wrapped array.
*/
void FlattenWrappedPhase(float **wrappedphase, float **unwrappedest,
long nrow, long ncol){
long row, col;
/* loop to subtract, rewrap, store in wrapped array. */
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;
}
}
}
}
/* function: Add2DFloatArrays()
* ----------------------------
* Addes the values of two 2-D arrays elementwise.
*/
void Add2DFloatArrays(float **arr1, float **arr2, long nrow, long ncol){
long row, col;
/* loop over all rows and columns, add and store result in first array */
for(row=0;row<nrow;row++){
for(col=0;col<ncol;col++){
arr1[row][col]+=arr2[row][col];
}
}
}
/* function: StringToDouble()
* --------------------------
* Uses strtod to convert a string to a double, but also does error checking.
* If any part of the string is not converted, the function does not make
* the assignment and returns TRUE. Otherwise, returns FALSE.
*/
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);
}
}
/* function: StringToLong()
* ------------------------
* Uses strtol to convert a string to a base-10 long, but also does error
* checking. If any part of the string is not converted, the function does
* not make the assignment and returns TRUE. Otherwise, returns 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);
}
}
/* function: CatchSignals()
* ------------------------
* Traps common signals that by default cause the program to abort.
* Sets (pointer to function) Handler as the signal handler for all.
* Note that SIGKILL usually cannot be caught. No return value.
*/
void 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);
}
/* function: SetDump()
* -------------------
* Set the global variable dumpresults_global to TRUE if SIGINT or SIGHUP
* signals recieved. Also sets requestedstop_global if SIGINT signal
* received. This function should only be called via signal() when
* a signal is caught.
*/
void SetDump(int signum){
if(signum==SIGINT){
/* exit if we receive another interrupt */
signal(SIGINT,exit);
/* print nice message and set global variables so program knows to exit */
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){
/* make sure the hangup signal doesn't revert to default behavior */
signal(SIGHUP,SetDump);
/* print a nice message, and set the dump variable */
fprintf(sp0,"\n\nSIGHUP signal caught. Dumping results\n");
dumpresults_global=TRUE;
}else{
fprintf(sp0,"WARNING: Invalid signal (%d) passed to signal handler\n",
signum);
}
}
/* function: KillChildrenExit()
* ----------------------------
* Signal handler that sends a KILL signal to all processes in the group
* so that children exit when parent exits.
*/
void KillChildrenExit(int signum){
fprintf(sp0,"Parent received signal %d\nKilling children and exiting\n",
signum);
fflush(NULL);
signal(SIGTERM,SIG_IGN);
kill(0,SIGTERM);
exit(ABNORMAL_EXIT);
}
/* function: SignalExit()
* ----------------------
* Signal hanlder that prints message about the signal received, then exits.
*/
void SignalExit(int signum){
signal(SIGTERM,SIG_IGN);
fprintf(sp0,"Exiting with status %d on signal %d\n",ABNORMAL_EXIT,signum);
fflush(NULL);
exit(ABNORMAL_EXIT);
}
/* function: StartTimers()
* -----------------------
* Starts the wall clock and CPU timers for use in conjunction with
* DisplayElapsedTime().
*/
void 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));
}
}
}
/* function: DisplayElapsedTime()
* ------------------------------
* Displays the elapsed wall clock and CPU times for the process and its
* children. Times should be initialized at the start of the program with
* StartTimers(). The code is written to show the total processor time
* for the parent process and all of its children, but whether or not
* this is actually done depends on the implementation of the system time
* functions.
*/
void 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);
}
}
/* function: LongCompare()
* -----------------------
* Compares two long integers. For use with qsort().
*/
int LongCompare(const void *c1, const void *c2){
return((*((long *)c1))-(*((long *)c2)));
}