PaxHeader/snaphu-v2.0.6000755 777777 777777 00000000043 14423062415 014624 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/000755 Ho)00000000000 14423062415 014130 5ustar00curtis000000 000000 snaphu-v2.0.6/PaxHeader/man000755 777777 777777 00000000043 14423062415 015377 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/man/000755 Ho)00000000000 14423062415 014703 5ustar00curtis000000 000000 snaphu-v2.0.6/PaxHeader/bin000755 777777 777777 00000000101 14423062610 015364 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 30 mtime=1682728328.669752948 snaphu-v2.0.6/bin/000755 Ho)00000000000 14423062610 014675 5ustar00curtis000000 000000 snaphu-v2.0.6/PaxHeader/README_releasenotes.txt000644 777777 777777 00000000043 14423062415 021145 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/README_releasenotes.txt000644 Ho)00000016165 14423062415 020410 0ustar00curtis000000 000000 Notable changes in v2.0.6 since v2.0.5: --------------------------------------- * Change conditions for breaking out of outermost loop over flow increments in optimizer to avoid possible infinite loop issue. Notable changes in v2.0.5 since v2.0.4: --------------------------------------- * Change definition of connectivity of nodes that are completely separated by masked pixels to fix bugs that could cause crash and/or infinite looping when regions are separated by single row or column of masked pixels. Notable changes in v2.0.4 since v2.0.3: --------------------------------------- * Fixed logic error that would sometimes cause crash in MCF solver when flow went from ground node to lower right corner node. * Untabify source files (whitespace changes only) Notable changes in v2.0.3 since v2.0.2: --------------------------------------- * Fixed limit-checking error that would sometimes cause segmentation fault when width of masked area was only one pixel at right or bottom edges. Notable changes in v2.0.2 since v2.0.1: --------------------------------------- * Fixed indexing error that would sometimes cause segmentation fault when discharging boundary of masked region. Notable changes in v2.0.1 since v2.0.0: --------------------------------------- * Bug fixes affecting externally generated costs read from a file and handling of zero-cost primary and secondary arcs. Notable changes in v2.0 since v1.4.2: ------------------------------------- * The new -S option invokes behavior whereby snaphu will first run in tile mode to produce an unwrapped solution then feed this unwrapped solution back into the cost calculator and optimizer as if an unwrapped phase file were read from the input. This option is equivalent to running snaphu in tile mode, then running snaphu again using the tile-mode output as an unwrapped input file using the -u option. Tile parameters must be specified when using the -S option. * Masking of input pixels is now supported. A typical usage of masking would be in unwrapping repeat-pass interferograms where water areas are expected to have zero correlation; a water mask can be used to exclude such areas in order to reduce the execution time. When computing costs, arcs through masked areas are assumed to have zero cost, so nodes internal to masked areas can be ignored in the solver, thereby reducing the total number of nodes and usually decreasing the solution time. An unwrapped phase output value will still be produced for each masked pixel, but the unwrapped value will not generally be reliable; often it will be whatever value is left from the initialization. The user can indicate masking by setting the magnitudes of the complex values of pixels to be masked to zero in the input file or by specifying a separate binary mask via the new -M option or the new BYTEMASKFILE keyword. See the comments in the template configuration file for the BYTEMASKFILE keyword for a full description of the file format. A fixed number of pixels at each edge of the input file can also be masked via the EDGEMASKTOP, EDGEMASKBOT, EDGEMASKLEFT, and EDGEMASKRIGHT keywords. If masked pixels separate regions of unmasked pixels, the unwrapped phase relationship between the disconnected regions will not generally be reliable, though a solution for each region will still produced (also see the NCONNNODEMIN keyword). * The new -C command-line option takes a string argument that is parsed as a configuration line like one that would be put into a configuration file. The string argument to the -C option may need to be protected from the shell by quotes to preserve whitespace. * The integer types of several internal variables have changed now that 64-bit systems have generally replaced 32-bit systems. The memory footprint of snaphu v2.0 is approximately 20% smaller than that of v1.4.2 when both are compiled as 64 bit binaries on an Intel system. The memory footprint of snaphu v2.0 is similar to (about 2% larger than) that of v1.4.2 when both are compiled as a 32-bit binary, but v2.0 should be less constrained in terms of the input interferogram size. The memory footprint of v2.0 when compiled as a 64-bit binary is about 30% larger than when the same code (v2.0) is compiled as a 32-bit binary, although it is expected that most users will compile snaphu as a 64-bit binary nonetheless given the availability of memory on most systems. * The syntax of the ASSEMBLEONLY keyword and the --assemble command-line option have changed so that they are now boolean flags. The name of the tile directory to assemble is specified through the new keyword TILEDIR or the --tiledir command-line option. Additionally, the new keyword DOTILEMASK allows the user to unwrap only selected tiles for manual experimentation and assembly of tiles. * When unwrapping in tile mode, the default behavior is now to remove temporary tile files rather than to keep them. Users can specify the new -k option on the command line or set the RMTMPTILE keyword to FALSE in a config file to keep temporary tile files. * A warning is now displayed if running in tile mode and the tile overlap is less than a semi-arbitrary constant warning threshold. A suggestion is displayed about increasing overlap or tile size if edge artifacts are present if the overlap is less than the tile size. * Connected components are now supported in tile mode. The connected components are assembled from the connected components of individual tiles and renumbered to be unique, but they will break at tile boundaries. It is possible that a component will not be fully connected in the assembled output if the component was connected only in the tile overlap area that was discarded while assembling the full output. * The connected components output file may be written as either 1-byte unsigned integers or 4-byte (32-bit) unsigned integers via the CONNCOMPOUTTYPE keyword. Using 4-byte values allows more than 255 connected components to be defined, although the default is still to use 1-byte values for backward compatibility. * Support for Lp-norm cost functions has been added. Note, however, that congruence is still enforced, meaning that the unwrapped phase will differ from the wrapped phase by only integer numbers cycles. Therefore, the use of an L2-norm cost functions is not equivalent to least-squares phase unwrapping approaches that do not enforce congruence (as described by Ghiglia and Romero, 1996). * Experimental code for tree pruning has been included. This behavior is controlled by the new NMAJORPRUNE and PRUNECOSTTHRESH keywords. This code has not been well tested and users are advised to use this code with only the lowest of expectations. * The SOURCEMODE keyword and associated functionality have been removed due to changes in the source selection algorithm to allow the unwrapping of multiple regions that are disconnected by masked pixels. * There have been many internal code cleanups that should be transparent to the user. * Several miscellaneous bugs have been fixed and several minor enhancements have been added. snaphu-v2.0.6/PaxHeader/config000755 777777 777777 00000000043 14423062415 016071 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/config/000755 Ho)00000000000 14423062415 015375 5ustar00curtis000000 000000 snaphu-v2.0.6/PaxHeader/README000644 777777 777777 00000000043 14423062415 015556 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/README000644 Ho)00000011025 14423062415 015007 0ustar00curtis000000 000000 SNAPHU Statistical-Cost, Netowrk-Flow Algorithm for Phase Unwrapping Author: Curtis W. Chen Version 2.0.6, April 2023 Contents -------- 1. Bugs and Bug Reporting 2. Notes on Compiling 3. Run-Time Configuration Files 4. Copyright Bugs And Bug Reporting ---------------------- Not all parts of snaphu have been well tested, so your bug reports and feedback are appreciated. Please email them to snaphu@gmail.com The man page included with the distribution lists known issues as well. Thanks, and good luck with the unwrapping. Notes on Compiling ------------------ To compile, edit the Makefile in the src directory to specify your compiler, the optimization flags, and the desired directory for the executable. After that, run make and see what happens. Most of the code should be pretty standard, but a few of the library functions that are used may be unavailable on some systems. In some cases, the problem code may only perform error checking, so you might be able to comment out the unavailable functions without ill effects. For example, the IsFinite() function in snaphu_util.c is a wrapper for calling the library function finite(), which is unavailable on some systems. You can modify IsFinite() to use an alternate implementation that you do have, or you can have it always return TRUE. The code was developed mainly with gcc, but has been tested with a number of vendor C compilers. The latter tend to produce faster executables. I have not tried running snaphu under Cygwin. I have not experimented with parallelizing compilers. The code is written to use multiple processors in tile mode by forking copies of itself to unwrap each tile. The structure of the solver does not lend itself to easy parallelization for a single tile, however. The CS2 MCF solver module is governed by the terms of the original authors (see the copyright below). In order to compile snaphu without this module, specify -D NO_CS2 as a compiler option in the Makefile. Run-Time Configuration Files ---------------------------- Two template run-time configuration files are provided in the config directory. The file snaphu.conf.brief contains the configuration parameters that a beginning user might need to specify. The file snaphu.conf.full contains all the options that the program will accept. Copyright --------- Copyright 2002-2023 Board of Trustees, Leland Stanford Jr. University Except as noted below, permission to use, copy, modify, and distribute, this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the copyright holders be used in advertising or publicity pertaining to distribution of the software with specific, written prior permission, and that no fee is charged for further distribution of this software, or any modifications thereof. The copyright holder makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA, PROFITS, QPA OR GPA, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. The parts of this software derived from the CS2 minimum cost flow solver written by A. V. Goldberg and B. Cherkassky are governed by the terms of the copyright holder of that software. Permission has been granted to use and distrubute that software for strictly noncommercial purposes as part of this package, provided that the following copyright notice from the original distribution and URL accompany the software: COPYRIGHT C 1995 IG Systems, Inc. Permission to use for evaluation purposes is granted provided that proper acknowledgments are given. For a commercial licence, contact igsys@eclipse.net. This software comes with NO WARRANTY, expressed or implied. By way of example, but not limitation, we make no representations of warranties of merchantability or fitness for any particular purpose or that the use of the software components or documentation will not infringe any patents, copyrights, trademarks, or other rights. http://www.igsystems.com/cs2 snaphu-v2.0.6/PaxHeader/src000755 777777 777777 00000000101 14423062613 015406 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 30 mtime=1682728331.324041826 snaphu-v2.0.6/src/000755 Ho)00000000000 14423062613 014717 5ustar00curtis000000 000000 snaphu-v2.0.6/src/PaxHeader/snaphu_cs2types.h000644 777777 777777 00000000043 14423062415 020770 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/src/snaphu_cs2types.h000644 Ho)00000004622 14423062415 020226 0ustar00curtis000000 000000 /************************************************************************* This code is derived from cs2 v3.7 Written by Andrew V. Goldberg and Boris Cherkassky Modifications for use in snaphu by Curtis W. Chen Header for cs2 minimum cost flow solver. This file is included with a #include from snaphu_cs2.c. The cs2 code is used here with permission for strictly noncommerical use. The original cs2 source code can be downloaded from http://www.igsystems.com/cs2 The original cs2 copyright is stated as follows: COPYRIGHT C 1995 IG Systems, Inc. Permission to use for evaluation purposes is granted provided that proper acknowledgments are given. For a commercial licence, contact igsys@eclipse.net. This software comes with NO WARRANTY, expressed or implied. By way of example, but not limitation, we make no representations of warranties of merchantability or fitness for any particular purpose or that the use of the software components or documentation will not infringe any patents, copyrights, trademarks, or other rights. Copyright 2002 Board of Trustees, Leland Stanford Jr. University *************************************************************************/ /* defs.h */ typedef long excess_t; typedef /* arc */ struct arc_st { short r_cap; /* residual capasity */ short cost; /* cost of the arc*/ struct node_st *head; /* head node */ struct arc_st *sister; /* opposite arc */ } arc; typedef /* node */ struct node_st { arc *first; /* first outgoing arc */ arc *current; /* current outgoing arc */ arc *suspended; double price; /* distance from a sink */ struct node_st *q_next; /* next node in push queue */ struct node_st *b_next; /* next node in bucket-list */ struct node_st *b_prev; /* previous node in bucket-list */ long rank; /* bucket number */ excess_t excess; /* excess of the node */ signed char inp; /* temporary number of input arcs */ } node; typedef /* bucket */ struct bucket_st { node *p_first; /* 1st node with positive excess or simply 1st node in the buket */ } bucket; snaphu-v2.0.6/src/PaxHeader/snaphu_solver.c000644 777777 777777 00000000043 14423062415 020521 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/src/snaphu_solver.c000644 Ho)00000364001 14423062415 017757 0ustar00curtis000000 000000 /************************************************************************* snaphu network-flow solver 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "snaphu.h" /* static variables local this file */ /* pointers to functions for tailoring network solver to specific topologies */ static nodeT *(*NeighborNode)(nodeT *, long, long *, nodeT **, nodeT *, long *, long *, long *, long, long, boundaryT *, nodesuppT **); static void (*GetArc)(nodeT *, nodeT *, long *, long *, long *, long, long, nodeT **, nodesuppT **); /* static (local) function prototypes */ static void AddNewNode(nodeT *from, nodeT *to, long arcdir, bucketT *bkts, long nflow, incrcostT **incrcosts, long arcrow, long arccol, paramT *params); static void CheckArcReducedCost(nodeT *from, nodeT *to, nodeT *apex, long arcrow, long arccol, long arcdir, candidateT **candidatebagptr, long *candidatebagnextptr, long *candidatebagsizeptr, incrcostT **incrcosts, signed char **iscandidate, paramT *params); static nodeT *InitBoundary(nodeT *source, nodeT **nodes, boundaryT *boundary, nodesuppT **nodesupp, float **mag, nodeT *ground, long ngroundarcs, long nrow, long ncol, paramT *params, long *nconnectedptr); static long CheckBoundary(nodeT **nodes, float **mag, nodeT *ground, long ngroundarcs, boundaryT *boundary, long nrow, long ncol, paramT *params, nodeT *start); static int IsRegionEdgeArc(float **mag, long arcrow, long arccol, long nrow, long ncol); static int IsRegionInteriorArc(float **mag, long arcrow, long arccol, long nrow, long ncol); static int IsRegionArc(float **mag, long arcrow, long arccol, long nrow, long ncol); static int IsRegionEdgeNode(float **mag, long row, long col, long nrow, long ncol); static int CleanUpBoundaryNodes(nodeT *source, boundaryT *boundary, float **mag, nodeT **nodes, nodeT *ground, long nrow, long ncol, long ngroundarcs, nodesuppT **nodesupp); static int DischargeBoundary(nodeT **nodes, nodeT *ground, boundaryT *boundary, nodesuppT **nodesupp, short **flows, signed char **iscandidate, float **mag, float **wrappedphase, long ngroundarcs, long nrow, long ncol); static int InitTree(nodeT *source, nodeT **nodes, boundaryT *boundary, nodesuppT **nodesupp, nodeT *ground, long ngroundarcs, bucketT *bkts, long nflow, incrcostT **incrcosts, long nrow, long ncol, paramT *params); static nodeT *FindApex(nodeT *from, nodeT *to); static int CandidateCompare(const void *c1, const void *c2); static nodeT *NeighborNodeGrid(nodeT *node1, long arcnum, long *upperarcnumptr, nodeT **nodes, nodeT *ground, long *arcrowptr, long *arccolptr, long *arcdirptr, long nrow, long ncol, boundaryT *boundary, nodesuppT **nodesupp); static inline long GetArcNumLims(long fromrow, long *upperarcnumptr, long ngroundarcs, boundaryT *boundary); static nodeT *NeighborNodeNonGrid(nodeT *node1, long arcnum, long *upperarcnumptr, nodeT **nodes, nodeT *ground, long *arcrowptr, long *arccolptr, long *arcdirptr, long nrow, long ncol, boundaryT *boundary, nodesuppT **nodesupp); static void GetArcGrid(nodeT *from, nodeT *to, long *arcrow, long *arccol, long *arcdir, long nrow, long ncol, nodeT **nodes, nodesuppT **nodesupp); static void GetArcNonGrid(nodeT *from, nodeT *to, long *arcrow, long *arccol, long *arcdir, long nrow, long ncol, nodeT **nodes, nodesuppT **nodesupp); static void NonDegenUpdateChildren(nodeT *startnode, nodeT *lastnode, nodeT *nextonpath, long dgroup, long ngroundarcs, long nflow, nodeT **nodes, nodesuppT **nodesupp, nodeT *ground, boundaryT *boundary, nodeT ***apexes, incrcostT **incrcosts, long nrow, long ncol, paramT *params); static long PruneTree(nodeT *source, nodeT **nodes, nodeT *ground, boundaryT *boundary, nodesuppT **nodesupp, incrcostT **incrcosts, short **flows, long ngroundarcs, long prunecostthresh, long nrow, long ncol); static int CheckLeaf(nodeT *node1, nodeT **nodes, nodeT *ground, boundaryT *boundary, nodesuppT **nodesupp, incrcostT **incrcosts, short **flows, long ngroundarcs, long nrow, long ncol, long prunecostthresh); static int GridNodeMaskStatus(long row, long col, float **mag); static int GroundMaskStatus(long nrow, long ncol, float **mag); static int InitBuckets(bucketT *bkts, nodeT *source, long nbuckets); static nodeT *MinOutCostNode(bucketT *bkts); static nodeT *SelectConnNodeSource(nodeT **nodes, float **mag, nodeT *ground, long ngroundarcs, long nrow, long ncol, paramT *params, nodeT *start, long *nconnectedptr); static long ScanRegion(nodeT *start, nodeT **nodes, float **mag, nodeT *ground, long ngroundarcs, long nrow, long ncol, int groupsetting); static short GetCost(incrcostT **incrcosts, long arcrow, long arccol, long arcdir); static void SolveMST(nodeT **nodes, nodeT *source, nodeT *ground, bucketT *bkts, short **mstcosts, signed char **residue, signed char **arcstatus, long nrow, long ncol); static long DischargeTree(nodeT *source, short **mstcosts, short **flows, signed char **residue, signed char **arcstatus, nodeT **nodes, nodeT *ground, long nrow, long ncol); static signed char ClipFlow(signed char **residue, short **flows, short **mstcosts, long nrow, long ncol, long maxflow); /* function: SetGridNetworkFunctionPointers() * ------------------------------------------ */ int SetGridNetworkFunctionPointers(void){ /* set static pointers to functions */ NeighborNode=NeighborNodeGrid; GetArc=GetArcGrid; return(0); } /* function: SetNonGridNetworkFunctionPointers() * --------------------------------------------- */ int SetNonGridNetworkFunctionPointers(void){ /* set static pointers to functions */ NeighborNode=NeighborNodeNonGrid; GetArc=GetArcNonGrid; return(0); } /* function: TreeSolve() * --------------------- * Solves the nonlinear network optimization problem. */ long TreeSolve(nodeT **nodes, nodesuppT **nodesupp, nodeT *ground, nodeT *source, candidateT **candidatelistptr, candidateT **candidatebagptr, long *candidatelistsizeptr, long *candidatebagsizeptr, bucketT *bkts, short **flows, void **costs, incrcostT **incrcosts, nodeT ***apexes, signed char **iscandidate, long ngroundarcs, long nflow, float **mag, float **wrappedphase, char *outfile, long nnoderow, int *nnodesperrow, long narcrow, int *narcsperrow, long nrow, long ncol, outfileT *outfiles, long nconnected, paramT *params){ long i, row, col, arcrow, arccol, arcdir, arcnum, upperarcnum; long arcrow1, arccol1, arcdir1, arcrow2, arccol2, arcdir2; long treesize, candidatelistsize, candidatebagsize; long violation, groupcounter, fromgroup, group1, apexlistbase, apexlistlen; long cyclecost, outcostto, startlevel, dlevel, doutcost, dincost; long candidatelistlen, candidatebagnext; long inondegen, ipivots, nnewnodes, maxnewnodes, templong; long nmajor, nmajorprune, npruned, prunecostthresh; signed char fromside; candidateT *candidatelist, *candidatebag, *tempcandidateptr; nodeT *from, *to, *cycleapex, *node1, *node2, *leavingparent, *leavingchild; nodeT *root, *mntpt, *oldmntpt, *skipthread, *tempnode1, *tempnode2; nodeT *firstfromnode, *firsttonode; nodeT **apexlist; boundaryT boundary[1]; float **unwrappedphase; /* initilize structures on stack to zero for good measure */ memset(boundary,0,sizeof(boundaryT)); /* initialize some variables to zero to stop compiler warnings */ from=NULL; to=NULL; cycleapex=NULL; node1=NULL; node2=NULL; leavingparent=NULL; leavingchild=NULL; root=NULL; mntpt=NULL; oldmntpt=NULL; skipthread=NULL; tempnode1=NULL; tempnode2=NULL; firstfromnode=NULL; firsttonode=NULL; /* dereference some pointers and store as local variables */ candidatelist=(*candidatelistptr); candidatebag=(*candidatebagptr); candidatelistsize=(*candidatelistsizeptr); candidatebagsize=(*candidatebagsizeptr); candidatelistlen=0; candidatebagnext=0; /* initialize boundary, which affects network structure */ /* recompute number of connected nodes since setting boundary may make */ /* some nodes inaccessible */ source=InitBoundary(source,nodes,boundary,nodesupp,mag, ground,ngroundarcs,nrow,ncol,params,&nconnected); /* set up */ bkts->curr=bkts->maxind; InitTree(source,nodes,boundary,nodesupp,ground,ngroundarcs,bkts,nflow, incrcosts,nrow,ncol,params); apexlistlen=INITARRSIZE; apexlist=MAlloc(apexlistlen*sizeof(nodeT *)); groupcounter=2; ipivots=0; inondegen=0; maxnewnodes=ceil(nconnected*params->maxnewnodeconst); nnewnodes=0; treesize=1; npruned=0; nmajor=0; nmajorprune=params->nmajorprune; prunecostthresh=params->prunecostthresh;; fprintf(sp3,"Treesize: %-10ld Pivots: %-11ld Improvements: %-11ld", treesize,ipivots,inondegen); /* loop over each entering node (note, source already on tree) */ while(treesizepred; /* add new node to the tree */ GetArc(from,to,&arcrow,&arccol,&arcdir,nrow,ncol,nodes,nodesupp); to->group=1; to->level=from->level+1; to->incost=from->incost+GetCost(incrcosts,arcrow,arccol,-arcdir); to->next=from->next; to->prev=from; to->next->prev=to; from->next=to; /* scan new node's neighbors */ from=to; arcnum=GetArcNumLims(from->row,&upperarcnum,ngroundarcs,boundary); while(arcnumgroup>0){ if(to!=from->pred){ cycleapex=FindApex(from,to); apexes[arcrow][arccol]=cycleapex; CheckArcReducedCost(from,to,cycleapex,arcrow,arccol,arcdir, &candidatebag,&candidatebagnext, &candidatebagsize,incrcosts,iscandidate, params); }else{ apexes[arcrow][arccol]=NULL; } }else if(to->group!=PRUNED && to->group!=MASKED){ /* if to is not on tree, update outcost and add to bucket */ AddNewNode(from,to,arcdir,bkts,nflow,incrcosts,arcrow,arccol,params); } } nnewnodes++; treesize++; } /* keep looping until no more arcs have negative reduced costs */ while(candidatebagnext){ /* if we received SIGINT or SIGHUP signal, dump results */ /* keep this stuff out of the signal handler so we don't risk */ /* writing a non-feasible solution (ie, if signal during augment) */ /* signal handler disabled for all but primary (grid) networks */ if(dumpresults_global){ fflush(NULL); fprintf(sp0,"\n\nDumping current solution to file %s\n", outfile); if(requestedstop_global){ Free2DArray((void **)costs,2*nrow-1); } unwrappedphase=(float **)Get2DMem(nrow,ncol,sizeof(float *), sizeof(float)); IntegratePhase(wrappedphase,unwrappedphase,flows,nrow,ncol); FlipPhaseArraySign(unwrappedphase,params,nrow,ncol); WriteOutputFile(mag,unwrappedphase,outfiles->outfile,outfiles, nrow,ncol); if(requestedstop_global){ fflush(NULL); fprintf(sp0,"Program exiting\n"); exit(ABNORMAL_EXIT); } Free2DArray((void **)unwrappedphase,nrow); dumpresults_global=FALSE; fflush(NULL); fprintf(sp0,"\n\nProgram continuing\n"); } /* swap candidate bag and candidate list pointers and sizes */ tempcandidateptr=candidatebag; candidatebag=candidatelist; candidatelist=tempcandidateptr; templong=candidatebagsize; candidatebagsize=candidatelistsize; candidatelistsize=templong; candidatelistlen=candidatebagnext; candidatebagnext=0; /* sort candidate list by violation, with augmenting arcs always first */ qsort((void *)candidatelist,candidatelistlen,sizeof(candidateT), CandidateCompare); /* set all arc directions to be plus/minus 1 */ for(i=0;i1){ candidatelist[i].arcdir=1; }else if(candidatelist[i].arcdir<-1){ candidatelist[i].arcdir=-1; } } /* this doesn't seem to make it any faster, so just do all of them */ /* set the number of candidates to process */ /* (must change candidatelistlen to ncandidates in for loop below) */ /* maxcandidates=MAXCANDIDATES; if(maxcandidates>candidatelistlen){ ncandidates=candidatelistlen; }else{ ncandidates=maxcandidates; } */ /* now pivot for each arc in the candidate list */ for(i=0;ioutcost+ GetCost(incrcosts,arcrow,arccol,arcdir); cyclecost=outcostto + to->incost -apexes[arcrow][arccol]->outcost -apexes[arcrow][arccol]->incost; /* if violation no longer negative, check reverse arc */ if(!((outcostto < to->outcost) || (cyclecost < 0))){ from=to; to=candidatelist[i].from; arcdir=-arcdir; outcostto=from->outcost+ GetCost(incrcosts,arcrow,arccol,arcdir); cyclecost=outcostto + to->incost -apexes[arcrow][arccol]->outcost -apexes[arcrow][arccol]->incost; } /* see if the cycle is negative (see if there is a violation) */ if((outcostto < to->outcost) || (cyclecost < 0)){ /* make sure the group counter hasn't gotten too big */ if(++groupcounter>MAXGROUPBASE){ for(row=0;row0){ nodes[row][col].group=1; } } } if(ground!=NULL && ground->group>0){ ground->group=1; } if(boundary->node->group>0){ boundary->node->group=1; } groupcounter=2; } /* if augmenting cycle (nondegenerate pivot) */ if(cyclecost<0){ /* augment flow along cycle and select leaving arc */ /* if we are augmenting non-zero flow, any arc with zero flow */ /* after the augmentation is a blocking arc */ while(TRUE){ fromside=TRUE; node1=from; node2=to; leavingchild=NULL; flows[arcrow][arccol]+=arcdir*nflow; ReCalcCost(costs,incrcosts,flows[arcrow][arccol],arcrow,arccol, nflow,nrow,params); violation=GetCost(incrcosts,arcrow,arccol,arcdir); if(node1->level > node2->level){ while(node1->level != node2->level){ GetArc(node1->pred,node1,&arcrow1,&arccol1,&arcdir1, nrow,ncol,nodes,nodesupp); flows[arcrow1][arccol1]+=(arcdir1*nflow); ReCalcCost(costs,incrcosts,flows[arcrow1][arccol1], arcrow1,arccol1,nflow,nrow,params); if(leavingchild==NULL && !flows[arcrow1][arccol1]){ leavingchild=node1; } violation+=GetCost(incrcosts,arcrow1,arccol1,arcdir1); node1->group=groupcounter+1; node1=node1->pred; } }else{ while(node1->level != node2->level){ GetArc(node2->pred,node2,&arcrow2,&arccol2,&arcdir2, nrow,ncol,nodes,nodesupp); flows[arcrow2][arccol2]-=(arcdir2*nflow); ReCalcCost(costs,incrcosts,flows[arcrow2][arccol2], arcrow2,arccol2,nflow,nrow,params); if(!flows[arcrow2][arccol2]){ leavingchild=node2; fromside=FALSE; } violation+=GetCost(incrcosts,arcrow2,arccol2,-arcdir2); node2->group=groupcounter; node2=node2->pred; } } while(node1!=node2){ GetArc(node1->pred,node1,&arcrow1,&arccol1,&arcdir1,nrow,ncol, nodes,nodesupp); GetArc(node2->pred,node2,&arcrow2,&arccol2,&arcdir2,nrow,ncol, nodes,nodesupp); flows[arcrow1][arccol1]+=(arcdir1*nflow); flows[arcrow2][arccol2]-=(arcdir2*nflow); ReCalcCost(costs,incrcosts,flows[arcrow1][arccol1], arcrow1,arccol1,nflow,nrow,params); ReCalcCost(costs,incrcosts,flows[arcrow2][arccol2], arcrow2,arccol2,nflow,nrow,params); violation+=(GetCost(incrcosts,arcrow1,arccol1,arcdir1) +GetCost(incrcosts,arcrow2,arccol2,-arcdir2)); if(!flows[arcrow2][arccol2]){ leavingchild=node2; fromside=FALSE; }else if(leavingchild==NULL && !flows[arcrow1][arccol1]){ leavingchild=node1; } node1->group=groupcounter+1; node2->group=groupcounter; node1=node1->pred; node2=node2->pred; } if(violation>=0){ break; } } inondegen++; }else{ /* We are not augmenting flow, but just updating potentials. */ /* Arcs with zero flow are implicitly directed upwards to */ /* maintain a strongly feasible spanning tree, so arcs with zero */ /* flow on the path between to node and apex are blocking arcs. */ /* Leaving arc is last one whose child's new outcost is less */ /* than its old outcost. Such an arc must exist, or else */ /* we'd be augmenting flow on a negative cycle. */ /* trace the cycle and select leaving arc */ fromside=FALSE; node1=from; node2=to; leavingchild=NULL; if(node1->level > node2->level){ while(node1->level != node2->level){ node1->group=groupcounter+1; node1=node1->pred; } }else{ while(node1->level != node2->level){ if(outcostto < node2->outcost){ leavingchild=node2; GetArc(node2->pred,node2,&arcrow2,&arccol2,&arcdir2, nrow,ncol,nodes,nodesupp); outcostto+=GetCost(incrcosts,arcrow2,arccol2,-arcdir2); }else{ outcostto=VERYFAR; } node2->group=groupcounter; node2=node2->pred; } } while(node1!=node2){ if(outcostto < node2->outcost){ leavingchild=node2; GetArc(node2->pred,node2,&arcrow2,&arccol2,&arcdir2,nrow,ncol, nodes,nodesupp); outcostto+=GetCost(incrcosts,arcrow2,arccol2,-arcdir2); }else{ outcostto=VERYFAR; } node1->group=groupcounter+1; node2->group=groupcounter; node1=node1->pred; node2=node2->pred; } } cycleapex=node1; /* set leaving parent */ if(leavingchild==NULL){ fromside=TRUE; leavingparent=from; }else{ leavingparent=leavingchild->pred; } /* swap from and to if leaving arc is on the from side */ if(fromside){ groupcounter++; fromgroup=groupcounter-1; tempnode1=from; from=to; to=tempnode1; }else{ fromgroup=groupcounter+1; } /* if augmenting pivot */ if(cyclecost<0){ /* find first child of apex on either cycle path */ firstfromnode=NULL; firsttonode=NULL; arcnum=GetArcNumLims(cycleapex->row,&upperarcnum, ngroundarcs,boundary); while(arcnumgroup==groupcounter && apexes[arcrow][arccol]==NULL){ firsttonode=tempnode1; if(firstfromnode!=NULL){ break; } }else if(tempnode1->group==fromgroup && apexes[arcrow][arccol]==NULL){ firstfromnode=tempnode1; if(firsttonode!=NULL){ break; } } } /* update potentials, mark stationary parts of tree */ cycleapex->group=groupcounter+2; if(firsttonode!=NULL){ NonDegenUpdateChildren(cycleapex,leavingparent,firsttonode,0, ngroundarcs,nflow,nodes,nodesupp,ground, boundary,apexes,incrcosts,nrow,ncol, params); } if(firstfromnode!=NULL){ NonDegenUpdateChildren(cycleapex,from,firstfromnode,1, ngroundarcs,nflow,nodes,nodesupp,ground, boundary,apexes,incrcosts,nrow,ncol, params); } groupcounter=from->group; apexlistbase=cycleapex->group; /* children of cycleapex are not marked, so we set fromgroup */ /* equal to cycleapex group for use with apex updates below */ /* all other children of cycle will be in apexlist if we had an */ /* augmenting pivot, so fromgroup only important for cycleapex */ fromgroup=cycleapex->group; }else{ /* set this stuff for use with apex updates below */ cycleapex->group=fromgroup; groupcounter+=2; apexlistbase=groupcounter+1; } /* remount subtree at new mount point */ if(leavingchild==NULL){ skipthread=to; }else{ root=from; oldmntpt=to; /* for each node on the path from to node to leaving child */ while(oldmntpt!=leavingparent){ /* remount the subtree at the new mount point */ mntpt=root; root=oldmntpt; oldmntpt=root->pred; root->pred=mntpt; GetArc(mntpt,root,&arcrow,&arccol,&arcdir,nrow,ncol, nodes,nodesupp); /* calculate differences for updating potentials and levels */ dlevel=mntpt->level-root->level+1; doutcost=mntpt->outcost - root->outcost + GetCost(incrcosts,arcrow,arccol,arcdir); dincost=mntpt->incost - root->incost + GetCost(incrcosts,arcrow,arccol,-arcdir); /* update all children */ /* group of each remounted tree used to reset apexes below */ node1=root; startlevel=root->level; groupcounter++; while(TRUE){ /* update the level, potentials, and group of the node */ node1->level+=dlevel; node1->outcost+=doutcost; node1->incost+=dincost; node1->group=groupcounter; /* break when node1 is no longer descendent of the root */ if(node1->next->level <= startlevel){ break; } node1=node1->next; } /* update threads */ root->prev->next=node1->next; node1->next->prev=root->prev; node1->next=mntpt->next; mntpt->next->prev=node1; mntpt->next=root; root->prev=mntpt; } skipthread=node1->next; /* reset apex pointers for entering and leaving arcs */ GetArc(from,to,&arcrow,&arccol,&arcdir,nrow,ncol,nodes,nodesupp); apexes[arcrow][arccol]=NULL; GetArc(leavingparent,leavingchild,&arcrow,&arccol, &arcdir,nrow,ncol,nodes,nodesupp); apexes[arcrow][arccol]=cycleapex; /* make sure we have enough memory for the apex list */ if(groupcounter-apexlistbase+1>apexlistlen){ apexlistlen=1.5*(groupcounter-apexlistbase+1); apexlist=ReAlloc(apexlist,apexlistlen*sizeof(nodeT *)); } /* set the apex list */ /* the apex list is a look up table of apex node pointers indexed */ /* by the group number relative to a base group value */ node2=leavingchild; for(group1=groupcounter;group1>=apexlistbase;group1--){ apexlist[group1-apexlistbase]=node2; node2=node2->pred; } /* reset apex pointers on remounted tree */ /* only nodes which are in different groups need new apexes */ node1=to; startlevel=to->level; while(TRUE){ /* loop over outgoing arcs */ arcnum=GetArcNumLims(node1->row,&upperarcnum, ngroundarcs,boundary); while(arcnumgroup>0){ /* if node2 is either not part of remounted tree or */ /* it is higher on remounted tree than node1, */ /* and arc isn't already on tree */ if(node2->group < node1->group && apexes[arcrow][arccol]!=NULL){ /* if new apex in apexlist */ /* node2 on remounted tree, if nonaugmenting pivot */ if(node2->group >= apexlistbase){ apexes[arcrow][arccol]=apexlist[node2->group -apexlistbase]; }else{ /* if old apex below level of cycleapex, */ /* node2 is on "to" node's side of tree */ /* implicitly, if old apex above cycleapex, */ /* we do nothing since apex won't change */ if(apexes[arcrow][arccol]->level > cycleapex->level){ /* since new apex not in apexlist (tested above), */ /* node2 above leaving arc so new apex is cycleapex */ apexes[arcrow][arccol]=cycleapex; }else{ /* node2 not on "to" side of tree */ /* if old apex is cycleapex, node2 is on "from" side */ if(apexes[arcrow][arccol]==cycleapex){ /* new apex will be on cycle, so trace node2->pred */ /* until we hit a node with group==fromgroup */ tempnode2=node2; while(tempnode2->group != fromgroup){ tempnode2=tempnode2->pred; } apexes[arcrow][arccol]=tempnode2; } } } /* check outgoing arcs for negative reduced costs */ CheckArcReducedCost(node1,node2,apexes[arcrow][arccol], arcrow,arccol,arcdir,&candidatebag, &candidatebagnext,&candidatebagsize, incrcosts,iscandidate,params); } /* end if node2 below node1 and arc not on tree */ }else if(node2->group!=PRUNED && node2->group!=MASKED){ /* node2 is not on tree, so put it in correct bucket */ AddNewNode(node1,node2,arcdir,bkts,nflow,incrcosts, arcrow,arccol,params); } /* end if node2 on tree */ } /* end loop over node1 outgoing arcs */ /* move to next node in thread, break if we left the subtree */ node1=node1->next; if(node1->level <= startlevel){ break; } } } /* end if leavingchild!=NULL */ /* if we had an augmenting cycle */ /* we need to check outarcs from descendents of any cycle node */ /* (except apex, since apex potentials don't change) */ if(cyclecost<0){ /* check descendents of cycle children of apex */ while(TRUE){ /* firstfromnode, firsttonode may have changed */ if(firstfromnode!=NULL && firstfromnode->pred==cycleapex){ node1=firstfromnode; firstfromnode=NULL; }else if(firsttonode!=NULL && firsttonode->pred==cycleapex){ node1=firsttonode; firsttonode=NULL; }else{ break; } startlevel=node1->level; /* loop over all descendents */ while(TRUE){ /* loop over outgoing arcs */ arcnum=GetArcNumLims(node1->row,&upperarcnum, ngroundarcs,boundary); while(arcnumgroup>0){ if(apexes[arcrow][arccol]!=NULL && (node2->group!=node1->group || node1->group==apexlistbase)){ CheckArcReducedCost(node1,node2,apexes[arcrow][arccol], arcrow,arccol,arcdir,&candidatebag, &candidatebagnext,&candidatebagsize, incrcosts,iscandidate,params); } }else if(node2->group!=PRUNED && node2->group!=MASKED){ AddNewNode(node1,node2,arcdir,bkts,nflow,incrcosts, arcrow,arccol,params); } } /* move to next node in thread, break if left the subtree */ /* but skip the remounted tree, since we checked it above */ node1=node1->next; if(node1==to){ node1=skipthread; } if(node1->level <= startlevel){ break; } } } } ipivots++; } /* end if cyclecost<0 || outcosttooutcost */ } /* end of for loop over candidates in list */ /* this is needed only if we don't process all candidates above */ /* copy remaining candidates into candidatebag */ /* while(candidatebagnext+(candidatelistlen-ncandidates)>candidatebagsize){ candidatebagsize+=CANDIDATEBAGSTEP; candidatebag=ReAlloc(candidatebag,candidatebagsize*sizeof(candidateT)); } for(i=ncandidates;inext; while(node1!=source){ if(node1->pred->level!=node1->level-1){ printf("Error detected: row %d, col%d, level %d " "has pred row %d, col%d, level %d\n", node1->row,node1->col,node1->level,node1->pred->row,node1->pred->col, node1->pred->level); } node1=node1->next; } /* discharge boundary */ /* flow to edge of region goes along normal grid arcs, but flow along edge */ /* of region that should go along zero-cost arcs along edge is not */ /* captured in solver code above since nodes of edge are collapsed into */ /* single boundary node. This accumulates surplus/demand at edge nodes. */ /* Here, find surplus/demand by balancing flow in/out of edge nodes and */ /* discharge sending flow along zero-cost edge arcs */ DischargeBoundary(nodes,ground,boundary,nodesupp,flows,iscandidate, mag,wrappedphase,ngroundarcs,nrow,ncol); /* sanity check that buckets are actually all empty after optimizer is done */ for(i=0;isize;i++){ if(bkts->bucketbase[i]!=NULL){ printf("ERROR: bucket %ld not empty after TreeSolve (row=%d, col=%d)\n", i,bkts->bucketbase[i]->row,bkts->bucketbase[i]->col); break; } } /* reset group numbers of nodes along boundary */ /* nodes in neighboring regions may have been set to be MASKED in */ /* in InitBoundary() to avoid reaching them across single line of */ /* masked pixels, so return mask status of nodes along boundary to normal */ CleanUpBoundaryNodes(source,boundary,mag,nodes,ground,nrow,ncol,ngroundarcs, nodesupp); if(boundary->neighborlist!=NULL){ free(boundary->neighborlist); } if(boundary->boundarylist!=NULL){ free(boundary->boundarylist); } /* clean up: set pointers for outputs */ fprintf(sp3,"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" "\b\b\b\b\b\b" "Treesize: %-10ld Pivots: %-11ld Improvements: %-11ld\n", treesize,ipivots,inondegen); fflush(sp3); *candidatelistptr=candidatelist; *candidatebagptr=candidatebag; *candidatelistsizeptr=candidatelistsize; *candidatebagsizeptr=candidatebagsize; free(apexlist); /* return the number of nondegenerate pivots (number of improvements) */ return(inondegen); } /* function: AddNewNode() * ---------------------- * Adds a node to a bucket if it is not already in a bucket. Updates * outcosts of to node if the new distance is less or if to's pred is * from (then we have to do the update). */ static void AddNewNode(nodeT *from, nodeT *to, long arcdir, bucketT *bkts, long nflow, incrcostT **incrcosts, long arcrow, long arccol, paramT *params){ long newoutcost; newoutcost=from->outcost +GetCost(incrcosts,arcrow,arccol,arcdir); if(newoutcostoutcost || to->pred==from){ if(to->group==INBUCKET){ /* if to is already in a bucket */ if(to->outcostmaxind){ if(to->outcost>bkts->minind){ BucketRemove(to,to->outcost,bkts); }else{ BucketRemove(to,bkts->minind,bkts); } }else{ BucketRemove(to,bkts->maxind,bkts); } } to->outcost=newoutcost; to->pred=from; if(newoutcostmaxind){ if(newoutcost>bkts->minind){ BucketInsert(to,newoutcost,bkts); if(newoutcostcurr){ bkts->curr=newoutcost; } }else{ BucketInsert(to,bkts->minind,bkts); bkts->curr=bkts->minind; } }else{ BucketInsert(to,bkts->maxind,bkts); } to->group=INBUCKET; } return; } /* function: CheckArcReducedCost() * ------------------------------- * Given a from and to node, checks for negative reduced cost, and adds * the arc to the entering arc candidate bag if one is found. */ static void CheckArcReducedCost(nodeT *from, nodeT *to, nodeT *apex, long arcrow, long arccol, long arcdir, candidateT **candidatebagptr, long *candidatebagnextptr, long *candidatebagsizeptr, incrcostT **incrcosts, signed char **iscandidate, paramT *params){ long apexcost, fwdarcdist, revarcdist, violation; nodeT *temp; /* do nothing if already candidate */ /* illegal corner arcs have iscandidate=TRUE set ahead of time */ if(iscandidate[arcrow][arccol]){ return; } /* set the apex cost */ apexcost=apex->outcost+apex->incost; /* check forward arc */ fwdarcdist=GetCost(incrcosts,arcrow,arccol,arcdir); violation=fwdarcdist+from->outcost+to->incost-apexcost; if(violation<0){ arcdir*=2; /* magnitude 2 for sorting */ }else{ revarcdist=GetCost(incrcosts,arcrow,arccol,-arcdir); violation=revarcdist+to->outcost+from->incost-apexcost; if(violation<0){ arcdir*=-2; /* magnitude 2 for sorting */ temp=from; from=to; to=temp; }else{ violation=fwdarcdist+from->outcost-to->outcost; if(violation>=0){ violation=revarcdist+to->outcost-from->outcost; if(violation<0){ arcdir=-arcdir; temp=from; from=to; to=temp; } } } } /* see if we have a violation, and if so, add arc to candidate bag */ if(violation<0){ if((*candidatebagnextptr)>=(*candidatebagsizeptr)){ (*candidatebagsizeptr)+=CANDIDATEBAGSTEP; (*candidatebagptr)=ReAlloc(*candidatebagptr, (*candidatebagsizeptr)*sizeof(candidateT)); } (*candidatebagptr)[*candidatebagnextptr].violation=violation; (*candidatebagptr)[*candidatebagnextptr].from=from; (*candidatebagptr)[*candidatebagnextptr].to=to; (*candidatebagptr)[*candidatebagnextptr].arcrow=arcrow; (*candidatebagptr)[*candidatebagnextptr].arccol=arccol; (*candidatebagptr)[*candidatebagnextptr].arcdir=arcdir; (*candidatebagnextptr)++; iscandidate[arcrow][arccol]=TRUE; } /* done */ return; } /* function: InitBoundary() * ------------------------ * Initialize boundary structure for region to be unwrapped assuming * source is on boundary. * * This function makes several passes over the boundary nodes. The * first pass finds nodes linked by zero-weight arcs that are candidates * for being on the boundary. The second pass decides which of the * candidate nodes should actually point to the boundary node while * ensuring that no node has multiple valid arcs to the boundary node. * The third pass builds the neighbor list given the boundary pointer * nodes from the previous pass. The fourth pass sets the group * members of boundary pointer nodes, which cannot be done earlier * since it would mess up how NeighborNodeGrid() works. * * Return pointer to source since source may become pointer to boundary. */ static nodeT *InitBoundary(nodeT *source, nodeT **nodes, boundaryT *boundary, nodesuppT **nodesupp, float **mag, nodeT *ground, long ngroundarcs, long nrow, long ncol, paramT *params, long *nconnectedptr){ int iseligible, isinteriornode; long k, nlist, ninteriorneighbor; long nlistmem, nboundarymem, nneighbormem; long arcnum, upperarcnum; long neighborarcnum, neighborupperarcnum; long arcrow, arccol, arcdir; long nconnected; nodeT **nodelist, **boundarylist, *from, *to, *end; neighborT *neighborlist; /* initialize to null first */ boundary->node->row=BOUNDARYROW; boundary->node->col=BOUNDARYCOL; boundary->node->next=NULL; boundary->node->prev=NULL; boundary->node->pred=NULL; boundary->node->level=0; boundary->node->group=0; boundary->node->incost=VERYFAR; boundary->node->outcost=VERYFAR; boundary->neighborlist=NULL; boundary->boundarylist=NULL; boundary->nneighbor=0; boundary->nboundary=0; /* if this is non-grid network, do nothing */ if(nodesupp!=NULL){ return(source); } /* make sure magnitude exists */ if(mag==NULL){ return(source); } /* scan region and mask any nodes that are not already masked but are not */ /* reachable through non-region arcs */ /* such nodes can exist if there is single line of masked pixels separating */ /* regions */ /* boundary is not yet set up, so scanning will search node neighbors as */ /* normal grid neighbors */ nconnected=ScanRegion(source,nodes,mag,ground,ngroundarcs,nrow,ncol,MASKED); /* if source is ground, do nothing, since do not want boundary with ground */ if(source==ground){ return(source); } /* make sure source is on edge */ /* we already know source is not ground from check above */ if(!IsRegionEdgeNode(mag,source->row,source->col,nrow,ncol)){ fprintf(sp0,"WARNING: Non edge node as source in InitBoundary()\n"); } /* get memory for node list */ nlistmem=NLISTMEMINCR; nodelist=(nodeT **)MAlloc(nlistmem*sizeof(nodeT *)); nodelist[0]=source; nlist=1; /* first pass: build list of nodes on boundary */ /* this should handle double-corner cases where all four arcs out of grid */ /* node will be region edge arcs (eg, mag[i][j] and mag[i+1][j+1] are */ /* both zero and mag[i+1][j] and mag[i][j+1] are both nonzero */ source->next=NULL; source->group=BOUNDARYCANDIDATE; from=source; end=source; while(TRUE){ /* see if neighbors can be reached through region-edge arcs */ arcnum=GetArcNumLims(from->row,&upperarcnum,ngroundarcs,NULL); while(arcnumgroup!=BOUNDARYCANDIDATE){ /* keep node in list */ if(nlist==nlistmem){ nlistmem+=NLISTMEMINCR; nodelist=(nodeT **)ReAlloc(nodelist,nlistmem*sizeof(nodeT *)); } nodelist[nlist++]=to; to->group=BOUNDARYCANDIDATE; /* add node to list of nodes to be searched */ end->next=to; to->next=NULL; end=to; } } /* move to next node to search */ if(from->next==NULL){ break; } from=from->next; } /* get memory for boundary list */ nboundarymem=NLISTMEMINCR; boundarylist=(nodeT **)MAlloc(nboundarymem*sizeof(nodeT *)); /* second pass to avoid multiple arcs to same node */ /* go through nodes in list and check criteria for including on boundary */ for(k=0;krow!=GROUNDROW){ /* loop over neighbors */ iseligible=TRUE; ninteriorneighbor=0; arcnum=GetArcNumLims(nodelist[k]->row,&upperarcnum,ngroundarcs,NULL); while(arcnumgroup!=MASKED && from->level!=BOUNDARYLEVEL); if(isinteriornode){ ninteriorneighbor++; } /* scan neighbor's neighbors if neighbor is interior node */ /* or if it is edge node that is not yet on boundary */ /* edge node may have been reached through a non-region arc, but */ /* that is okay since that non-region arc will have zero cost */ /* given that non-region nodes will be masked; need to let this */ /* happen because solver will use such an arc too */ if(isinteriornode || (from->group==BOUNDARYCANDIDATE && from->level!=BOUNDARYLEVEL)){ /* loop over neighbors of neighbor */ neighborarcnum=GetArcNumLims(from->row,&neighborupperarcnum, ngroundarcs,NULL); while(neighborarcnumlevel==BOUNDARYLEVEL){ iseligible=FALSE; break; } } } /* break if already ineligible */ if(!iseligible){ break; } } /* see if we should include this node in boundary */ if(iseligible && ninteriorneighbor>0){ nodelist[k]->level=BOUNDARYLEVEL; if(++boundary->nboundary > nboundarymem){ nboundarymem+=NLISTMEMINCR; boundarylist=(nodeT **)ReAlloc(boundarylist, nboundarymem*sizeof(nodeT *)); } boundarylist[boundary->nboundary-1]=nodelist[k]; } } } /* set groups of all edge nodes back to zero */ for(k=0;kgroup=0; nodelist[k]->next=NULL; } free(nodelist); /* punt if there were too few boundary nodes */ /* region should be unwrapped with nodes behaving like normal grid nodes */ /* but with neighbors that are not part of region masked */ if(boundary->nboundarynboundary;k++){ boundarylist[k]->level=0; boundarylist[k]->group=0; } free(boundarylist); boundary->node->row=BOUNDARYROW; boundary->node->col=BOUNDARYCOL; boundary->node->next=NULL; boundary->node->prev=NULL; boundary->node->pred=NULL; boundary->node->level=0; boundary->node->group=0; boundary->node->incost=VERYFAR; boundary->node->outcost=VERYFAR; boundary->neighborlist=NULL; boundary->boundarylist=NULL; boundary->nneighbor=0; boundary->nboundary=0; return(source); } /* third pass */ /* set up for creating neighbor list */ nneighbormem=NLISTMEMINCR; neighborlist=(neighborT *)MAlloc(nneighbormem*sizeof(neighborT)); /* now go through boundary pointer nodes and build neighbor list */ for(k=0;knboundary;k++){ /* loop over neighbors to keep in neighbor list */ /* checks above should ensure that unmasked neighbors of this boundary */ /* pointer node are not reachable by any other boundary pointer node */ arcnum=GetArcNumLims(boundarylist[k]->row,&upperarcnum,ngroundarcs,NULL); while(arcnumgroup!=MASKED && to->level!=BOUNDARYLEVEL){ /* add neighbor as neighbor of boundary */ boundary->nneighbor++; if(boundary->nneighbor>nneighbormem){ nneighbormem+=NLISTMEMINCR; neighborlist=(neighborT *)ReAlloc(neighborlist, nneighbormem*sizeof(neighborT)); } neighborlist[boundary->nneighbor-1].neighbor=to; neighborlist[boundary->nneighbor-1].arcrow=arcrow; neighborlist[boundary->nneighbor-1].arccol=arccol; neighborlist[boundary->nneighbor-1].arcdir=arcdir; } } } /* fourth pass */ /* now that boundary is properly set up, make one last pass to set groups */ for(k=0;knboundary;k++){ boundarylist[k]->group=BOUNDARYPTR; boundarylist[k]->level=0; } /* keep only needed memory and store pointers in boundary structure */ boundary->neighborlist=(neighborT *)ReAlloc(neighborlist, (boundary->nneighbor *sizeof(neighborT))); boundary->boundarylist=(nodeT **)ReAlloc(boundarylist,(boundary->nboundary *sizeof(nodeT *))); /* check boundary for consistency */ /* count number of connected nodes, which should have changed by number */ /* outer edge nodes that got collapsed into single boundary node (minus 1) */ nconnected=CheckBoundary(nodes,mag,ground,ngroundarcs,boundary,nrow,ncol, params,boundary->node); if(nconnectedptr!=NULL){ if(nconnected+boundary->nboundary-1!=(*nconnectedptr)){ fprintf(sp1, "WARNING: Changed number of connected nodes in InitBoundary()\n"); } (*nconnectedptr)=nconnected; } /* done */ return(boundary->node); } /* function: CheckBoundary() * ------------------------- * Similar to SelectConnNodeSource, but reset group to zero and check boundary. */ static long CheckBoundary(nodeT **nodes, float **mag, nodeT *ground, long ngroundarcs, boundaryT *boundary, long nrow, long ncol, paramT *params, nodeT *start){ long arcrow, arccol, arcdir, arcnum, upperarcnum; long nontree, nboundaryarc, nboundarynode, nconnected; nodeT *node1, *node2, *end; nodesuppT **nodesupp; /* if start node is not eligible, give error */ if(start->group==MASKED){ fflush(NULL); fprintf(sp0,"ERROR: ineligible starting node in CheckBoundary()\n"); exit(ABNORMAL_EXIT); } /* initialize local variables */ nconnected=0; end=start; nodesupp=NULL; node1=start; node1->group=INBUCKET; /* loop to search for connected, unmasked nodes */ while(node1!=NULL){ /* loop over neighbors of current node */ arcnum=GetArcNumLims(node1->row,&upperarcnum,ngroundarcs,boundary); while(arcnumgroup!=MASKED && node2->group!=ONTREE && node2->group!=INBUCKET){ node2->group=INBUCKET; end->next=node2; node2->next=NULL; end=node2; } } /* mark this node visited */ node1->group=ONTREE; nconnected++; /* move to next node in list */ node1=node1->next; } /* loop over connected nodes to check connectivity and reset group numbers */ node1=start; nontree=0; nboundaryarc=0; nboundarynode=0; while(node1!=NULL){ /* loop over neighbors of current node */ arcnum=GetArcNumLims(node1->row,&upperarcnum,ngroundarcs,boundary); while(arcnumrow==BOUNDARYROW){ nboundaryarc++; } } /* check number of boundary nodes */ if(node1->row==BOUNDARYROW){ nboundarynode++; } /* count total number of nodes */ nontree++; /* reset group number */ if(node1->group==ONTREE){ node1->group=0; } /* move to next node in list */ node1=node1->next; } /* check for consistency */ if(nontree!=nconnected){ fflush(NULL); fprintf(sp0, "ERROR: inconsistent num connected nodes in CheckBoundary()\n"); exit(ABNORMAL_EXIT); } if(nboundaryarc!=boundary->nneighbor){ fflush(NULL); fprintf(sp0, "ERROR: inconsistent num neighbor nodes in CheckBoundary()\n"); exit(ABNORMAL_EXIT); } if(nboundarynode!=1){ fflush(NULL); fprintf(sp0, "ERROR: number of boundary nodes is not 1 in CheckBoundary()\n"); exit(ABNORMAL_EXIT); } /* return number of connected nodes */ return(nconnected); } /* function: IsRegionEdgeArc() * --------------------------- * Return TRUE if arc is on edge of region, FALSE otherwise. */ static int IsRegionEdgeArc(float **mag, long arcrow, long arccol, long nrow, long ncol){ long row1, col1, row2, col2, nzeromag; /* if no magnitude, then everything is in single region */ if(mag==NULL){ return(FALSE); } /* determine indices of pixels on either side of this arc */ if(arcrow0 && mag[row2][col2]>0){ return(TRUE); } return(FALSE); } /* function: IsRegionArc() * ----------------------- * Return TRUE if arc goes between two nodes in same region such that * at least one pixel magnitude on either side of arc is nonzero. */ static int IsRegionArc(float **mag, long arcrow, long arccol, long nrow, long ncol){ long row1, col1, row2, col2; /* if no magnitude, everything is in single region */ if(mag==NULL){ return(TRUE); } /* determine indices of pixels on either side of this arc */ if(arcrow0 || mag[row2][col2]>0){ return(TRUE); } return(FALSE); } /* function: IsInteriorNode() * -------------------------- * Return TRUE if node does not touch any zero magnitude pixels, FALSE * otherwise. */ /* * This function is no longer used */ #if 0 static int IsInteriorNode(float **mag, long row, long col, long nrow, long ncol); static int IsInteriorNode(float **mag, long row, long col, long nrow, long ncol){ /* if there is no magnitude info, then all nodes are interior nodes */ if(mag==NULL){ return(TRUE); } /* check for ground */ if(row==GROUNDROW){ return(FALSE); } /* check mag */ if(mag[row][col]==0 || mag[row+1][col]==0 || mag[row][col+1]==0 || mag[row+1][col+1]==0){ return(FALSE); } return(TRUE); } #endif /* function: IsRegionEdgeNode() * ---------------------------- * Return TRUE if node touches at least one zero magnitude pixel and * at least one non-zero magnitude pixel, FALSE otherwise. */ static int IsRegionEdgeNode(float **mag, long row, long col, long nrow, long ncol){ int onezeromag, onenonzeromag; /* if there is no magnitude info, then no nodes are on edge */ if(mag==NULL){ return(FALSE); } /* check for ground */ if(row==GROUNDROW){ return(FALSE); } /* check mag for one zero mag and one nonzero mag pixel around node */ onezeromag=FALSE; onenonzeromag=FALSE; if(mag[row][col]==0 || mag[row+1][col]==0 || mag[row][col+1]==0 || mag[row+1][col+1]==0){ onezeromag=TRUE; } if(mag[row][col]!=0 || mag[row+1][col]!=0 || mag[row][col+1]!=0 || mag[row+1][col+1]!=0){ onenonzeromag=TRUE; } if(onezeromag && onenonzeromag){ return(TRUE); } return(FALSE); } /* function: CleanUpBoundaryNodes() * -------------------------------- * Unset group values indicating boundary nodes on network. This is * necessary because InitBoundary() temporarily sets node groups to * MASKED if the node is in a different region than the current but * can be reached from the current region. This can occur if two * regions are separated by a single row or column of masked pixels. */ static int CleanUpBoundaryNodes(nodeT *source, boundaryT *boundary, float **mag, nodeT **nodes, nodeT *ground, long nrow, long ncol, long ngroundarcs, nodesuppT **nodesupp){ long nconnected; nodeT *start; /* do nothing if this is not a grid network */ if(nodesupp!=NULL){ return(0); } /* starting node should not be boundary */ if(source->row==BOUNDARYROW){ start=boundary->neighborlist[0].neighbor; }else{ start=source; } /* scan region and unmask any nodes that touch good pixels since they */ /* may have been masked by the ScanRegion() call in InitBoundaries() */ nconnected=ScanRegion(start,nodes,mag,ground,ngroundarcs,nrow,ncol,0); /* done */ return(nconnected); } /* function: DischargeBoundary() * ----------------------------- * Find nodes and arcs along edge of region (defined by zero magnitude) and * compute surplus/demand by balancing flow in/out of nodes. Then discharge * surplus/demand by sending flow along zero-cost arcs along region edge. */ static int DischargeBoundary(nodeT **nodes, nodeT *ground, boundaryT *boundary, nodesuppT **nodesupp, short **flows, signed char **iscandidate, float **mag, float **wrappedphase, long ngroundarcs, long nrow, long ncol){ long nedgenode; long row, col, fromrow, fromcol, todir; long arcnum, upperarcnum, arcrow, arccol, arcdir, narccol; long surplus, residue, excess; nodeT *from, *to, *nextnode; /* do nothing if we have no boundary */ if(nodesupp!=NULL || boundary==NULL || boundary->nboundary==0 || boundary->nneighbor==0){ return(0); } /* find initial region edge node */ nextnode=boundary->boundarylist[0]; row=nextnode->row; col=nextnode->col; if(!IsRegionEdgeNode(mag,row,col,nrow,ncol)){ fprintf(sp0,"ERROR: DischargeBoundary() start node %ld, %ld not on edge\n", row,col); exit(ABNORMAL_EXIT); } /* silence compiler warnings */ row=0; col=0; todir=0; /* make sure iscandidate is zero */ /* temporarily set illegal corner arcs to 0 to simplify logic (reset later) */ for(row=0;row<2*nrow-1;row++){ if(rowoutcost=-1; nextnode=NULL; /* loop over outgoing arcs */ /* pass NULL to NeighborNode() for boundary so as not to follow */ /* node pointers to boundary node */ arcnum=GetArcNumLims(from->row,&upperarcnum,ngroundarcs,NULL); while(arcnumoutcost!=-1))){ /* save arc */ nextnode=to; row=arcrow; col=arccol; todir=arcdir; /* stop and follow arc if arc not yet followed */ if(!iscandidate[arcrow][arccol]){ break; } } } /* break if no unfollowed arcs (ie, we are done examining tree) */ if(nextnode==NULL){ break; } /* if we found leaf and we're moving back up the tree, do a push */ /* otherwise, just mark the path by decrementing iscandidate */ if((--iscandidate[row][col])==-2){ /* integrate flow into current node */ fromrow=from->row; fromcol=from->col; surplus=(flows[fromrow][fromcol] -flows[fromrow][fromcol+1] +flows[fromrow+nrow-1][fromcol] -flows[fromrow+1+nrow-1][fromcol]); /* compute residue from wrapped phase */ residue=NodeResidue(wrappedphase,fromrow,fromcol); /* compute excess as surplus plus residue */ excess=surplus+residue; /* augment flow */ flows[row][col]+=todir*excess; /* increment counter of edge nodes */ nedgenode++; } } /* reset all iscandidate and outcost values */ /* set illegal corner arc iscandidate values back to TRUE */ /* outcost of region edge nodes should be zero if source was on edge */ /* and arc costs along boundary are all zero */ for(row=0;row0){ nodes[row][col-1].outcost=0; } if(col0){ nodes[row-1][col].outcost=0; } if(rowgroup=1; source->outcost=0; source->incost=0; source->pred=NULL; source->prev=source; source->next=source; source->level=0; /* loop over outgoing arcs and add to buckets */ arcnum=GetArcNumLims(source->row,&upperarcnum,ngroundarcs,boundary); while(arcnumgroup!=PRUNED && to->group!=MASKED){ AddNewNode(source,to,arcdir,bkts,nflow,incrcosts,arcrow,arccol,params); } } /* done */ return(0); } /* function: FindApex() * -------------------- * Given pointers to two nodes on a spanning tree, the function finds * and returns a pointer to their deepest common ancestor, the apex of * a cycle formed by joining the two nodes with an arc. */ static nodeT *FindApex(nodeT *from, nodeT *to){ if(from->level > to->level){ while(from->level != to->level){ from=from->pred; } }else{ while(from->level != to->level){ to=to->pred; } } while(from != to){ from=from->pred; to=to->pred; } return(from); } /* function: CandidateCompare() * ---------------------------- * Compares the violations of candidate arcs for sorting. First checks * if either candidate has an arcdir magnitude greater than 1, denoting * an augmenting cycle. Augmenting candidates are always placed before * non-augmenting candidates. Otherwise, returns positive if the first * candidate has a greater (less negative) violation than the second, 0 * if they are the same, and negative otherwise. */ static int CandidateCompare(const void *c1, const void *c2){ if(labs(((candidateT *)c1)->arcdir) > 1){ if(labs(((candidateT *)c2)->arcdir) < 2){ return(-1); } }else if(labs(((candidateT *)c2)->arcdir) > 1){ return(1); } return(((candidateT *)c1)->violation - ((candidateT *)c2)->violation); /* if(((candidateT *)c1)->violation > ((candidateT *)c2)->violation){ return(1); }else if(((candidateT *)c1)->violation < ((candidateT *)c2)->violation){ return(-1); }else{ return(0); } */ } /* function: GetArcNumLims() * ------------------------- * Get the initial and ending values for arcnum to find neighbors of * the passed node. */ static inline long GetArcNumLims(long fromrow, long *upperarcnumptr, long ngroundarcs, boundaryT *boundary){ long arcnum; /* set arcnum limits based on node type */ if(fromrow<0){ arcnum=-1; if(fromrow==GROUNDROW){ *upperarcnumptr=ngroundarcs-1; }else{ *upperarcnumptr=boundary->nneighbor-1; } }else{ arcnum=-5; *upperarcnumptr=-1; } return(arcnum); } /* function: NeighborNodeGrid() * ---------------------------- * Return the neighboring node of the given node corresponding to the * given arc number for a grid network with a ground node. */ static nodeT *NeighborNodeGrid(nodeT *node1, long arcnum, long *upperarcnumptr, nodeT **nodes, nodeT *ground, long *arcrowptr, long *arccolptr, long *arcdirptr, long nrow, long ncol, boundaryT *boundary, nodesuppT **nodesupp){ long row, col; nodeT *neighbor; /* get starting node row and col for convenience */ row=node1->row; col=node1->col; /* see if starting node is boundary node */ if(row==BOUNDARYROW){ /* get neighbor info from boundary structure */ neighbor=boundary->neighborlist[arcnum].neighbor; *arcrowptr=boundary->neighborlist[arcnum].arcrow; *arccolptr=boundary->neighborlist[arcnum].arccol; *arcdirptr=boundary->neighborlist[arcnum].arcdir; }else{ /* starting node is normal node */ switch(arcnum){ case -4: *arcrowptr=row; *arccolptr=col+1; *arcdirptr=1; if(col==ncol-2){ neighbor=ground; }else{ neighbor=&nodes[row][col+1]; } break; case -3: *arcrowptr=nrow+row; *arccolptr=col; *arcdirptr=1; if(row==nrow-2){ neighbor=ground; }else{ neighbor=&nodes[row+1][col]; } break; case -2: *arcrowptr=row; *arccolptr=col; *arcdirptr=-1; if(col==0){ neighbor=ground; }else{ neighbor=&nodes[row][col-1]; } break; case -1: *arcrowptr=nrow-1+row; *arccolptr=col; *arcdirptr=-1; if(row==0){ neighbor=ground; }else{ neighbor=&nodes[row-1][col]; } break; default: if(arcnumgroup==BOUNDARYPTR && boundary!=NULL){ neighbor=boundary->node; } } /* return neighbor */ return(neighbor); } /* function: NeighborNodeNonGrid() * ------------------------------- * Return the neighboring node of the given node corresponding to the * given arc number for a nongrid network (ie, arbitrary topology). */ static nodeT *NeighborNodeNonGrid(nodeT *node1, long arcnum, long *upperarcnumptr, nodeT **nodes, nodeT *ground, long *arcrowptr, long *arccolptr, long *arcdirptr, long nrow, long ncol, boundaryT *boundary, nodesuppT **nodesupp){ long tilenum, nodenum; scndryarcT *outarc; /* set up */ tilenum=node1->row; nodenum=node1->col; *upperarcnumptr=nodesupp[tilenum][nodenum].noutarcs-5; /* set the arc row (tilenumber) and column (arcnumber) */ outarc=nodesupp[tilenum][nodenum].outarcs[arcnum+4]; *arcrowptr=outarc->arcrow; *arccolptr=outarc->arccol; if(node1==outarc->from){ *arcdirptr=1; }else{ *arcdirptr=-1; } /* return the neighbor node */ return(nodesupp[tilenum][nodenum].neighbornodes[arcnum+4]); } /* function: GetArcGrid() * ---------------------- * Given a from node and a to node, sets pointers for indices into * arc arrays, assuming primary (grid) network. */ static void GetArcGrid(nodeT *from, nodeT *to, long *arcrow, long *arccol, long *arcdir, long nrow, long ncol, nodeT **nodes, nodesuppT **nodesupp){ long fromrow, fromcol, torow, tocol; fromrow=from->row; fromcol=from->col; torow=to->row; tocol=to->col; if(fromcol==tocol-1){ /* normal arcs (neither endpoint ground) */ *arcrow=fromrow; *arccol=fromcol+1; *arcdir=1; }else if(fromcol==tocol+1){ *arcrow=fromrow; *arccol=fromcol; *arcdir=-1; }else if(fromrow==torow-1){ *arcrow=fromrow+1+nrow-1; *arccol=fromcol; *arcdir=1; }else if(fromrow==torow+1){ *arcrow=fromrow+nrow-1; *arccol=fromcol; *arcdir=-1; }else if(fromrow==BOUNDARYROW){ /* arc from boundary pointer */ if(tocol0 && nodes[torow][tocol-1].group==BOUNDARYPTR){ *arcrow=torow; *arccol=tocol; *arcdir=1; }else if(torow0 && nodes[fromrow][fromcol-1].group==BOUNDARYPTR){ *arcrow=fromrow; *arccol=fromcol; *arcdir=-1; }else if(fromrowrow; nodenum=from->col; /* loop over all outgoing arcs of from node */ arcnum=0; while(TRUE){ outarc=nodesupp[tilenum][nodenum].outarcs[arcnum++]; if(outarc->from==to){ *arcrow=outarc->arcrow; *arccol=outarc->arccol; *arcdir=-1; return; }else if(outarc->to==to){ *arcrow=outarc->arcrow; *arccol=outarc->arccol; *arcdir=1; return; } } return; } /* Function: NonDegenUpdateChildren() * ---------------------------------- * Updates potentials and groups of all childredn along an augmenting path, * until a stop node is hit. */ static void NonDegenUpdateChildren(nodeT *startnode, nodeT *lastnode, nodeT *nextonpath, long dgroup, long ngroundarcs, long nflow, nodeT **nodes, nodesuppT **nodesupp, nodeT *ground, boundaryT *boundary, nodeT ***apexes, incrcostT **incrcosts, long nrow, long ncol, paramT *params){ nodeT *node1, *node2; long dincost, doutcost, arcnum, upperarcnum, startlevel; long group1, pathgroup, arcrow, arccol, arcdir; /* loop along flow path */ node1=startnode; pathgroup=lastnode->group; while(node1!=lastnode){ /* update potentials along the flow path by calculating arc distances */ node2=nextonpath; GetArc(node2->pred,node2,&arcrow,&arccol,&arcdir,nrow,ncol, nodes,nodesupp); doutcost=node1->outcost - node2->outcost + GetCost(incrcosts,arcrow,arccol,arcdir); node2->outcost+=doutcost; dincost=node1->incost - node2->incost + GetCost(incrcosts,arcrow,arccol,-arcdir); node2->incost+=dincost; node2->group=node1->group+dgroup; /* update potentials of children of this node in the flow path */ node1=node2; arcnum=GetArcNumLims(node1->row,&upperarcnum,ngroundarcs,boundary); while(arcnumpred==node1 && node2->group>0){ if(node2->group==pathgroup){ nextonpath=node2; }else{ startlevel=node2->level; group1=node1->group; while(TRUE){ node2->group=group1; node2->incost+=dincost; node2->outcost+=doutcost; node2=node2->next; if(node2->level <= startlevel){ break; } } } } } } return; } /* function: PruneTree() * --------------------- * Descends the tree from the source and finds leaves that can be * removed. */ static long PruneTree(nodeT *source, nodeT **nodes, nodeT *ground, boundaryT *boundary, nodesuppT **nodesupp, incrcostT **incrcosts, short **flows, long ngroundarcs, long prunecostthresh, long nrow, long ncol){ long npruned; nodeT *node1; /* set up */ npruned=0; /* descend tree and look for leaves to prune */ node1=source->next; while(node1!=source){ /* see if current node is a leaf that should be pruned */ if(CheckLeaf(node1,nodes,ground,boundary,nodesupp,incrcosts,flows, ngroundarcs,nrow,ncol,prunecostthresh)){ /* remove the current node from the tree */ node1->prev->next=node1->next; node1->next->prev=node1->prev; node1->group=PRUNED; npruned++; /* see if last node checked was current node's parent */ /* if so, it may need pruning since its child has been pruned */ if(node1->prev->level < node1->level){ node1=node1->prev; }else{ node1=node1->next; } }else{ /* move on to next node */ node1=node1->next; } } /* show status */ fprintf(sp3,"\n Pruned %ld nodes\n",npruned); /* return number of pruned nodes */ return(npruned); } /* function: CheckLeaf() * --------------------- * Checks to see if the passed node should be pruned from the tree. * The node should be pruned if it is a leaf and if all of its outgoing * arcs have very high costs and only lead to other nodes that are already * on the tree or are already pruned. */ static int CheckLeaf(nodeT *node1, nodeT **nodes, nodeT *ground, boundaryT *boundary, nodesuppT **nodesupp, incrcostT **incrcosts, short **flows, long ngroundarcs, long nrow, long ncol, long prunecostthresh){ long arcnum, upperarcnum, arcrow, arccol, arcdir; nodeT *node2; /* first, check to see if node1 is a leaf */ if(node1->next->level > node1->level){ return(FALSE); } /* loop over outgoing arcs */ arcnum=GetArcNumLims(node1->row,&upperarcnum,ngroundarcs,boundary); while(arcnumgroup==0 || node2->group==INBUCKET || incrcosts[arcrow][arccol].poscostnshortcycle>LARGESHORT){ fprintf(sp1,"Maximum flow on network: %ld\n",*mostflowptr); fflush(NULL); fprintf(sp0,"((Maximum flow) * NSHORTCYCLE) too large\nAbort\n"); exit(ABNORMAL_EXIT); } if(ncol>2){ *ngroundarcsptr=2*(nrow+ncol-2)-4; /* don't include corner column arcs */ }else{ *ngroundarcsptr=2*(nrow+ncol-2)-2; } *iscandidateptr=(signed char **)Get2DRowColMem(nrow,ncol, sizeof(signed char *), sizeof(signed char)); *apexesptr=(nodeT ***)Get2DRowColMem(nrow,ncol,sizeof(nodeT **), sizeof(nodeT *)); } /* set up buckets for TreeSolve (MSTInitFlows() has local set of buckets) */ *bktsptr=MAlloc(sizeof(bucketT)); if(ground!=NULL){ (*bktsptr)->minind=-LRound((params->maxcost+1)*(nrow+ncol) *NEGBUCKETFRACTION); (*bktsptr)->maxind=LRound((params->maxcost+1)*(nrow+ncol) *POSBUCKETFRACTION); }else{ (*bktsptr)->minind=-LRound((params->maxcost+1)*(nrow) *NEGBUCKETFRACTION); (*bktsptr)->maxind=LRound((params->maxcost+1)*(nrow) *POSBUCKETFRACTION); } (*bktsptr)->size=(*bktsptr)->maxind-(*bktsptr)->minind+1; (*bktsptr)->bucketbase=(nodeT **)MAlloc((*bktsptr)->size*sizeof(nodeT *)); (*bktsptr)->bucket=&((*bktsptr)->bucketbase[-(*bktsptr)->minind]); for(i=0;i<(*bktsptr)->size;i++){ (*bktsptr)->bucketbase[i]=NULL; } /* get memory for incremental cost arrays */ *iincrcostfileptr=0; if(ground!=NULL){ (*incrcostsptr)=(incrcostT **)Get2DRowColMem(nrow,ncol,sizeof(incrcostT *), sizeof(incrcostT)); } /* set number of nodes and arcs per row */ if(ground!=NULL){ (*nnoderowptr)=nrow-1; (*nnodesperrowptr)=(int *)MAlloc((nrow-1)*sizeof(int)); for(i=0;igroup!=MASKED){ ground->group=0; nnodes++; } ground->incost=VERYFAR; ground->outcost=VERYFAR; ground->pred=NULL; } /* initialize arcs */ for(row=0;row0){ return(0); } } } return(1); } /* function: MaskNodes() * --------------------- * Set group numbers of nodes to MASKED if they are surrounded by * zero-magnitude pixels, 0 otherwise. */ int MaskNodes(long nrow, long ncol, nodeT **nodes, nodeT *ground, float **mag){ long row, col; /* loop over grid nodes and see if masking is necessary */ for(row=0;rowgroup=GroundMaskStatus(nrow,ncol,mag); /* done */ return(0); } /* function: GridNodeMaskStatus() * --------------------------------- * Given row and column of grid node, return MASKED if all pixels around node * have zero magnitude, and 0 otherwise. */ static int GridNodeMaskStatus(long row, long col, float **mag){ /* return 0 if any pixel is not masked */ if(mag[row][col] || mag[row][col+1] || mag[row+1][col] || mag[row+1][col+1]){ return(0); } return(MASKED); } /* function: GroundMaskStatus() * ---------------------------- * Return MASKED if all pixels around grid edge have zero magnitude, 0 * otherwise. */ static int GroundMaskStatus(long nrow, long ncol, float **mag){ long row, col; /* check all pixels along edge */ for(row=0;rowmostflow && mag[row][col]>0 && mag[row+1][col]>0){ mostflow=flowvalue; } } } for(row=nrow-1;row<2*nrow-1;row++){ for(col=0;colmostflow && mag[row-nrow+1][col]>0 && mag[row-nrow+1][col+1]>0){ mostflow=flowvalue; } } } return(mostflow); } /* function: InitNodeNums() * ------------------------ */ int InitNodeNums(long nrow, long ncol, nodeT **nodes, nodeT *ground){ long row, col; /* loop over each element and initialize values */ for(row=0;rowrow=GROUNDROW; ground->col=GROUNDCOL; } /* done */ return(0); } /* function: InitBuckets() * ----------------------- */ static int InitBuckets(bucketT *bkts, nodeT *source, long nbuckets){ long i; /* set up bucket array parameters */ bkts->curr=0; bkts->wrapped=FALSE; /* initialize the buckets */ for(i=0;ibucketbase[i]=NULL; } /* put the source in the zeroth distance index bucket */ bkts->bucket[0]=source; source->next=NULL; source->prev=NULL; source->group=INBUCKET; source->outcost=0; /* done */ return(0); } /* function: InitNodes() * --------------------- */ int InitNodes(long nnrow, long nncol, nodeT **nodes, nodeT *ground){ long row, col; /* loop over each element and initialize values */ for(row=0;rowgroup=NOTINBUCKET; ground->incost=VERYFAR; ground->outcost=VERYFAR; ground->pred=NULL; } /* done */ return(0); } /* function: BucketInsert() * ------------------------ */ void BucketInsert(nodeT *node, long ind, bucketT *bkts){ /* put node at beginning of bucket list */ node->next=bkts->bucket[ind]; if((bkts->bucket[ind])!=NULL){ bkts->bucket[ind]->prev=node; } bkts->bucket[ind]=node; node->prev=NULL; /* mark node in bucket array */ node->group=INBUCKET; /* done */ return; } /* function: BucketRemove() * ------------------------ */ void BucketRemove(nodeT *node, long ind, bucketT *bkts){ /* remove node from doubly linked list */ if((node->next)!=NULL){ node->next->prev=node->prev; } if(node->prev!=NULL){ node->prev->next=node->next; }else if(node->next==NULL){ bkts->bucket[ind]=NULL; }else{ bkts->bucket[ind]=node->next; } /* done */ return; } /* function: ClosestNode() * ----------------------- */ nodeT *ClosestNode(bucketT *bkts){ nodeT *node; /* find the first bucket with nodes in it */ while(TRUE){ /* see if we got to the last bucket */ if((bkts->curr)>(bkts->maxind)){ return(NULL); } /* see if we found a nonempty bucket; if so, return it */ if((bkts->bucket[bkts->curr])!=NULL){ node=bkts->bucket[bkts->curr]; node->group=ONTREE; bkts->bucket[bkts->curr]=node->next; if((node->next)!=NULL){ node->next->prev=NULL; } return(node); } /* move to next bucket */ bkts->curr++; } } /* function: ClosestNodeCircular() * ------------------------------- * Similar to ClosestNode(), but assumes circular buckets. This * function should NOT be used if negative arc weights exist on the * network; initial value of bkts->minind should always be zero. */ /* * This function is no longer used */ #if 0 static nodeT *ClosestNodeCircular(bucketT *bkts); static nodeT *ClosestNodeCircular(bucketT *bkts){ nodeT *node; /* find the first bucket with nodes in it */ while(TRUE){ /* see if we got to the last bucket */ if((bkts->curr+bkts->minind)>(bkts->maxind)){ if(bkts->wrapped){ bkts->wrapped=FALSE; bkts->curr=0; bkts->minind+=bkts->size; bkts->maxind+=bkts->size; }else{ return(NULL); } } /* see if we found a nonempty bucket; if so, return it */ if((bkts->bucket[bkts->curr])!=NULL){ node=bkts->bucket[bkts->curr]; node->group=ONTREE; bkts->bucket[bkts->curr]=node->next; if((node->next)!=NULL){ node->next->prev=NULL; } return(node); } /* move to next bucket */ bkts->curr++; } } #endif /* function: MinOutCostNode() * -------------------------- * Similar to ClosestNode(), but always returns closest node even if its * outcost is less than the minimum bucket index. Does not handle circular * buckets. Does not handle no nodes left condition (this should be handled * by calling function). */ static nodeT *MinOutCostNode(bucketT *bkts){ long minoutcost; nodeT *node1, *node2; /* move to next non-empty bucket */ while(bkts->currmaxind && bkts->bucket[bkts->curr]==NULL){ bkts->curr++; } /* scan the whole bucket if it is the overflow or underflow bag */ if(bkts->curr==bkts->minind || bkts->curr==bkts->maxind){ node2=bkts->bucket[bkts->curr]; node1=node2; minoutcost=node1->outcost; while(node2!=NULL){ if(node2->outcostoutcost; node1=node2; } node2=node2->next; } BucketRemove(node1,bkts->curr,bkts); }else{ node1=bkts->bucket[bkts->curr]; bkts->bucket[bkts->curr]=node1->next; if(node1->next!=NULL){ node1->next->prev=NULL; } } return(node1); } /* function: SelectSources() * ------------------------- * Create a list of node pointers to be sources for each set of * connected pixels (not disconnected by masking). Return the number * of sources (ie, the number of connected sets of pixels). */ long SelectSources(nodeT **nodes, float **mag, nodeT *ground, long nflow, short **flows, long ngroundarcs, long nrow, long ncol, paramT *params, nodeT ***sourcelistptr, long **nconnectedarrptr){ long row, col, nsource, nsourcelistmem, nconnected; long *nconnectedarr; nodeT *source; nodeT **sourcelist; /* initialize local variables */ nsource=0; nsourcelistmem=0; sourcelist=NULL; nconnectedarr=NULL; /* loop over nodes to initialize */ if(ground->group!=MASKED && ground->group!=BOUNDARYPTR){ ground->group=0; } ground->next=NULL; for(row=0;rownsourcelistmem){ nsourcelistmem+=NSOURCELISTMEMINCR; sourcelist=ReAlloc(sourcelist,nsourcelistmem*sizeof(nodeT *)); nconnectedarr=ReAlloc(nconnectedarr,nsourcelistmem*sizeof(long)); } /* store source in list */ sourcelist[nsource-1]=source; nconnectedarr[nsource-1]=nconnected; } /* loop over nodes to find next set of connected nodes */ for(row=0;rownsourcelistmem){ nsourcelistmem+=NSOURCELISTMEMINCR; sourcelist=ReAlloc(sourcelist,nsourcelistmem*sizeof(nodeT *)); nconnectedarr=ReAlloc(nconnectedarr,nsourcelistmem*sizeof(long)); } /* store source in list */ sourcelist[nsource-1]=source; nconnectedarr[nsource-1]=nconnected; } } } /* show message about number of connected regions */ fprintf(sp1,"Found %ld valid set(s) of connected nodes\n",nsource); /* reset group values for all nodes */ if(ground->group!=MASKED && ground->group!=BOUNDARYPTR){ ground->group=0; } ground->next=NULL; for(row=0;rowgroup==MASKED || start->group==ONTREE){ return(NULL); } /* find all nodes for this set of connected pixels and mark them on tree */ nconnected=ScanRegion(start,nodes,mag,ground,ngroundarcs,nrow,ncol,ONTREE); /* see if number of nodes in this connected set is big enough */ if(nconnected>params->nconnnodemin){ /* set source to first node in chain */ /* this ensures that the soruce is the ground node or on the edge */ /* of the connected region, which tends to be faster */ source = start; }else{ source=NULL; } /* set number of connected nodes and return source */ if(nconnectedptr!=NULL){ (*nconnectedptr)=nconnected; } return(source); } /* function: ScanRegion() * ---------------------- * Find all connected grid nodes of region, defined by reachability without * crossing non-region arcs, and set group according to desired * behavior defined by groupsetting, which should be either ONTREE for * call from SelectConnNodeSourcre(), MASKED for a call from * InitBoundary(), or 0 for a call from CleanUpBoundaryNodes(). Return * number of connected nodes. */ static long ScanRegion(nodeT *start, nodeT **nodes, float **mag, nodeT *ground, long ngroundarcs, long nrow, long ncol, int groupsetting){ nodeT *node1, *node2, *end; long arcrow, arccol, arcdir, arcnum, upperarcnum, nconnected; nodesuppT **nodesupp; boundaryT *boundary; /* set up */ nconnected=0; end=start; nodesupp=NULL; boundary=NULL; node1=start; node1->group=INBUCKET; /* loop to search for connected nodes */ while(node1!=NULL){ /* loop over neighbors of current node */ arcnum=GetArcNumLims(node1->row,&upperarcnum,ngroundarcs,boundary); while(arcnumgroup==BOUNDARYPTR){ node2->group=0; } /* see if neighbor is in region */ if(IsRegionArc(mag,arcrow,arccol,nrow,ncol)){ /* if neighbor is in region and not yet in list to be scanned, add it */ if(node2->group!=ONTREE && node2->group!=INBUCKET){ node2->group=INBUCKET; end->next=node2; node2->next=NULL; end=node2; } } } /* mark this node visited */ node1->group=ONTREE; /* make sure level is initialized */ if(groupsetting==ONTREE){ node1->level=0; } /* count this node */ nconnected++; /* move to next node in list */ node1=node1->next; } /* for each node in region, scan neighbors to mask or unmask unreachable */ /* nodes that may be in other regions and therefore not yet masked */ if(groupsetting!=ONTREE){ /* loop over nodes in region */ node1=start; while(node1!=NULL){ /* loop over neighbors of current node */ arcnum=GetArcNumLims(node1->row,&upperarcnum,ngroundarcs,boundary); while(arcnumgroup!=ONTREE){ /* set mask status according to desired behavior */ if(groupsetting==MASKED){ node2->group=MASKED; }else if(groupsetting==0){ if(node2->row==GROUNDROW){ node2->group=GroundMaskStatus(nrow,ncol,mag); }else{ node2->group=GridNodeMaskStatus(node2->row,node2->col,mag); } } } } /* move to next node */ node1=node1->next; } /* reset groups of all nodes within region */ node1=start; while(node1!=NULL){ node1->group=0; node1=node1->next; } } /* return number of connected nodes */ return(nconnected); } /* function: GetCost() * ------------------- * Returns incremental flow cost for current flow increment dflow from * lookup array. */ static short GetCost(incrcostT **incrcosts, long arcrow, long arccol, long arcdir){ /* look up cost and return it for the appropriate arc direction */ /* we may want add a check here for clipped incremental costs */ if(arcdir>0){ return(incrcosts[arcrow][arccol].poscost); }else{ return(incrcosts[arcrow][arccol].negcost); } } /* function: ReCalcCost() * ---------------------- * Updates the incremental cost for an arc. */ long ReCalcCost(void **costs, incrcostT **incrcosts, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params){ long poscost, negcost, iclipped; /* calculate new positive and negative nflow costs, as long ints */ CalcCost(costs,flow,arcrow,arccol,nflow,nrow,params, &poscost,&negcost); /* clip costs to short int */ iclipped=0; if(poscost>LARGESHORT){ incrcosts[arcrow][arccol].poscost=LARGESHORT; iclipped++; }else{ if(poscost<-LARGESHORT){ incrcosts[arcrow][arccol].poscost=-LARGESHORT; iclipped++; }else{ incrcosts[arcrow][arccol].poscost=poscost; } } if(negcost>LARGESHORT){ incrcosts[arcrow][arccol].negcost=LARGESHORT; iclipped++; }else{ if(negcost<-LARGESHORT){ incrcosts[arcrow][arccol].negcost=-LARGESHORT; iclipped++; }else{ incrcosts[arcrow][arccol].negcost=negcost; } } /* return the number of clipped incremental costs (0, 1, or 2) */ return(iclipped); } /* function: SetupIncrFlowCosts() * ------------------------------ * Calculates the costs for positive and negative dflow flow increment * if there is zero flow on the arc. */ int SetupIncrFlowCosts(void **costs, incrcostT **incrcosts, short **flows, long nflow, long nrow, long narcrow, int *narcsperrow, paramT *params){ long arcrow, arccol, iclipped, narcs; char pl[2]; /* loop over all rows and columns */ narcs=0; iclipped=0; for(arcrow=0;arcrow1){ strcpy(pl,"s"); }else{ strcpy(pl,""); } fflush(NULL); fprintf(sp0,"%ld incremental cost%s clipped to avoid overflow (%.3f%%)\n", iclipped,pl,((double )iclipped)/(2*narcs)); } /* done */ return(0); } /* function: EvaluateTotalCost() * ----------------------------- * Computes the total cost of the flow array and prints it out. Pass nrow * and ncol if in grid mode (primary network), or pass nrow=ntiles and * ncol=0 for nongrid mode (secondary network). */ totalcostT EvaluateTotalCost(void **costs, short **flows, long nrow, long ncol, int *narcsperrow,paramT *params){ totalcostT rowcost, totalcost; long row, col, maxrow, maxcol; /* sum cost for each row and column arc */ totalcost=0; if(ncol){ maxrow=2*nrow-1; }else{ maxrow=nrow; } for(row=0;rowmaxcost && !((row==nrow-1 || 2*nrow-2) && (col==0 || col==ncol-2))){ maxcost=mstcosts[row][col]; } } } /* get memory for buckets and arc status */ bkts->size=LRound((maxcost+1)*(nrow+ncol+1)); bkts->bucketbase=(nodeT **)MAlloc(bkts->size*sizeof(nodeT *)); bkts->minind=0; bkts->maxind=bkts->size-1; bkts->bucket=bkts->bucketbase; arcstatus=(signed char **)Get2DRowColMem(nrow,ncol,sizeof(signed char *), sizeof(signed char)); /* calculate phase residues (integer numbers of cycles) */ fprintf(sp1,"Initializing flows with MST algorithm\n"); residue=(signed char **)Get2DMem(nrow-1,ncol-1,sizeof(signed char *), sizeof(signed char)); CycleResidue(wrappedphase,residue,nrow,ncol); /* get memory for flow arrays */ (*flowsptr)=(short **)Get2DRowColZeroMem(nrow,ncol, sizeof(short *),sizeof(short)); flows=*flowsptr; /* loop until no flows exceed the maximum flow */ fprintf(sp2,"Running approximate minimum spanning tree solver\n"); while(TRUE){ /* set up the source to be the first non-zero residue that we find */ source=NULL; for(row=0;rowsize); /* solve the mst problem */ SolveMST(*nodesptr,source,ground,bkts,mstcosts,residue,arcstatus, nrow,ncol); /* find flows on minimum tree (only one feasible flow exists) */ DischargeTree(source,mstcosts,flows,residue,arcstatus, *nodesptr,ground,nrow,ncol); /* do pushes to clip the flows and make saturated arcs ineligible */ /* break out of loop if there is no flow greater than the limit */ if(ClipFlow(residue,flows,mstcosts,nrow,ncol,maxflow)){ break; } } /* free memory and return */ Free2DArray((void **)residue,nrow-1); Free2DArray((void **)arcstatus,2*nrow-1); Free2DArray((void **)mstcosts,2*nrow-1); free(bkts->bucketbase); return(0); } /* function: SolveMST() * -------------------- * Finds tree which spans all residue nodes of approximately minimal length. * Note that this function may produce a Steiner tree (tree may split at * non-residue node), though finding the exactly minimum Steiner tree is * NP-hard. This function uses Prim's algorithm, nesting Dijkstra's * shortest path algorithm in each iteration to find next closest residue * node to tree. See Ahuja, Orlin, and Magnanti 1993 for details. * * Dijkstra implementation and some associated functions adapted from SPLIB * shortest path codes written by Cherkassky, Goldberg, and Radzik. */ static void SolveMST(nodeT **nodes, nodeT *source, nodeT *ground, bucketT *bkts, short **mstcosts, signed char **residue, signed char **arcstatus, long nrow, long ncol){ nodeT *from, *to, *pathfrom, *pathto; nodesuppT **nodesupp; long fromdist, newdist, arcdist, ngroundarcs, groundcharge; long fromrow, fromcol, row, col, arcnum, upperarcnum, maxcol; long pathfromrow, pathfromcol; long arcrow, arccol, arcdir; /* initialize some variables */ nodesupp=NULL; /* calculate the number of ground arcs */ ngroundarcs=2*(nrow+ncol-2)-4; /* calculate charge on ground */ groundcharge=0; for(row=0;rowrow; fromcol=from->col; /* if we found a residue */ if(((fromrow!=GROUNDROW && residue[fromrow][fromcol]) || (fromrow==GROUNDROW && groundcharge)) && from!=source){ /* set node and its predecessor */ pathto=from; pathfrom=from->pred; /* go back and make arcstatus -1 along path */ while(TRUE){ /* give to node zero distance label */ pathto->outcost=0; /* get arc indices for arc between pathfrom and pathto */ GetArc(pathfrom,pathto,&arcrow,&arccol,&arcdir,nrow,ncol, nodes,nodesupp); /* set arc status to -1 to mark arc on tree */ arcstatus[arcrow][arccol]=-1; /* stop when we get to a residue */ pathfromrow=pathfrom->row; pathfromcol=pathfrom->col; if((pathfromrow!=GROUNDROW && residue[pathfromrow][pathfromcol]) || (pathfromrow==GROUNDROW && groundcharge)){ break; } /* move up to previous node pair in path */ pathto=pathfrom; pathfrom=pathfrom->pred; } /* end while loop marking costs on path */ } /* end if we found a residue */ /* set a variable for from node's distance */ fromdist=from->outcost; /* scan from's neighbors */ arcnum=GetArcNumLims(fromrow,&upperarcnum,ngroundarcs,NULL); while(arcnumrow; col=to->col; /* get cost of arc to new node (if arc on tree, cost is 0) */ if(arcstatus[arcrow][arccol]<0){ arcdist=0; }else if((arcdist=mstcosts[arcrow][arccol])==LARGESHORT){ arcdist=VERYFAR; } /* compare distance of new nodes to temp labels */ if((newdist=fromdist+arcdist)<(to->outcost)){ /* if to node is already in a bucket, remove it */ if(to->group==INBUCKET){ if(to->outcostmaxind){ BucketRemove(to,to->outcost,bkts); }else{ BucketRemove(to,bkts->maxind,bkts); } } /* update to node */ to->outcost=newdist; to->pred=from; /* insert to node into appropriate bucket */ if(newdistmaxind){ BucketInsert(to,newdist,bkts); if(newdistcurr){ bkts->curr=newdist; } }else{ BucketInsert(to,bkts->maxind,bkts); } } /* end if newdist < old dist */ } /* end loop over outgoing arcs */ } /* end while ClosestNode()!=NULL */ } /* function: DischargeTree() * ------------------------- * Does depth-first search on result tree from SolveMST. Integrates * charges from tree leaves back up to set arc flows. This implementation * is non-recursive; a recursive implementation might be faster, but * would also use much more stack memory. This method is equivalent to * walking the tree, so it should be nore more than a factor of 2 slower. */ static long DischargeTree(nodeT *source, short **mstcosts, short **flows, signed char **residue, signed char **arcstatus, nodeT **nodes, nodeT *ground, long nrow, long ncol){ long row, col, todir, arcrow, arccol, arcdir; long arcnum, upperarcnum, ngroundarcs; nodeT *from, *to, *nextnode; nodesuppT **nodesupp; /* set up */ /* use outcost member of node structure to temporarily store charge */ nextnode=source; ground->outcost=0; for(row=0;rowoutcost-=residue[row][col]; } } ngroundarcs=2*(nrow+ncol-2)-4; nodesupp=NULL; todir=0; /* keep looping unitl we've walked the entire tree */ while(TRUE){ from=nextnode; nextnode=NULL; /* loop over outgoing arcs from this node */ arcnum=GetArcNumLims(from->row,&upperarcnum,ngroundarcs,NULL); while(arcnumoutcost; nextnode->outcost+=from->outcost; from->outcost=0; } } /* finish up */ return(from->outcost); } /* end of DischargeTree() */ /* function: ClipFlow() * --------------------- * Given a flow, clips flow magnitudes to a computed limit, resets * residues so sum of solution of network problem with new residues * and solution of clipped problem give total solution. Upper flow limit * is 2/3 the maximum flow on the network or the passed value maxflow, * whichever is greater. Clipped flow arcs get costs of passed variable * maxcost. Residues should have been set to zero by DischargeTree(). */ static signed char ClipFlow(signed char **residue, short **flows, short **mstcosts, long nrow, long ncol, long maxflow){ long row, col, cliplimit, maxcol, excess, tempcharge, sign; long mostflow, maxcost; /* find maximum flow */ mostflow=Short2DRowColAbsMax(flows,nrow,ncol); /* if there is no flow greater than the maximum, return TRUE */ if(mostflow<=maxflow){ return(TRUE); } fprintf(sp2,"Maximum flow on network: %ld\n",mostflow); /* set upper flow limit */ cliplimit=(long )ceil(mostflow*CLIPFACTOR)+1; if(maxflow>cliplimit){ cliplimit=maxflow; } /* find maximum cost (excluding ineligible corner arcs) */ maxcost=0; for(row=0;row<2*nrow-1;row++){ if(rowmaxcost && mstcosts[row][col]=LARGESHORT){ fflush(NULL); fprintf(sp0,"WARNING: escaping ClipFlow loop to prevent cost overflow\n"); return(TRUE); } /* clip flows and do pushes */ for(row=0;row<2*nrow-1;row++){ if(rowcliplimit){ if(flows[row][col]>0){ sign=1; excess=flows[row][col]-cliplimit; }else{ sign=-1; excess=flows[row][col]+cliplimit; } if(rowMAXRES || tempchargeMAXRES){ fflush(NULL); fprintf(sp0,"Overflow of residue data type\nAbort\n"); exit(ABNORMAL_EXIT); } residue[row][col]=tempcharge; } }else{ if(row!=nrow-1){ tempcharge=residue[row-nrow][col]+excess; if(tempcharge>MAXRES || tempchargeMAXRES){ fflush(NULL); fprintf(sp0,"Overflow of residue data type\nAbort\n"); exit(ABNORMAL_EXIT); } residue[row-nrow+1][col]=tempcharge; } } flows[row][col]=sign*cliplimit; mstcosts[row][col]=maxcost; } } } /* return value indicates that flows have been clipped */ fprintf(sp2,"Flows clipped to %ld. Rerunning MST solver.\n",cliplimit); return(FALSE); } /* function: MCFInitFlows() * ------------------------ * Initializes the flow on a the network using minimum cost flow * algorithm. */ int MCFInitFlows(float **wrappedphase, short ***flowsptr, short **mstcosts, long nrow, long ncol, long cs2scalefactor){ #ifndef NO_CS2 signed char **residue; /* calculate phase residues (integer numbers of cycles) */ fprintf(sp1,"Initializing flows with MCF algorithm\n"); residue=(signed char **)Get2DMem(nrow-1,ncol-1,sizeof(signed char *), sizeof(signed char)); CycleResidue(wrappedphase,residue,nrow,ncol); /* run the solver (memory freed within solver) */ SolveCS2(residue,mstcosts,nrow,ncol,cs2scalefactor,flowsptr); #endif /* done */ return(0); } snaphu-v2.0.6/src/PaxHeader/snaphu_tile.c000644 777777 777777 00000000043 14423062415 020144 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/src/snaphu_tile.c000644 Ho)00000447464 14423062415 017421 0ustar00curtis000000 000000 /************************************************************************* snaphu tile-mode 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "snaphu.h" /* static (local) function prototypes */ static long ThickenCosts(incrcostT **incrcosts, long nrow, long ncol); static nodeT *RegionsNeighborNode(nodeT *node1, long *arcnumptr, nodeT **nodes, long *arcrowptr, long *arccolptr, long nrow, long ncol); static int ClearBuckets(bucketT *bkts); static int MergeRegions(nodeT **nodes, nodeT *source, long *regionsizes, long closestregion, long nrow, long ncol); static int RenumberRegion(nodeT **nodes, nodeT *source, long newnum, long nrow, long ncol); static int ReadNextRegion(long tilerow, long tilecol, long nlines, long linelen, outfileT *outfiles, paramT *params, short ***nextregionsptr, float ***nextunwphaseptr, void ***nextcostsptr, long *nextnrowptr, long *nextncolptr); static int SetTileReadParams(tileparamT *tileparams, long nexttilenlines, long nexttilelinelen, long tilerow, long tilecol, long nlines, long linelen, paramT *params); static int ReadEdgesAboveAndBelow(long tilerow, long tilecol, long nlines, long linelen, paramT *params, outfileT *outfiles, short *regionsabove, short *regionsbelow, float *unwphaseabove, float *unwphasebelow, void *costsabove, void *costsbelow); static int TraceRegions(short **regions, short **nextregions, short **lastregions, short *regionsabove, short *regionsbelow, float **unwphase, float **nextunwphase, float **lastunwphase, float *unwphaseabove, float *unwphasebelow, void **costs, void **nextcosts, void **lastcosts, void *costsabove, void *costsbelow, long prevnrow, long prevncol, long tilerow, long tilecol, long nrow, long ncol, nodeT **scndrynodes, nodesuppT **nodesupp, scndryarcT **scndryarcs, long ***scndrycosts, int *nscndrynodes, int *nscndryarcs, long *totarclens, short **bulkoffsets, paramT *params); static long FindNumPathsOut(nodeT *from, paramT *params, long tilerow, long tilecol, long nnrow, long nncol, short **regions, short **nextregions, short **lastregions, short *regionsabove, short *regionsbelow, long prevncol); static int RegionTraceCheckNeighbors(nodeT *from, nodeT **nextnodeptr, nodeT **primarynodes, short **regions, short **nextregions, short **lastregions, short *regionsabove, short *regionsbelow, long tilerow, long tilecol, long nnrow, long nncol, nodeT **scndrynodes, nodesuppT **nodesupp, scndryarcT **scndryarcs, long *nnewnodesptr, long *nnewarcsptr, long flowmax, long nrow, long ncol, long prevnrow, long prevncol, paramT *params, void **costs, void **rightedgecosts, void **loweredgecosts, void **leftedgecosts, void **upperedgecosts, short **flows, short **rightedgeflows, short **loweredgeflows, short **leftedgeflows, short **upperedgeflows, long ***scndrycosts, nodeT ***updatednontilenodesptr, long *nupdatednontilenodesptr, long *updatednontilenodesizeptr, short **inontilenodeoutarcptr, long *totarclenptr); static int SetUpperEdge(long ncol, long tilerow, long tilecol, void **voidcosts, void *voidcostsabove, float **unwphase, float *unwphaseabove, void **voidupperedgecosts, short **upperedgeflows, paramT *params, short **bulkoffsets); static int SetLowerEdge(long nrow, long ncol, long tilerow, long tilecol, void **voidcosts, void *voidcostsbelow, float **unwphase, float *unwphasebelow, void **voidloweredgecosts, short **loweredgeflows, paramT *params, short **bulkoffsets); static int SetLeftEdge(long nrow, long prevncol, long tilerow, long tilecol, void **voidcosts, void **voidlastcosts, float **unwphase, float **lastunwphase, void **voidleftedgecosts, short **leftedgeflows, paramT *params, short **bulkoffsets); static int SetRightEdge(long nrow, long ncol, long tilerow, long tilecol, void **voidcosts, void **voidnextcosts, float **unwphase, float **nextunwphase, void **voidrightedgecosts, short **rightedgeflows, paramT *params, short **bulkoffsets); static short AvgSigSq(short sigsq1, short sigsq2); static int TraceSecondaryArc(nodeT *primaryhead, nodeT **scndrynodes, nodesuppT **nodesupp, scndryarcT **scndryarcs, long ***scndrycosts, long *nnewnodesptr, long *nnewarcsptr, long tilerow, long tilecol, long flowmax, long nrow, long ncol, long prevnrow, long prevncol, paramT *params, void **tilecosts, void **rightedgecosts, void **loweredgecosts, void **leftedgecosts, void **upperedgecosts, short **tileflows, short **rightedgeflows, short **loweredgeflows, short **leftedgeflows, short **upperedgeflows, nodeT ***updatednontilenodesptr, long *nupdatednontilenodesptr, long *updatednontilenodesizeptr, short **inontilenodeoutarcptr, long *totarclenptr); static nodeT *FindScndryNode(nodeT **scndrynodes, nodesuppT **nodesupp, long tilenum, long primaryrow, long primarycol); static int IntegrateSecondaryFlows(long linelen, long nlines, nodeT **scndrynodes, nodesuppT **nodesupp, scndryarcT **scndryarcs, int *nscndryarcs, short **scndryflows, short **bulkoffsets, outfileT *outfiles, paramT *params); static int ParseSecondaryFlows(long tilenum, int *nscndryarcs, short **tileflows, short **regions, short **scndryflows, nodesuppT **nodesupp, scndryarcT **scndryarcs, long nrow, long ncol, long ntilerow, long ntilecol, paramT *params); static int AssembleTileConnComps(long linelen, long nlines, outfileT *outfiles, paramT *params); static int ConnCompSizeNPixCompare(const void *ptr1, const void *ptr2); /* function: SetupTile() * --------------------- * Sets up tile parameters and output file names for the current tile. */ int SetupTile(long nlines, long linelen, paramT *params, tileparamT *tileparams, outfileT *outfiles, outfileT *tileoutfiles, long tilerow, long tilecol){ long ni, nj; char tempstring[MAXTMPSTRLEN], path[MAXSTRLEN], basename[MAXSTRLEN]; char *tiledir; /* set parameters for current tile */ ni=ceil((nlines+(params->ntilerow-1)*params->rowovrlp) /(double )params->ntilerow); nj=ceil((linelen+(params->ntilecol-1)*params->colovrlp) /(double )params->ntilecol); tileparams->firstrow=tilerow*(ni-params->rowovrlp); tileparams->firstcol=tilecol*(nj-params->colovrlp); if(tilerow==params->ntilerow-1){ tileparams->nrow=nlines-(params->ntilerow-1)*(ni-params->rowovrlp); }else{ tileparams->nrow=ni; } if(tilecol==params->ntilecol-1){ tileparams->ncol=linelen-(params->ntilecol-1)*(nj-params->colovrlp); }else{ tileparams->ncol=nj; } /* error checking on tile size */ if(params->minregionsize > (tileparams->nrow)*(tileparams->ncol)){ fflush(NULL); fprintf(sp0,"Minimum region size cannot exceed tile size\nAbort\n"); exit(ABNORMAL_EXIT); } /* set output files */ tiledir=params->tiledir; ParseFilename(outfiles->outfile,path,basename); sprintf(tempstring,"%s/%s%s_%ld_%ld.%ld", tiledir,TMPTILEROOT,basename,tilerow,tilecol,tileparams->ncol); StrNCopy(tileoutfiles->outfile,tempstring,MAXSTRLEN); if(strlen(outfiles->initfile)){ ParseFilename(outfiles->initfile,path,basename); sprintf(tempstring,"%s/%s%s_%ld_%ld.%ld", tiledir,TMPTILEROOT,basename,tilerow,tilecol,tileparams->ncol); StrNCopy(tileoutfiles->initfile,tempstring,MAXSTRLEN); }else{ StrNCopy(tileoutfiles->initfile,"",MAXSTRLEN); } if(strlen(outfiles->flowfile)){ ParseFilename(outfiles->flowfile,path,basename); sprintf(tempstring,"%s/%s%s_%ld_%ld.%ld", tiledir,TMPTILEROOT,basename,tilerow,tilecol,tileparams->ncol); StrNCopy(tileoutfiles->flowfile,tempstring,MAXSTRLEN); }else{ StrNCopy(tileoutfiles->flowfile,"",MAXSTRLEN); } if(strlen(outfiles->eifile)){ ParseFilename(outfiles->eifile,path,basename); sprintf(tempstring,"%s/%s%s_%ld_%ld.%ld", tiledir,TMPTILEROOT,basename,tilerow,tilecol,tileparams->ncol); StrNCopy(tileoutfiles->eifile,tempstring,MAXSTRLEN); }else{ StrNCopy(tileoutfiles->eifile,"",MAXSTRLEN); } if(strlen(outfiles->rowcostfile)){ ParseFilename(outfiles->rowcostfile,path,basename); sprintf(tempstring,"%s/%s%s_%ld_%ld.%ld", tiledir,TMPTILEROOT,basename,tilerow,tilecol,tileparams->ncol); StrNCopy(tileoutfiles->rowcostfile,tempstring,MAXSTRLEN); }else{ StrNCopy(tileoutfiles->rowcostfile,"",MAXSTRLEN); } if(strlen(outfiles->colcostfile)){ ParseFilename(outfiles->colcostfile,path,basename); sprintf(tempstring,"%s/%s%s_%ld_%ld.%ld", tiledir,TMPTILEROOT,basename,tilerow,tilecol,tileparams->ncol); StrNCopy(tileoutfiles->colcostfile,tempstring,MAXSTRLEN); }else{ StrNCopy(tileoutfiles->colcostfile,"",MAXSTRLEN); } if(strlen(outfiles->mstrowcostfile)){ ParseFilename(outfiles->mstrowcostfile,path,basename); sprintf(tempstring,"%s/%s%s_%ld_%ld.%ld", tiledir,TMPTILEROOT,basename,tilerow,tilecol,tileparams->ncol); StrNCopy(tileoutfiles->mstrowcostfile,tempstring,MAXSTRLEN); }else{ StrNCopy(tileoutfiles->mstrowcostfile,"",MAXSTRLEN); } if(strlen(outfiles->mstcolcostfile)){ ParseFilename(outfiles->mstcolcostfile,path,basename); sprintf(tempstring,"%s/%s%s_%ld_%ld.%ld", tiledir,TMPTILEROOT,basename,tilerow,tilecol,tileparams->ncol); StrNCopy(tileoutfiles->mstcolcostfile,tempstring,MAXSTRLEN); }else{ StrNCopy(tileoutfiles->mstcolcostfile,"",MAXSTRLEN); } if(strlen(outfiles->mstcostsfile)){ ParseFilename(outfiles->mstcostsfile,path,basename); sprintf(tempstring,"%s/%s%s_%ld_%ld.%ld", tiledir,TMPTILEROOT,basename,tilerow,tilecol,tileparams->ncol); StrNCopy(tileoutfiles->mstcostsfile,tempstring,MAXSTRLEN); }else{ StrNCopy(tileoutfiles->mstcostsfile,"",MAXSTRLEN); } if(strlen(outfiles->corrdumpfile)){ ParseFilename(outfiles->corrdumpfile,path,basename); sprintf(tempstring,"%s/%s%s_%ld_%ld.%ld", tiledir,TMPTILEROOT,basename,tilerow,tilecol,tileparams->ncol); StrNCopy(tileoutfiles->corrdumpfile,tempstring,MAXSTRLEN); }else{ StrNCopy(tileoutfiles->corrdumpfile,"",MAXSTRLEN); } if(strlen(outfiles->rawcorrdumpfile)){ ParseFilename(outfiles->rawcorrdumpfile,path,basename); sprintf(tempstring,"%s/%s%s_%ld_%ld.%ld", tiledir,TMPTILEROOT,basename,tilerow,tilecol,tileparams->ncol); StrNCopy(tileoutfiles->rawcorrdumpfile,tempstring,MAXSTRLEN); }else{ StrNCopy(tileoutfiles->rawcorrdumpfile,"",MAXSTRLEN); } if(strlen(outfiles->conncompfile)){ ParseFilename(outfiles->conncompfile,path,basename); sprintf(tempstring,"%s/%s%s_%ld_%ld.%ld", tiledir,TMPTILEROOT,basename,tilerow,tilecol,tileparams->ncol); StrNCopy(tileoutfiles->conncompfile,tempstring,MAXSTRLEN); }else{ StrNCopy(tileoutfiles->conncompfile,"",MAXSTRLEN); } if(strlen(outfiles->costoutfile)){ ParseFilename(outfiles->costoutfile,path,basename); sprintf(tempstring,"%s/%s%s_%ld_%ld.%ld", tiledir,TMPTILEROOT,basename,tilerow,tilecol,tileparams->ncol); StrNCopy(tileoutfiles->costoutfile,tempstring,MAXSTRLEN); }else{ sprintf(tempstring,"%s/%s%s%ld_%ld.%ld", tiledir,TMPTILEROOT,TMPTILECOSTSUFFIX,tilerow,tilecol, tileparams->ncol); StrNCopy(tileoutfiles->costoutfile,tempstring,MAXSTRLEN); } if(strlen(outfiles->logfile)){ ParseFilename(outfiles->logfile,path,basename); sprintf(tempstring,"%s/%s%s_%ld_%ld.%ld", tiledir,TMPTILEROOT,basename,tilerow,tilecol,tileparams->ncol); StrNCopy(tileoutfiles->logfile,tempstring,MAXSTRLEN); }else{ StrNCopy(tileoutfiles->logfile,"",MAXSTRLEN); } tileoutfiles->outfileformat=TMPTILEOUTFORMAT; /* done */ return(0); } /* function: SetUpDoTileMask() * --------------------------- * Read the tile mask if a file name is specified in the infiles structure, * otherwise return an array of all ones. */ signed char **SetUpDoTileMask(infileT *infiles, long ntilerow, long ntilecol){ long row, col; signed char **dotilemask; tileparamT readparams[1]; /* initialize stack structures to zero for good measure */ memset(readparams,0,sizeof(tileparamT)); /* get memory */ dotilemask=(signed char **)Get2DMem(ntilerow,ntilecol,sizeof(signed char *), sizeof(signed char)); /* see if a file name was passed */ if(strlen(infiles->dotilemaskfile)){ /* read the input file */ readparams->nrow=ntilerow; readparams->ncol=ntilecol; readparams->firstrow=0; readparams->firstcol=0; Read2DArray((void ***)&dotilemask,infiles->dotilemaskfile,ntilecol, ntilerow,readparams,sizeof(signed char *),sizeof(signed char)); }else{ /* set array to be all ones */ for(row=0;rowminregionsize; costthresh=params->tilecostthresh; closestregion=0; /* store current values of CalcCost and EvalCost function pointers */ tempcalccostfnptr=CalcCost; tempevalcostfnptr=EvalCost; /* reread statistical costs from stored file if costs array is for Lp mode */ if(params->p >= 0){ if(params->costmode==TOPO){ costtypesize=sizeof(costT); CalcCost=CalcCostTopo; EvalCost=EvalCostTopo; }else if(params->costmode==DEFO){ costtypesize=sizeof(costT); CalcCost=CalcCostDefo; EvalCost=EvalCostDefo; }else if(params->costmode==SMOOTH){ costtypesize=sizeof(smoothcostT); CalcCost=CalcCostSmooth; EvalCost=EvalCostSmooth; }else{ fflush(NULL); fprintf(sp0,"Illegal cost mode in GrowRegions(). This is a bug.\n"); exit(ABNORMAL_EXIT); } temptileparams->firstrow=0; temptileparams->firstcol=0; temptileparams->nrow=nrow; temptileparams->ncol=ncol; growregionscosts=NULL; Read2DRowColFile((void ***)&growregionscosts,outfiles->costoutfile, ncol,nrow,temptileparams,costtypesize); }else{ growregionscosts=costs; } /* loop over all arcs */ for(arcrow=0;arcrow<2*nrow-1;arcrow++){ if(arcrowsize=maxcost+2; bkts->minind=0; bkts->maxind=bkts->size-1; bkts->curr=0; bkts->wrapped=FALSE; bkts->bucketbase=(nodeT **)MAlloc(bkts->size*sizeof(nodeT *)); bkts->bucket=bkts->bucketbase; for(i=0;isize;i++){ bkts->bucket[i]=NULL; } /* initialize region variables */ regioncounter=-1; regionsizeslen=INITARRSIZE; regionsizes=(long *)MAlloc(regionsizeslen*sizeof(long)); for(row=0;rownext=NULL; source->prev=NULL; source->group=INBUCKET; source->outcost=0; bkts->bucket[0]=source; bkts->curr=0; lastfromdist=0; /* increment the region counter */ if(++regioncounter>=regionsizeslen){ regionsizeslen+=INITARRSIZE; regionsizes=(long *)ReAlloc(regionsizes, regionsizeslen*sizeof(long)); } thisregionsize=®ionsizes[regioncounter]; /* set up */ (*thisregionsize)=0; closestregiondist=VERYFAR; /* loop to grow region */ while(TRUE){ /* set from node to closest node in circular bucket structure */ from=ClosestNode(bkts); /* break if we can't grow any more and the region is big enough */ if(from==NULL){ if(*thisregionsize>=minsize){ /* no more nonregion nodes, and current region is big enough */ break; }else{ /* no more nonregion nodes, but current region still too small */ /* merge with another region */ MergeRegions(nodes,source,regionsizes,closestregion,nrow,ncol); regioncounter--; break; } }else{ fromdist=from->outcost; if(fromdist>lastfromdist){ if(regionsizes[regioncounter]>=minsize){ /* region grown to all nodes within mincost, is big enough */ break; } if(fromdist>closestregiondist){ /* another region closer than new node, so merge regions */ MergeRegions(nodes,source,regionsizes,closestregion,nrow,ncol); regioncounter--; break; } } } /* make from node a part of the current region */ from->incost=regioncounter; (*thisregionsize)++; lastfromdist=fromdist; /* scan from's neighbors */ arcnum=0; while((to=RegionsNeighborNode(from,&arcnum,nodes, &arcrow,&arccol,nrow,ncol))!=NULL){ /* get cost of arc to the to node */ arcdist=incrcosts[arcrow][arccol].negcost; /* see if to node is already in another region */ if(to->incost>=0){ /* keep track of which neighboring region is closest */ if(to->incost!=regioncounter && arcdistincost; } }else{ /* to node is not in another region */ /* compare distance of new nodes to temp labels */ if(arcdist<(to->outcost)){ /* if to node is already in a (circular) bucket, remove it */ if(to->group==INBUCKET){ BucketRemove(to,to->outcost,bkts); } /* update to node */ to->outcost=arcdist; to->pred=from; /* insert to node into appropriate (circular) bucket */ BucketInsert(to,arcdist,bkts); if(arcdistcurr){ bkts->curr=arcdist; } } } } } } } } fprintf(sp2,"Tile partitioned into %ld regions\n",regioncounter+1); /* write regions array */ /* write as shorts if multiple tiles */ if(params->ntilerow > 1 || params->ntilecol>1){ regions=(short **)Get2DMem(nrow,ncol,sizeof(short *),sizeof(short)); for(row=0;rowLARGESHORT){ fflush(NULL); fprintf(sp0, "Number of regions in tile exceeds max allowed\nAbort\n"); exit(ABNORMAL_EXIT); } regions[row][col]=nodes[row][col].incost; } } sprintf(regionfile,"%s%s",outfiles->outfile,REGIONSUFFIX); fprintf(sp2,"Writing region data to file %s\n",regionfile); Write2DArray((void **)regions,regionfile,nrow,ncol,sizeof(short)); }else{ regions=NULL; } /* return CalcCost and EvalCost function pointers to initial values */ CalcCost=tempcalccostfnptr; EvalCost=tempevalcostfnptr; /* free memory */ if(params->p >= 0){ Free2DArray((void **)growregionscosts,2*nrow-1); } Free2DArray((void **)nodes,nrow); if(regions!=NULL){ Free2DArray((void **)regions,nrow); } free(bkts->bucketbase); /* done */ return(0); } /* function: GrowConnCompsMask() * ----------------------------- * Grows contiguous regions demarcated by arcs whose residual costs are * less than some threshold. Numbers the regions sequentially from 1. * Writes out byte file of connected component mask, with 0 for any pixels * not assigned to a component. */ int GrowConnCompsMask(void **costs, short **flows, long nrow, long ncol, incrcostT **incrcosts, outfileT *outfiles, paramT *params){ long i, row, col, maxcol; long arcrow, arccol, arcnum; long regioncounter, *regionsizes, regionsizeslen, *thisregionsize; long *sortedregionsizes; long costthresh, minsize, maxncomps, ntied, newnum; unsigned long outtypemax, outtypesize; nodeT **nodes; nodeT *source, *from, *to, *ground; unsigned char *ucharbuf; unsigned int *uintbuf; void *outbufptr; bucketT bkts[1]; char realoutfile[MAXSTRLEN]; FILE *conncompfp; /* initialize stack structures to zero for good measure */ memset(bkts,0,sizeof(bucketT)); /* error checking */ fprintf(sp1,"Growing connected component mask\n"); minsize=params->minconncompfrac*nrow*ncol; maxncomps=params->maxncomps; costthresh=params->conncompthresh; if(minsize>nrow*ncol){ fflush(NULL); fprintf(sp0,"Minimum region size cannot exceed tile size\nAbort\n"); exit(ABNORMAL_EXIT); } /* loop over all arcs */ for(arcrow=0;arcrow<2*nrow-1;arcrow++){ if(arcrowsize=1; bkts->minind=0; bkts->maxind=0; bkts->wrapped=FALSE; bkts->bucketbase=(nodeT **)MAlloc(sizeof(nodeT *)); bkts->bucket=bkts->bucketbase; bkts->bucket[0]=NULL; /* initialize region variables */ regioncounter=0; regionsizeslen=INITARRSIZE; regionsizes=(long *)MAlloc(regionsizeslen*sizeof(long)); for(row=0;rownext=NULL; source->prev=NULL; source->group=INBUCKET; source->outcost=0; bkts->bucket[0]=source; bkts->curr=0; /* increment the region counter */ if(++regioncounter>=regionsizeslen){ regionsizeslen+=INITARRSIZE; regionsizes=(long *)ReAlloc(regionsizes, regionsizeslen*sizeof(long)); } thisregionsize=®ionsizes[regioncounter]; /* set up */ (*thisregionsize)=0; /* loop to grow region */ while(TRUE){ /* set from node to closest node in circular bucket structure */ from=ClosestNode(bkts); /* break if we can't grow any more and the region is big enough */ if(from==NULL){ if(regionsizes[regioncounter]>=minsize){ /* no more nonregion nodes, and current region is big enough */ break; }else{ /* no more nonregion nodes, but current region still too small */ /* zero out the region */ RenumberRegion(nodes,source,0,nrow,ncol); regioncounter--; break; } } /* make from node a part of the current region */ from->incost=regioncounter; (*thisregionsize)++; /* scan from's neighbors */ arcnum=0; while((to=RegionsNeighborNode(from,&arcnum,nodes, &arcrow,&arccol,nrow,ncol))!=NULL){ /* see if to can be reached */ if(to->incost<0 && incrcosts[arcrow][arccol].negcost==0 && to->group!=INBUCKET){ /* update to node */ to->pred=from; BucketInsert(to,0,bkts); } } } } } } fprintf(sp2,"%ld connected components formed\n",regioncounter); /* make sure we don't have too many components */ if(regioncounter>maxncomps){ /* copy regionsizes array and sort to find new minimum region size */ fprintf(sp2,"Keeping only %ld connected components\n",maxncomps); sortedregionsizes=(long *)MAlloc(regioncounter*sizeof(long)); for(i=0;i=0 && sortedregionsizes[i]==minsize){ ntied++; i--; } /* zero out regions that are too small */ newnum=-1; for(row=0;row0){ if(regionsizes[i]0)){ /* region too small, so zero it out */ RenumberRegion(nodes,&(nodes[row][col]),0,nrow,ncol); }else{ /* keep region, assign it new region number */ /* temporarily assign negative of new number to avoid collisions */ RenumberRegion(nodes,&(nodes[row][col]),newnum--,nrow,ncol); } } } } /* flip temporary negative region numbers so they are positive */ for(row=0;rowconncompouttype==CONNCOMPOUTTYPEUCHAR){ outtypemax=UCHAR_MAX; outtypesize=(int )sizeof(unsigned char); outbufptr=(void *)ucharbuf; }else if(params->conncompouttype==CONNCOMPOUTTYPEUINT){ outtypemax=UINT_MAX; outtypesize=(int )sizeof(unsigned int); outbufptr=(void *)uintbuf; }else{ fflush(NULL); fprintf(sp0,"Bad conncompouttype in GrowConnCompMask()\n"); exit(ABNORMAL_EXIT); } fprintf(sp1,"Writing connected components to file %s" " as %d-byte unsigned ints\n", outfiles->conncompfile,((int )outtypesize)); conncompfp=OpenOutputFile(outfiles->conncompfile,realoutfile); for(row=0;rowouttypemax){ fflush(NULL); fprintf(sp0,"Number of connected components too large for output type\n" "Abort\n"); exit(ABNORMAL_EXIT); } uintbuf[col]=(unsigned int)(nodes[row][col].incost); } if(params->conncompouttype==CONNCOMPOUTTYPEUCHAR){ for(col=0;colconncompfile); } /* free memory */ Free2DArray((void **)nodes,nrow); free(bkts->bucketbase); free(uintbuf); free(ucharbuf); return(0); } /* function: ThickenCosts() * ------------------------ */ static long ThickenCosts(incrcostT **incrcosts, long nrow, long ncol){ long row, col, templong, maxcost; double n; /* initialize variable storing maximum cost */ maxcost=-LARGEINT; /* loop over row arcs and convolve */ for(row=0;rowLARGESHORT){ fflush(NULL); fprintf(sp0,"WARNING: COSTS CLIPPED IN ThickenCosts()\n"); incrcosts[row][col].negcost=LARGESHORT; }else{ incrcosts[row][col].negcost=templong; } if(incrcosts[row][col].negcost>maxcost){ maxcost=incrcosts[row][col].negcost; } } } /* loop over column arcs and convolve */ for(row=nrow-1;row<2*nrow-1;row++){ for(col=0;colLARGESHORT){ fflush(NULL); fprintf(sp0,"WARNING: COSTS CLIPPED IN ThickenCosts()\n"); incrcosts[row][col].negcost=LARGESHORT; }else{ incrcosts[row][col].negcost=templong; } if(incrcosts[row][col].negcost>maxcost){ maxcost=incrcosts[row][col].negcost; } } } /* return maximum cost */ return(maxcost); } /* function: RegionsNeighborNode() * ------------------------------- * Return the neighboring node of the given node corresponding to the * given arc number. */ static nodeT *RegionsNeighborNode(nodeT *node1, long *arcnumptr, nodeT **nodes, long *arcrowptr, long *arccolptr, long nrow, long ncol){ long row, col; row=node1->row; col=node1->col; while(TRUE){ switch((*arcnumptr)++){ case 0: if(col!=ncol-1){ *arcrowptr=nrow-1+row; *arccolptr=col; return(&nodes[row][col+1]); } break; case 1: if(row!=nrow-1){ *arcrowptr=row; *arccolptr=col; return(&nodes[row+1][col]); } break; case 2: if(col!=0){ *arcrowptr=nrow-1+row; *arccolptr=col-1; return(&nodes[row][col-1]); } break; case 3: if(row!=0){ *arcrowptr=row-1; *arccolptr=col; return(&nodes[row-1][col]); } break; default: return(NULL); } } } /* function: ClearBuckets() * ------------------------ * Removes any nodes in the bucket data structure passed, and resets * their distances to VERYFAR. Assumes bukets indexed from 0. */ static int ClearBuckets(bucketT *bkts){ nodeT *currentnode, *nextnode; long i; /* loop over all buckets */ for(i=0;isize;i++){ /* clear the bucket */ nextnode=bkts->bucketbase[i]; while(nextnode!=NULL){ currentnode=nextnode; nextnode=currentnode->next; currentnode->group=NOTINBUCKET; currentnode->outcost=VERYFAR; currentnode->pred=NULL; } bkts->bucketbase[i]=NULL; } /* reset bucket parameters */ bkts->minind=0; bkts->maxind=bkts->size-1; bkts->wrapped=FALSE; /* done */ return(0); } /* function: MergeRegions() * ------------------------ * */ static int MergeRegions(nodeT **nodes, nodeT *source, long *regionsizes, long closestregion, long nrow, long ncol){ long nextnodelistlen, nextnodelistnext, arcnum, arcrow, arccol, regionnum; nodeT *from, *to, **nextnodelist; /* initialize */ nextnodelistlen=INITARRSIZE; nextnodelist=(nodeT **)MAlloc(nextnodelistlen*sizeof(nodeT **)); nextnodelist[0]=source; nextnodelistnext=1; regionnum=source->incost; /* find all nodes in current region and switch their regions */ while(nextnodelistnext){ from=nextnodelist[--nextnodelistnext]; from->incost=closestregion; arcnum=0; while((to=RegionsNeighborNode(from,&arcnum,nodes, &arcrow,&arccol,nrow,ncol))!=NULL){ if(to->incost==regionnum){ if(nextnodelistnext>=nextnodelistlen){ nextnodelistlen+=INITARRSIZE; nextnodelist=(nodeT **)ReAlloc(nextnodelist, nextnodelistlen*sizeof(nodeT *)); } nextnodelist[nextnodelistnext++]=to; } } } /* update size of region to which we are merging */ regionsizes[closestregion]+=regionsizes[regionnum]; /* free memory */ free(nextnodelist); return(0); } /* function: RenumberRegion() * -------------------------- * */ static int RenumberRegion(nodeT **nodes, nodeT *source, long newnum, long nrow, long ncol){ long nextnodelistlen, nextnodelistnext, arcnum, arcrow, arccol, regionnum; nodeT *from, *to, **nextnodelist; /* initialize */ nextnodelistlen=INITARRSIZE; nextnodelist=(nodeT **)MAlloc(nextnodelistlen*sizeof(nodeT **)); nextnodelist[0]=source; nextnodelistnext=1; regionnum=source->incost; /* find all nodes in current region and switch their regions */ while(nextnodelistnext){ from=nextnodelist[--nextnodelistnext]; from->incost=newnum; arcnum=0; while((to=RegionsNeighborNode(from,&arcnum,nodes, &arcrow,&arccol,nrow,ncol))!=NULL){ if(to->incost==regionnum){ if(nextnodelistnext>=nextnodelistlen){ nextnodelistlen+=INITARRSIZE; nextnodelist=(nodeT **)ReAlloc(nextnodelist, nextnodelistlen*sizeof(nodeT *)); } nextnodelist[nextnodelistnext++]=to; } } } /* free memory */ free(nextnodelist); return(0); } /* function: AssembleTiles() * ------------------------- */ int AssembleTiles(outfileT *outfiles, paramT *params, long nlines, long linelen){ long tilerow, tilecol, ntilerow, ntilecol, ntiles, rowovrlp, colovrlp; long i, j, k, ni, nj, dummylong, costtypesize; long nrow, ncol, prevnrow, prevncol, nextnrow, nextncol; long n, ncycle, nflowdone, nflow, candidatelistsize, candidatebagsize; long nnodes, maxnflowcycles, arclen, narcs, sourcetilenum, flowmax; long nnondecreasedcostiter; long *totarclens; long ***scndrycosts; double avgarclen; float **unwphase, **nextunwphase, **lastunwphase, **tempunwphase; float *unwphaseabove, *unwphasebelow; void **costs, **nextcosts, **lastcosts, **tempcosts; void *costsabove, *costsbelow; short **scndryflows, **bulkoffsets, **regions, **nextregions, **lastregions; short **tempregions, *regionsbelow, *regionsabove; int *nscndrynodes, *nscndryarcs; incrcostT **incrcosts; totalcostT totalcost, oldtotalcost, mintotalcost; nodeT *source; nodeT **scndrynodes, ***scndryapexes; signed char **iscandidate; signed char notfirstloop; candidateT *candidatebag, *candidatelist; nodesuppT **nodesupp; scndryarcT **scndryarcs; bucketT *bkts; char filename[MAXSTRLEN]; /* set up */ fprintf(sp1,"Assembling tiles\n"); ntilerow=params->ntilerow; ntilecol=params->ntilecol; ntiles=ntilerow*ntilecol; rowovrlp=params->rowovrlp; colovrlp=params->colovrlp; ni=ceil((nlines+(ntilerow-1)*rowovrlp)/(double )ntilerow); nj=ceil((linelen+(ntilecol-1)*colovrlp)/(double )ntilecol); nrow=0; ncol=0; flowmax=params->scndryarcflowmax; prevnrow=0; /* we are reading statistical costs from file even if (params->p >= 0) */ /* need to set size of cost type and CalcCost function pointer to */ /* be consistent with data stored in file written by BuildCostArrays() */ if(params->costmode==TOPO){ costtypesize=sizeof(costT); CalcCost=CalcCostTopo; EvalCost=EvalCostTopo; }else if(params->costmode==DEFO){ costtypesize=sizeof(costT); CalcCost=CalcCostDefo; EvalCost=EvalCostDefo; }else if(params->costmode==SMOOTH){ costtypesize=sizeof(smoothcostT); CalcCost=CalcCostSmooth; EvalCost=EvalCostSmooth; }else{ fflush(NULL); fprintf(sp0,"Illegal cost mode in AssembleTiles(). Abort\n"); exit(ABNORMAL_EXIT); } /* if(CalcCost==CalcCostTopo || CalcCost==CalcCostDefo){ costtypesize=sizeof(costT); }else if(CalcCost==CalcCostSmooth){ costtypesize=sizeof(smoothcostT); }else if(CalcCost==CalcCostL0 || CalcCost==CalcCostL1 || CalcCost==CalcCostL2 || CalcCost==CalcCostLP){ costtypesize=sizeof(short); }else if(CalcCost==CalcCostL0BiDir || CalcCost==CalcCostL1BiDir || CalcCost==CalcCostL2BiDir || CalcCost==CalcCostLPBiDir){ costtypesize=sizeof(bidircostT); } */ /* get memory */ regions=(short **)Get2DMem(ni,nj,sizeof(short *),sizeof(short)); nextregions=(short **)Get2DMem(ni,nj,sizeof(short *),sizeof(short)); lastregions=(short **)Get2DMem(ni,nj,sizeof(short *),sizeof(short)); regionsbelow=(short *)MAlloc(nj*sizeof(short)); regionsabove=(short *)MAlloc(nj*sizeof(short)); unwphase=(float **)Get2DMem(ni,nj,sizeof(float *),sizeof(float)); nextunwphase=(float **)Get2DMem(ni,nj,sizeof(float *),sizeof(float)); lastunwphase=(float **)Get2DMem(ni,nj,sizeof(float *),sizeof(float)); unwphaseabove=(float *)MAlloc(nj*sizeof(float)); unwphasebelow=(float *)MAlloc(nj*sizeof(float)); scndrynodes=(nodeT **)MAlloc(ntiles*sizeof(nodeT *)); nodesupp=(nodesuppT **)MAlloc(ntiles*sizeof(nodesuppT *)); scndryarcs=(scndryarcT **)MAlloc(ntiles*sizeof(scndryarcT *)); scndrycosts=(long ***)MAlloc(ntiles*sizeof(long **)); nscndrynodes=(int *)MAlloc(ntiles*sizeof(int)); nscndryarcs=(int *)MAlloc(ntiles*sizeof(int)); totarclens=(long *)MAlloc(ntiles*sizeof(long)); bulkoffsets=(short **)Get2DMem(ntilerow,ntilecol,sizeof(short *), sizeof(short)); costs=(void **)Get2DRowColMem(ni+2,nj+2,sizeof(void *),costtypesize); nextcosts=(void **)Get2DRowColMem(ni+2,nj+2,sizeof(void *),costtypesize); lastcosts=(void **)Get2DRowColMem(ni+2,nj+2,sizeof(void *),costtypesize); costsabove=(void *)MAlloc(nj*costtypesize); costsbelow=(void *)MAlloc(nj*costtypesize); /* trace regions and parse secondary nodes and arcs for each tile */ bulkoffsets[0][0]=0; for(tilerow=0;tilerowmaxcyclefraction); while(TRUE){ fprintf(sp1,"Flow increment: %ld (Total improvements: %ld)\n", nflow,ncycle); /* set up the incremental (residual) cost arrays */ SetupIncrFlowCosts((void **)scndrycosts,incrcosts,scndryflows,nflow,ntiles, ntiles,nscndryarcs,params); /* set the tree root (equivalent to source of shortest path problem) */ sourcetilenum=(long )ntilecol*floor(ntilerow/2.0)+floor(ntilecol/2.0); source=&scndrynodes[sourcetilenum][0]; /* set up network variables for tree solver */ SetupTreeSolveNetwork(scndrynodes,NULL,scndryapexes,iscandidate, ntiles,nscndrynodes,ntiles,nscndryarcs, ntiles,0); /* run the solver, and increment nflowdone if no cycles are found */ n=TreeSolve(scndrynodes,nodesupp,NULL,source,&candidatelist,&candidatebag, &candidatelistsize,&candidatebagsize,bkts,scndryflows, (void **)scndrycosts,incrcosts,scndryapexes,iscandidate,0, nflow,NULL,NULL,NULL,ntiles,nscndrynodes,ntiles,nscndryarcs, ntiles,0,NULL,nnodes,params); /* evaluate and save the total cost (skip if first loop through nflow) */ if(notfirstloop){ oldtotalcost=totalcost; totalcost=EvaluateTotalCost((void **)scndrycosts,scndryflows,ntiles,0, nscndryarcs,params); if(totalcostoldtotalcost || (n>0 && totalcost==oldtotalcost)){ fflush(NULL); fprintf(sp1,"Caution: Unexpected increase in total cost\n"); } if(totalcost>=mintotalcost){ nnondecreasedcostiter++; }else{ nnondecreasedcostiter=0; } } /* consider this flow increment done if not too many neg cycles found */ ncycle+=n; if(n<=maxnflowcycles){ nflowdone++; }else{ nflowdone=1; } /* break if lack of total cost reduction is sustained */ if(nnondecreasedcostiter>=2*params->maxflow){ fflush(NULL); fprintf(sp0,"WARNING: No overall cost reduction for too many iterations." " Breaking loop\n"); break; } /* break if we're done with all flow increments or problem is convex */ if(nflowdone>=params->maxflow){ break; } /* update flow increment */ nflow++; if(nflow>params->maxflow){ nflow=1; notfirstloop=TRUE; } } /* end loop until no more neg cycles */ /* free some memory */ for(i=0;ibucketbase); /* assemble connected component files if needed */ if(strlen(outfiles->conncompfile)){ AssembleTileConnComps(linelen,nlines,outfiles,params); } /* integrate phase from secondary network problem */ IntegrateSecondaryFlows(linelen,nlines,scndrynodes,nodesupp,scndryarcs, nscndryarcs,scndryflows,bulkoffsets,outfiles,params); /* free remaining memory */ for(i=0;irmtmptile){ fflush(NULL); fprintf(sp1,"Removing temporary directory %s\n",params->tiledir); for(tilerow=0;tilerowtiledir,LOGFILEROOT,tilerow,tilecol); unlink(filename); } } rmdir(params->tiledir); } /* Give notice about increasing overlap if there are edge artifacts */ if(params->rowovrlpcolovrlpnrow; nexttilelinelen=nexttileparams->ncol; /* set tile parameters, overwriting values set by SetupTile() above */ SetTileReadParams(nexttileparams,nexttilenlines,nexttilelinelen, tilerow,tilecol,nlines,linelen,params); /* read region data */ ParseFilename(outfiles->outfile,path,basename); sprintf(tempstring,"%s/%s%s_%ld_%ld.%ld%s", params->tiledir,TMPTILEROOT,basename,tilerow,tilecol, nexttilelinelen,REGIONSUFFIX); StrNCopy(nextfile,tempstring,MAXSTRLEN); Read2DArray((void ***)nextregionsptr,nextfile, nexttilelinelen,nexttilenlines, nexttileparams,sizeof(short *),sizeof(short)); /* read unwrapped phase data */ if(TMPTILEOUTFORMAT==ALT_LINE_DATA){ ReadAltLineFilePhase(nextunwphaseptr,nexttileoutfiles->outfile, nexttilelinelen,nexttilenlines,nexttileparams); }else if(TMPTILEOUTFORMAT==FLOAT_DATA){ Read2DArray((void ***)nextunwphaseptr,nexttileoutfiles->outfile, nexttilelinelen,nexttilenlines,nexttileparams, sizeof(float *),sizeof(float)); }else{ fflush(NULL); fprintf(sp0,"Cannot read format of unwrapped phase tile data\nAbort\n"); exit(ABNORMAL_EXIT); } /* read cost data */ Read2DRowColFile((void ***)nextcostsptr,nexttileoutfiles->costoutfile, nexttilelinelen,nexttilenlines,nexttileparams, costtypesize); /* flip sign of wrapped phase if flip flag is set */ FlipPhaseArraySign(*nextunwphaseptr,params, nexttileparams->nrow,nexttileparams->ncol); /* set outputs */ (*nextnrowptr)=nexttileparams->nrow; (*nextncolptr)=nexttileparams->ncol; return(0); } /* function: SetTileReadParams() * ----------------------------- * Set parameters for reading the nonoverlapping piece of each tile. * ni and nj are the numbers of rows and columns in this particular tile. * The meanings of these variables are different for the last row * and column. */ static int SetTileReadParams(tileparamT *tileparams, long nexttilenlines, long nexttilelinelen, long tilerow, long tilecol, long nlines, long linelen, paramT *params){ long rowovrlp, colovrlp; /* set temporary variables */ rowovrlp=params->rowovrlp; colovrlp=params->colovrlp; /* row parameters */ if(tilerow==0){ tileparams->firstrow=0; }else{ tileparams->firstrow=ceil(rowovrlp/2.0); } if(tilerow!=params->ntilerow-1){ tileparams->nrow=nexttilenlines-floor(rowovrlp/2.0)-tileparams->firstrow; }else{ tileparams->nrow=nexttilenlines-tileparams->firstrow; } /* column parameters */ if(tilecol==0){ tileparams->firstcol=0; }else{ tileparams->firstcol=ceil(colovrlp/2.0); } if(tilecol!=params->ntilecol-1){ tileparams->ncol=nexttilelinelen-floor(colovrlp/2.0)-tileparams->firstcol; }else{ tileparams->ncol=nexttilelinelen-tileparams->firstcol; } return(0); } /* function: ReadEdgesAboveAndBelow() * ---------------------------------- */ static int ReadEdgesAboveAndBelow(long tilerow, long tilecol, long nlines, long linelen, paramT *params, outfileT *outfiles, short *regionsabove, short *regionsbelow, float *unwphaseabove, float *unwphasebelow, void *costsabove, void *costsbelow){ long ni, nj, readtilelinelen, readtilenlines, costtypesize; long ntilerow, ntilecol, rowovrlp, colovrlp; tileparamT tileparams[1]; outfileT outfilesabove[1], outfilesbelow[1]; float **unwphaseaboveptr, **unwphasebelowptr; void **costsaboveptr, **costsbelowptr; short **regionsaboveptr, **regionsbelowptr; char tempstring[MAXTMPSTRLEN], readregionfile[MAXSTRLEN]; char path[MAXSTRLEN], basename[MAXSTRLEN]; /* initialize stack structures to zero for good measure */ memset(tileparams,0,sizeof(tileparamT)); memset(outfilesabove,0,sizeof(outfileT)); memset(outfilesbelow,0,sizeof(outfileT)); memset(tempstring,0,MAXSTRLEN); memset(readregionfile,0,MAXSTRLEN); memset(path,0,MAXSTRLEN); memset(basename,0,MAXSTRLEN); /* set temporary variables */ ntilerow=params->ntilerow; ntilecol=params->ntilecol; rowovrlp=params->rowovrlp; colovrlp=params->colovrlp; ni=ceil((nlines+(ntilerow-1)*rowovrlp)/(double )ntilerow); nj=ceil((linelen+(ntilecol-1)*colovrlp)/(double )ntilecol); /* size of the data type for holding cost data depends on cost mode */ if(CalcCost==CalcCostTopo || CalcCost==CalcCostDefo){ costtypesize=sizeof(costT); }else if(CalcCost==CalcCostSmooth){ costtypesize=sizeof(smoothcostT); }else if(CalcCost==CalcCostL0 || CalcCost==CalcCostL1 || CalcCost==CalcCostL2 || CalcCost==CalcCostLP){ costtypesize=sizeof(short); }else if(CalcCost==CalcCostL0BiDir || CalcCost==CalcCostL1BiDir || CalcCost==CalcCostL2BiDir || CalcCost==CalcCostLPBiDir){ costtypesize=sizeof(bidircostT); }else{ fflush(NULL); fprintf(sp0,"ERROR: Bad CalcCost func ptr in ReadEdgesAboveAndBelow()\n"); exit(ABNORMAL_EXIT); } /* set names of files with SetupTile() */ /* tile parameters set by SetupTile() will be overwritten below */ if(tilerow!=0){ SetupTile(nlines,linelen,params,tileparams,outfiles,outfilesabove, tilerow-1,tilecol); } if(tilerow!=ntilerow-1){ SetupTile(nlines,linelen,params,tileparams,outfiles,outfilesbelow, tilerow+1,tilecol); } /* temporary pointers, so we can use Read2DArray() with 1D output array */ unwphaseaboveptr=&unwphaseabove; unwphasebelowptr=&unwphasebelow; costsaboveptr=&costsabove; costsbelowptr=&costsbelow; regionsaboveptr=®ionsabove; regionsbelowptr=®ionsbelow; /* set some reading parameters */ if(tilecol==0){ tileparams->firstcol=0; }else{ tileparams->firstcol=ceil(colovrlp/2.0); } if(tilecol!=params->ntilecol-1){ readtilelinelen=nj; tileparams->ncol=readtilelinelen-floor(colovrlp/2.0)-tileparams->firstcol; }else{ readtilelinelen=linelen-(ntilecol-1)*(nj-colovrlp); tileparams->ncol=readtilelinelen-tileparams->firstcol; } tileparams->nrow=1; /* read last line of tile above */ readtilenlines=ni; if(tilerow!=0){ tileparams->firstrow=readtilenlines-floor(rowovrlp/2.0)-1; /* read region data */ ParseFilename(outfiles->outfile,path,basename); sprintf(tempstring,"%s/%s%s_%ld_%ld.%ld%s", params->tiledir,TMPTILEROOT,basename,tilerow-1,tilecol, readtilelinelen,REGIONSUFFIX); StrNCopy(readregionfile,tempstring,MAXSTRLEN); Read2DArray((void ***)®ionsaboveptr,readregionfile, readtilelinelen,readtilenlines, tileparams,sizeof(short *),sizeof(short)); /* read unwrapped phase data */ if(TMPTILEOUTFORMAT==ALT_LINE_DATA){ ReadAltLineFilePhase(&unwphaseaboveptr,outfilesabove->outfile, readtilelinelen,readtilenlines,tileparams); }else if(TMPTILEOUTFORMAT==FLOAT_DATA){ Read2DArray((void ***)&unwphaseaboveptr,outfilesabove->outfile, readtilelinelen,readtilenlines,tileparams, sizeof(float *),sizeof(float)); } /* flip sign of wrapped phase if flip flag is set */ FlipPhaseArraySign(unwphaseaboveptr,params, tileparams->nrow,tileparams->ncol); /* read costs data */ tileparams->firstrow--; Read2DRowColFileRows((void ***)&costsaboveptr,outfilesabove->costoutfile, readtilelinelen,readtilenlines,tileparams, costtypesize); /* remove temporary tile cost file unless told to save it */ if(params->rmtmptile && !strlen(outfiles->costoutfile)){ unlink(outfilesabove->costoutfile); } } /* read first line of tile below */ if(tilerow!=ntilerow-1){ if(tilerow==params->ntilerow-2){ readtilenlines=nlines-(ntilerow-1)*(ni-rowovrlp); } tileparams->firstrow=ceil(rowovrlp/2.0); /* read region data */ ParseFilename(outfiles->outfile,path,basename); sprintf(tempstring,"%s/%s%s_%ld_%ld.%ld%s", params->tiledir,TMPTILEROOT,basename,tilerow+1,tilecol, readtilelinelen,REGIONSUFFIX); StrNCopy(readregionfile,tempstring,MAXSTRLEN); Read2DArray((void ***)®ionsbelowptr,readregionfile, readtilelinelen,readtilenlines, tileparams,sizeof(short *),sizeof(short)); /* read unwrapped phase data */ if(TMPTILEOUTFORMAT==ALT_LINE_DATA){ ReadAltLineFilePhase(&unwphasebelowptr,outfilesbelow->outfile, readtilelinelen,readtilenlines,tileparams); }else if(TMPTILEOUTFORMAT==FLOAT_DATA){ Read2DArray((void ***)&unwphasebelowptr,outfilesbelow->outfile, readtilelinelen,readtilenlines,tileparams, sizeof(float *),sizeof(float)); } /* flip the sign of the wrapped phase if flip flag is set */ FlipPhaseArraySign(unwphasebelowptr,params, tileparams->nrow,tileparams->ncol); /* read costs data */ Read2DRowColFileRows((void ***)&costsbelowptr,outfilesbelow->costoutfile, readtilelinelen,readtilenlines,tileparams, costtypesize); }else{ /* remove temporoary tile cost file for last row unless told to save it */ if(params->rmtmptile && !strlen(outfiles->costoutfile)){ SetupTile(nlines,linelen,params,tileparams,outfiles,outfilesbelow, tilerow,tilecol); unlink(outfilesbelow->costoutfile); } } /* done */ return(0); } /* function: TraceRegions() * ------------------------ * Trace edges of region data to form nodes and arcs of secondary * (ie, region-level) network problem. Primary nodes and arcs are * those of the original, pixel-level network problem. Flows along * edges are computed knowing the unwrapped phase values of edges * of adjacent tiles. Costs along edges are approximated in that they * are calculated from combining adjacent cost parameters, not from * using the exact method in BuildCostArrays(). */ static int TraceRegions(short **regions, short **nextregions, short **lastregions, short *regionsabove, short *regionsbelow, float **unwphase, float **nextunwphase, float **lastunwphase, float *unwphaseabove, float *unwphasebelow, void **costs, void **nextcosts, void **lastcosts, void *costsabove, void *costsbelow, long prevnrow, long prevncol, long tilerow, long tilecol, long nrow, long ncol, nodeT **scndrynodes, nodesuppT **nodesupp, scndryarcT **scndryarcs, long ***scndrycosts, int *nscndrynodes, int *nscndryarcs, long *totarclens, short **bulkoffsets, paramT *params){ long i, j, row, col, nnrow, nncol, tilenum, costtypesize; long nnewnodes, nnewarcs, npathsout, flowmax, totarclen; long nupdatednontilenodes, updatednontilenodesize, ntilecol; short **flows; short **rightedgeflows, **loweredgeflows, **leftedgeflows, **upperedgeflows; short *inontilenodeoutarc; void **rightedgecosts, **loweredgecosts, **leftedgecosts, **upperedgecosts; nodeT **primarynodes, **updatednontilenodes; nodeT *from, *to, *nextnode, *tempnode; nodesuppT *fromsupp, *tosupp; /* initialize */ ntilecol=params->ntilecol; nnrow=nrow+1; nncol=ncol+1; primarynodes=(nodeT **)Get2DMem(nnrow,nncol,sizeof(nodeT *),sizeof(nodeT)); for(row=0;rowscndryarcflowmax; updatednontilenodesize=INITARRSIZE; nupdatednontilenodes=0; /* size of the data type for holding cost data depends on cost mode */ if(CalcCost==CalcCostTopo || CalcCost==CalcCostDefo){ costtypesize=sizeof(costT); }else if(CalcCost==CalcCostSmooth){ costtypesize=sizeof(smoothcostT); }else if(CalcCost==CalcCostL0 || CalcCost==CalcCostL1 || CalcCost==CalcCostL2 || CalcCost==CalcCostLP){ costtypesize=sizeof(short); }else if(CalcCost==CalcCostL0BiDir || CalcCost==CalcCostL1BiDir || CalcCost==CalcCostL2BiDir || CalcCost==CalcCostLPBiDir){ costtypesize=sizeof(bidircostT); }else{ fflush(NULL); fprintf(sp0,"ERROR: Bad CalcCost func ptr in TraceRegions()\n"); exit(ABNORMAL_EXIT); } /* get memory */ updatednontilenodes=(nodeT **)MAlloc(updatednontilenodesize*sizeof(nodeT *)); inontilenodeoutarc=(short *)MAlloc(updatednontilenodesize*sizeof(short)); flows=(short **)Get2DRowColMem(nrow+1,ncol+1,sizeof(short *),sizeof(short)); rightedgeflows=(short **)Get2DMem(nrow,1,sizeof(short *),sizeof(short)); leftedgeflows=(short **)Get2DMem(nrow,1,sizeof(short *),sizeof(short)); upperedgeflows=(short **)Get2DMem(1,ncol,sizeof(short *),sizeof(short)); loweredgeflows=(short **)Get2DMem(1,ncol,sizeof(short *),sizeof(short)); rightedgecosts=(void **)Get2DMem(nrow,1,sizeof(void *),costtypesize); leftedgecosts=(void **)Get2DMem(nrow,1,sizeof(void *),costtypesize); upperedgecosts=(void **)Get2DMem(1,ncol,sizeof(void *),costtypesize); loweredgecosts=(void **)Get2DMem(1,ncol,sizeof(void *),costtypesize); /* parse flows for this tile */ CalcFlow(unwphase,&flows,nrow,ncol); /* set up cost and flow arrays for boundaries */ SetUpperEdge(ncol,tilerow,tilecol,costs,costsabove,unwphase,unwphaseabove, upperedgecosts,upperedgeflows,params, bulkoffsets); SetLowerEdge(nrow,ncol,tilerow,tilecol,costs,costsbelow,unwphase, unwphasebelow,loweredgecosts,loweredgeflows, params,bulkoffsets); SetLeftEdge(nrow,prevncol,tilerow,tilecol,costs,lastcosts,unwphase, lastunwphase,leftedgecosts,leftedgeflows,params, bulkoffsets); SetRightEdge(nrow,ncol,tilerow,tilecol,costs,nextcosts,unwphase, nextunwphase,rightedgecosts,rightedgeflows, params,bulkoffsets); /* trace edges between regions */ while(nextnode!=NULL){ /* get next primary node from stack */ from=nextnode; nextnode=nextnode->next; from->group=NOTINBUCKET; /* find number of paths out of from node */ npathsout=FindNumPathsOut(from,params,tilerow,tilecol,nnrow,nncol,regions, nextregions,lastregions,regionsabove, regionsbelow,prevncol); /* secondary node exists if region edges fork */ if(npathsout>2){ /* mark primary node to indicate that secondary node exists for it */ from->group=ONTREE; /* create secondary node if not already created in another tile */ if((from->row!=0 || tilerow==0) && (from->col!=0 || tilecol==0)){ /* create the secondary node */ nnewnodes++; if(nnewnodes > SHRT_MAX){ fflush(NULL); fprintf(sp0,"Exceeded maximum number of secondary nodes\n" "Decrease TILECOSTTHRESH and/or increase MINREGIONSIZE\n"); exit(ABNORMAL_EXIT); } scndrynodes[tilenum]=(nodeT *)ReAlloc(scndrynodes[tilenum], nnewnodes*sizeof(nodeT)); nodesupp[tilenum]=(nodesuppT *)ReAlloc(nodesupp[tilenum], nnewnodes*sizeof(nodesuppT)); scndrynodes[tilenum][nnewnodes-1].row=tilenum; scndrynodes[tilenum][nnewnodes-1].col=nnewnodes-1; nodesupp[tilenum][nnewnodes-1].row=from->row; nodesupp[tilenum][nnewnodes-1].col=from->col; nodesupp[tilenum][nnewnodes-1].noutarcs=0; nodesupp[tilenum][nnewnodes-1].neighbornodes=NULL; nodesupp[tilenum][nnewnodes-1].outarcs=NULL; } /* create the secondary arc to this node if it doesn't already exist */ if(from->pred!=NULL && ((from->row==from->pred->row && (from->row!=0 || tilerow==0)) || (from->col==from->pred->col && (from->col!=0 || tilecol==0)))){ TraceSecondaryArc(from,scndrynodes,nodesupp,scndryarcs,scndrycosts, &nnewnodes,&nnewarcs,tilerow,tilecol,flowmax, nrow,ncol,prevnrow,prevncol,params,costs, rightedgecosts,loweredgecosts,leftedgecosts, upperedgecosts,flows,rightedgeflows,loweredgeflows, leftedgeflows,upperedgeflows,&updatednontilenodes, &nupdatednontilenodes,&updatednontilenodesize, &inontilenodeoutarc,&totarclen); } } /* scan neighboring primary nodes and place path candidates into stack */ RegionTraceCheckNeighbors(from,&nextnode,primarynodes,regions, nextregions,lastregions,regionsabove, regionsbelow,tilerow,tilecol,nnrow,nncol, scndrynodes,nodesupp,scndryarcs,&nnewnodes, &nnewarcs,flowmax,nrow,ncol,prevnrow,prevncol, params,costs,rightedgecosts,loweredgecosts, leftedgecosts,upperedgecosts,flows, rightedgeflows,loweredgeflows,leftedgeflows, upperedgeflows,scndrycosts,&updatednontilenodes, &nupdatednontilenodes,&updatednontilenodesize, &inontilenodeoutarc,&totarclen); } /* reset temporary secondary node and arc pointers in data structures */ /* secondary node row, col stored level, incost of primary node pointed to */ /* update nodes in this tile */ for(i=0;ilevel][tempnode->incost]; } } /* update nodes not in this tile that were affected (that have new arcs) */ for(i=0;irow; col=updatednontilenodes[i]->col; j=inontilenodeoutarc[i]; tempnode=nodesupp[row][col].neighbornodes[j]; nodesupp[row][col].neighbornodes[j] =&scndrynodes[tempnode->level][tempnode->incost]; } /* update secondary arcs */ for(i=0;ilevel][tempnode->incost]; from=scndryarcs[tilenum][i].from; tempnode=scndryarcs[tilenum][i].to; scndryarcs[tilenum][i].to =&scndrynodes[tempnode->level][tempnode->incost]; to=scndryarcs[tilenum][i].to; /* update secondary arc pointers in nodesupp strcutres */ fromsupp=&nodesupp[from->row][from->col]; j=0; while(fromsupp->neighbornodes[j]!=to){ j++; } fromsupp->outarcs[j]=&scndryarcs[tilenum][i]; tosupp=&nodesupp[to->row][to->col]; j=0; while(tosupp->neighbornodes[j]!=from){ j++; } tosupp->outarcs[j]=&scndryarcs[tilenum][i]; } /* set outputs */ nscndrynodes[tilenum]=nnewnodes; nscndryarcs[tilenum]=nnewarcs; totarclens[tilenum]=totarclen; /* free memory */ Free2DArray((void **)primarynodes,nnrow); Free2DArray((void **)flows,2*nrow-1); Free2DArray((void **)rightedgeflows,nrow); Free2DArray((void **)leftedgeflows,nrow); Free2DArray((void **)upperedgeflows,1); Free2DArray((void **)loweredgeflows,1); Free2DArray((void **)rightedgecosts,nrow); Free2DArray((void **)leftedgecosts,nrow); Free2DArray((void **)upperedgecosts,1); Free2DArray((void **)loweredgecosts,1); return(0); } /* function: FindNumPathsOut() * --------------------------- * Check all outgoing arcs to see how many paths out there are. */ static long FindNumPathsOut(nodeT *from, paramT *params, long tilerow, long tilecol, long nnrow, long nncol, short **regions, short **nextregions, short **lastregions, short *regionsabove, short *regionsbelow, long prevncol){ long npathsout, ntilerow, ntilecol, fromrow, fromcol; /* initialize */ ntilerow=params->ntilerow; ntilecol=params->ntilecol; fromrow=from->row; fromcol=from->col; npathsout=0; /* rightward arc */ if(fromcol!=nncol-1){ if(fromrow==0 || fromrow==nnrow-1 || regions[fromrow-1][fromcol]!=regions[fromrow][fromcol]){ npathsout++; } }else{ if(fromrow==0 || fromrow==nnrow-1 || (tilecol!=ntilecol-1 && nextregions[fromrow-1][0]!=nextregions[fromrow][0])){ npathsout++; } } /* downward arc */ if(fromrow!=nnrow-1){ if(fromcol==0 || fromcol==nncol-1 || regions[fromrow][fromcol]!=regions[fromrow][fromcol-1]){ npathsout++; } }else{ if(fromcol==0 || fromcol==nncol-1 || (tilerow!=ntilerow-1 && regionsbelow[fromcol]!=regionsbelow[fromcol-1])){ npathsout++; } } /* leftward arc */ if(fromcol!=0){ if(fromrow==0 || fromrow==nnrow-1 || regions[fromrow][fromcol-1]!=regions[fromrow-1][fromcol-1]){ npathsout++; } }else{ if(fromrow==0 || fromrow==nnrow-1 || (tilecol!=0 && (lastregions[fromrow][prevncol-1] !=lastregions[fromrow-1][prevncol-1]))){ npathsout++; } } /* upward arc */ if(fromrow!=0){ if(fromcol==0 || fromcol==nncol-1 || regions[fromrow-1][fromcol-1]!=regions[fromrow-1][fromcol]){ npathsout++; } }else{ if(fromcol==0 || fromcol==nncol-1 || (tilerow!=0 && regionsabove[fromcol-1]!=regionsabove[fromcol])){ npathsout++; } } /* return number of paths out of node */ return(npathsout); } /* function: RegionTraceCheckNeighbors() * ------------------------------------- */ static int RegionTraceCheckNeighbors(nodeT *from, nodeT **nextnodeptr, nodeT **primarynodes, short **regions, short **nextregions, short **lastregions, short *regionsabove, short *regionsbelow, long tilerow, long tilecol, long nnrow, long nncol, nodeT **scndrynodes, nodesuppT **nodesupp, scndryarcT **scndryarcs, long *nnewnodesptr, long *nnewarcsptr, long flowmax, long nrow, long ncol, long prevnrow, long prevncol, paramT *params, void **costs, void **rightedgecosts, void **loweredgecosts, void **leftedgecosts, void **upperedgecosts, short **flows, short **rightedgeflows, short **loweredgeflows, short **leftedgeflows, short **upperedgeflows, long ***scndrycosts, nodeT ***updatednontilenodesptr, long *nupdatednontilenodesptr, long *updatednontilenodesizeptr, short **inontilenodeoutarcptr, long *totarclenptr){ long fromrow, fromcol; nodeT *to, *nextnode; /* initialize */ fromrow=from->row; fromcol=from->col; nextnode=(*nextnodeptr); /* check rightward arc */ if(fromcol!=nncol-1){ to=&primarynodes[fromrow][fromcol+1]; if(fromrow==0 || fromrow==nnrow-1 || regions[fromrow-1][fromcol]!=regions[fromrow][fromcol]){ if(to!=from->pred){ to->pred=from; if(to->group==NOTINBUCKET){ to->group=INBUCKET; to->next=nextnode; nextnode=to; }else if(to->group==ONTREE && (fromrow!=0 || tilerow==0)){ TraceSecondaryArc(to,scndrynodes,nodesupp,scndryarcs,scndrycosts, nnewnodesptr,nnewarcsptr,tilerow,tilecol,flowmax, nrow,ncol,prevnrow,prevncol,params,costs, rightedgecosts,loweredgecosts,leftedgecosts, upperedgecosts,flows,rightedgeflows, loweredgeflows,leftedgeflows,upperedgeflows, updatednontilenodesptr,nupdatednontilenodesptr, updatednontilenodesizeptr,inontilenodeoutarcptr, totarclenptr); } } } } /* check downward arc */ if(fromrow!=nnrow-1){ to=&primarynodes[fromrow+1][fromcol]; if(fromcol==0 || fromcol==nncol-1 || regions[fromrow][fromcol]!=regions[fromrow][fromcol-1]){ if(to!=from->pred){ to->pred=from; if(to->group==NOTINBUCKET){ to->group=INBUCKET; to->next=nextnode; nextnode=to; }else if(to->group==ONTREE && (fromcol!=0 || tilecol==0)){ TraceSecondaryArc(to,scndrynodes,nodesupp,scndryarcs,scndrycosts, nnewnodesptr,nnewarcsptr,tilerow,tilecol,flowmax, nrow,ncol,prevnrow,prevncol,params,costs, rightedgecosts,loweredgecosts,leftedgecosts, upperedgecosts,flows,rightedgeflows, loweredgeflows,leftedgeflows,upperedgeflows, updatednontilenodesptr,nupdatednontilenodesptr, updatednontilenodesizeptr,inontilenodeoutarcptr, totarclenptr); } } } } /* check leftward arc */ if(fromcol!=0){ to=&primarynodes[fromrow][fromcol-1]; if(fromrow==0 || fromrow==nnrow-1 || regions[fromrow][fromcol-1]!=regions[fromrow-1][fromcol-1]){ if(to!=from->pred){ to->pred=from; if(to->group==NOTINBUCKET){ to->group=INBUCKET; to->next=nextnode; nextnode=to; }else if(to->group==ONTREE && (fromrow!=0 || tilerow==0)){ TraceSecondaryArc(to,scndrynodes,nodesupp,scndryarcs,scndrycosts, nnewnodesptr,nnewarcsptr,tilerow,tilecol,flowmax, nrow,ncol,prevnrow,prevncol,params,costs, rightedgecosts,loweredgecosts,leftedgecosts, upperedgecosts,flows,rightedgeflows, loweredgeflows,leftedgeflows,upperedgeflows, updatednontilenodesptr,nupdatednontilenodesptr, updatednontilenodesizeptr,inontilenodeoutarcptr, totarclenptr); } } } } /* check upward arc */ if(fromrow!=0){ to=&primarynodes[fromrow-1][fromcol]; if(fromcol==0 || fromcol==nncol-1 || regions[fromrow-1][fromcol-1]!=regions[fromrow-1][fromcol]){ if(to!=from->pred){ to->pred=from; if(to->group==NOTINBUCKET){ to->group=INBUCKET; to->next=nextnode; nextnode=to; }else if(to->group==ONTREE && (fromcol!=0 || tilecol==0)){ TraceSecondaryArc(to,scndrynodes,nodesupp,scndryarcs,scndrycosts, nnewnodesptr,nnewarcsptr,tilerow,tilecol,flowmax, nrow,ncol,prevnrow,prevncol,params,costs, rightedgecosts,loweredgecosts,leftedgecosts, upperedgecosts,flows,rightedgeflows, loweredgeflows,leftedgeflows,upperedgeflows, updatednontilenodesptr,nupdatednontilenodesptr, updatednontilenodesizeptr,inontilenodeoutarcptr, totarclenptr); } } } } /* set return values */ *nextnodeptr=nextnode; return(0); } /* function: SetUpperEdge() * ------------------------ */ static int SetUpperEdge(long ncol, long tilerow, long tilecol, void **voidcosts, void *voidcostsabove, float **unwphase, float *unwphaseabove, void **voidupperedgecosts, short **upperedgeflows, paramT *params, short **bulkoffsets){ long col, reloffset; double dphi, dpsi; costT **upperedgecosts, **costs, *costsabove; smoothcostT **upperedgesmoothcosts, **smoothcosts, *smoothcostsabove; long nshortcycle; /* typecast generic pointers to costT pointers */ upperedgecosts=(costT **)voidupperedgecosts; costs=(costT **)voidcosts; costsabove=(costT *)voidcostsabove; upperedgesmoothcosts=(smoothcostT **)voidupperedgecosts; smoothcosts=(smoothcostT **)voidcosts; smoothcostsabove=(smoothcostT *)voidcostsabove; /* see if tile is in top row */ if(tilerow!=0){ /* set up */ nshortcycle=params->nshortcycle; reloffset=bulkoffsets[tilerow-1][tilecol]-bulkoffsets[tilerow][tilecol]; /* loop over all arcs on the boundary */ for(col=0;col0.5){ dpsi-=1.0; } if(CalcCost==CalcCostTopo || CalcCost==CalcCostDefo){ upperedgecosts[0][col].offset=(short )LRound(nshortcycle*dpsi); upperedgecosts[0][col].sigsq=AvgSigSq(costs[0][col].sigsq, costsabove[col].sigsq); if(costs[0][col].dzmax>costsabove[col].dzmax){ upperedgecosts[0][col].dzmax=costs[0][col].dzmax; }else{ upperedgecosts[0][col].dzmax=costsabove[col].dzmax; } if(costs[0][col].laycostntilerow-1){ /* set up */ nshortcycle=params->nshortcycle; flowlimhi=LARGESHORT; flowlimlo=-LARGESHORT; flowhistogram=(long *)CAlloc(flowlimhi-flowlimlo+1,sizeof(long)); minflow=flowlimhi; maxflow=flowlimlo; /* loop over all arcs on the boundary */ for(col=0;colmaxflow){ if(tempflow>flowlimhi){ fflush(NULL); fprintf(sp0,"Overflow in tile offset\nAbort\n"); exit(ABNORMAL_EXIT); } maxflow=tempflow; } flowhistogram[tempflow-flowlimlo]++; dpsi=dphi-floor(dphi); if(dpsi>0.5){ dpsi-=1.0; } if(CalcCost==CalcCostTopo || CalcCost==CalcCostDefo){ loweredgecosts[0][col].offset=(short )LRound(nshortcycle*dpsi); loweredgecosts[0][col].sigsq=AvgSigSq(costs[nrow-2][col].sigsq, costsbelow[col].sigsq); if(costs[nrow-2][col].dzmax>costsbelow[col].dzmax){ loweredgecosts[0][col].dzmax=costs[nrow-2][col].dzmax; }else{ loweredgecosts[0][col].dzmax=costsbelow[col].dzmax; } if(costs[nrow-2][col].laycostnmax){ nmax=flowhistogram[iflow-flowlimlo]; reloffset=iflow; } } bulkoffsets[tilerow+1][tilecol]=bulkoffsets[tilerow][tilecol]-reloffset; /* subtract relative tile offset from edge flows */ for(col=0;colnshortcycle; reloffset=bulkoffsets[tilerow][tilecol]-bulkoffsets[tilerow][tilecol-1]; /* loop over all arcs on the boundary */ for(row=0;row0.5){ dpsi-=1.0; } if(CalcCost==CalcCostTopo || CalcCost==CalcCostDefo){ leftedgecosts[row][0].offset=(short )LRound(TILEDPSICOLFACTOR *nshortcycle*dpsi); leftedgecosts[row][0].sigsq =AvgSigSq(costs[row+nrow-1][0].sigsq, lastcosts[row+nrow-1][prevncol-2].sigsq); if(costs[row+nrow-1][0].dzmax>lastcosts[row+nrow-1][prevncol-2].dzmax){ leftedgecosts[row][0].dzmax=costs[row+nrow-1][0].dzmax; }else{ leftedgecosts[row][0].dzmax=lastcosts[row+nrow-1][prevncol-2].dzmax; } if(costs[row+nrow-1][0].laycost >lastcosts[row+nrow-1][prevncol-2].laycost){ leftedgecosts[row][0].laycost=costs[row+nrow-1][0].laycost; }else{ leftedgecosts[row][0].laycost =lastcosts[row+nrow-1][prevncol-2].laycost; } }else if(CalcCost==CalcCostSmooth){ leftedgesmoothcosts[row][0].offset =(short )LRound(TILEDPSICOLFACTOR*nshortcycle*dpsi); leftedgesmoothcosts[row][0].sigsq =AvgSigSq(smoothcosts[row+nrow-1][0].sigsq, lastsmoothcosts[row+nrow-1][prevncol-2].sigsq); }else if(CalcCost==CalcCostL0 || CalcCost==CalcCostL1 || CalcCost==CalcCostL2 || CalcCost==CalcCostLP){ ((short **)voidleftedgecosts)[row][0]= (((short **)voidcosts)[row+nrow-1][0] +((short **)voidlastcosts)[row+nrow-1][prevncol-2])/2; }else if(CalcCost==CalcCostL0BiDir || CalcCost==CalcCostL1BiDir || CalcCost==CalcCostL2BiDir || CalcCost==CalcCostLPBiDir){ ((bidircostT **)voidleftedgecosts)[row][0].posweight= (((bidircostT **)voidcosts)[row+nrow-1][0].posweight +((bidircostT **)voidlastcosts)[row+nrow-1][prevncol-2].posweight) /2; ((bidircostT **)voidleftedgecosts)[row][0].negweight= (((bidircostT **)voidcosts)[row+nrow-1][0].negweight +((bidircostT **)voidlastcosts)[row+nrow-1][prevncol-2].negweight) /2; }else{ fflush(NULL); fprintf(sp0,"Illegal cost mode in SetLeftEdge(). This is a bug.\n"); exit(ABNORMAL_EXIT); } } }else{ if(CalcCost==CalcCostTopo || CalcCost==CalcCostDefo){ for(row=0;rowntilecol-1){ /* set up */ nshortcycle=params->nshortcycle; flowlimhi=LARGESHORT; flowlimlo=-LARGESHORT; flowhistogram=(long *)CAlloc(flowlimhi-flowlimlo+1,sizeof(long)); minflow=flowlimhi; maxflow=flowlimlo; /* loop over all arcs on the boundary */ for(row=0;rowmaxflow){ if(tempflow>flowlimhi){ fflush(NULL); fprintf(sp0,"Overflow in tile offset\nAbort\n"); exit(ABNORMAL_EXIT); } maxflow=tempflow; } flowhistogram[tempflow-flowlimlo]++; dpsi=dphi-floor(dphi); if(dpsi>0.5){ dpsi-=1.0; } if(CalcCost==CalcCostTopo || CalcCost==CalcCostDefo){ rightedgecosts[row][0].offset=(short )LRound(TILEDPSICOLFACTOR *nshortcycle*dpsi); rightedgecosts[row][0].sigsq =AvgSigSq(costs[row+nrow-1][ncol-2].sigsq, nextcosts[row+nrow-1][0].sigsq); if(costs[row+nrow-1][ncol-2].dzmax>nextcosts[row+nrow-1][0].dzmax){ rightedgecosts[row][0].dzmax=costs[row+nrow-1][ncol-2].dzmax; }else{ rightedgecosts[row][0].dzmax=nextcosts[row+nrow-1][0].dzmax; } if(costs[row+nrow-1][ncol-2].laycost>nextcosts[row+nrow-1][0].laycost){ rightedgecosts[row][0].laycost=costs[row+nrow-1][ncol-2].laycost; }else{ rightedgecosts[row][0].laycost=nextcosts[row+nrow-1][0].laycost; } }else if(CalcCost==CalcCostSmooth){ rightedgesmoothcosts[row][0].offset =(short )LRound(TILEDPSICOLFACTOR*nshortcycle*dpsi); rightedgesmoothcosts[row][0].sigsq =AvgSigSq(smoothcosts[row+nrow-1][ncol-2].sigsq, nextsmoothcosts[row+nrow-1][0].sigsq); }else if(CalcCost==CalcCostL0 || CalcCost==CalcCostL1 || CalcCost==CalcCostL2 || CalcCost==CalcCostLP){ ((short **)voidrightedgecosts)[row][0]= (((short **)voidcosts)[row+nrow-1][ncol-2] +((short **)voidnextcosts)[row+nrow-1][0])/2; }else if(CalcCost==CalcCostL0BiDir || CalcCost==CalcCostL1BiDir || CalcCost==CalcCostL2BiDir || CalcCost==CalcCostLPBiDir){ ((bidircostT **)voidrightedgecosts)[row][0].posweight= (((bidircostT **)voidcosts)[row+nrow-1][ncol-2].posweight +((bidircostT **)voidnextcosts)[row+nrow-1][ncol-2].posweight)/2; ((bidircostT **)voidrightedgecosts)[row][0].negweight= (((bidircostT **)voidcosts)[row+nrow-1][ncol-2].negweight +((bidircostT **)voidnextcosts)[row+nrow-1][ncol-2].negweight)/2; }else{ fflush(NULL); fprintf(sp0,"Illegal cost mode in SetRightEdge(). This is a bug.\n"); exit(ABNORMAL_EXIT); } } /* set bulk tile offset equal to mode of flow histogram */ if(tilerow==0){ nmax=0; reloffset=0; for(iflow=minflow;iflow<=maxflow;iflow++){ if(flowhistogram[iflow-flowlimlo]>nmax){ nmax=flowhistogram[iflow-flowlimlo]; reloffset=iflow; } } bulkoffsets[tilerow][tilecol+1]=bulkoffsets[tilerow][tilecol]+reloffset; }else{ reloffset=bulkoffsets[tilerow][tilecol+1]-bulkoffsets[tilerow][tilecol]; } /* subtract relative tile offset from edge flows */ for(row=0;rowpred==NULL || (tilerow!=0 && primaryhead->row==0 && primaryhead->pred->row==0) || (tilecol!=0 && primaryhead->col==0 && primaryhead->pred->col==0)){ return(0); } /* set up */ ntilerow=params->ntilerow; ntilecol=params->ntilecol; nnrow=nrow+1; nncol=ncol+1; tilenum=tilerow*ntilecol+tilecol; scndrycostarr=(long *)MAlloc((2*flowmax+2)*sizeof(long)); tileedgearcweight=params->tileedgeweight; nshortcycle=params->nshortcycle; zerocost=FALSE; arroffset=0; sigsq=0; /* loop to determine appropriate value for arroffset */ while(TRUE){ /* initialize variables */ arclen=0; sumsigsqinv=0; for(nflow=1;nflow<=2*flowmax;nflow++){ scndrycostarr[nflow]=0; } /* loop over primary arcs on secondary arc again to get costs */ primarytail=primaryhead->pred; tempnode=primaryhead; while(TRUE){ /* get primary arc just traversed */ arclen++; if(tempnode->col==primarytail->col+1){ /* rightward arc */ primaryarcdir=1; primaryarccol=primarytail->col; if(primarytail->row==0){ /* top edge */ if(tilerow==0){ zerocost=TRUE; }else{ primaryarcrow=0; costs=upperedgecosts; flows=upperedgeflows; calccostnrow=2; } }else if(primarytail->row==nnrow-1){ /* bottom edge */ if(tilerow==ntilerow-1){ zerocost=TRUE; }else{ primaryarcrow=0; costs=loweredgecosts; flows=loweredgeflows; calccostnrow=2; } }else{ /* normal arc */ primaryarcrow=primarytail->row-1; costs=tilecosts; flows=tileflows; calccostnrow=nrow; } }else if(tempnode->row==primarytail->row+1){ /* downward arc */ primaryarcdir=1; if(primarytail->col==0){ /* left edge */ if(tilecol==0){ zerocost=TRUE; }else{ primaryarcrow=primarytail->row; primaryarccol=0; costs=leftedgecosts; flows=leftedgeflows; calccostnrow=0; } }else if(primarytail->col==nncol-1){ /* right edge */ if(tilecol==ntilecol-1){ zerocost=TRUE; }else{ primaryarcrow=primarytail->row; primaryarccol=0; costs=rightedgecosts; flows=rightedgeflows; calccostnrow=0; } }else{ /* normal arc */ primaryarcrow=primarytail->row+nrow-1; primaryarccol=primarytail->col-1; costs=tilecosts; flows=tileflows; calccostnrow=nrow; } }else if(tempnode->col==primarytail->col-1){ /* leftward arc */ primaryarcdir=-1; primaryarccol=primarytail->col-1; if(primarytail->row==0){ /* top edge */ if(tilerow==0){ zerocost=TRUE; }else{ primaryarcrow=0; costs=upperedgecosts; flows=upperedgeflows; calccostnrow=2; } }else if(primarytail->row==nnrow-1){ /* bottom edge */ if(tilerow==ntilerow-1){ zerocost=TRUE; }else{ primaryarcrow=0; costs=loweredgecosts; flows=loweredgeflows; calccostnrow=2; } }else{ /* normal arc */ primaryarcrow=primarytail->row-1; costs=tilecosts; flows=tileflows; calccostnrow=nrow; } }else{ /* upward arc */ primaryarcdir=-1; if(primarytail->col==0){ /* left edge */ if(tilecol==0){ zerocost=TRUE; }else{ primaryarcrow=primarytail->row-1; primaryarccol=0; costs=leftedgecosts; flows=leftedgeflows; calccostnrow=0; } }else if(primarytail->col==nncol-1){ /* right edge */ if(tilecol==ntilecol-1){ zerocost=TRUE; }else{ primaryarcrow=primarytail->row-1; primaryarccol=0; costs=rightedgecosts; flows=rightedgeflows; calccostnrow=0; } }else{ /* normal arc */ primaryarcrow=primarytail->row+nrow-2; primaryarccol=primarytail->col-1; costs=tilecosts; flows=tileflows; calccostnrow=nrow; } } /* keep absolute cost of arc to the previous node */ if(!zerocost){ /* accumulate incremental cost in table for each nflow increment */ /* offset flow in flow array temporarily by arroffset then undo below */ flows[primaryarcrow][primaryarccol]-=primaryarcdir*arroffset; nomcost=EvalCost(costs,flows,primaryarcrow,primaryarccol,calccostnrow, params); for(nflow=1;nflow<=flowmax;nflow++){ flows[primaryarcrow][primaryarccol]+=(primaryarcdir*nflow); poscost=EvalCost(costs,flows,primaryarcrow,primaryarccol, calccostnrow,params); flows[primaryarcrow][primaryarccol]-=(2*primaryarcdir*nflow); negcost=EvalCost(costs,flows,primaryarcrow,primaryarccol, calccostnrow,params); flows[primaryarcrow][primaryarccol]+=(primaryarcdir*nflow); tempdouble=(scndrycostarr[nflow]+(poscost-nomcost)); if(tempdouble>LARGEINT){ scndrycostarr[nflow]=LARGEINT; }else if(tempdouble<-LARGEINT){ scndrycostarr[nflow]=-LARGEINT; }else{ scndrycostarr[nflow]+=(poscost-nomcost); } tempdouble=(scndrycostarr[nflow+flowmax]+(negcost-nomcost)); if(tempdouble>LARGEINT){ scndrycostarr[nflow+flowmax]=LARGEINT; }else if(tempdouble<-LARGEINT){ scndrycostarr[nflow+flowmax]=-LARGEINT; }else{ scndrycostarr[nflow+flowmax]+=(negcost-nomcost); } } flows[primaryarcrow][primaryarccol]+=primaryarcdir*arroffset; /* accumulate term to be used for cost growth beyond table bounds */ if(CalcCost==CalcCostTopo || CalcCost==CalcCostDefo){ sigsq=((costT **)costs)[primaryarcrow][primaryarccol].sigsq; }else if(CalcCost==CalcCostSmooth){ sigsq=((smoothcostT **)costs)[primaryarcrow][primaryarccol].sigsq; }else if(CalcCost==CalcCostL0 || CalcCost==CalcCostL1 || CalcCost==CalcCostL2 || CalcCost==CalcCostLP){ minweight=((short **)costs)[primaryarcrow][primaryarccol]; if(minweight<1){ sigsq=LARGESHORT; }else{ sigsq=1.0/(double )minweight; } }else if(CalcCost==CalcCostL0BiDir || CalcCost==CalcCostL1BiDir || CalcCost==CalcCostL2BiDir || CalcCost==CalcCostLPBiDir){ minweight=LMin(((bidircostT **)costs)[primaryarcrow][primaryarccol] .posweight, ((bidircostT **)costs)[primaryarcrow][primaryarccol] .negweight); if(minweight<1){ sigsq=LARGESHORT; }else{ sigsq=1.0/(double )minweight; } } if(sigsqgroup==ONTREE){ break; } /* move up the tree */ tempnode=primarytail; primarytail=primarytail->pred; } /* end while loop for tracing secondary arc for costs */ /* break if we have a zero-cost arc on the edge of the full array */ if(zerocost){ break; } /* find flow index with minimum cost */ mincost=0; maxcost=0; mincostflow=0; for(nflow=1;nflow<=flowmax;nflow++){ if(scndrycostarr[nflow]maxcost){ maxcost=scndrycostarr[nflow]; } if(scndrycostarr[flowmax+nflow]>maxcost){ maxcost=scndrycostarr[flowmax+nflow]; } } /* if cost was all zero, treat as zero cost arc */ if(maxcost==mincost){ zerocost=TRUE; sumsigsqinv=0; } /* break if cost array adequately centered on minimum cost flow */ if(mincostflow==0){ break; } /* correct value of arroffset for next loop */ if(mincostflow==flowmax){ arroffset-=((long )floor(1.5*flowmax)); }else if(mincostflow==-flowmax){ arroffset+=((long )floor(1.5*flowmax)); }else{ arroffset-=mincostflow; } } /* end while loop for determining arroffset */ /* ignore this arc if primary head is same as tail (ie, if arc loops) */ /* only way this can happen is if region is connected at one corner only */ /* so any possible improvements should have been made by primary solver */ if(primaryhead==primarytail){ free(scndrycostarr); return(0); } /* see if we have a secondary arc on the edge of the full-sized array */ /* these arcs have zero cost since the edge is treated as a single node */ /* secondary arcs whose primary arcs all have zero cost are also zeroed */ if(zerocost){ /* set sum of standard deviations to indicate zero-cost secondary arc */ scndrycostarr[0]=0; for(nflow=1;nflow<=2*flowmax;nflow++){ scndrycostarr[nflow]=0; } scndrycostarr[2*flowmax+1]=ZEROCOSTARC; }else{ /* give extra weight to arcs on tile edges */ if((primaryhead->row==primarytail->row && (primaryhead->row==0 || primaryhead->row==nnrow-1)) || (primaryhead->col==primarytail->col && (primaryhead->col==0 || primaryhead->col==nncol-1))){ for(nflow=1;nflow<=2*flowmax;nflow++){ tempdouble=scndrycostarr[nflow]*tileedgearcweight; if(tempdouble>LARGEINT){ scndrycostarr[nflow]=LARGEINT; }else if(tempdouble<-LARGEINT){ scndrycostarr[nflow]=-LARGEINT; }else{ scndrycostarr[nflow]=LRound(tempdouble); } } sumsigsqinv*=tileedgearcweight; } /* store sum of primary cost variances at end of secondary cost array */ tempdouble=sumsigsqinv*nshortcycle*nshortcycle; if(tempdoublerow==0 && tilerow!=0){ scndrytail=FindScndryNode(scndrynodes,nodesupp, (tilerow-1)*ntilecol+tilecol, prevnrow,primarytail->col); }else if(primarytail->col==0 && tilecol!=0){ scndrytail=FindScndryNode(scndrynodes,nodesupp, tilerow*ntilecol+(tilecol-1), primarytail->row,prevncol); }else{ scndrytail=FindScndryNode(scndrynodes,nodesupp,tilenum, primarytail->row,primarytail->col); } if(primaryhead->row==0 && tilerow!=0){ scndryhead=FindScndryNode(scndrynodes,nodesupp, (tilerow-1)*ntilecol+tilecol, prevnrow,primaryhead->col); }else if(primaryhead->col==0 && tilecol!=0){ scndryhead=FindScndryNode(scndrynodes,nodesupp, tilerow*ntilecol+(tilecol-1), primaryhead->row,prevncol); }else{ scndryhead=FindScndryNode(scndrynodes,nodesupp,tilenum, primaryhead->row,primaryhead->col); } /* see if there is already arc between secondary head, tail */ row=scndrytail->row; col=scndrytail->col; for(i=0;irow==primaryhead->row && tempnode->col==primaryhead->col) || (nodesupp[row][col].outarcs[i]!=NULL && tempnode->row==scndryhead->row && tempnode->col==scndryhead->col)){ /* see if secondary arc traverses only one primary arc */ primarydummy=primaryhead->pred; if(primarydummy->group!=ONTREE){ /* arc already exists, free memory for cost array (will trace again) */ free(scndrycostarr); /* set up dummy node */ primarydummy->group=ONTREE; nnewnodes=++(*nnewnodesptr); scndrynodes[tilenum]=(nodeT *)ReAlloc(scndrynodes[tilenum], nnewnodes*sizeof(nodeT)); scndrydummy=&scndrynodes[tilenum][nnewnodes-1]; nodesupp[tilenum]=(nodesuppT *)ReAlloc(nodesupp[tilenum], nnewnodes*sizeof(nodesuppT)); suppdummy=&nodesupp[tilenum][nnewnodes-1]; scndrydummy->row=tilenum; scndrydummy->col=nnewnodes-1; suppdummy->row=primarydummy->row; suppdummy->col=primarydummy->col; suppdummy->noutarcs=0; suppdummy->neighbornodes=NULL; suppdummy->outarcs=NULL; /* recursively call TraceSecondaryArc() to set up arcs */ TraceSecondaryArc(primarydummy,scndrynodes,nodesupp,scndryarcs, scndrycosts,nnewnodesptr,nnewarcsptr,tilerow,tilecol, flowmax,nrow,ncol,prevnrow,prevncol,params,tilecosts, rightedgecosts,loweredgecosts,leftedgecosts, upperedgecosts,tileflows,rightedgeflows, loweredgeflows,leftedgeflows,upperedgeflows, updatednontilenodesptr,nupdatednontilenodesptr, updatednontilenodesizeptr,inontilenodeoutarcptr, totarclenptr); TraceSecondaryArc(primaryhead,scndrynodes,nodesupp,scndryarcs, scndrycosts,nnewnodesptr,nnewarcsptr,tilerow,tilecol, flowmax,nrow,ncol,prevnrow,prevncol,params,tilecosts, rightedgecosts,loweredgecosts,leftedgecosts, upperedgecosts,tileflows,rightedgeflows, loweredgeflows,leftedgeflows,upperedgeflows, updatednontilenodesptr,nupdatednontilenodesptr, updatednontilenodesizeptr,inontilenodeoutarcptr, totarclenptr); }else{ /* only one primary arc; just delete other secondary arc */ /* find existing secondary arc (must be in this tile) */ /* swap direction of existing secondary arc if necessary */ arcnum=0; while(TRUE){ if(scndryarcs[tilenum][arcnum].from==primarytail && scndryarcs[tilenum][arcnum].to==primaryhead){ break; }else if(scndryarcs[tilenum][arcnum].from==primaryhead && scndryarcs[tilenum][arcnum].to==primarytail){ scndryarcs[tilenum][arcnum].from=primarytail; scndryarcs[tilenum][arcnum].to=primaryhead; break; } arcnum++; } /* assign cost of this secondary arc to existing secondary arc */ free(scndrycosts[tilenum][arcnum]); scndrycosts[tilenum][arcnum]=scndrycostarr; /* update direction data in secondary arc structure */ if(primarytail->col==primaryhead->col+1){ scndryarcs[tilenum][arcnum].fromdir=RIGHT; }else if(primarytail->row==primaryhead->row+1){ scndryarcs[tilenum][arcnum].fromdir=DOWN; }else if(primarytail->col==primaryhead->col-1){ scndryarcs[tilenum][arcnum].fromdir=LEFT; }else{ scndryarcs[tilenum][arcnum].fromdir=UP; } } /* we're done */ return(0); } } /* set up secondary arc datastructures */ nnewarcs=++(*nnewarcsptr); if(nnewarcs > SHRT_MAX){ fflush(NULL); fprintf(sp0,"Exceeded maximum number of secondary arcs\n" "Decrease TILECOSTTHRESH and/or increase MINREGIONSIZE\n"); exit(ABNORMAL_EXIT); } scndryarcs[tilenum]=(scndryarcT *)ReAlloc(scndryarcs[tilenum], nnewarcs*sizeof(scndryarcT)); newarc=&scndryarcs[tilenum][nnewarcs-1]; newarc->arcrow=tilenum; newarc->arccol=nnewarcs-1; scndrycosts[tilenum]=(long **)ReAlloc(scndrycosts[tilenum], nnewarcs*sizeof(long *)); scndrycosts[tilenum][nnewarcs-1]=scndrycostarr; /* update secondary node data */ /* store primary nodes in nodesuppT neighbornodes[] arrays since */ /* secondary node addresses change in ReAlloc() calls in TraceRegions() */ supptail=&nodesupp[scndrytail->row][scndrytail->col]; supphead=&nodesupp[scndryhead->row][scndryhead->col]; supptail->noutarcs++; supptail->neighbornodes=(nodeT **)ReAlloc(supptail->neighbornodes, supptail->noutarcs *sizeof(nodeT *)); supptail->neighbornodes[supptail->noutarcs-1]=primaryhead; primarytail->level=scndrytail->row; primarytail->incost=scndrytail->col; supptail->outarcs=(scndryarcT **)ReAlloc(supptail->outarcs, supptail->noutarcs *sizeof(scndryarcT *)); supptail->outarcs[supptail->noutarcs-1]=NULL; supphead->noutarcs++; supphead->neighbornodes=(nodeT **)ReAlloc(supphead->neighbornodes, supphead->noutarcs *sizeof(nodeT *)); supphead->neighbornodes[supphead->noutarcs-1]=primarytail; primaryhead->level=scndryhead->row; primaryhead->incost=scndryhead->col; supphead->outarcs=(scndryarcT **)ReAlloc(supphead->outarcs, supphead->noutarcs *sizeof(scndryarcT *)); supphead->outarcs[supphead->noutarcs-1]=NULL; /* keep track of updated secondary nodes that were not in this tile */ if(scndrytail->row!=tilenum){ if(++(*nupdatednontilenodesptr)==(*updatednontilenodesizeptr)){ (*updatednontilenodesizeptr)+=INITARRSIZE; (*updatednontilenodesptr)=(nodeT **)ReAlloc((*updatednontilenodesptr), (*updatednontilenodesizeptr) *sizeof(nodeT *)); (*inontilenodeoutarcptr)=(short *)ReAlloc((*inontilenodeoutarcptr), (*updatednontilenodesizeptr) *sizeof(short)); } (*updatednontilenodesptr)[*nupdatednontilenodesptr-1]=scndrytail; (*inontilenodeoutarcptr)[*nupdatednontilenodesptr-1]=supptail->noutarcs-1; } if(scndryhead->row!=tilenum){ if(++(*nupdatednontilenodesptr)==(*updatednontilenodesizeptr)){ (*updatednontilenodesizeptr)+=INITARRSIZE; (*updatednontilenodesptr)=(nodeT **)ReAlloc((*updatednontilenodesptr), (*updatednontilenodesizeptr) *sizeof(nodeT *)); (*inontilenodeoutarcptr)=(short *)ReAlloc((*inontilenodeoutarcptr), (*updatednontilenodesizeptr) *sizeof(short)); } (*updatednontilenodesptr)[*nupdatednontilenodesptr-1]=scndryhead; (*inontilenodeoutarcptr)[*nupdatednontilenodesptr-1]=supphead->noutarcs-1; } /* set up node data in secondary arc structure */ newarc->from=primarytail; newarc->to=primaryhead; /* set up direction data in secondary arc structure */ tempnode=primaryhead->pred; if(tempnode->col==primaryhead->col+1){ newarc->fromdir=RIGHT; }else if(tempnode->row==primaryhead->row+1){ newarc->fromdir=DOWN; }else if(tempnode->col==primaryhead->col-1){ newarc->fromdir=LEFT; }else{ newarc->fromdir=UP; } /* add number of primary arcs in secondary arc to counter */ (*totarclenptr)+=arclen; /* done */ return(0); } /* function: FindScndryNode() * -------------------------- */ static nodeT *FindScndryNode(nodeT **scndrynodes, nodesuppT **nodesupp, long tilenum, long primaryrow, long primarycol){ long nodenum; nodesuppT *nodesuppptr; /* set temporary variables */ nodesuppptr=nodesupp[tilenum]; /* loop over all nodes in the tile until we find a match */ nodenum=0; while(nodesuppptr[nodenum].row!=primaryrow || nodesuppptr[nodenum].col!=primarycol){ nodenum++; } return(&scndrynodes[tilenum][nodenum]); } /* function: IntegrateSecondaryFlows() * ----------------------------------- */ static int IntegrateSecondaryFlows(long linelen, long nlines, nodeT **scndrynodes, nodesuppT **nodesupp, scndryarcT **scndryarcs, int *nscndryarcs, short **scndryflows, short **bulkoffsets, outfileT *outfiles, paramT *params){ FILE *outfp; float **unwphase, **tileunwphase, **mag, **tilemag; float *outline; long row, col, colstart, nrow, ncol, nnrow, nncol, maxcol; long readtilelinelen, readtilenlines, nextcoloffset, nextrowoffset; long tilerow, tilecol, ntilerow, ntilecol, rowovrlp, colovrlp; long ni, nj, tilenum; double tileoffset; short **regions, **tileflows; char realoutfile[MAXSTRLEN], readfile[MAXSTRLEN], tempstring[MAXTMPSTRLEN]; char path[MAXSTRLEN], basename[MAXSTRLEN]; signed char writeerror; tileparamT readtileparams[1]; outfileT readtileoutfiles[1]; /* initialize stack structures to zero for good measure */ memset(readtileparams,0,sizeof(tileparamT)); memset(readtileoutfiles,0,sizeof(outfileT)); memset(realoutfile,0,MAXSTRLEN); memset(readfile,0,MAXSTRLEN); memset(tempstring,0,MAXSTRLEN); memset(path,0,MAXSTRLEN); memset(basename,0,MAXSTRLEN); /* set up */ fprintf(sp1,"Integrating secondary flows\n"); ntilerow=params->ntilerow; ntilecol=params->ntilecol; rowovrlp=params->rowovrlp; colovrlp=params->colovrlp; ni=ceil((nlines+(ntilerow-1)*rowovrlp)/(double )ntilerow); nj=ceil((linelen+(ntilecol-1)*colovrlp)/(double )ntilecol); nextcoloffset=0; writeerror=FALSE; nrow=0; /* get memory */ regions=(short **)Get2DMem(ni,nj,sizeof(short *),sizeof(short)); tileflows=(short **)Get2DRowColMem(ni+2,nj+2,sizeof(short *),sizeof(short)); tileunwphase=(float **)Get2DMem(ni,nj,sizeof(float *),sizeof(float)); tilemag=(float **)Get2DMem(ni,nj,sizeof(float *),sizeof(float)); unwphase=(float **)Get2DMem(ni,linelen,sizeof(float *),sizeof(float)); mag=(float **)Get2DMem(ni,linelen,sizeof(float *),sizeof(float)); outline=(float *)MAlloc(2*linelen*sizeof(float)); /* flip sign of bulk offsets if flip flag is set */ /* do this and flip flow signs instead of flipping phase signs */ if(params->flipphasesign){ for(row=0;rowoutfile,realoutfile); /* process each tile row */ for(tilerow=0;tilerowfirstcol; readtilenlines=readtileparams->nrow; readtilelinelen=readtileparams->ncol; /* set tile read parameters */ SetTileReadParams(readtileparams,readtilenlines,readtilelinelen, tilerow,tilecol,nlines,linelen,params); colstart+=readtileparams->firstcol; nrow=readtileparams->nrow; ncol=readtileparams->ncol; nnrow=nrow+1; nncol=ncol+1; /* read unwrapped phase */ /* phase sign not flipped for positive baseline */ /* since flow will be flipped if necessary */ if(TMPTILEOUTFORMAT==ALT_LINE_DATA){ ReadAltLineFile(&tilemag,&tileunwphase,readtileoutfiles->outfile, readtilelinelen,readtilenlines,readtileparams); }else if(TMPTILEOUTFORMAT==FLOAT_DATA){ Read2DArray((void ***)&tileunwphase,readtileoutfiles->outfile, readtilelinelen,readtilenlines,readtileparams, sizeof(float *),sizeof(float)); } /* read regions */ ParseFilename(outfiles->outfile,path,basename); sprintf(tempstring,"%s/%s%s_%ld_%ld.%ld%s", params->tiledir,TMPTILEROOT,basename,tilerow,tilecol, readtilelinelen,REGIONSUFFIX); StrNCopy(readfile,tempstring,MAXSTRLEN); Read2DArray((void ***)®ions,readfile,readtilelinelen,readtilenlines, readtileparams,sizeof(short *),sizeof(short)); /* remove temporary files unless told so save them */ if(params->rmtmptile){ unlink(readtileoutfiles->outfile); unlink(readfile); } /* zero out primary flow array */ for(row=0;row<2*nrow+1;row++){ if(rowoutfileformat==ALT_LINE_DATA){ if(fwrite(mag[row],sizeof(float),linelen,outfp)!=linelen || fwrite(unwphase[row],sizeof(float),linelen,outfp)!=linelen){ writeerror=TRUE; break; } }else if(outfiles->outfileformat==ALT_SAMPLE_DATA){ for(col=0;colflipphasesign){ phaseflipsign=-1; }else{ phaseflipsign=1; } /* loop over all arcs in tile */ for(arcnum=0;arcnumrow==tilenum){ primaryfromrow=nodesupp[scndryfrom->row][scndryfrom->col].row; primaryfromcol=nodesupp[scndryfrom->row][scndryfrom->col].col; }else if(scndryfrom->row==tilenum-ntilecol){ primaryfromrow=0; primaryfromcol=nodesupp[scndryfrom->row][scndryfrom->col].col; }else if(scndryfrom->row==tilenum-1){ primaryfromrow=nodesupp[scndryfrom->row][scndryfrom->col].row; primaryfromcol=0; }else{ primaryfromrow=0; primaryfromcol=0; } if(scndryto->row==tilenum){ thisrow=nodesupp[scndryto->row][scndryto->col].row; thiscol=nodesupp[scndryto->row][scndryto->col].col; }else if(scndryto->row==tilenum-ntilecol){ thisrow=0; thiscol=nodesupp[scndryto->row][scndryto->col].col; }else if(scndryto->row==tilenum-1){ thisrow=nodesupp[scndryto->row][scndryto->col].row; thiscol=0; }else{ thisrow=0; thiscol=0; } /* set initial direction out of secondary arc head */ switch(scndryarcs[tilenum][arcnum].fromdir){ case RIGHT: nextrow=thisrow; nextcol=thiscol+1; tileflows[thisrow][thiscol]-=nflow; break; case DOWN: nextrow=thisrow+1; nextcol=thiscol; tileflows[nnrow+thisrow][thiscol]-=nflow; break; case LEFT: nextrow=thisrow; nextcol=thiscol-1; tileflows[thisrow][thiscol-1]+=nflow; break; default: nextrow=thisrow-1; nextcol=thiscol; tileflows[nnrow+thisrow-1][thiscol]+=nflow; break; } /* use region data to trace path between secondary from, to */ while(!(nextrow==primaryfromrow && nextcol==primaryfromcol)){ /* move to next node */ prevrow=thisrow; prevcol=thiscol; thisrow=nextrow; thiscol=nextcol; /* check rightward arc */ if(thiscol!=nncol-1){ if(thisrow==0 || thisrow==nnrow-1 || regions[thisrow-1][thiscol]!=regions[thisrow][thiscol]){ if(!(thisrow==prevrow && thiscol+1==prevcol)){ tileflows[thisrow][thiscol]-=nflow; nextcol++; } } } /* check downward arc */ if(thisrow!=nnrow-1){ if(thiscol==0 || thiscol==nncol-1 || regions[thisrow][thiscol]!=regions[thisrow][thiscol-1]){ if(!(thisrow+1==prevrow && thiscol==prevcol)){ tileflows[nnrow+thisrow][thiscol]-=nflow; nextrow++; } } } /* check leftward arc */ if(thiscol!=0){ if(thisrow==0 || thisrow==nnrow-1 || regions[thisrow][thiscol-1]!=regions[thisrow-1][thiscol-1]){ if(!(thisrow==prevrow && thiscol-1==prevcol)){ tileflows[thisrow][thiscol-1]+=nflow; nextcol--; } } } /* check upward arc */ if(thisrow!=0){ if(thiscol==0 || thiscol==nncol-1 || regions[thisrow-1][thiscol-1]!=regions[thisrow-1][thiscol]){ if(!(thisrow-1==prevrow && thiscol==prevcol)){ tileflows[nnrow+thisrow-1][thiscol]+=nflow; nextrow--; } } } } } } return(0); } /* function: AssembleTileConnComps() * --------------------------------- * Assemble conntected components per tile. */ static int AssembleTileConnComps(long linelen, long nlines, outfileT *outfiles, paramT *params){ int ipass; long k; long row, col, colstart, nrow, ncol; long readtilelinelen, readtilenlines; long tilerow, tilecol, ntilerow, ntilecol, rowovrlp, colovrlp; long ni, nj, tilenum; unsigned int iconncomp, iconncompmax; long ntileconncomp, nconncomp; long ntileconncompmem, nconncompmem, nmemold; char realoutfile[MAXSTRLEN], readfile[MAXSTRLEN], tempstring[MAXTMPSTRLEN]; char path[MAXSTRLEN], basename[MAXSTRLEN]; signed char writeerror; tileparamT readtileparams[1]; outfileT readtileoutfiles[1]; unsigned int *tilemapping; unsigned int **tileconncomps, **tilerowconncomps; unsigned char **ucharbuf; unsigned char *ucharoutbuf; conncompsizeT *tileconncompsizes, *conncompsizes; FILE *outfp; /* initialize stack structures to zero for good measure */ memset(readtileparams,0,sizeof(tileparamT)); memset(readtileoutfiles,0,sizeof(outfileT)); memset(realoutfile,0,MAXSTRLEN); memset(readfile,0,MAXSTRLEN); memset(tempstring,0,MAXSTRLEN); memset(path,0,MAXSTRLEN); memset(basename,0,MAXSTRLEN); /* set up */ fprintf(sp1,"Assembling tile connected components\n"); ntilerow=params->ntilerow; ntilecol=params->ntilecol; rowovrlp=params->rowovrlp; colovrlp=params->colovrlp; ni=ceil((nlines+(ntilerow-1)*rowovrlp)/(double )ntilerow); nj=ceil((linelen+(ntilecol-1)*colovrlp)/(double )ntilecol); writeerror=FALSE; nrow=0; conncompsizes=NULL; nconncomp=0; nconncompmem=0; tileconncompsizes=NULL; ntileconncompmem=0; iconncompmax=0; /* get memory */ tileconncomps=(unsigned int **)Get2DMem(ni,nj,sizeof(unsigned int *), sizeof(unsigned int)); tilerowconncomps=(unsigned int **)Get2DMem(ni,linelen,sizeof(unsigned int *), sizeof(unsigned int)); ucharbuf=(unsigned char **)Get2DMem(ni,nj,sizeof(unsigned char *), sizeof(unsigned char)); ucharoutbuf=(unsigned char *)MAlloc(linelen*sizeof(unsigned char)); tilemapping=NULL; /* open output file */ outfp=OpenOutputFile(outfiles->conncompfile,realoutfile); /* do two passes looping over all tiles */ for(ipass=0;ipass<2;ipass++){ /* process each tile row */ for(tilerow=0;tilerowfirstcol; readtilenlines=readtileparams->nrow; readtilelinelen=readtileparams->ncol; /* set tile read parameters */ SetTileReadParams(readtileparams,readtilenlines,readtilelinelen, tilerow,tilecol,nlines,linelen,params); colstart+=readtileparams->firstcol; nrow=readtileparams->nrow; ncol=readtileparams->ncol; /* set tile number */ tilenum=tilerow*ntilecol+tilecol; /* read connected components for tile */ if(params->conncompouttype==CONNCOMPOUTTYPEUCHAR){ Read2DArray((void ***)&ucharbuf,readtileoutfiles->conncompfile, readtilelinelen,readtilenlines,readtileparams, sizeof(unsigned char *),sizeof(unsigned char)); for(row=0;rowconncompfile, readtilelinelen,readtilenlines,readtileparams, sizeof(unsigned int *),sizeof(unsigned int)); } /* see which pass we are in */ if(ipass==0){ /* first pass */ /* initialize tileconncomps array for this tile */ ntileconncomp=0; for(k=0;k0){ /* get more memory for tile conncompsizeT array if needed */ while(iconncomp>ntileconncompmem){ nmemold=ntileconncompmem; ntileconncompmem+=CONNCOMPMEMINCR; tileconncompsizes =(conncompsizeT *)ReAlloc(tileconncompsizes, (ntileconncompmem *sizeof(conncompsizeT))); for(k=nmemold;kiconncompmax){ iconncompmax=iconncomp; } } } } /* get more memory for full set of connected components sizes */ nmemold=nconncompmem; nconncompmem+=ntileconncomp; conncompsizes=(conncompsizeT *)ReAlloc(conncompsizes, (nconncompmem *sizeof(conncompsizeT))); /* store conncomp sizes from tile in full list */ for(k=0;k0){ conncompsizes[nconncomp].tilenum=tileconncompsizes[k].tilenum; conncompsizes[nconncomp].icomptile=tileconncompsizes[k].icomptile; conncompsizes[nconncomp].icompfull=0; conncompsizes[nconncomp].npix=tileconncompsizes[k].npix; nconncomp++; } } }else{ /* second pass */ /* build lookup table for tile mapping for this tile */ /* lookup table index is conncomp number minus one */ for(k=0;k0){ tilerowconncomps[row][colstart+col]=tilemapping[iconncomp-1]; }else{ tilerowconncomps[row][colstart+col]=0; } } } /* remove temporary files unless told so save them */ if(params->rmtmptile){ unlink(readtileoutfiles->conncompfile); } } } /* end loop over tile columns */ /* write out tile row at end of second pass */ if(ipass>0){ for(row=0;rowconncompouttype==CONNCOMPOUTTYPEUCHAR){ for(k=0;kparams->maxncomps){ nconncomp=params->maxncomps; } /* assign tile mappings */ for(k=0;k0){ free(tileconncompsizes); } if(nconncompmem>0){ free(conncompsizes); } free(tilemapping); /* done */ return(0); } /* function: ConnCompSizeNPixCompare() * ----------------------------------- * Compare npix member of conncompsizeT structures pointed to by * inputs for use with qsort() into descending order. */ static int ConnCompSizeNPixCompare(const void *ptr1, const void *ptr2){ return(((conncompsizeT *)ptr2)->npix-((conncompsizeT *)ptr1)->npix); } snaphu-v2.0.6/src/PaxHeader/snaphu_cost.c000644 777777 777777 00000000043 14423062415 020157 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/src/snaphu_cost.c000644 Ho)00000251212 14423062415 017414 0ustar00curtis000000 000000 /************************************************************************* snaphu statistical cost model 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "snaphu.h" /* static (local) function prototypes */ static void **BuildStatCostsTopo(float **wrappedphase, float **mag, float **unwrappedest, float **pwr, float **corr, short **rowweight, short **colweight, long nrow, long ncol, tileparamT *tileparams, outfileT *outfiles, paramT *params); static void **BuildStatCostsDefo(float **wrappedphase, float **mag, float **unwrappedest, float **corr, short **rowweight, short **colweight, long nrow, long ncol, tileparamT *tileparams, outfileT *outfiles, paramT *params); static void **BuildStatCostsSmooth(float **wrappedphase, float **mag, float **unwrappedest, float **corr, short **rowweight, short **colweight, long nrow, long ncol, tileparamT *tileparams, outfileT *outfiles, paramT *params); static void MaskCost(costT *costptr); static void MaskSmoothCost(smoothcostT *smoothcostptr); static int MaskPrespecifiedArcCosts(void **costsptr, short **weights, long nrow, long ncol, paramT *params); static int GetIntensityAndCorrelation(float **mag, float **wrappedphase, float ***pwrptr, float ***corrptr, infileT *infiles, long linelen, long nlines, long nrow, long ncol, outfileT *outfiles, paramT *params, tileparamT *tileparams); static int RemoveMean(float **ei, long nrow, long ncol, long krowei, long kcolei); static float *BuildDZRCritLookupTable(double *nominc0ptr, double *dnomincptr, long *tablesizeptr, tileparamT *tileparams, paramT *params); static double SolveDZRCrit(double sinnomincangle, double cosnomincangle, paramT *params, double threshold); static int SolveEIModelParams(double *slope1ptr, double *slope2ptr, double *const1ptr, double *const2ptr, double dzrcrit, double dzr0, double sinnomincangle, double cosnomincangle, paramT *params); static double EIofDZR(double dzr, double sinnomincangle, double cosnomincangle, paramT *params); static float **BuildDZRhoMaxLookupTable(double nominc0, double dnominc, long nominctablesize, double rhomin, double drho, long nrho, paramT *params); static double CalcDZRhoMax(double rho, double nominc, paramT *params, double threshold); static int CalcInitMaxFlow(paramT *params, void **costs, long nrow, long ncol); /* function: BuildCostArrays() * --------------------------- * Builds cost arrays for arcs based on interferogram intensity * and correlation, depending on options and passed parameters. */ int BuildCostArrays(void ***costsptr, short ***mstcostsptr, float **mag, float **wrappedphase, float **unwrappedest, long linelen, long nlines, long nrow, long ncol, paramT *params, tileparamT *tileparams, infileT *infiles, outfileT *outfiles){ long row, col, maxcol, tempcost; long poscost, negcost, costtypesize; float **pwr, **corr; short **weights, **rowweight, **colweight, **scalarcosts; bidircostT **bidircosts; void **costs, **rowcost, **colcost; void (*CalcStatCost)(void **, long, long, long, long, long, paramT *, long *, long *); /* initializations to silence compiler warnings */ costtypesize=0; bidircosts=NULL; scalarcosts=NULL; /* set global pointers to functions for calculating and evaluating costs */ if(params->p<0){ if(params->costmode==TOPO){ CalcCost=CalcCostTopo; EvalCost=EvalCostTopo; }else if(params->costmode==DEFO){ CalcCost=CalcCostDefo; EvalCost=EvalCostDefo; }else if(params->costmode==SMOOTH){ CalcCost=CalcCostSmooth; EvalCost=EvalCostSmooth; } }else{ if(params->bidirlpn){ if(params->p==0){ CalcCost=CalcCostL0BiDir; EvalCost=EvalCostL0BiDir; }else if(params->p==1){ CalcCost=CalcCostL1BiDir; EvalCost=EvalCostL1BiDir; }else if(params->p==2){ CalcCost=CalcCostL2BiDir; EvalCost=EvalCostL2BiDir; }else{ CalcCost=CalcCostLPBiDir; EvalCost=EvalCostLPBiDir; } }else{ if(params->p==0){ CalcCost=CalcCostL0; EvalCost=EvalCostL0; }else if(params->p==1){ CalcCost=CalcCostL1; EvalCost=EvalCostL1; }else if(params->p==2){ CalcCost=CalcCostL2; EvalCost=EvalCostL2; }else{ CalcCost=CalcCostLP; EvalCost=EvalCostLP; } } } /* read weights */ weights=NULL; ReadWeightsFile(&weights,infiles->weightfile,linelen,nlines,tileparams); rowweight=weights; colweight=&weights[nrow-1]; /* set weights to zero for arcs adjacent to zero-magnitude pixels */ if(mag!=NULL){ for(row=0;row0){ rowweight[row-1][col]=0; } if(row0){ colweight[row][col-1]=0; } if(colinitonly && params->costmode==NOSTATCOSTS){ *mstcostsptr=weights; return(0); } /* size of the data type for holding cost data depends on cost mode */ if(params->costmode==TOPO){ costtypesize=sizeof(costT); }else if(params->costmode==DEFO){ costtypesize=sizeof(costT); }else if(params->costmode==SMOOTH){ costtypesize=sizeof(smoothcostT); } /* build or read the statistical cost arrays unless we were told not to */ if(strlen(infiles->costinfile)){ /* read cost info from file */ fprintf(sp1,"Reading cost information from file %s\n",infiles->costinfile); costs=NULL; Read2DRowColFile((void ***)&costs,infiles->costinfile, linelen,nlines,tileparams,costtypesize); (*costsptr)=costs; /* weights of arcs next to masked pixels are set to zero */ /* make sure corresponding costs are nulled when costs are read from */ /* file rather than internally generated since read costs are not */ /* multiplied by weights */ MaskPrespecifiedArcCosts(costs,weights,nrow,ncol,params); }else if(params->costmode!=NOSTATCOSTS){ /* get intensity and correlation info */ /* correlation generated from interferogram and amplitude if not given */ GetIntensityAndCorrelation(mag,wrappedphase,&pwr,&corr,infiles, linelen,nlines,nrow,ncol,outfiles, params,tileparams); /* call specific functions for building cost array and */ /* set global pointers to functions for calculating and evaluating costs */ if(params->costmode==TOPO){ fprintf(sp1,"Calculating topography-mode cost parameters\n"); costs=BuildStatCostsTopo(wrappedphase,mag,unwrappedest,pwr,corr, rowweight,colweight,nrow,ncol,tileparams, outfiles,params); }else if(params->costmode==DEFO){ fprintf(sp1,"Calculating deformation-mode cost parameters\n"); costs=BuildStatCostsDefo(wrappedphase,mag,unwrappedest,corr, rowweight,colweight,nrow,ncol,tileparams, outfiles,params); }else if(params->costmode==SMOOTH){ fprintf(sp1,"Calculating smooth-solution cost parameters\n"); costs=BuildStatCostsSmooth(wrappedphase,mag,unwrappedest,corr, rowweight,colweight,nrow,ncol,tileparams, outfiles,params); }else{ costs=NULL; fflush(NULL); fprintf(sp0,"unrecognized cost mode\n"); exit(ABNORMAL_EXIT); } (*costsptr)=costs; }/* end if(params->costmode!=NOSTATCOSTS) */ /* set array subpointers and temporary cost-calculation function pointer */ if(params->costmode==TOPO){ rowcost=costs; colcost=(void **)&(((costT **)costs)[nrow-1]); CalcStatCost=CalcCostTopo; }else if(params->costmode==DEFO){ rowcost=costs; colcost=(void **)&(((costT **)costs)[nrow-1]); CalcStatCost=CalcCostDefo; }else if(params->costmode==SMOOTH){ rowcost=costs; colcost=(void **)&(((smoothcostT **)costs)[nrow-1]); CalcStatCost=CalcCostSmooth; }else{ rowcost=NULL; colcost=NULL; CalcStatCost=NULL; fflush(NULL); fprintf(sp0,"unrecognized cost mode\n"); exit(ABNORMAL_EXIT); } /* dump statistical cost arrays */ if(strlen(infiles->costinfile) || params->costmode!=NOSTATCOSTS){ if(strlen(outfiles->costoutfile)){ Write2DRowColArray((void **)costs,outfiles->costoutfile, nrow,ncol,costtypesize); }else{ if(strlen(outfiles->rowcostfile)){ Write2DArray((void **)rowcost,outfiles->rowcostfile, nrow-1,ncol,costtypesize); } if(strlen(outfiles->colcostfile)){ Write2DArray((void **)colcost,outfiles->colcostfile, nrow,ncol-1,costtypesize); } } } /* get memory for scalar costs if in Lp mode */ if(params->p>=0){ if(params->bidirlpn){ bidircosts=(bidircostT **)Get2DRowColMem(nrow,ncol,sizeof(bidircostT *), sizeof(bidircostT)); (*costsptr)=(void **)bidircosts; }else{ scalarcosts=(short **)Get2DRowColMem(nrow,ncol,sizeof(short *), sizeof(short)); (*costsptr)=(void **)scalarcosts; } } /* now, set scalar costs for MST initialization or optimization if needed */ if(params->costmode==NOSTATCOSTS){ /* if in no-statistical-costs mode, copy weights to scalarcosts array */ if(!params->initonly){ for(row=0;row<2*nrow-1;row++){ if(rowbidirlpn){ bidircosts[row][col].posweight=weights[row][col]; bidircosts[row][col].negweight=weights[row][col]; }else{ scalarcosts[row][col]=weights[row][col]; } } } } /* unless input is already unwrapped, use weights memory for mstcosts */ if(!params->unwrapped){ (*mstcostsptr)=weights; }else{ Free2DArray((void **)weights,2*nrow-1); (*mstcostsptr)=NULL; } }else if(!params->unwrapped || params->p>=0){ /* if we got here, we had statistical costs and we need scalar weights */ /* from them for MST initialization or for Lp optimization */ for(row=0;row<2*nrow-1;row++){ if(rowmaxcost */ /* note: weights used for MST algorithm will not be zero along */ /* masked edges since they are clipped to 1, but MST is run */ /* once on entire network, not just non-masked regions */ weights[row][col]=LClip(tempcost,MINSCALARCOST,params->maxcost); /* assign Lp costs if in Lp mode */ /* let scalar cost be zero if costs in both directions are zero */ if(params->p>=0){ if(params->bidirlpn){ bidircosts[row][col].posweight=LClip(poscost,0,params->maxcost); bidircosts[row][col].negweight=LClip(negcost,0,params->maxcost); }else{ scalarcosts[row][col]=weights[row][col]; if(poscost==0 && negcost==0){ scalarcosts[row][col]=0; } } } } } /* set costs for corner arcs to prevent ambiguous flows */ weights[nrow-1][0]=LARGESHORT; weights[nrow-1][ncol-2]=LARGESHORT; weights[2*nrow-2][0]=LARGESHORT; weights[2*nrow-2][ncol-2]=LARGESHORT; if(params->p>=0){ if(params->bidirlpn){ bidircosts[nrow-1][0].posweight=LARGESHORT; bidircosts[nrow-1][0].negweight=LARGESHORT; bidircosts[nrow-1][ncol-2].posweight=LARGESHORT; bidircosts[nrow-1][ncol-2].negweight=LARGESHORT; bidircosts[2*nrow-2][0].posweight=LARGESHORT; bidircosts[2*nrow-2][0].negweight=LARGESHORT; bidircosts[2*nrow-2][ncol-2].posweight=LARGESHORT; bidircosts[2*nrow-2][ncol-2].negweight=LARGESHORT; }else{ scalarcosts[nrow-1][0]=LARGESHORT; scalarcosts[nrow-1][ncol-2]=LARGESHORT; scalarcosts[2*nrow-2][0]=LARGESHORT; scalarcosts[2*nrow-2][ncol-2]=LARGESHORT; } } /* dump mst initialization costs */ if(strlen(outfiles->mstrowcostfile)){ Write2DArray((void **)rowweight,outfiles->mstrowcostfile, nrow-1,ncol,sizeof(short)); } if(strlen(outfiles->mstcolcostfile)){ Write2DArray((void **)colweight,outfiles->mstcolcostfile, nrow,ncol-1,sizeof(short)); } if(strlen(outfiles->mstcostsfile)){ Write2DRowColArray((void **)rowweight,outfiles->mstcostsfile, nrow,ncol,sizeof(short)); } /* unless input is unwrapped, calculate initialization max flow */ if(params->initmaxflow==AUTOCALCSTATMAX && !params->unwrapped){ CalcInitMaxFlow(params,(void **)costs,nrow,ncol); } /* free costs memory if in init-only or Lp mode */ if(params->initonly || params->p>=0){ Free2DArray((void **)costs,2*nrow-1); } /* use memory allocated for weights arrays for mstcosts if needed */ if(!params->unwrapped){ (*mstcostsptr)=weights; }else{ Free2DArray((void **)weights,2*nrow-1); } }else{ Free2DArray((void **)weights,2*nrow-1); } /* done */ return(0); } /* function: BuildStatCostsTopo() * ------------------------------ * Builds statistical cost arrays for topography mode. */ static void **BuildStatCostsTopo(float **wrappedphase, float **mag, float **unwrappedest, float **pwr, float **corr, short **rowweight, short **colweight, long nrow, long ncol, tileparamT *tileparams, outfileT *outfiles, paramT *params){ long row, col, iei, nrho, nominctablesize; long kperpdpsi, kpardpsi, sigsqshortmin; double a, re, dr, slantrange, nearrange, nominc0, dnominc; double nomincangle, nomincind, sinnomincangle, cosnomincangle, bperp; double baseline, baselineangle, lambda, lookangle; double dzlay, dzei, dzr0, dzrcrit, dzeimin, dphilaypeak, dzrhomax; double azdzfactor, dzeifactor, dzeiweight, dzlayfactor; double avgei, eicrit, layminei, laywidth, slope1, const1, slope2, const2; double rho, rho0, rhomin, drho, rhopow; double sigsqrho, sigsqrhoconst, sigsqei, sigsqlay; double glay, costscale, ambiguityheight, ztoshort, ztoshortsq; double nshortcycle, midrangeambight; float **ei, **dpsi, **avgdpsi, *dzrcrittable, **dzrhomaxtable; costT **costs, **rowcost, **colcost; signed char noshadow, nolayover; /* get memory and set cost array pointers */ costs=(costT **)Get2DRowColMem(nrow,ncol,sizeof(costT *),sizeof(costT)); rowcost=(costT **)costs; colcost=(costT **)&costs[nrow-1]; /* set up */ rho0=(params->rhosconst1)/(params->ncorrlooks)+(params->rhosconst2); rhomin=params->rhominfactor*rho0; rhopow=2*(params->cstd1)+(params->cstd2)*log(params->ncorrlooks) +(params->cstd3)*(params->ncorrlooks); sigsqshortmin=params->sigsqshortmin; kperpdpsi=params->kperpdpsi; kpardpsi=params->kpardpsi; dr=params->dr; nearrange=params->nearrange+dr*tileparams->firstcol; drho=params->drho; nrho=(long )floor((1-rhomin)/drho)+1; nshortcycle=params->nshortcycle; layminei=params->layminei; laywidth=params->laywidth; azdzfactor=params->azdzfactor; dzeifactor=params->dzeifactor; dzeiweight=params->dzeiweight; dzeimin=params->dzeimin; dzlayfactor=params->dzlayfactor; sigsqei=params->sigsqei; lambda=params->lambda; noshadow=!(params->shadow); a=params->orbitradius; re=params->earthradius; /* despeckle the interferogram intensity */ fprintf(sp2,"Despeckling intensity image\n"); ei=NULL; Despeckle(pwr,&ei,nrow,ncol); Free2DArray((void **)pwr,nrow); /* remove large-area average intensity */ fprintf(sp2,"Normalizing intensity\n"); RemoveMean(ei,nrow,ncol,params->krowei,params->kcolei); /* dump normalized, despeckled intensity */ if(strlen(outfiles->eifile)){ Write2DArray((void **)ei,outfiles->eifile,nrow,ncol,sizeof(float)); } /* compute some midswath parameters */ slantrange=nearrange+ncol/2*dr; sinnomincangle=sin(acos((a*a-slantrange*slantrange-re*re) /(2*slantrange*re))); lookangle=asin(re/a*sinnomincangle); /* see if we were passed bperp rather than baseline and baselineangle */ if(params->bperp){ if(params->bperp>0){ params->baselineangle=lookangle; }else{ params->baselineangle=lookangle+PI; } params->baseline=fabs(params->bperp); } /* the baseline should be halved if we are in single antenna transmit mode */ if(params->transmitmode==SINGLEANTTRANSMIT){ params->baseline/=2.0; } baseline=params->baseline; baselineangle=params->baselineangle; /* build lookup table for dzrcrit vs incidence angle */ dzrcrittable=BuildDZRCritLookupTable(&nominc0,&dnominc,&nominctablesize, tileparams,params); /* build lookup table for dzrhomax vs incidence angle */ dzrhomaxtable=BuildDZRhoMaxLookupTable(nominc0,dnominc,nominctablesize, rhomin,drho,nrho,params); /* set cost autoscale factor based on midswath parameters */ bperp=baseline*cos(lookangle-baselineangle); midrangeambight=fabs(lambda*slantrange*sinnomincangle/(2*bperp)); costscale=params->costscale*fabs(params->costscaleambight/midrangeambight); glay=-costscale*log(params->layconst); /* get memory for wrapped difference arrays */ dpsi=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float)); avgdpsi=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float)); /* build array of mean wrapped phase differences in range */ /* simple average of phase differences is biased, but mean phase */ /* differences usually near zero, so don't bother with complex average */ fprintf(sp2,"Building range cost arrays\n"); CalcWrappedRangeDiffs(dpsi,avgdpsi,wrappedphase,kperpdpsi,kpardpsi, nrow,ncol); /* build colcost array (range slopes) */ /* loop over range */ for(col=0;colsigsqlayfactor; /* interpolate scattering model parameters */ nomincind=(nomincangle-nominc0)/dnominc; dzrcrit=LinInterp1D(dzrcrittable,nomincind,nominctablesize); SolveEIModelParams(&slope1,&slope2,&const1,&const2,dzrcrit,dzr0, sinnomincangle,cosnomincangle,params); eicrit=(dzrcrit-const1)/slope1; dphilaypeak=params->dzlaypeak/ambiguityheight; /* loop over azimuth */ for(row=0;roweicrit){ dzei=(slope2*ei[row][col]+const2)*dzeifactor; }else{ dzei=(slope1*ei[row][col]+const1)*dzeifactor; } if(noshadow && dzeilayminei){ for(iei=0;ieieicrit){ dzlay+=slope2*ei[row][col+iei]+const2; }else{ dzlay+=slope1*ei[row][col+iei]+const1; } if(col+iei>ncol-2){ break; } } } if(dzlay){ dzlay=(dzlay+iei*(-2.0*dzr0))*dzlayfactor; } /* set maximum dz based on unbiased correlation and layover max */ if(rho>0){ dzrhomax=LinInterp2D(dzrhomaxtable,nomincind,(rho-rhomin)/drho, nominctablesize,nrho); if(dzrhomax0){ colcost[row][col].offset=nshortcycle* (dpsi[row][col]-0.5*(avgdpsi[row][col]+dphilaypeak)); }else{ colcost[row][col].offset=nshortcycle* (dpsi[row][col]-0.25*avgdpsi[row][col]-0.75*dphilaypeak); } colcost[row][col].sigsq=(sigsqrho+sigsqei+sigsqlay)*ztoshortsq /(costscale*colweight[row][col]); if(colcost[row][col].sigsqfloor(sqrt(colcost[row][col].laycost*colcost[row][col].sigsq))){ nolayover=FALSE; } } if(nolayover){ colcost[row][col].sigsq=(sigsqrho+sigsqei)*ztoshortsq /(costscale*colweight[row][col]); if(colcost[row][col].sigsq0){ colcost[row][col].offset=ztoshort* (ambiguityheight*(dpsi[row][col]-0.5*avgdpsi[row][col]) -0.5*dzeiweight*dzei); }else{ colcost[row][col].offset=ztoshort* (ambiguityheight*(dpsi[row][col]-0.25*avgdpsi[row][col]) -0.75*dzeiweight*dzei); } colcost[row][col].laycost=NOCOSTSHELF; colcost[row][col].dzmax=LARGESHORT; } /* shift PDF to account for flattening by coarse unwrapped estimate */ if(unwrappedest!=NULL){ colcost[row][col].offset+=(nshortcycle/TWOPI* (unwrappedest[row][col+1] -unwrappedest[row][col])); } } } } /* end of range gradient cost calculation */ /* reset layover constant for row (azimuth) costs */ glay+=(-costscale*log(azdzfactor)); /* build array of mean wrapped phase differences in azimuth */ /* biased, but not much, so don't bother with complex averaging */ fprintf(sp2,"Building azimuth cost arrays\n"); CalcWrappedAzDiffs(dpsi,avgdpsi,wrappedphase,kperpdpsi,kpardpsi, nrow,ncol); /* build rowcost array */ /* for the rowcost array, there is symmetry between positive and */ /* negative flows, so we average ei[][] and corr[][] values in azimuth */ /* loop over range */ for(col=0;colsigsqlayfactor; /* interpolate scattering model parameters */ nomincind=(nomincangle-nominc0)/dnominc; dzrcrit=LinInterp1D(dzrcrittable,nomincind,nominctablesize); SolveEIModelParams(&slope1,&slope2,&const1,&const2,dzrcrit,dzr0, sinnomincangle,cosnomincangle,params); eicrit=(dzrcrit-const1)/slope1; dphilaypeak=params->dzlaypeak/ambiguityheight; /* loop over azimuth */ for(row=0;rowlayminei){ for(iei=0;ieieicrit){ dzlay+=slope2*avgei+const2; }else{ dzlay+=slope1*avgei+const1; } if(col+iei>ncol-2){ break; } } } if(dzlay){ dzlay=(dzlay+iei*(-2.0*dzr0))*dzlayfactor; } /* set maximum dz based on correlation max and layover max */ if(rho>0){ dzrhomax=LinInterp2D(dzrhomaxtable,nomincind,(rho-rhomin)/drho, nominctablesize,nrho); if(dzrhomax0){ rowcost[row][col].offset=nshortcycle* (dpsi[row][col]-avgdpsi[row][col]); }else{ rowcost[row][col].offset=nshortcycle* (dpsi[row][col]-0.5*avgdpsi[row][col]); } nolayover=TRUE; if(dzlay){ rowcost[row][col].sigsq=(sigsqrho+sigsqei+sigsqlay)*ztoshortsq /(costscale*rowweight[row][col]); if(rowcost[row][col].sigsqfloor(sqrt(rowcost[row][col].laycost*rowcost[row][col].sigsq))){ nolayover=FALSE; } } if(nolayover){ rowcost[row][col].sigsq=(sigsqrho+sigsqei)*ztoshortsq /(costscale*rowweight[row][col]); if(rowcost[row][col].sigsqrhosconst1)/(params->ncorrlooks)+(params->rhosconst2); defocorrthresh=params->defothreshfactor*rho0; rhopow=2*(params->cstd1)+(params->cstd2)*log(params->ncorrlooks) +(params->cstd3)*(params->ncorrlooks); sigsqrhoconst=2.0/12.0; sigsqcorr=params->sigsqcorr; sigsqshortmin=params->sigsqshortmin; kperpdpsi=params->kperpdpsi; kpardpsi=params->kpardpsi; costscale=params->costscale; nshortcycle=params->nshortcycle; nshortcyclesq=nshortcycle*nshortcycle; glay=-costscale*log(params->defolayconst); defomax=(long )ceil(params->defomax*nshortcycle); /* get memory for wrapped difference arrays */ dpsi=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float)); avgdpsi=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float)); /* build array of mean wrapped phase differences in range */ /* simple average of phase differences is biased, but mean phase */ /* differences usually near zero, so don't bother with complex average */ fprintf(sp2,"Building range cost arrays\n"); CalcWrappedRangeDiffs(dpsi,avgdpsi,wrappedphase,kperpdpsi,kpardpsi, nrow,ncol); /* build colcost array (range slopes) */ for(col=0;col0){ colcost[row][col].offset=nshortcycle* (dpsi[row][col]-avgdpsi[row][col]); }else{ colcost[row][col].offset=nshortcycle* (dpsi[row][col]-0.5*avgdpsi[row][col]); } colcost[row][col].sigsq=sigsqrho/(costscale*colweight[row][col]); if(colcost[row][col].sigsq0){ rowcost[row][col].offset=nshortcycle* (dpsi[row][col]-avgdpsi[row][col]); }else{ rowcost[row][col].offset=nshortcycle* (dpsi[row][col]-0.5*avgdpsi[row][col]); } rowcost[row][col].sigsq=sigsqrho/(costscale*rowweight[row][col]); if(rowcost[row][col].sigsqrhosconst1)/(params->ncorrlooks)+(params->rhosconst2); defocorrthresh=params->defothreshfactor*rho0; rhopow=2*(params->cstd1)+(params->cstd2)*log(params->ncorrlooks) +(params->cstd3)*(params->ncorrlooks); sigsqrhoconst=2.0/12.0; sigsqcorr=params->sigsqcorr; sigsqshortmin=params->sigsqshortmin; kperpdpsi=params->kperpdpsi; kpardpsi=params->kpardpsi; costscale=params->costscale; nshortcycle=params->nshortcycle; nshortcyclesq=nshortcycle*nshortcycle; /* get memory for wrapped difference arrays */ dpsi=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float)); avgdpsi=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float)); /* build array of mean wrapped phase differences in range */ /* simple average of phase differences is biased, but mean phase */ /* differences usually near zero, so don't bother with complex average */ fprintf(sp2,"Building range cost arrays\n"); CalcWrappedRangeDiffs(dpsi,avgdpsi,wrappedphase,kperpdpsi,kpardpsi, nrow,ncol); /* build colcost array (range slopes) */ for(col=0;col0){ colcost[row][col].offset=nshortcycle* (dpsi[row][col]-avgdpsi[row][col]); }else{ colcost[row][col].offset=nshortcycle* (dpsi[row][col]-0.5*avgdpsi[row][col]); } colcost[row][col].sigsq=sigsqrho/(costscale*colweight[row][col]); if(colcost[row][col].sigsq0){ rowcost[row][col].offset=nshortcycle* (dpsi[row][col]-avgdpsi[row][col]); }else{ rowcost[row][col].offset=nshortcycle* (dpsi[row][col]-0.5*avgdpsi[row][col]); } rowcost[row][col].sigsq=sigsqrho/(costscale*rowweight[row][col]); if(rowcost[row][col].sigsqlaycost=0; costptr->offset=LARGESHORT/2; costptr->dzmax=LARGESHORT; costptr->sigsq=LARGESHORT; } /* function: MaskSmoothCost() * -------------------------- * Set values of smoothcostT structure pointed to by input pointer to give zero * cost, as for arcs next to masked pixels. */ static void MaskSmoothCost(smoothcostT *smoothcostptr){ /* set to special values */ smoothcostptr->offset=LARGESHORT/2; smoothcostptr->sigsq=LARGESHORT; } /* function: MaskPrespecifiedArcCosts() * ------------------------------------ * Loop over grid arcs and set costs to null if corresponding weights * are null. */ static int MaskPrespecifiedArcCosts(void **costsptr, short **weights, long nrow, long ncol, paramT *params){ long row, col, maxcol; costT **costs; smoothcostT **smoothcosts; /* set up pointers */ costs=NULL; smoothcosts=NULL; if(params->costmode==TOPO || params->costmode==DEFO){ costs=(costT **)costsptr; }else if(params->costmode==SMOOTH){ smoothcosts=(smoothcostT **)costsptr; }else{ fprintf(sp0,"illegal cost mode in MaskPrespecifiedArcCosts()\n"); exit(ABNORMAL_EXIT); } /* loop over all arcs */ for(row=0;row<2*nrow-1;row++){ if(rowampfile)){ ReadIntensity(&pwr,&pwr1,&pwr2,infiles,linelen,nlines,params,tileparams); }else{ if(params->costmode==TOPO){ fprintf(sp1,"No brightness file specified. "); fprintf(sp1,"Using interferogram magnitude as intensity\n"); } pwr=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float)); for(row=0;rowcorrfile)){ ReadCorrelation(&corr,infiles,linelen,nlines,tileparams); }else if(pwr1!=NULL && pwr2!=NULL && params->havemagnitude){ /* generate the correlation info from the interferogram and amplitude */ fprintf(sp1,"Generating correlation from interferogram and intensity\n"); /* get the correct number of looks, and make sure its odd */ krowcorr=1+2*floor(params->ncorrlooksaz/(double )params->nlooksaz/2); kcolcorr=1+2*floor(params->ncorrlooksrange/(double )params->nlooksrange/2); /* calculate equivalent number of independent looks */ params->ncorrlooks=(kcolcorr*(params->dr/params->rangeres)) *(krowcorr*(params->da/params->azres))*params->nlooksother; fprintf(sp1," (%.1f equivalent independent looks)\n", params->ncorrlooks); /* get real and imaginary parts of interferogram */ realcomp=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float)); imagcomp=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float)); for(row=0;rowdefaultcorr); rho0=(params->rhosconst1)/(params->ncorrlooks)+(params->rhosconst2); rhomin=params->rhominfactor*rho0; if(params->defaultcorr>rhomin){ biaseddefaultcorr=params->defaultcorr; }else{ biaseddefaultcorr=0.0; } for(row=0;rowrawcorrdumpfile)){ Write2DArray((void **)corr,outfiles->rawcorrdumpfile, nrow,ncol,sizeof(float)); } /* check correlation data validity */ iclipped=0; for(row=0;row1.0){ if(corr[row][col]>1.001){ iclipped++; /* don't warn for minor numerical errors */ } corr[row][col]=1.0; }else if(corr[row][col]<0.0){ if(corr[row][col]<-0.001){ iclipped++; /* don't warn for minor numerical errors */ } corr[row][col]=0.0; } } } if(iclipped){ fflush(NULL); fprintf(sp0,"WARNING: %ld illegal correlation values clipped to [0,1]\n", iclipped); } /* dump correlation data if necessary */ if(strlen(outfiles->corrdumpfile)){ Write2DArray((void **)corr,outfiles->corrdumpfile, nrow,ncol,sizeof(float)); } /* free memory and set output pointers */ if(pwr1!=NULL){ Free2DArray((void **)pwr1,nrow); } if(pwr2!=NULL){ Free2DArray((void **)pwr2,nrow); } if(params->costmode==DEFO && pwr!=NULL){ Free2DArray((void **)pwr,nrow); pwr=NULL; } *pwrptr=pwr; *corrptr=corr; /* done */ return(0); } /* function: RemoveMean() * ------------------------- * Divides intensity by average over sliding window. */ static int RemoveMean(float **ei, long nrow, long ncol, long krowei, long kcolei){ float **avgei, **padei; long row, col; /* make sure krowei, kcolei are odd */ if(!(krowei % 2)){ krowei++; } if(!(kcolei % 2)){ kcolei++; } /* get memory */ avgei=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float)); /* pad ei in new array */ padei=MirrorPad(ei,nrow,ncol,(krowei-1)/2,(kcolei-1)/2); if(padei==ei){ fflush(NULL); fprintf(sp0,"Intensity-normalization averaging box too large " "for input array size\nAbort\n"); exit(ABNORMAL_EXIT); } /* calculate average ei by using sliding window */ BoxCarAvg(avgei,padei,nrow,ncol,krowei,kcolei); /* divide ei by avgei */ for(row=0;roworbitradius; re=params->earthradius; slantrange=params->nearrange+params->dr*tileparams->firstcol; nominc0=acos((a*a-slantrange*slantrange-re*re)/(2*slantrange*re)); slantrange+=params->dr*tileparams->ncol; nomincmax=acos((a*a-slantrange*slantrange-re*re)/(2*slantrange*re)); if(!IsFinite(nominc0) || !IsFinite(nomincmax)){ fflush(NULL); fprintf(sp0,"Geometry error detected. " "Check altitude, near range, and earth radius parameters\n" "Abort\n"); exit(ABNORMAL_EXIT); } /* build lookup table */ dnominc=params->dnomincangle; tablesize=(long )floor((nomincmax-nominc0)/dnominc)+1; dzrcrittable=MAlloc(tablesize*sizeof(float)); nominc=nominc0; for(k=0;kthreshold); nominc+=dnominc; if(nominc>PI/2.0){ nominc-=dnominc; } } /* set return variables */ (*nominc0ptr)=nominc; (*dnomincptr)=dnominc; (*tablesizeptr)=tablesize; return(dzrcrittable); } /* function: SolveDZRCrit() * ------------------------ * Numerically solve for the transition point of the linearized scattering * model. */ static double SolveDZRCrit(double sinnomincangle, double cosnomincangle, paramT *params, double threshold){ double residual, thetai, kds, n, dr, dzr, dx; double costhetai, cos2thetai, step; double dzrcritfactor, diffuse, specular; long i; /* get parameters */ kds=params->kds; n=params->specularexp; dr=params->dr; dzrcritfactor=params->dzrcritfactor; /* solve for critical incidence angle */ thetai=PI/4; step=PI/4-1e-6; i=0; while(TRUE){ if((cos2thetai=cos(2*thetai))<0){ cos2thetai=0; } diffuse=dzrcritfactor*kds*cos(thetai); specular=pow(cos2thetai,n); if(fabs(residual=diffuse-specular)MAXITERATION){ fflush(NULL); fprintf(sp0,"Couldn't find critical incidence angle "); fprintf(sp0,"(check scattering parameters)\nAbort\n"); exit(ABNORMAL_EXIT); } } /* solve for critical height change */ costhetai=cos(thetai); dzr=params->initdzr; step=dzr+dr*cosnomincangle-1e-2; i=0; while(TRUE){ dx=(dr+dzr*cosnomincangle)/sinnomincangle; if(fabs(residual=costhetai-(dzr*sinnomincangle+dx*cosnomincangle) /sqrt(dzr*dzr+dx*dx)) MAXITERATION){ fflush(NULL); fprintf(sp0,"Couldn't find critical slope "); fprintf(sp0,"(check geometry parameters)\nAbort\n"); exit(ABNORMAL_EXIT); } } } /* function: SolveEIModelParams() * ------------------------------ * Calculates parameters for linearized model of EI vs. range slope * relationship. */ int SolveEIModelParams(double *slope1ptr, double *slope2ptr, double *const1ptr, double *const2ptr, double dzrcrit, double dzr0, double sinnomincangle, double cosnomincangle, paramT *params){ double slope1, slope2, const1, const2, sloperatio; double dzr3, ei3; /* set up */ sloperatio=params->kds*params->sloperatiofactor; /* find normalized intensity at 15(dzrcrit-dzr0)+dzr0 */ dzr3=15.0*(dzrcrit-dzr0)+dzr0; ei3=EIofDZR(dzr3,sinnomincangle,cosnomincangle,params) /EIofDZR(0,sinnomincangle,cosnomincangle,params); /* calculate parameters */ const1=dzr0; slope2=(sloperatio*(dzrcrit-const1)-dzrcrit+dzr3)/ei3; slope1=slope2/sloperatio; const2=dzr3-slope2*ei3; /* set return values */ *slope1ptr=slope1; *slope2ptr=slope2; *const1ptr=const1; *const2ptr=const2; return(0); } /* function: EIofDZR() * ------------------- * Calculates expected value of intensity with arbitrary units for given * parameters. Assumes azimuth slope is zero. */ static double EIofDZR(double dzr, double sinnomincangle, double cosnomincangle, paramT *params){ double dr, da, dx, kds, n, dzr0, projarea; double costhetai, cos2thetai, sigma0; dr=params->dr; da=params->da; dx=dr/sinnomincangle+dzr*cosnomincangle/sinnomincangle; kds=params->kds; n=params->specularexp; dzr0=-dr*cosnomincangle; projarea=da*fabs((dzr-dzr0)/sinnomincangle); costhetai=projarea/sqrt(dzr*dzr*da*da + da*da*dx*dx); if(costhetai>SQRTHALF){ cos2thetai=2*costhetai*costhetai-1; sigma0=kds*costhetai+pow(cos2thetai,n); }else{ sigma0=kds*costhetai; } return(sigma0*projarea); } /* function: BuildDZRhoMaxLookupTable() * ------------------------------------ * Builds a 2-D lookup table of dzrhomax values vs nominal incidence angle * (rad) and correlation. */ static float **BuildDZRhoMaxLookupTable(double nominc0, double dnominc, long nominctablesize, double rhomin, double drho, long nrho, paramT *params){ long krho, knominc; double nominc, rho; float **dzrhomaxtable; dzrhomaxtable=(float **)Get2DMem(nominctablesize,nrho, sizeof(float *),sizeof(float)); nominc=nominc0; for(knominc=0;knomincthreshold); rho+=drho; } nominc+=dnominc; } return(dzrhomaxtable); } /* function: CalcDZRhoMax() * ------------------------ * Calculates the maximum slope (in range) for the given unbiased correlation * using spatial decorrelation as an upper limit (Zebker & Villasenor, * 1992). */ static double CalcDZRhoMax(double rho, double nominc, paramT *params, double threshold){ long i; double dx, dr, dz, dzstep, rhos, sintheta, costheta, numerator; double a, re, bperp, slantrange, lookangle; double costhetairsq, rhosfactor, residual; /* set up */ i=0; dr=params->dr; costheta=cos(nominc); sintheta=sin(nominc); dzstep=params->initdzstep; a=params->orbitradius; re=params->earthradius; lookangle=asin(re/a*sintheta); bperp=params->baseline*cos(lookangle-params->baselineangle); slantrange=sqrt(a*a+re*re-2*a*re*cos(nominc-lookangle)); rhosfactor=2.0*fabs(bperp)*(params->rangeres)/((params->lambda)*slantrange); /* take care of the extremes */ if(rho>=1.0){ return(-dr*costheta); }else if(rho<=0){ return(LARGEFLOAT); } /* start with slope for unity correlation, step slope upwards */ dz=-dr*costheta; rhos=1.0; while(rhos>rho){ dz+=dzstep; dx=(dr+dz*costheta)/sintheta; numerator=dz*sintheta+dx*costheta; costhetairsq=numerator*numerator/(dz*dz+dx*dx); rhos=1-rhosfactor*sqrt(costhetairsq/(1-costhetairsq)); if(rhos<0){ rhos=0; } if(dz>BIGGESTDZRHOMAX){ return(BIGGESTDZRHOMAX); } } /* now iteratively decrease step size and narrow in on correct slope */ while(fabs(residual=rhos-rho)>threshold*rho){ dzstep/=2.0; if(residual<0){ dz-=dzstep; }else{ dz+=dzstep; } dx=(dr+dz*costheta)/sintheta; numerator=dz*sintheta+dx*costheta; costhetairsq=numerator*numerator/(dz*dz+dx*dx); rhos=1-rhosfactor*sqrt(costhetairsq/(1-costhetairsq)); if(rhos<0){ rhos=0; } if(++i>MAXITERATION){ fflush(NULL); fprintf(sp0,"Couldn't find slope for correlation of %f\n",rho); fprintf(sp0,"(check geometry and spatial decorrelation parameters)\n"); fprintf(sp0,"Abort\n"); exit(ABNORMAL_EXIT); } } return(dz); } /* function: CalcCostTopo() * ------------------------ * Calculates topography arc distance given an array of cost data structures. */ void CalcCostTopo(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr){ long idz1, idz2pos, idz2neg, cost1, nflowsq, poscost, negcost; long nshortcycle, layfalloffconst; long offset, sigsq, laycost, dzmax; costT *cost; /* get arc info */ cost=&((costT **)(costs))[arcrow][arccol]; offset=cost->offset; sigsq=cost->sigsq; dzmax=cost->dzmax; laycost=cost->laycost; /* just return 0 if we have zero cost arc */ if(sigsq==LARGESHORT){ (*poscostptr)=0; (*negcostptr)=0; return; } /* compute argument to cost function */ nshortcycle=params->nshortcycle; layfalloffconst=params->layfalloffconst; if(arcrowdzmax){ idz1-=dzmax; cost1=(idz1*idz1)/(layfalloffconst*sigsq)+laycost; }else{ cost1=(idz1*idz1)/sigsq; if(laycost!=NOCOSTSHELF && idz1>0 && cost1>laycost){ cost1=laycost; } } /* calculate positive cost increment */ if(idz2pos>dzmax){ idz2pos-=dzmax; poscost=(idz2pos*idz2pos)/(layfalloffconst*sigsq) +laycost-cost1; }else{ poscost=(idz2pos*idz2pos)/sigsq; if(laycost!=NOCOSTSHELF && idz2pos>0 && poscost>laycost){ poscost=laycost-cost1; }else{ poscost-=cost1; } } /* calculate negative cost increment */ if(idz2neg>dzmax){ idz2neg-=dzmax; negcost=(idz2neg*idz2neg)/(layfalloffconst*sigsq) +laycost-cost1; }else{ negcost=(idz2neg*idz2neg)/sigsq; if(laycost!=NOCOSTSHELF && idz2neg>0 && negcost>laycost){ negcost=laycost-cost1; }else{ negcost-=cost1; } } /* scale costs for this nflow */ nflowsq=nflow*nflow; if(poscost>0){ *poscostptr=(long )ceil((double )poscost/nflowsq); }else{ *poscostptr=(long )floor((double )poscost/nflowsq); } if(negcost>0){ *negcostptr=(long )ceil((double )negcost/nflowsq); }else{ *negcostptr=(long )floor((double )negcost/nflowsq); } /* done */ return; } /* function: CalcCostDefo() * ------------------------ * Calculates deformation arc distance given an array of cost data structures. */ void CalcCostDefo(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr){ long idz1, idz2pos, idz2neg, cost1, nflowsq, poscost, negcost; long nshortcycle, layfalloffconst; costT *cost; /* get arc info */ cost=&((costT **)(costs))[arcrow][arccol]; /* just return 0 if we have zero cost arc */ if(cost->sigsq==LARGESHORT){ (*poscostptr)=0; (*negcostptr)=0; return; } /* compute argument to cost function */ nshortcycle=params->nshortcycle; layfalloffconst=params->layfalloffconst; idz1=labs(flow*nshortcycle+cost->offset); idz2pos=labs((flow+nflow)*nshortcycle+cost->offset); idz2neg=labs((flow-nflow)*nshortcycle+cost->offset); /* calculate cost1 */ if(idz1>cost->dzmax){ idz1-=cost->dzmax; cost1=(idz1*idz1)/(layfalloffconst*(cost->sigsq))+cost->laycost; }else{ cost1=(idz1*idz1)/cost->sigsq; if(cost->laycost!=NOCOSTSHELF && cost1>cost->laycost){ cost1=cost->laycost; } } /* calculate positive cost increment */ if(idz2pos>cost->dzmax){ idz2pos-=cost->dzmax; poscost=(idz2pos*idz2pos)/(layfalloffconst*(cost->sigsq)) +cost->laycost-cost1; }else{ poscost=(idz2pos*idz2pos)/cost->sigsq; if(cost->laycost!=NOCOSTSHELF && poscost>cost->laycost){ poscost=cost->laycost-cost1; }else{ poscost-=cost1; } } /* calculate negative cost increment */ if(idz2neg>cost->dzmax){ idz2neg-=cost->dzmax; negcost=(idz2neg*idz2neg)/(layfalloffconst*(cost->sigsq)) +cost->laycost-cost1; }else{ negcost=(idz2neg*idz2neg)/cost->sigsq; if(cost->laycost!=NOCOSTSHELF && negcost>cost->laycost){ negcost=cost->laycost-cost1; }else{ negcost-=cost1; } } /* scale costs for this nflow */ nflowsq=nflow*nflow; if(poscost>0){ *poscostptr=(long )ceil((double )poscost/nflowsq); }else{ *poscostptr=(long )floor((double )poscost/nflowsq); } if(negcost>0){ *negcostptr=(long )ceil((double )negcost/nflowsq); }else{ *negcostptr=(long )floor((double )negcost/nflowsq); } /* done */ return; } /* function: CalcCostSmooth() * -------------------------- * Calculates smooth-solution arc distance given an array of smoothcost * data structures. */ void CalcCostSmooth(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr){ long idz1, idz2pos, idz2neg, cost1, nflowsq, poscost, negcost; long nshortcycle; smoothcostT *cost; /* get arc info */ cost=&((smoothcostT **)(costs))[arcrow][arccol]; /* just return 0 if we have zero cost arc */ if(cost->sigsq==LARGESHORT){ (*poscostptr)=0; (*negcostptr)=0; return; } /* compute argument to cost function */ nshortcycle=params->nshortcycle; idz1=labs(flow*nshortcycle+cost->offset); idz2pos=labs((flow+nflow)*nshortcycle+cost->offset); idz2neg=labs((flow-nflow)*nshortcycle+cost->offset); /* calculate cost1 */ cost1=(idz1*idz1)/cost->sigsq; /* calculate positive cost increment */ poscost=(idz2pos*idz2pos)/cost->sigsq-cost1; /* calculate negative cost increment */ negcost=(idz2neg*idz2neg)/cost->sigsq-cost1; /* scale costs for this nflow */ nflowsq=nflow*nflow; if(poscost>0){ *poscostptr=(long )ceil((double )poscost/nflowsq); }else{ *poscostptr=(long )floor((double )poscost/nflowsq); } if(negcost>0){ *negcostptr=(long )ceil((double )negcost/nflowsq); }else{ *negcostptr=(long )floor((double )negcost/nflowsq); } /* done */ return; } /* function: CalcCostL0() * ---------------------- * Calculates the L0 arc distance given an array of short integer weights. */ void CalcCostL0(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr){ /* L0-norm */ if(flow){ if(flow+nflow){ *poscostptr=0; }else{ *poscostptr=-((short **)costs)[arcrow][arccol]; } if(flow-nflow){ *negcostptr=0; }else{ *negcostptr=-((short **)costs)[arcrow][arccol]; } }else{ *poscostptr=((short **)costs)[arcrow][arccol]; *negcostptr=((short **)costs)[arcrow][arccol]; } /* done */ return; } /* function: CalcCostL1() * ---------------------- * Calculates the L1 arc distance given an array of short integer weights. */ void CalcCostL1(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr){ /* L1-norm */ *poscostptr=((short **)costs)[arcrow][arccol]*(labs(flow+nflow)-labs(flow)); *negcostptr=((short **)costs)[arcrow][arccol]*(labs(flow-nflow)-labs(flow)); /* done */ return; } /* function: CalcCostL2() * ---------------------- * Calculates the L2 arc distance given an array of short integer weights. */ void CalcCostL2(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr){ long flow2, flowsq; /* L2-norm */ flowsq=flow*flow; flow2=flow+nflow; *poscostptr=((short **)costs)[arcrow][arccol]*(flow2*flow2-flowsq); flow2=flow-nflow; *negcostptr=((short **)costs)[arcrow][arccol]*(flow2*flow2-flowsq); /* done */ return; } /* function: CalcCostLP() * ---------------------- * Calculates the Lp arc distance given an array of short integer weights. */ void CalcCostLP(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr){ double p; short flow2; /* Lp-norm */ flow2=flow+nflow; p=params->p; *poscostptr=LRound(((short **)costs)[arcrow][arccol]* (pow(labs(flow2),p)-pow(labs(flow),p))); flow2=flow-nflow; *negcostptr=LRound(((short **)costs)[arcrow][arccol]* (pow(labs(flow2),p)-pow(labs(flow),p))); /* done */ return; } /* function: CalcCostL0BiDir() * --------------------------- * Calculates the L0 arc cost given an array of bidirectional cost weights. */ void CalcCostL0BiDir(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr){ long newflow, cost0; /* L0-norm */ if(flow>0){ cost0=((bidircostT **)costs)[arcrow][arccol].posweight; }else if(flow<0){ cost0=((bidircostT **)costs)[arcrow][arccol].negweight; }else{ cost0=0; } newflow=flow+nflow; if(newflow>0){ *poscostptr=((bidircostT **)costs)[arcrow][arccol].posweight-cost0; }else if(newflow<0){ *poscostptr=((bidircostT **)costs)[arcrow][arccol].negweight-cost0; }else{ *poscostptr=-cost0; } newflow=flow-nflow; if(newflow>0){ *negcostptr=((bidircostT **)costs)[arcrow][arccol].posweight-cost0; }else if(newflow<0){ *negcostptr=((bidircostT **)costs)[arcrow][arccol].negweight-cost0; }else{ *negcostptr=-cost0; } /* done */ return; } /* function: CalcCostL1BiDir() * --------------------------- * Calculates the L1 arc cost given an array of bidirectional cost weights. */ void CalcCostL1BiDir(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr){ long newflow, cost0; /* L1-norm */ if(flow>0){ cost0=((bidircostT **)costs)[arcrow][arccol].posweight*flow; }else{ cost0=-((bidircostT **)costs)[arcrow][arccol].negweight*flow; } newflow=flow+nflow; if(newflow>0){ *poscostptr=(((bidircostT **)costs)[arcrow][arccol].posweight*newflow -cost0); }else{ *poscostptr=(-((bidircostT **)costs)[arcrow][arccol].negweight*newflow -cost0); } newflow=flow-nflow; if(newflow>0){ *negcostptr=(((bidircostT **)costs)[arcrow][arccol].posweight*newflow -cost0); }else{ *negcostptr=(-((bidircostT **)costs)[arcrow][arccol].negweight*newflow -cost0); } /* done */ return; } /* function: CalcCostL2BiDir() * --------------------------- * Calculates the L2 arc cost given an array of bidirectional cost weights. */ void CalcCostL2BiDir(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr){ long newflow, cost0; /* L2-norm */ if(flow>0){ cost0=((bidircostT **)costs)[arcrow][arccol].posweight*flow*flow; }else{ cost0=((bidircostT **)costs)[arcrow][arccol].negweight*flow*flow; } newflow=flow+nflow; if(newflow>0){ *poscostptr=(((bidircostT **)costs)[arcrow][arccol].posweight *newflow*newflow-cost0); }else{ *poscostptr=(((bidircostT **)costs)[arcrow][arccol].negweight *newflow*newflow-cost0); } newflow=flow-nflow; if(newflow>0){ *negcostptr=(((bidircostT **)costs)[arcrow][arccol].posweight *newflow*newflow-cost0); }else{ *negcostptr=(((bidircostT **)costs)[arcrow][arccol].negweight *newflow*newflow-cost0); } /* done */ return; } /* function: CalcCostLPBiDir() * --------------------------- * Calculates the Lp arc cost given an array of bidirectional cost weights. */ void CalcCostLPBiDir(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr){ long newflow; double p, cost0; /* Lp-norm */ p=params->p; if(flow>0){ cost0=((bidircostT **)costs)[arcrow][arccol].posweight*pow(flow,p); }else{ cost0=((bidircostT **)costs)[arcrow][arccol].negweight*pow(-flow,p); } newflow=flow+nflow; if(newflow>0){ *poscostptr=LRound(((bidircostT **)costs)[arcrow][arccol].posweight *pow(newflow,p)-cost0); }else{ *poscostptr=LRound(((bidircostT **)costs)[arcrow][arccol].negweight *pow(newflow,p)-cost0); } newflow=flow-nflow; if(newflow>0){ *negcostptr=LRound(((bidircostT **)costs)[arcrow][arccol].posweight *pow(newflow,p)-cost0); }else{ *negcostptr=LRound(((bidircostT **)costs)[arcrow][arccol].negweight *pow(newflow,p)-cost0); } /* done */ return; } /* function: CalcCostNonGrid() * --------------------------- * Calculates the arc cost given an array of long integer cost lookup tables. * * The cost array for each arc gives the cost for +/-flowmax units of * flow around the flow value with minimum cost, which is not * necessarily flow == 0. The offset between the flow value with * minimum cost and flow == 0 is given by arroffset = costarr[0]. * Positive flow values k for k = 1 to flowmax relative to this min * cost flow value are in costarr[k]. Negative flow values k relative * to the min cost flow from k = -1 to -flowmax costarr[flowmax-k]. * costarr[2*flowmax+1] contains a scaling factor for extrapolating * beyond the ends of the cost table, assuming quadratically (with an offset) * increasing cost (subject to rounding and scaling). * * As of summer 2019, the rationale for how seconeary costs are * extrapolated beyond the end of the table has been lost to time, but * the logic at least does give a self-consistent cost function that * is continuous at +/-flowmax and quadratically increases beyond, * albeit not necessarily with a starting slope that has an easily * intuitive basis. */ void CalcCostNonGrid(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr){ long xflow, flowmax, poscost, negcost, nflowsq, arroffset, sumsigsqinv; long abscost0; long *costarr; double c1; /* set up */ flowmax=params->scndryarcflowmax; costarr=((long ***)costs)[arcrow][arccol]; arroffset=costarr[0]; sumsigsqinv=costarr[2*flowmax+1]; /* return zero costs if this is a zero cost arc */ if(sumsigsqinv==ZEROCOSTARC){ *poscostptr=0; *negcostptr=0; return; } /* compute cost of current flow */ xflow=flow+arroffset; if(xflow>flowmax){ c1=costarr[flowmax]/(double )flowmax-sumsigsqinv*flowmax; abscost0=(sumsigsqinv*xflow+LRound(c1))*xflow; }else if(xflow<-flowmax){ c1=costarr[2*flowmax]/(double )flowmax-sumsigsqinv*flowmax; abscost0=(sumsigsqinv*xflow+LRound(c1))*xflow; }else{ if(xflow>0){ abscost0=costarr[xflow]; }else if(xflow<0){ abscost0=costarr[flowmax-xflow]; }else{ abscost0=0; } } /* compute costs of positive and negative flow increments */ xflow=flow+arroffset+nflow; if(xflow>flowmax){ c1=costarr[flowmax]/(double )flowmax-sumsigsqinv*flowmax; poscost=((sumsigsqinv*xflow+LRound(c1))*xflow)-abscost0; }else if(xflow<-flowmax){ c1=costarr[2*flowmax]/(double )flowmax-sumsigsqinv*flowmax; poscost=((sumsigsqinv*xflow+LRound(c1))*xflow)-abscost0; }else{ if(xflow>0){ poscost=costarr[xflow]-abscost0; }else if(xflow<0){ poscost=costarr[flowmax-xflow]-abscost0; }else{ poscost=-abscost0; } } xflow=flow+arroffset-nflow; if(xflow>flowmax){ c1=costarr[flowmax]/(double )flowmax-sumsigsqinv*flowmax; negcost=((sumsigsqinv*xflow+LRound(c1))*xflow)-abscost0; }else if(xflow<-flowmax){ c1=costarr[2*flowmax]/(double )flowmax-sumsigsqinv*flowmax; negcost=((sumsigsqinv*xflow+LRound(c1))*xflow)-abscost0; }else{ if(xflow>0){ negcost=costarr[xflow]-abscost0; }else if(xflow<0){ negcost=costarr[flowmax-xflow]-abscost0; }else{ negcost=-abscost0; } } /* scale for this flow increment and set output values */ nflowsq=nflow*nflow; if(poscost>0){ *poscostptr=(long )ceil((double )poscost/nflowsq); }else{ *poscostptr=(long )floor((double )poscost/nflowsq); } if(negcost>0){ *negcostptr=(long )ceil((double )negcost/nflowsq); }else{ *negcostptr=(long )floor((double )negcost/nflowsq); } /* done */ return; } /* function: EvalCostTopo() * ------------------------ * Calculates topography arc cost given an array of cost data structures. */ long EvalCostTopo(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params){ long idz1, cost1, dzmax; costT *cost; /* get arc info */ cost=&((costT **)(costs))[arcrow][arccol]; /* just return 0 if we have zero cost arc */ if(cost->sigsq==LARGESHORT){ return(0); } /* compute argument to cost function */ if(arcrownshortcycle)+cost->offset); dzmax=cost->dzmax; }else{ /* column cost: non-symmetric dz */ idz1=flows[arcrow][arccol]*(params->nshortcycle)+cost->offset; if((dzmax=cost->dzmax)<0){ idz1*=-1; dzmax*=-1; } } /* calculate and return cost */ if(idz1>dzmax){ idz1-=dzmax; cost1=(idz1*idz1)/((params->layfalloffconst)*(cost->sigsq))+cost->laycost; }else{ cost1=(idz1*idz1)/cost->sigsq; if(cost->laycost!=NOCOSTSHELF && idz1>0 && cost1>cost->laycost){ cost1=cost->laycost; } } return(cost1); } /* function: EvalCostDefo() * ------------------------ * Calculates deformation arc cost given an array of cost data structures. */ long EvalCostDefo(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params){ long idz1, cost1; costT *cost; /* get arc info */ cost=&((costT **)(costs))[arcrow][arccol]; /* just return 0 if we have zero cost arc */ if(cost->sigsq==LARGESHORT){ return(0); } /* compute argument to cost function */ idz1=labs(flows[arcrow][arccol]*(params->nshortcycle)+cost->offset); /* calculate and return cost */ if(idz1>cost->dzmax){ idz1-=cost->dzmax; cost1=(idz1*idz1)/((params->layfalloffconst)*(cost->sigsq))+cost->laycost; }else{ cost1=(idz1*idz1)/cost->sigsq; if(cost->laycost!=NOCOSTSHELF && cost1>cost->laycost){ cost1=cost->laycost; } } return(cost1); } /* function: EvalCostSmooth() * -------------------------- * Calculates smooth-solution arc cost given an array of * smoothcost data structures. */ long EvalCostSmooth(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params){ long idz1; smoothcostT *cost; /* get arc info */ cost=&((smoothcostT **)(costs))[arcrow][arccol]; /* just return 0 if we have zero cost arc */ if(cost->sigsq==LARGESHORT){ return(0); } /* compute argument to cost function */ idz1=labs(flows[arcrow][arccol]*(params->nshortcycle)+cost->offset); /* calculate and return cost */ return((idz1*idz1)/cost->sigsq); } /* function: EvalCostL0() * ---------------------- * Calculates the L0 arc cost given an array of cost data structures. */ long EvalCostL0(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params){ /* L0-norm */ if(flows[arcrow][arccol]){ return((long)((short **)costs)[arcrow][arccol]); }else{ return(0); } } /* function: EvalCostL1() * ---------------------- * Calculates the L1 arc cost given an array of cost data structures. */ long EvalCostL1(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params){ /* L1-norm */ return((long )((((short **)costs)[arcrow][arccol]) *labs(flows[arcrow][arccol]))); } /* function: EvalCostL2() * ---------------------- * Calculates the L2 arc cost given an array of cost data structures. */ long EvalCostL2(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params){ /* L2-norm */ return((long )((((short **)costs)[arcrow][arccol]) *(flows[arcrow][arccol]*flows[arcrow][arccol]))); } /* function: EvalCostLP() * ---------------------- * Calculates the Lp arc cost given an array of cost data structures. */ long EvalCostLP(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params){ /* Lp-norm */ return(LRound((((short **)costs)[arcrow][arccol]) * pow(labs(flows[arcrow][arccol]),params->p))); } /* function: EvalCostL0BiDir() * --------------------------- * Calculates the L0 arc cost given an array of bidirectional cost structures. */ long EvalCostL0BiDir(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params){ /* L0-norm */ if(flows[arcrow][arccol]>0){ return((long )((bidircostT **)costs)[arcrow][arccol].posweight); }else if(flows[arcrow][arccol]<0){ return((long )((bidircostT **)costs)[arcrow][arccol].negweight); }else{ return(0); } } /* function: EvalCostL1BiDir() * --------------------------- * Calculates the L1 arc cost given an array of bidirectional cost structures. */ long EvalCostL1BiDir(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params){ /* L1-norm */ if(flows[arcrow][arccol]>0){ return((long )((((bidircostT **)costs)[arcrow][arccol].posweight) *(flows[arcrow][arccol]))); }else{ return((long )((((bidircostT **)costs)[arcrow][arccol].negweight) *(-flows[arcrow][arccol]))); } } /* function: EvalCostL2BiDir() * --------------------------- * Calculates the L2 arc cost given an array of bidirectional cost structures. */ long EvalCostL2BiDir(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params){ /* L2-norm */ if(flows[arcrow][arccol]>0){ return((long )((((bidircostT **)costs)[arcrow][arccol].posweight) *(flows[arcrow][arccol]*flows[arcrow][arccol]))); }else{ return((long )((((bidircostT **)costs)[arcrow][arccol].negweight) *(flows[arcrow][arccol]*flows[arcrow][arccol]))); } } /* function: EvalCostLPBiDir() * --------------------------- * Calculates the Lp arc cost given an array of bidirectional cost structures. */ long EvalCostLPBiDir(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params){ /* Lp-norm */ if(flows[arcrow][arccol]>0){ return(LRound((((bidircostT **)costs)[arcrow][arccol].posweight) *pow(flows[arcrow][arccol],params->p))); }else{ return(LRound((((bidircostT **)costs)[arcrow][arccol].posweight) *pow(-flows[arcrow][arccol],params->p))); } } /* function: EvalCostNonGrid() * --------------------------- * Calculates the arc cost given an array of long integer cost lookup tables. */ long EvalCostNonGrid(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params){ long flow, xflow, flowmax, arroffset, sumsigsqinv; long *costarr; double c1; /* set up */ flow=flows[arcrow][arccol]; flowmax=params->scndryarcflowmax; costarr=((long ***)costs)[arcrow][arccol]; arroffset=costarr[0]; sumsigsqinv=costarr[2*flowmax+1]; /* return zero costs if this is a zero cost arc */ if(sumsigsqinv==ZEROCOSTARC){ return(0); } /* compute cost of current flow */ xflow=flow+arroffset; if(xflow>flowmax){ c1=costarr[flowmax]/(double )flowmax-sumsigsqinv*flowmax; return((sumsigsqinv*xflow+LRound(c1))*xflow); }else if(xflow<-flowmax){ c1=costarr[2*flowmax]/(double )flowmax-sumsigsqinv*flowmax; return((sumsigsqinv*xflow+LRound(c1))*xflow); }else{ if(xflow>0){ return(costarr[xflow]); }else if(xflow<0){ return(costarr[flowmax-xflow]); }else{ return(0); } } } /* function: CalcInitMaxFlow() * --------------------------- * Calculates the maximum flow magnitude to allow in the initialization * by examining the dzmax members of arc statistical cost data structures. */ static int CalcInitMaxFlow(paramT *params, void **costs, long nrow, long ncol){ long row, col, maxcol, initmaxflow, arcmaxflow; if(params->initmaxflow<=0){ if(params->costmode==NOSTATCOSTS){ params->initmaxflow=NOSTATINITMAXFLOW; }else{ if(params->costmode==TOPO || params->costmode==DEFO){ initmaxflow=0; for(row=0;row<2*nrow-1;row++){ if(rownshortcycle) +params->arcmaxflowconst); if(arcmaxflow>initmaxflow){ initmaxflow=arcmaxflow; } } } } params->initmaxflow=initmaxflow; }else{ params->initmaxflow=DEF_INITMAXFLOW; } } } return(0); } snaphu-v2.0.6/src/PaxHeader/Makefile000644 777777 777777 00000000043 14423062415 017125 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/src/Makefile000644 Ho)00000003067 14423062415 016365 0ustar00curtis000000 000000 # Makefile for statistical-cost network-flow algorithm for phase unwrapping # Curtis W. Chen # Copyright 2002,2017 Board of Trustees, Leland Stanford Jr. University # Specify your compiler (CC), whatever compiler flags (CFLAGS) you # need, and the directory (BINDIR) in which the produced binary should # be written. # # If you want to copy the man page and executable to a system directory, # specify the appropriate directories in the INSTALLDIR and MANDIR # variables and do 'make install' (you will probably need to be root). # # If you specify -D NO_CS2, the program will be compiled without the # CS2 MCF solver module. CC = cc OPTIMFLAGS = -O3 DEBUGFLAGS = -ggdb CFLAGS = $(OPTIMFLAGS) -Wall # -Wuninitialized -m64 -D NO_CS2 LIBS = -lm BINDIR = ../bin INSTALLDIR = /usr/local/bin MANDIR = /usr/local/man SNAPHU = $(BINDIR)/snaphu SNAPHUMAN = ../man/man1/snaphu.1 OBJS = snaphu_tile.o \ snaphu_solver.o \ snaphu_io.o \ snaphu_util.o \ snaphu_cost.o \ snaphu_cs2.o .PHONY: all all: $(SNAPHU) $(SNAPHU): snaphu.c $(OBJS) snaphu.h Makefile $(CC) $(CFLAGS) \ snaphu.c \ $(OBJS) \ -o $(SNAPHU) \ $(LIBS) .PHONY: gdebug gdebug: snaphu.c snaphu_tile.c snaphu_solver.c snaphu_io.c snaphu_util.c snaphu_cost.c snaphu_cs2.c snaphu.h $(CC) $(DEBUGFLAGS) snaphu.c snaphu_tile.c snaphu_solver.c snaphu_io.c snaphu_util.c snaphu_cost.c snaphu_cs2.c -o $(SNAPHU) $(LIBS) install: $(SNAPHU) cp $(SNAPHU) $(INSTALLDIR); cp $(SNAPHUMAN) $(MANDIR)/man1/ clean: @rm -f *.o Clean: @rm -f *.o *~ #*# clobber: @rm -f $(SNAPHU) # end of Makefile snaphu-v2.0.6/src/PaxHeader/snaphu_cs2.c000644 777777 777777 00000000043 14423062415 017676 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/src/snaphu_cs2.c000644 Ho)00000131027 14423062415 017134 0ustar00curtis000000 000000 /*********************************************************************** This code is derived from cs2 v3.7 Written by Andrew V. Goldberg and Boris Cherkassky Modifications for use in snaphu by Curtis W. Chen The cs2 code is used here with permission for strictly noncommerical use. The original cs2 source code can be downloaded from http://www.igsystems.com/cs2 The original cs2 copyright is stated as follows: COPYRIGHT C 1995 IG Systems, Inc. Permission to use for evaluation purposes is granted provided that proper acknowledgments are given. For a commercial licence, contact igsys@eclipse.net. This software comes with NO WARRANTY, expressed or implied. By way of example, but not limitation, we make no representations of warranties of merchantability or fitness for any particular purpose or that the use of the software components or documentation will not infringe any patents, copyrights, trademarks, or other rights. Copyright 2002 Board of Trustees, Leland Stanford Jr. University *************************************************************************/ /* min-cost flow */ /* successive approximation algorithm */ /* Copyright C IG Systems, igsys@eclipse.com */ /* any use except for evaluation purposes requires a licence */ /* parser changed to take input from passed data */ /* main() changed to callable function */ /* outputs parsed as flow */ /* functions made static */ /* MAX and MIN macros renamed GREATEROF and LESSEROF */ #ifndef NO_CS2 /************************************** constants & parameters ********/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "snaphu.h" /* for measuring time */ /* definitions of types: node & arc */ #define PRICE_MAX 1e30 #define BIGGEST_FLOW LARGESHORT #include "snaphu_cs2types.h" /* parser for getting DIMACS format input and transforming the data to the internal representation */ #include "snaphu_cs2parse.c" #define N_NODE( i ) ( ( (i) == NULL ) ? -1 : ( (i) - ndp + nmin ) ) #define N_ARC( a ) ( ( (a) == NULL )? -1 : (a) - arp ) #define UNFEASIBLE 2 #define ALLOCATION_FAULT 5 #define PRICE_OFL 6 /* parameters */ #define UPDT_FREQ 0.4 #define UPDT_FREQ_S 30 #define SCALE_DEFAULT 12.0 /* PRICE_OUT_START may not be less than 1 */ #define PRICE_OUT_START 1 #define CUT_OFF_POWER 0.44 #define CUT_OFF_COEF 1.5 #define CUT_OFF_POWER2 0.75 #define CUT_OFF_COEF2 1 #define CUT_OFF_GAP 0.8 #define CUT_OFF_MIN 12 #define CUT_OFF_INCREASE 4 /* #define TIME_FOR_PRICE_IN 5 */ #define TIME_FOR_PRICE_IN1 2 #define TIME_FOR_PRICE_IN2 4 #define TIME_FOR_PRICE_IN3 6 #define EMPTY_PUSH_COEF 1.0 /* #define MAX_CYCLES_CANCELLED 10 #define START_CYCLE_CANCEL 3 */ #define MAX_CYCLES_CANCELLED 0 #define START_CYCLE_CANCEL 100 /************************************************ shared macros *******/ #define GREATEROF( x, y ) ( ( (x) > (y) ) ? x : y ) #define LESSEROF( x, y ) ( ( (x) < (y) ) ? x : y ) #define OPEN( a ) ( a -> r_cap > 0 ) #define CLOSED( a ) ( a -> r_cap <= 0 ) #define REDUCED_COST( i, j, a ) ( (i->price) + dn*(a->cost) - (j->price) ) #define FEASIBLE( i, j, a ) ( (i->price) + dn*(a->cost) < (j->price) ) #define ADMISSIBLE( i, j, a ) ( OPEN(a) && FEASIBLE( i, j, a ) ) #define INCREASE_FLOW( i, j, a, df )\ {\ (i) -> excess -= df;\ (j) -> excess += df;\ (a) -> r_cap -= df;\ ((a) -> sister) -> r_cap += df;\ }\ /*---------------------------------- macros for excess queue */ #define RESET_EXCESS_Q \ {\ for ( ; excq_first != NULL; excq_first = excq_last )\ {\ excq_last = excq_first -> q_next;\ excq_first -> q_next = sentinel_node;\ }\ } #define OUT_OF_EXCESS_Q( i ) ( i -> q_next == sentinel_node ) #define EMPTY_EXCESS_Q ( excq_first == NULL ) #define NONEMPTY_EXCESS_Q ( excq_first != NULL ) #define INSERT_TO_EXCESS_Q( i )\ {\ if ( NONEMPTY_EXCESS_Q )\ excq_last -> q_next = i;\ else\ excq_first = i;\ \ i -> q_next = NULL;\ excq_last = i;\ } #define INSERT_TO_FRONT_EXCESS_Q( i )\ {\ if ( EMPTY_EXCESS_Q )\ excq_last = i;\ \ i -> q_next = excq_first;\ excq_first = i;\ } #define REMOVE_FROM_EXCESS_Q( i )\ {\ i = excq_first;\ excq_first = i -> q_next;\ i -> q_next = sentinel_node;\ } /*---------------------------------- excess queue as a stack */ #define EMPTY_STACKQ EMPTY_EXCESS_Q #define NONEMPTY_STACKQ NONEMPTY_EXCESS_Q #define RESET_STACKQ RESET_EXCESS_Q #define STACKQ_PUSH( i )\ {\ i -> q_next = excq_first;\ excq_first = i;\ } #define STACKQ_POP( i ) REMOVE_FROM_EXCESS_Q( i ) /*------------------------------------ macros for buckets */ node dnd, *dnode; #define RESET_BUCKET( b ) ( b -> p_first ) = dnode; #define INSERT_TO_BUCKET( i, b )\ {\ i -> b_next = ( b -> p_first );\ ( b -> p_first ) -> b_prev = i;\ ( b -> p_first ) = i;\ } #define NONEMPTY_BUCKET( b ) ( ( b -> p_first ) != dnode ) #define GET_FROM_BUCKET( i, b )\ {\ i = ( b -> p_first );\ ( b -> p_first ) = i -> b_next;\ } #define REMOVE_FROM_BUCKET( i, b )\ {\ if ( i == ( b -> p_first ) )\ ( b -> p_first ) = i -> b_next;\ else\ {\ ( i -> b_prev ) -> b_next = i -> b_next;\ ( i -> b_next ) -> b_prev = i -> b_prev;\ }\ } /*------------------------------------------- misc macros */ #define UPDATE_CUT_OFF \ {\ if (n_bad_pricein + n_bad_relabel == 0) \ {\ cut_off_factor = CUT_OFF_COEF2 * pow ( (double)n, CUT_OFF_POWER2 );\ cut_off_factor = GREATEROF ( cut_off_factor, CUT_OFF_MIN );\ cut_off = cut_off_factor * epsilon;\ cut_on = cut_off * CUT_OFF_GAP;\ }\ else\ {\ cut_off_factor *= CUT_OFF_INCREASE;\ cut_off = cut_off_factor * epsilon;\ cut_on = cut_off * CUT_OFF_GAP;\ }\ } #define TIME_FOR_UPDATE \ ( n_rel > n * UPDT_FREQ + n_src * UPDT_FREQ_S ) #define FOR_ALL_NODES_i for ( i = nodes; i != sentinel_node; i ++ ) #define FOR_ALL_ARCS_a_FROM_i \ for ( a = i -> first, a_stop = ( i + 1 ) -> suspended; a != a_stop; a ++ ) #define FOR_ALL_CURRENT_ARCS_a_FROM_i \ for ( a = i -> current, a_stop = ( i + 1 ) -> suspended; a != a_stop; a ++ ) #define WHITE 0 #define GREY 1 #define BLACK 2 arc *sa, *sb; long d_cap; #define EXCHANGE( a, b )\ {\ if ( a != b )\ {\ sa = a -> sister;\ sb = b -> sister;\ \ d_arc.r_cap = a -> r_cap;\ d_arc.cost = a -> cost;\ d_arc.head = a -> head;\ \ a -> r_cap = b -> r_cap;\ a -> cost = b -> cost;\ a -> head = b -> head;\ \ b -> r_cap = d_arc.r_cap;\ b -> cost = d_arc.cost;\ b -> head = d_arc.head;\ \ if ( a != sb )\ {\ b -> sister = sa;\ a -> sister = sb;\ sa -> sister = b;\ sb -> sister = a;\ }\ \ d_cap = cap[a-arcs];\ cap[a-arcs] = cap[b-arcs];\ cap[b-arcs] = d_cap;\ }\ } #define SUSPENDED( i, a ) ( a < i -> first ) long n_push =0, n_relabel =0, n_discharge =0, n_refine =0, n_update =0, n_scan =0, n_prscan =0, n_prscan1 =0, n_prscan2 =0, n_bad_pricein = 0, n_bad_relabel = 0, n_prefine =0; long n, /* number of nodes */ m; /* number of arcs */ short *cap; /* array containig capacities */ node *nodes, /* array of nodes */ *sentinel_node, /* next after last */ *excq_first, /* first node in push-queue */ *excq_last; /* last node in push-queue */ arc *arcs, /* array of arcs */ *sentinel_arc; /* next after last */ bucket *buckets, /* array of buckets */ *l_bucket; /* last bucket */ long linf; /* number of l_bucket + 1 */ double dlinf; /* copy of linf in double mode */ int time_for_price_in; double epsilon, /* optimality bound */ low_bound, /* lowest bound for epsilon */ price_min, /* lowest bound for prices */ f_scale, /* scale factor */ dn, /* cost multiplier - number of nodes + 1 */ mmc, /* multiplied maximal cost */ cut_off_factor, /* multiplier to produce cut_on and cut_off from n and epsilon */ cut_on, /* the bound for returning suspended arcs */ cut_off; /* the bound for suspending arcs */ double total_excess; /* total excess */ long n_rel, /* number of relabels from last price update */ n_ref, /* current number of refines */ n_src; /* current number of nodes with excess */ int flag_price = 0, /* if = 1 - signal to start price-in ASAP - maybe there is infeasibility because of susoended arcs */ flag_updt = 0; /* if = 1 - update failed some sources are unreachable: either the problem is unfeasible or you have to return suspended arcs */ long empty_push_bound; /* maximal possible number of zero pushes during one discharge */ int snc_max; /* maximal number of cycles cancelled during price refine */ arc d_arc; /* dummy arc - for technical reasons */ node d_node, /* dummy node - for technical reasons */ *dummy_node; /* the address of d_node */ /************************************************ abnormal finish **********/ static void err_end ( cc ) int cc; { fprintf ( sp0, "\ncs2 solver: Error %d ", cc ); if(cc==ALLOCATION_FAULT){ fprintf(sp0,"(allocation fault)\n"); }else if(cc==UNFEASIBLE){ fprintf(sp0,"(problem infeasible)\n"); }else if(cc==PRICE_OFL){ fprintf(sp0,"(price overflow)\n"); } /* 2 - problem is unfeasible 5 - allocation fault 6 - price overflow */ exit(ABNORMAL_EXIT); /* exit ( cc ); */ } /************************************************* initialization **********/ static void cs_init ( n_p, m_p, nodes_p, arcs_p, f_sc, max_c, cap_p ) long n_p, /* number of nodes */ m_p; /* number of arcs */ node *nodes_p; /* array of nodes */ arc *arcs_p; /* array of arcs */ long f_sc; /* scaling factor */ double max_c; /* maximal cost */ short *cap_p; /* array of capacities (changed to short by CWC) */ { node *i; /* current node */ /*arc *a; */ /* current arc */ bucket *b; /* current bucket */ n = n_p; nodes = nodes_p; sentinel_node = nodes + n; m = m_p; arcs = arcs_p; sentinel_arc = arcs + m; cap = cap_p; f_scale = f_sc; low_bound = 1.00001; dn = (double) n ; /* for ( a = arcs ; a != sentinel_arc ; a ++ ) a -> cost *= dn; */ mmc = max_c * dn; linf = n * f_scale + 2; dlinf = (double)linf; buckets = (bucket*) CAlloc ( linf, sizeof (bucket) ); if ( buckets == NULL ) err_end ( ALLOCATION_FAULT ); l_bucket = buckets + linf; dnode = &dnd; for ( b = buckets; b != l_bucket; b ++ ) RESET_BUCKET ( b ); epsilon = mmc; if ( epsilon < 1 ) epsilon = 1; price_min = - PRICE_MAX; FOR_ALL_NODES_i { i -> price = 0; i -> suspended = i -> first; i -> q_next = sentinel_node; } sentinel_node -> first = sentinel_node -> suspended = sentinel_arc; cut_off_factor = CUT_OFF_COEF * pow ( (double)n, CUT_OFF_POWER ); cut_off_factor = GREATEROF ( cut_off_factor, CUT_OFF_MIN ); n_ref = 0; flag_price = 0; dummy_node = &d_node; excq_first = NULL; empty_push_bound = n * EMPTY_PUSH_COEF; } /* end of initialization */ /********************************************** up_node_scan *************/ static void up_node_scan ( i ) node *i; /* node for scanning */ { node *j; /* opposite node */ arc *a, /* ( i, j ) */ *a_stop, /* first arc from the next node */ *ra; /* ( j, i ) */ bucket *b_old, /* old bucket contained j */ *b_new; /* new bucket for j */ long i_rank, j_rank, /* ranks of nodes */ j_new_rank; double rc, /* reduced cost of (j,i) */ dr; /* rank difference */ n_scan ++; i_rank = i -> rank; FOR_ALL_ARCS_a_FROM_i { ra = a -> sister; if ( OPEN ( ra ) ) { j = a -> head; j_rank = j -> rank; if ( j_rank > i_rank ) { if ( ( rc = REDUCED_COST ( j, i, ra ) ) < 0 ) j_new_rank = i_rank; else { dr = rc / epsilon; j_new_rank = ( dr < dlinf ) ? i_rank + (long)dr + 1 : linf; } if ( j_rank > j_new_rank ) { j -> rank = j_new_rank; j -> current = ra; if ( j_rank < linf ) { b_old = buckets + j_rank; REMOVE_FROM_BUCKET ( j, b_old ) } b_new = buckets + j_new_rank; INSERT_TO_BUCKET ( j, b_new ) } } } } /* end of scanning arcs */ i -> price -= i_rank * epsilon; i -> rank = -1; } /*************************************************** price_update *******/ static void price_update () { register node *i; double remain; /* total excess of unscanned nodes with positive excess */ bucket *b; /* current bucket */ double dp; /* amount to be subtracted from prices */ n_update ++; FOR_ALL_NODES_i { if ( i -> excess < 0 ) { INSERT_TO_BUCKET ( i, buckets ); i -> rank = 0; } else { i -> rank = linf; } } remain = total_excess; if ( remain < 0.5 ) return; /* main loop */ for ( b = buckets; b != l_bucket; b ++ ) { while ( NONEMPTY_BUCKET ( b ) ) { GET_FROM_BUCKET ( i, b ) up_node_scan ( i ); if ( i -> excess > 0 ) { remain -= (double)(i -> excess); if ( remain <= 0 ) break; } } /* end of scanning the bucket */ if ( remain <= 0 ) break; } /* end of scanning buckets */ if ( remain > 0.5 ) flag_updt = 1; /* finishup */ /* changing prices for nodes which were not scanned during main loop */ dp = ( b - buckets ) * epsilon; FOR_ALL_NODES_i { if ( i -> rank >= 0 ) { if ( i -> rank < linf ) REMOVE_FROM_BUCKET ( i, (buckets + i -> rank) ); if ( i -> price > price_min ) i -> price -= dp; } } } /* end of price_update */ /****************************************************** relabel *********/ static int relabel ( i ) register node *i; /* node for relabelling */ { register arc *a, /* current arc from i */ *a_stop, /* first arc from the next node */ *a_max; /* arc which provides maximum price */ register double p_max, /* current maximal price */ i_price, /* price of node i */ dp; /* current arc partial residual cost */ p_max = price_min; i_price = i -> price; for ( a = i -> current + 1, a_stop = ( i + 1 ) -> suspended; a != a_stop; a ++ ) { if ( OPEN ( a ) && ( ( dp = ( ( a -> head ) -> price ) - dn*( a -> cost ) ) > p_max ) ) { if ( i_price < dp ) { i -> current = a; return ( 1 ); } p_max = dp; a_max = a; } } /* 1/2 arcs are scanned */ for ( a = i -> first, a_stop = ( i -> current ) + 1; a != a_stop; a ++ ) { if ( OPEN ( a ) && ( ( dp = ( ( a -> head ) -> price ) - dn*( a -> cost ) ) > p_max ) ) { if ( i_price < dp ) { i -> current = a; return ( 1 ); } p_max = dp; a_max = a; } } /* 2/2 arcs are scanned */ /* finishup */ if ( p_max != price_min ) { i -> price = p_max - epsilon; i -> current = a_max; } else { /* node can't be relabelled */ if ( i -> suspended == i -> first ) { if ( i -> excess == 0 ) { i -> price = price_min; } else { if ( n_ref == 1 ) { err_end ( UNFEASIBLE ); } else { err_end ( PRICE_OFL ); } } } else /* node can't be relabelled because of suspended arcs */ { flag_price = 1; } } n_relabel ++; n_rel ++; return ( 0 ); } /* end of relabel */ /***************************************************** discharge *********/ static void discharge ( i ) register node *i; /* node to be discharged */ { register arc *a; /* an arc from i */ arc *b, /* an arc from j */ *ra; /* reversed arc (j,i) */ register node *j; /* head of a */ register long df; /* amoumt of flow to be pushed through a */ excess_t j_exc; /* former excess of j */ int empty_push; /* number of unsuccessful attempts to push flow out of i. If it is too big - it is time for global update */ n_discharge ++; empty_push = 0; a = i -> current; j = a -> head; if ( !ADMISSIBLE ( i, j, a ) ) { relabel ( i ); a = i -> current; j = a -> head; } while ( 1 ) { j_exc = j -> excess; if ( j_exc >= 0 ) { b = j -> current; if ( ADMISSIBLE ( j, b -> head, b ) || relabel ( j ) ) { /* exit from j exists */ df = LESSEROF ( i -> excess, a -> r_cap ); if (j_exc == 0) n_src++; INCREASE_FLOW ( i, j, a, df ) n_push ++; if ( OUT_OF_EXCESS_Q ( j ) ) { INSERT_TO_EXCESS_Q ( j ); } } else { /* push back */ ra = a -> sister; df = LESSEROF ( j -> excess, ra -> r_cap ); if ( df > 0 ) { INCREASE_FLOW ( j, i, ra, df ); if (j->excess == 0) n_src--; n_push ++; } if ( empty_push ++ >= empty_push_bound ) { flag_price = 1; return; } } } else /* j_exc < 0 */ { df = LESSEROF ( i -> excess, a -> r_cap ); INCREASE_FLOW ( i, j, a, df ) n_push ++; if ( j -> excess >= 0 ) { if ( j -> excess > 0 ) { n_src++; relabel ( j ); INSERT_TO_EXCESS_Q ( j ); } total_excess += j_exc; } else total_excess -= df; } if (i -> excess <= 0) n_src--; if ( i -> excess <= 0 || flag_price ) break; relabel ( i ); a = i -> current; j = a -> head; } i -> current = a; } /* end of discharge */ /***************************************************** price_in *******/ static int price_in () { node *i, /* current node */ *j; arc *a, /* current arc from i */ *a_stop, /* first arc from the next node */ *b, /* arc to be exchanged with suspended */ *ra, /* opposite to a */ *rb; /* opposite to b */ double rc; /* reduced cost */ int n_in_bad, /* number of priced_in arcs with negative reduced cost */ bad_found; /* if 1 we are at the second scan if 0 we are at the first scan */ excess_t i_exc, /* excess of i */ df; /* an amount to increase flow */ bad_found = 0; n_in_bad = 0; restart: FOR_ALL_NODES_i { for ( a = ( i -> first ) - 1, a_stop = ( i -> suspended ) - 1; a != a_stop; a -- ) { rc = REDUCED_COST ( i, a -> head, a ); if ( (rc < 0) && ( a -> r_cap > 0) ) { /* bad case */ if ( bad_found == 0 ) { bad_found = 1; UPDATE_CUT_OFF; goto restart; } df = a -> r_cap; INCREASE_FLOW ( i, a -> head, a, df ); ra = a -> sister; j = a -> head; b = -- ( i -> first ); EXCHANGE ( a, b ); if ( SUSPENDED ( j, ra ) ) { rb = -- ( j -> first ); EXCHANGE ( ra, rb ); } n_in_bad ++; } else if ( ( rc < cut_on ) && ( rc > -cut_on ) ) { b = -- ( i -> first ); EXCHANGE ( a, b ); } } } if ( n_in_bad != 0 ) { n_bad_pricein ++; /* recalculating excess queue */ total_excess = 0; n_src=0; RESET_EXCESS_Q; FOR_ALL_NODES_i { i -> current = i -> first; i_exc = i -> excess; if ( i_exc > 0 ) { /* i is a source */ total_excess += i_exc; n_src++; INSERT_TO_EXCESS_Q ( i ); } } INSERT_TO_EXCESS_Q ( dummy_node ); } if (time_for_price_in == TIME_FOR_PRICE_IN2) time_for_price_in = TIME_FOR_PRICE_IN3; if (time_for_price_in == TIME_FOR_PRICE_IN1) time_for_price_in = TIME_FOR_PRICE_IN2; return ( n_in_bad ); } /* end of price_in */ /************************************************** refine **************/ static void refine () { node *i; /* current node */ excess_t i_exc; /* excess of i */ /* long np, nr, ns; */ /* variables for additional print */ int pr_in_int; /* current number of updates between price_in */ /* np = n_push; nr = n_relabel; ns = n_scan; */ n_refine ++; n_ref ++; n_rel = 0; pr_in_int = 0; /* initialize */ total_excess = 0; n_src=0; RESET_EXCESS_Q time_for_price_in = TIME_FOR_PRICE_IN1; FOR_ALL_NODES_i { i -> current = i -> first; i_exc = i -> excess; if ( i_exc > 0 ) { /* i is a source */ total_excess += i_exc; n_src++; INSERT_TO_EXCESS_Q ( i ) } } if ( total_excess <= 0 ) return; /* main loop */ while ( 1 ) { if ( EMPTY_EXCESS_Q ) { if ( n_ref > PRICE_OUT_START ) { price_in (); } if ( EMPTY_EXCESS_Q ) break; } REMOVE_FROM_EXCESS_Q ( i ); /* push all excess out of i */ if ( i -> excess > 0 ) { discharge ( i ); if ( TIME_FOR_UPDATE || flag_price ) { if ( i -> excess > 0 ) { INSERT_TO_EXCESS_Q ( i ); } if ( flag_price && ( n_ref > PRICE_OUT_START ) ) { pr_in_int = 0; price_in (); flag_price = 0; } price_update(); while ( flag_updt ) { if ( n_ref == 1 ) { err_end ( UNFEASIBLE ); } else { flag_updt = 0; UPDATE_CUT_OFF; n_bad_relabel++; pr_in_int = 0; price_in (); price_update (); } } n_rel = 0; if ( n_ref > PRICE_OUT_START && (pr_in_int ++ > time_for_price_in) ) { pr_in_int = 0; price_in (); } } /* time for update */ } } /* end of main loop */ return; } /*----- end of refine */ /*************************************************** price_refine **********/ static int price_refine () { node *i, /* current node */ *j, /* opposite node */ *ir, /* nodes for passing over the negative cycle */ *is; arc *a, /* arc (i,j) */ *a_stop, /* first arc from the next node */ *ar; long bmax; /* number of farest nonempty bucket */ long i_rank, /* rank of node i */ j_rank, /* rank of node j */ j_new_rank; /* new rank of node j */ bucket *b, /* current bucket */ *b_old, /* old and new buckets of current node */ *b_new; double rc, /* reduced cost of a */ dr, /* ranks difference */ dp; int cc; /* return code: 1 - flow is epsilon optimal 0 - refine is needed */ long df; /* cycle capacity */ int nnc, /* number of negative cycles cancelled during one iteration */ snc; /* total number of negative cycle cancelled */ n_prefine ++; cc=1; snc=0; snc_max = ( n_ref >= START_CYCLE_CANCEL ) ? MAX_CYCLES_CANCELLED : 0; /* main loop */ while ( 1 ) { /* while negative cycle is found or eps-optimal solution is constructed */ nnc=0; FOR_ALL_NODES_i { i -> rank = 0; i -> inp = WHITE; i -> current = i -> first; } RESET_STACKQ FOR_ALL_NODES_i { if ( i -> inp == BLACK ) continue; i -> b_next = NULL; /* deapth first search */ while ( 1 ) { i -> inp = GREY; /* scanning arcs from node i starting from current */ FOR_ALL_CURRENT_ARCS_a_FROM_i { if ( OPEN ( a ) ) { j = a -> head; if ( REDUCED_COST ( i, j, a ) < 0 ) { if ( j -> inp == WHITE ) { /* fresh node - step forward */ i -> current = a; j -> b_next = i; i = j; a = j -> current; a_stop = (j+1) -> suspended; break; } if ( j -> inp == GREY ) { /* cycle detected */ cc = 0; nnc++; i -> current = a; is = ir = i; df = BIGGEST_FLOW; while ( 1 ) { ar = ir -> current; if ( ar -> r_cap <= df ) { df = ar -> r_cap; is = ir; } if ( ir == j ) break; ir = ir -> b_next; } ir = i; while ( 1 ) { ar = ir -> current; INCREASE_FLOW( ir, ar -> head, ar, df) if ( ir == j ) break; ir = ir -> b_next; } if ( is != i ) { for ( ir = i; ir != is; ir = ir -> b_next ) ir -> inp = WHITE; i = is; a = (is -> current) + 1; a_stop = (is+1) -> suspended; break; } } } /* if j-color is BLACK - continue search from i */ } } /* all arcs from i are scanned */ if ( a == a_stop ) { /* step back */ i -> inp = BLACK; n_prscan1++; j = i -> b_next; STACKQ_PUSH ( i ); if ( j == NULL ) break; i = j; i -> current ++; } } /* end of deapth first search */ } /* all nodes are scanned */ /* no negative cycle */ /* computing longest paths with eps-precision */ snc += nnc; if ( snc rank; FOR_ALL_ARCS_a_FROM_i { if ( OPEN ( a ) ) { j = a -> head; rc = REDUCED_COST ( i, j, a ); if ( rc < 0 ) /* admissible arc */ { dr = ( - rc - 0.5 ) / epsilon; if (( j_rank = dr + i_rank ) < dlinf ) { if ( j_rank > j -> rank ) j -> rank = j_rank; } } } } /* all arcs from i are scanned */ if ( i_rank > 0 ) { if ( i_rank > bmax ) bmax = i_rank; b = buckets + i_rank; INSERT_TO_BUCKET ( i, b ) } } /* end of while-cycle: all nodes are scanned - longest distancess are computed */ if ( bmax == 0 ) /* preflow is eps-optimal */ { break; } for ( b = buckets + bmax; b != buckets; b -- ) { i_rank = b - buckets; dp = (double)i_rank * epsilon; while ( NONEMPTY_BUCKET( b ) ) { GET_FROM_BUCKET ( i, b ); n_prscan++; FOR_ALL_ARCS_a_FROM_i { if ( OPEN ( a ) ) { j = a -> head; j_rank = j -> rank; if ( j_rank < i_rank ) { rc = REDUCED_COST ( i, j, a ); if ( rc < 0 ) j_new_rank = i_rank; else { dr = rc / epsilon; j_new_rank = ( dr < dlinf ) ? i_rank - ( (long)dr + 1 ) : 0; } if ( j_rank < j_new_rank ) { if ( cc == 1 ) { j -> rank = j_new_rank; if ( j_rank > 0 ) { b_old = buckets + j_rank; REMOVE_FROM_BUCKET ( j, b_old ) } b_new = buckets + j_new_rank; INSERT_TO_BUCKET ( j, b_new ) } else { df = a -> r_cap; INCREASE_FLOW ( i, j, a, df ) } } } } /* end if opened arc */ } /* all arcs are scanned */ i -> price -= dp; } /* end of while-cycle: the bucket is scanned */ } /* end of for-cycle: all buckets are scanned */ if ( cc == 0 ) break; } /* end of main loop */ /* finish: */ /* if refine needed - saturate non-epsilon-optimal arcs */ if ( cc == 0 ) { FOR_ALL_NODES_i { FOR_ALL_ARCS_a_FROM_i { if ( REDUCED_COST ( i, a -> head, a ) < -epsilon ) { if ( ( df = a -> r_cap ) > 0 ) { INCREASE_FLOW ( i, a -> head, a, df ) } } } } } /*neg_cyc();*/ return ( cc ); } /* end of price_refine */ void compute_prices () { node *i, /* current node */ *j; /* opposite node */ arc *a, /* arc (i,j) */ *a_stop; /* first arc from the next node */ long bmax; /* number of farest nonempty bucket */ long i_rank, /* rank of node i */ j_rank, /* rank of node j */ j_new_rank; /* new rank of node j */ bucket *b, /* current bucket */ *b_old, /* old and new buckets of current node */ *b_new; double rc, /* reduced cost of a */ dr, /* ranks difference */ dp; int cc; /* return code: 1 - flow is epsilon optimal 0 - refine is needed */ n_prefine ++; cc=1; /* main loop */ while ( 1 ) { /* while negative cycle is found or eps-optimal solution is constructed */ FOR_ALL_NODES_i { i -> rank = 0; i -> inp = WHITE; i -> current = i -> first; } RESET_STACKQ FOR_ALL_NODES_i { if ( i -> inp == BLACK ) continue; i -> b_next = NULL; /* deapth first search */ while ( 1 ) { i -> inp = GREY; /* scanning arcs from node i */ FOR_ALL_ARCS_a_FROM_i { if ( OPEN ( a ) ) { j = a -> head; if ( REDUCED_COST ( i, j, a ) < 0 ) { if ( j -> inp == WHITE ) { /* fresh node - step forward */ i -> current = a; j -> b_next = i; i = j; a = j -> current; a_stop = (j+1) -> suspended; break; } if ( j -> inp == GREY ) { /* cycle detected; should not happen */ cc = 0; } } /* if j-color is BLACK - continue search from i */ } } /* all arcs from i are scanned */ if ( a == a_stop ) { /* step back */ i -> inp = BLACK; n_prscan1++; j = i -> b_next; STACKQ_PUSH ( i ); if ( j == NULL ) break; i = j; i -> current ++; } } /* end of deapth first search */ } /* all nodes are scanned */ /* no negative cycle */ /* computing longest paths */ if ( cc == 0 ) break; bmax = 0; while ( NONEMPTY_STACKQ ) { n_prscan2++; STACKQ_POP ( i ); i_rank = i -> rank; FOR_ALL_ARCS_a_FROM_i { if ( OPEN ( a ) ) { j = a -> head; rc = REDUCED_COST ( i, j, a ); if ( rc < 0 ) /* admissible arc */ { dr = - rc; if (( j_rank = dr + i_rank ) < dlinf ) { if ( j_rank > j -> rank ) j -> rank = j_rank; } } } } /* all arcs from i are scanned */ if ( i_rank > 0 ) { if ( i_rank > bmax ) bmax = i_rank; b = buckets + i_rank; INSERT_TO_BUCKET ( i, b ) } } /* end of while-cycle: all nodes are scanned - longest distancess are computed */ if ( bmax == 0 ) { break; } for ( b = buckets + bmax; b != buckets; b -- ) { i_rank = b - buckets; dp = (double) i_rank; while ( NONEMPTY_BUCKET( b ) ) { GET_FROM_BUCKET ( i, b ) n_prscan++; FOR_ALL_ARCS_a_FROM_i { if ( OPEN ( a ) ) { j = a -> head; j_rank = j -> rank; if ( j_rank < i_rank ) { rc = REDUCED_COST ( i, j, a ); if ( rc < 0 ) j_new_rank = i_rank; else { dr = rc; j_new_rank = ( dr < dlinf ) ? i_rank - ( (long)dr + 1 ) : 0; } if ( j_rank < j_new_rank ) { if ( cc == 1 ) { j -> rank = j_new_rank; if ( j_rank > 0 ) { b_old = buckets + j_rank; REMOVE_FROM_BUCKET ( j, b_old ) } b_new = buckets + j_new_rank; INSERT_TO_BUCKET ( j, b_new ) } } } } /* end if opened arc */ } /* all arcs are scanned */ i -> price -= dp; } /* end of while-cycle: the bucket is scanned */ } /* end of for-cycle: all buckets are scanned */ if ( cc == 0 ) break; } /* end of main loop */ } /* end of compute_prices */ /***************************************************** price_out ************/ static void price_out () { node *i; /* current node */ arc *a, /* current arc from i */ *a_stop, /* first arc from the next node */ *b; /* arc to be exchanged with suspended */ double n_cut_off, /* -cut_off */ rc; /* reduced cost */ n_cut_off = - cut_off; FOR_ALL_NODES_i { FOR_ALL_ARCS_a_FROM_i { rc = REDUCED_COST ( i, a -> head, a ); if (((rc > cut_off) && (CLOSED(a -> sister))) || ((rc < n_cut_off) && (CLOSED(a))) ) { /* suspend the arc */ b = ( i -> first ) ++ ; EXCHANGE ( a, b ); } } } } /* end of price_out */ /**************************************************** update_epsilon *******/ /*----- decrease epsilon after epsilon-optimal flow is constructed */ static int update_epsilon() { if ( epsilon <= low_bound ) return ( 1 ); epsilon = ceil ( epsilon / f_scale ); cut_off = cut_off_factor * epsilon; cut_on = cut_off * CUT_OFF_GAP; return ( 0 ); } /*************************************************** finishup ***********/ static void finishup ( obj_ad ) double *obj_ad; /* objective */ { arc *a; /* current arc */ long na; /* corresponding position in capacity array */ double obj_internal;/* objective */ double cs; /* actual arc cost */ long flow; /* flow through an arc */ obj_internal = 0; for ( a = arcs, na = 0; a != sentinel_arc ; a ++, na ++ ) { /* cs = a -> cost / dn; */ cs = a -> cost; if ( cap[na] > 0 && ( flow = cap[na] - (a -> r_cap) ) != 0 ) obj_internal += cs * (double) flow; /* a -> cost = cs; */ } *obj_ad = obj_internal; } /*********************************************** init_solution ***********/ /* static void init_solution ( ) */ /* { */ /* arc *a; */ /* current arc (i,j) */ /* node *i, */ /* tail of a */ /* *j; */ /* head of a */ /* long df; */ /* ricidual capacity */ /* for ( a = arcs; a != sentinel_arc ; a ++ ) */ /* { */ /* if ( a -> r_cap > 0 && a -> cost < 0 ) */ /* { */ /* df = a -> r_cap; */ /* i = ( a -> sister ) -> head; */ /* j = a -> head; */ /* INCREASE_FLOW ( i, j, a, df ); */ /* } */ /* } */ /* } */ /* check complimentary slackness */ /* int check_cs () */ /* { */ /* node *i; */ /* arc *a, *a_stop; */ /* FOR_ALL_NODES_i */ /* FOR_ALL_ARCS_a_FROM_i */ /* if (OPEN(a) && (REDUCED_COST(i, a->head, a) < 0)) */ /* assert(0); */ /* return(1); */ /* } */ /************************************************* cs2 - head program ***/ static void cs2 ( n_p, m_p, nodes_p, arcs_p, f_sc, max_c, cap_p, obj_ad) long n_p, /* number of nodes */ m_p; /* number of arcs */ node *nodes_p; /* array of nodes */ arc *arcs_p; /* array of arcs */ long f_sc; /* scaling factor */ double max_c; /* maximal cost */ short *cap_p; /* capacities (changed to short by CWC) */ double *obj_ad; /* objective */ { int cc; /* for storing return code */ cs_init ( n_p, m_p, nodes_p, arcs_p, f_sc, max_c, cap_p ); /*init_solution ( );*/ cc = 0; update_epsilon (); do{ /* scaling loop */ refine (); if ( n_ref >= PRICE_OUT_START ) { price_out ( ); } if ( update_epsilon () ) break; while ( 1 ) { if ( ! price_refine () ) break; if ( n_ref >= PRICE_OUT_START ) { if ( price_in () ) { break; } } if ((cc = update_epsilon ())) break; } } while ( cc == 0 ); finishup ( obj_ad ); } /*-----------------------------------------------------------------------*/ /* SolveCS2-- formerly main() */ void SolveCS2(signed char **residue, short **mstcosts, long nrow, long ncol, long cs2scalefactor, short ***flowsptr) { /* double t; */ arc *arp; node *ndp; long n, m, m2, nmin; node *i; long ni; arc *a; long nNrow, nNcol; long to, from, num, flow, ground; long f_sc; double cost, c_max; short *cap; /* cap changed to short by CWC */ short **rowcost, **colcost; short **rowflow, **colflow; /* number of rows, cols, in residue network */ nNrow=nrow-1; nNcol=ncol-1; ground=nNrow*nNcol+1; /* parse input, set up the problem */ rowcost=mstcosts; colcost=&(mstcosts[nrow-1]); f_sc=cs2scalefactor; cs2mcfparse( residue,rowcost,colcost,nNrow,nNcol, &n,&m,&ndp,&arp,&nmin,&c_max,&cap ); /* free memory that is no longer needed */ Free2DArray((void **)residue,nrow-1); Free2DArray((void **)mstcosts,2*nrow-1); /* solve it! */ fprintf(sp2,"Running cs2 MCF solver\n"); m2 = 2 * m; cs2 ( n, m2, ndp, arp, f_sc, c_max, cap, &cost ); /* parse flow solution and place into flow arrays */ /* get memory for flow arrays */ (*flowsptr)=(short **)Get2DRowColZeroMem(nrow,ncol, sizeof(short *),sizeof(short)); rowflow=(*flowsptr); colflow=&((*flowsptr)[nrow-1]); /* loop over nodes */ for ( i = ndp; i < ndp + n; i ++ ){ ni = N_NODE ( i ); /* loop over arcs */ for ( a = i -> suspended; a != (i+1)->suspended; a ++ ){ /* if finite (non-zero) flow */ if ( cap[ N_ARC (a) ] > 0 && (cap[ N_ARC (a) ] - ( a -> r_cap ) ) ){ /* get to, from nodes and flow amount */ from=ni; to=N_NODE( a -> head ); flow=cap[ N_ARC (a) ] - ( a -> r_cap ); if(flow>LARGESHORT || flow<-LARGESHORT){ fprintf(sp0,"Flow will overflow short data type\nAbort\n"); exit(ABNORMAL_EXIT); } /* node indices are indexed from 1, not 0 */ /* node indices are in column major order, not row major */ /* handle flow to/from ground first */ if((from==ground) || (to==ground)){ if(to==ground){ num=to; to=from; from=num; flow=-flow; } if(!((to-1) % nNrow)){ colflow[0][(int )((to-1)/nNrow)]+=flow; }else if(to<=nNrow){ rowflow[to-1][0]+=flow; }else if(to>=(ground-nNrow-1)){ rowflow[(to-1) % nNrow][nNcol]-=flow; }else if(!(to % nNrow)){ colflow[nNrow][(int )((to/nNrow)-1)]-=flow; }else{ fprintf(sp0,"Unassigned ground arc parsing cs2 solution\nAbort\n"); exit(ABNORMAL_EXIT); } }else if(from==(to+1)){ num=from+(int )((from-1)/nNrow); colflow[(num-1) % (nNrow+1)][(int )(num-1)/(nNrow+1)]-=flow; }else if(from==(to-1)){ num=from+(int )((from-1)/nNrow)+1; colflow[(num-1) % (nNrow+1)][(int )(num-1)/(nNrow+1)]+=flow; }else if(from==(to-nNrow)){ num=from+nNrow; rowflow[(num-1) % nNrow][(int )((num-1)/nNrow)]+=flow; }else if(from==(to+nNrow)){ num=from; rowflow[(num-1) % nNrow][(int )((num-1)/nNrow)]-=flow; }else{ fprintf(sp0,"Non-grid arc parsing cs2 solution\nAbort\n"); exit(ABNORMAL_EXIT); } } /* end if flow on arc */ } /* end for loop over arcs of node */ } /* end for loop over nodes */ /* free memory */ free(ndp-nmin); free(arp); free(cap); free(buckets); } #endif /* end #ifndef NO_CS2 */ snaphu-v2.0.6/src/PaxHeader/snaphu.c000644 777777 777777 00000000043 14423062415 017127 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/src/snaphu.c000644 Ho)00000061063 14423062415 016367 0ustar00curtis000000 000000 /************************************************************************* snaphu main 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "snaphu.h" /* global (external) variable definitions */ /* flags used for signal handling */ char dumpresults_global = FALSE; char requestedstop_global = FALSE; /* ouput stream pointers */ /* sp0=error messages, sp1=status output, sp2=verbose, sp3=verbose counter */ FILE *sp0 = NULL; FILE *sp1 = NULL; FILE *sp2 = NULL; FILE *sp3 = NULL; /* node pointer for marking arc not on tree in apex array */ /* this should be treated as a constant */ nodeT NONTREEARC[1]; /* pointers to functions which calculate arc costs */ void (*CalcCost)(void **, long, long, long, long, long, paramT *, long *, long *) = NULL; long (*EvalCost)(void **, short **, long, long, long, paramT *) = NULL; /* static (local) function prototypes */ static int Unwrap(infileT *infiles, outfileT *outfiles, paramT *params, long linelen, long nlines); static int UnwrapTile(infileT *infiles, outfileT *outfiles, paramT *params, tileparamT *tileparams, long nlines, long linelen); /***************************/ /* main program for snaphu */ /***************************/ int main(int argc, char **argv){ /* variable declarations */ infileT infiles[1]; outfileT outfiles[1]; paramT params[1]; time_t tstart; double cputimestart; long linelen, nlines; /* get current wall clock and CPU time */ StartTimers(&tstart,&cputimestart); /* set output stream pointers (may be reset after inputs parsed) */ SetStreamPointers(); /* print greeting */ fprintf(sp1,"\n%s v%s\n",PROGRAMNAME,VERSION); /* set default parameters */ SetDefaults(infiles,outfiles,params); ReadConfigFile(DEF_SYSCONFFILE,infiles,outfiles,&linelen,params); /* parse the command line inputs */ ProcessArgs(argc,argv,infiles,outfiles,&linelen,params); /* set verbose output if specified */ SetVerboseOut(params); /* set names of dump files if necessary */ SetDumpAll(outfiles,params); /* get number of lines in file */ nlines=GetNLines(infiles,linelen,params); /* check validity of parameters */ CheckParams(infiles,outfiles,linelen,nlines,params); /* log the runtime parameters */ WriteConfigLogFile(argc,argv,infiles,outfiles,linelen,params); /* unwrap, forming tiles and reassembling if necessary */ Unwrap(infiles,outfiles,params,linelen,nlines); /* finish up */ fprintf(sp1,"Program %s done\n",PROGRAMNAME); DisplayElapsedTime(tstart,cputimestart); exit(NORMAL_EXIT); } /* end of main() */ /* function: Unwrap() * ------------------ * Sets parameters for each tile and calls UnwrapTile() to do the * unwrapping. */ static int Unwrap(infileT *infiles, outfileT *outfiles, paramT *params, long linelen, long nlines){ long optiter, noptiter; long nexttilerow, nexttilecol, ntilerow, ntilecol, nthreads, nchildren; long sleepinterval; tileparamT tileparams[1]; infileT iterinfiles[1]; outfileT iteroutfiles[1]; outfileT tileoutfiles[1]; paramT iterparams[1]; char tileinitfile[MAXSTRLEN]; pid_t pid; int childstatus; double tilecputimestart; time_t tiletstart; signed char **dotilemask; /* initialize structure stack memory to zero for extra robustness */ memset(tileparams,0,sizeof(tileparamT)); memset(iterinfiles,0,sizeof(infileT)); memset(iteroutfiles,0,sizeof(outfileT)); memset(tileoutfiles,0,sizeof(outfileT)); memset(iterparams,0,sizeof(paramT)); memset(tileinitfile,0,MAXSTRLEN); /* see if we need to do single-tile reoptimization and set up if so */ if(params->onetilereopt){ noptiter=2; }else{ noptiter=1; } /* iterate if necessary for single-tile reoptimization */ for(optiter=0;optiter1){ /* set up to write tile-mode unwrapped result to temporary file */ SetTileInitOutfile(iteroutfiles->outfile,iterparams->parentpid); StrNCopy(tileinitfile,iteroutfiles->outfile,MAXSTRLEN); iteroutfiles->outfileformat=TILEINITFILEFORMAT; fprintf(sp1,"Starting first-round tile-mode unwrapping\n"); } }else if(optiter==1){ /* second iteration */ /* set up to read unwrapped tile-mode result as single tile */ StrNCopy(iterinfiles->infile,tileinitfile,MAXSTRLEN); iterinfiles->unwrappedinfileformat=TILEINITFILEFORMAT; iterparams->unwrapped=TRUE; iterparams->ntilerow=1; iterparams->ntilecol=1; iterparams->rowovrlp=0; iterparams->colovrlp=0; fprintf(sp1,"Starting second-round single-tile unwrapping\n"); }else{ fprintf(sp0,"ERROR: illegal optiter value in Unwrap()\n"); exit(ABNORMAL_EXIT); } /* set up for unwrapping */ ntilerow=iterparams->ntilerow; ntilecol=iterparams->ntilecol; nthreads=iterparams->nthreads; dumpresults_global=FALSE; requestedstop_global=FALSE; /* do the unwrapping */ if(ntilerow==1 && ntilecol==1){ /* only single tile */ /* do the unwrapping */ tileparams->firstrow=iterparams->piecefirstrow; tileparams->firstcol=iterparams->piecefirstcol; tileparams->nrow=iterparams->piecenrow; tileparams->ncol=iterparams->piecencol; UnwrapTile(iterinfiles,iteroutfiles,iterparams,tileparams,nlines,linelen); }else{ /* don't unwrap if in assemble-only mode */ if(!iterparams->assembleonly){ /* set up mask for which tiles should be unwrapped */ dotilemask=SetUpDoTileMask(iterinfiles,ntilerow,ntilecol); /* make a temporary directory into which tile files will be written */ MakeTileDir(iterparams,iteroutfiles); /* different code for parallel or nonparallel operation */ if(nthreads>1){ /* parallel code */ /* initialize */ nexttilerow=0; nexttilecol=0; nchildren=0; sleepinterval=(long )ceil(nlines*linelen /((double )(ntilerow*ntilecol)) *SECONDSPERPIXEL); /* trap signals so children get killed if parent dies */ CatchSignals(KillChildrenExit); /* loop until we're done unwrapping */ while(TRUE){ /* unwrap next tile if there are free processors and tiles left */ if(nchildrenparentpid; } /* see if parent or child (or error) */ if(pid<0){ /* parent kills children and exits if there was a fork error */ fflush(NULL); fprintf(sp0,"Error while forking\nAbort\n"); kill(0,SIGKILL); exit(ABNORMAL_EXIT); }else if(pid==0){ /* child executes this code after fork */ /* reset signal handlers so that children exit nicely */ CatchSignals(SignalExit); /* start timers for this tile */ StartTimers(&tiletstart,&tilecputimestart); /* set up tile parameters */ pid=getpid(); fprintf(sp1, "Unwrapping tile at row %ld, column %ld (pid %ld)\n", nexttilerow,nexttilecol,(long )pid); SetupTile(nlines,linelen,iterparams,tileparams, iteroutfiles,tileoutfiles, nexttilerow,nexttilecol); /* reset stream pointers for logging */ ChildResetStreamPointers(pid,nexttilerow,nexttilecol, iterparams); /* unwrap the tile */ UnwrapTile(iterinfiles,tileoutfiles,iterparams,tileparams, nlines,linelen); /* log elapsed time */ DisplayElapsedTime(tiletstart,tilecputimestart); /* child exits when done unwrapping */ exit(NORMAL_EXIT); } /* parent executes this code after fork */ /* increment tile counters */ if(++nexttilecol==ntilecol){ nexttilecol=0; nexttilerow++; } /* increment counter of running child processes */ if(pid!=iterparams->parentpid){ nchildren++; } }else{ /* wait for a child to finish (only parent gets here) */ pid=wait(&childstatus); /* make sure child exited cleanly */ if(!(WIFEXITED(childstatus)) || (WEXITSTATUS(childstatus))!=0){ fflush(NULL); fprintf(sp0,"Unexpected or abnormal exit of child process %ld\n" "Abort\n",(long )pid); signal(SIGTERM,SIG_IGN); kill(0,SIGTERM); exit(ABNORMAL_EXIT); } /* we're done if there are no more active children */ /* shouldn't really need this sleep(), but be extra sure child */ /* outputs are really flushed and written to disk by OS */ if(--nchildren==0){ sleep(sleepinterval); break; } } /* end if free processor and tiles remaining */ } /* end while loop */ /* return signal handlers to default behavior */ CatchSignals(SIG_DFL); }else{ /* nonparallel code */ /* loop over all tiles */ for(nexttilerow=0;nexttilerow1 */ /* free tile mask memory */ Free2DArray((void **)dotilemask,ntilerow); } /* end if !iterparams->assembleonly */ /* reassemble tiles */ AssembleTiles(iteroutfiles,iterparams,nlines,linelen); } /* end if multiple tiles */ /* remove temporary tile file if desired at end of second iteration */ if(iterparams->rmtileinit && optiter>0){ unlink(tileinitfile); } } /* end of optiter loop */ /* done */ return(0); } /* end of Unwrap() */ /* function: UnwrapTile() * ---------------------- * This is the main phase unwrapping function for a single tile. */ static int UnwrapTile(infileT *infiles, outfileT *outfiles, paramT *params, tileparamT *tileparams, long nlines, long linelen){ /* variable declarations */ long nrow, ncol, nnoderow, narcrow, n, ngroundarcs, iincrcostfile; long nflow, ncycle, mostflow, nflowdone; long candidatelistsize, candidatebagsize; long isource, nsource; long nnondecreasedcostiter; long *nconnectedarr; int *nnodesperrow, *narcsperrow; short **flows, **mstcosts; float **wrappedphase, **unwrappedphase, **mag, **unwrappedest; incrcostT **incrcosts; void **costs; totalcostT totalcost, oldtotalcost, mintotalcost; nodeT **sourcelist; nodeT *source, ***apexes; nodeT **nodes, ground[1]; candidateT *candidatebag, *candidatelist; signed char **iscandidate; signed char notfirstloop, allmasked; bucketT *bkts; /* get size of tile */ nrow=tileparams->nrow; ncol=tileparams->ncol; /* read input file (memory allocated by read function) */ ReadInputFile(infiles,&mag,&wrappedphase,&flows,linelen,nlines, params,tileparams); /* read interferogram magnitude if specified separately */ ReadMagnitude(mag,infiles,linelen,nlines,tileparams); /* read mask file and apply to magnitude */ ReadByteMask(mag,infiles,linelen,nlines,tileparams,params); /* make sure we have at least one pixel that is not masked */ allmasked=CheckMagMasking(mag,nrow,ncol); /* read the coarse unwrapped estimate, if provided */ unwrappedest=NULL; if(strlen(infiles->estfile)){ ReadUnwrappedEstimateFile(&unwrappedest,infiles,linelen,nlines, params,tileparams); /* subtract the estimate from the wrapped phase (and re-wrap) */ FlattenWrappedPhase(wrappedphase,unwrappedest,nrow,ncol); } /* build the cost arrays */ BuildCostArrays(&costs,&mstcosts,mag,wrappedphase,unwrappedest, linelen,nlines,nrow,ncol,params,tileparams,infiles,outfiles); /* if in quantify-only mode, evaluate cost of unwrapped input then return */ if(params->eval){ mostflow=Short2DRowColAbsMax(flows,nrow,ncol); fprintf(sp1,"Maximum flow on network: %ld\n",mostflow); totalcost=EvaluateTotalCost(costs,flows,nrow,ncol,NULL,params); fprintf(sp1,"Total solution cost: %.9g\n",(double )totalcost); Free2DArray((void **)costs,2*nrow-1); Free2DArray((void **)mag,nrow); Free2DArray((void **)wrappedphase,nrow); Free2DArray((void **)flows,2*nrow-1); return(1); } /* set network function pointers for grid network */ SetGridNetworkFunctionPointers(); /* initialize the flows (find simple unwrapping to get a feasible flow) */ unwrappedphase=NULL; nodes=NULL; if(!params->unwrapped){ /* see which initialization method to use */ if(params->initmethod==MSTINIT){ /* use minimum spanning tree (MST) algorithm */ MSTInitFlows(wrappedphase,&flows,mstcosts,nrow,ncol, &nodes,ground,params->initmaxflow); }else if(params->initmethod==MCFINIT){ /* use minimum cost flow (MCF) algorithm */ MCFInitFlows(wrappedphase,&flows,mstcosts,nrow,ncol, params->cs2scalefactor); }else{ fflush(NULL); fprintf(sp0,"Illegal initialization method\nAbort\n"); exit(ABNORMAL_EXIT); } /* integrate the phase and write out if necessary */ if(params->initonly || strlen(outfiles->initfile)){ fprintf(sp1,"Integrating phase\n"); unwrappedphase=(float **)Get2DMem(nrow,ncol, sizeof(float *),sizeof(float)); IntegratePhase(wrappedphase,unwrappedphase,flows,nrow,ncol); if(unwrappedest!=NULL){ Add2DFloatArrays(unwrappedphase,unwrappedest,nrow,ncol); } FlipPhaseArraySign(unwrappedphase,params,nrow,ncol); /* return if called in init only; otherwise, free memory and continue */ if(params->initonly){ fprintf(sp1,"Writing output to file %s\n",outfiles->outfile); WriteOutputFile(mag,unwrappedphase,outfiles->outfile,outfiles, nrow,ncol); Free2DArray((void **)mag,nrow); Free2DArray((void **)wrappedphase,nrow); Free2DArray((void **)unwrappedphase,nrow); if(nodes!=NULL){ Free2DArray((void **)nodes,nrow-1); } Free2DArray((void **)flows,2*nrow-1); return(1); }else{ fprintf(sp2,"Writing initialization to file %s\n",outfiles->initfile); WriteOutputFile(mag,unwrappedphase,outfiles->initfile,outfiles, nrow,ncol); Free2DArray((void **)unwrappedphase,nrow); } } } /* initialize network variables */ InitNetwork(flows,&ngroundarcs,&ncycle,&nflowdone,&mostflow,&nflow, &candidatebagsize,&candidatebag,&candidatelistsize, &candidatelist,&iscandidate,&apexes,&bkts,&iincrcostfile, &incrcosts,&nodes,ground,&nnoderow,&nnodesperrow,&narcrow, &narcsperrow,nrow,ncol,¬firstloop,&totalcost,params); oldtotalcost=totalcost; mintotalcost=totalcost; nnondecreasedcostiter=0; /* regrow regions with -G parameter */ if(params->regrowconncomps){ /* free up some memory */ Free2DArray((void **)apexes,2*nrow-1); Free2DArray((void **)iscandidate,2*nrow-1); Free2DArray((void **)nodes,nrow-1); free(candidatebag); free(candidatelist); free(bkts->bucketbase); /* grow connected components */ GrowConnCompsMask(costs,flows,nrow,ncol,incrcosts,outfiles,params); /* free up remaining memory and return */ Free2DArray((void **)incrcosts,2*nrow-1); Free2DArray((void **)costs,2*nrow-1); Free2DArray((void **)mag,nrow); Free2DArray((void **)wrappedphase,nrow); Free2DArray((void **)flows,2*nrow-1); free(nnodesperrow); free(narcsperrow); return(1); } /* mask zero-magnitude nodes so they are not considered in optimization */ MaskNodes(nrow,ncol,nodes,ground,mag); /* if we have a single tile, trap signals for dumping results */ if(params->ntilerow==1 && params->ntilecol==1){ signal(SIGINT,SetDump); signal(SIGHUP,SetDump); } /* main loop: loop over flow increments and sources */ if(!allmasked){ fprintf(sp1,"Running nonlinear network flow optimizer\n"); fprintf(sp1,"Maximum flow on network: %ld\n",mostflow); fprintf(sp2,"Number of nodes in network: %ld\n",(nrow-1)*(ncol-1)+1); while(TRUE){ fprintf(sp1,"Flow increment: %ld (Total improvements: %ld)\n", nflow,ncycle); /* set up the incremental (residual) cost arrays */ SetupIncrFlowCosts(costs,incrcosts,flows,nflow,nrow,narcrow,narcsperrow, params); if(params->dumpall && params->ntilerow==1 && params->ntilecol==1){ DumpIncrCostFiles(incrcosts,++iincrcostfile,nflow,nrow,ncol); } /* set the tree root (equivalent to source of shortest path problem) */ sourcelist=NULL; nconnectedarr=NULL; nsource=SelectSources(nodes,mag,ground,nflow,flows,ngroundarcs, nrow,ncol,params,&sourcelist,&nconnectedarr); /* set up network variables for tree solver */ SetupTreeSolveNetwork(nodes,ground,apexes,iscandidate, nnoderow,nnodesperrow,narcrow,narcsperrow, nrow,ncol); /* loop over sources */ n=0; for(isource=0;isourcerow==GROUNDROW){ fprintf(sp3,"Source %ld: (edge ground)\n",isource); }else{ fprintf(sp3,"Source %ld: row, col = %d, %d\n", isource,source->row,source->col); } /* run the solver, and increment nflowdone if no cycles are found */ n+=TreeSolve(nodes,NULL,ground,source, &candidatelist,&candidatebag, &candidatelistsize,&candidatebagsize, bkts,flows,costs,incrcosts,apexes,iscandidate, ngroundarcs,nflow,mag,wrappedphase,outfiles->outfile, nnoderow,nnodesperrow,narcrow,narcsperrow,nrow,ncol, outfiles,nconnectedarr[isource],params); } /* free temporary memory */ free(sourcelist); free(nconnectedarr); /* evaluate and save the total cost (skip if first loop through nflow) */ fprintf(sp2,"Current solution cost: %.16g\n", (double )EvaluateTotalCost(costs,flows,nrow,ncol,NULL,params)); fflush(NULL); if(notfirstloop){ oldtotalcost=totalcost; totalcost=EvaluateTotalCost(costs,flows,nrow,ncol,NULL,params); if(totalcostoldtotalcost || (n>0 && totalcost==oldtotalcost)){ fflush(NULL); fprintf(sp1,"Caution: Unexpected increase in total cost\n"); } if(totalcost > mintotalcost){ nnondecreasedcostiter++; }else{ nnondecreasedcostiter=0; } } /* consider this flow increment done if not too many neg cycles found */ ncycle+=n; if(n<=params->maxnflowcycles){ nflowdone++; }else{ nflowdone=1; } /* find maximum flow on network, excluding arcs affected by masking */ mostflow=MaxNonMaskFlow(flows,mag,nrow,ncol); if(nnondecreasedcostiter>=2*mostflow){ fflush(NULL); fprintf(sp0,"WARNING: No overall cost reduction for too many iterations." " Breaking loop\n"); break; } /* break if we're done with all flow increments or problem is convex */ if(nflowdone>=params->maxflow || nflowdone>=mostflow || params->p>=1.0){ break; } /* update flow increment */ nflow++; if(nflow>params->maxflow || nflow>mostflow){ nflow=1; notfirstloop=TRUE; } fprintf(sp2,"Maximum valid flow on network: %ld\n",mostflow); /* dump flow arrays if necessary */ if(strlen(outfiles->flowfile)){ FlipFlowArraySign(flows,params,nrow,ncol); Write2DRowColArray((void **)flows,outfiles->flowfile,nrow,ncol, sizeof(short)); FlipFlowArraySign(flows,params,nrow,ncol); } } /* end loop until no more neg cycles */ } /* end if all pixels masked */ /* if we have single tile, return signal handlers to default behavior */ if(params->ntilerow==1 && params->ntilecol==1){ signal(SIGINT,SIG_DFL); signal(SIGHUP,SIG_DFL); } /* free some memory */ Free2DArray((void **)apexes,2*nrow-1); Free2DArray((void **)iscandidate,2*nrow-1); Free2DArray((void **)nodes,nrow-1); free(candidatebag); free(candidatelist); free(bkts->bucketbase); /* grow connected component mask */ if(strlen(outfiles->conncompfile)){ GrowConnCompsMask(costs,flows,nrow,ncol,incrcosts,outfiles,params); } /* grow regions for tiling */ if(params->ntilerow!=1 || params->ntilecol!=1){ GrowRegions(costs,flows,nrow,ncol,incrcosts,outfiles,tileparams,params); } /* free some more memory */ Free2DArray((void **)incrcosts,2*nrow-1); /* evaluate and display the maximum flow and total cost */ totalcost=EvaluateTotalCost(costs,flows,nrow,ncol,NULL,params); fprintf(sp1,"Maximum flow on network: %ld\n",mostflow); fprintf(sp1,"Total solution cost: %.9g\n",(double )totalcost); /* integrate the wrapped phase using the solution flow */ fprintf(sp1,"Integrating phase\n"); unwrappedphase=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float)); IntegratePhase(wrappedphase,unwrappedphase,flows,nrow,ncol); /* reinsert the coarse estimate, if it was given */ if(unwrappedest!=NULL){ Add2DFloatArrays(unwrappedphase,unwrappedest,nrow,ncol); } /* flip the sign of the unwrapped phase array if it was flipped initially, */ FlipPhaseArraySign(unwrappedphase,params,nrow,ncol); /* write the unwrapped output */ fprintf(sp1,"Writing output to file %s\n",outfiles->outfile); WriteOutputFile(mag,unwrappedphase,outfiles->outfile,outfiles, nrow,ncol); /* free remaining memory and return */ Free2DArray((void **)costs,2*nrow-1); Free2DArray((void **)mag,nrow); Free2DArray((void **)wrappedphase,nrow); Free2DArray((void **)unwrappedphase,nrow); Free2DArray((void **)flows,2*nrow-1); free(nnodesperrow); free(narcsperrow); return(0); } /* end of UnwrapTile() */ snaphu-v2.0.6/src/PaxHeader/snaphu_util.c000644 777777 777777 00000000043 14423062415 020164 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/src/snaphu_util.c000644 Ho)00000100530 14423062415 017415 0ustar00curtis000000 000000 /************************************************************************* 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "snaphu.h" /* static (local) function prototypes */ static int IsTrue(char *str); static int IsFalse(char *str); static double ModDiff(double f1, double f2); /* function: IsTrue() * ------------------ * Returns TRUE if the string input is any of TRUE, True, true, 1, * y, Y, yes, YES */ 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); } } /* function: IsFalse() * ------------------ * Returns FALSE if the string input is any of FALSE, False, false, * 0, n, N, no, NO */ 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); } } /* 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. */ 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); } /* function: WrapPhase() * --------------------- * Makes sure the passed float array is properly wrapped into the [0,2pi) * interval. */ int WrapPhase(float **wrappedphase, long nrow, long ncol){ long row, col; for(row=0;row=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); } /* 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. */ 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=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); } /* 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. */ 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;rowflipphasesign){ for(row=0;rowflipphasesign){ for(row=0;row<2*nrow-1;row++){ if(rowmaxval){ return(maxval); }else{ return(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;rowmaxval){ maxval=labs(arr[row][col]); } } } for(row=nrow-1;row<2*nrow-1;row++){ for(col=0;colmaxval){ 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. */ 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}; /* 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){ fflush(NULL); fprintf(sp0,"Despeckling box size too large for input array size\n" "Abort\n"); exit(ABNORMAL_EXIT); } /* do the filtering */ for(row=0;rowratiomax){ ratiomax=ratio; (*ei)[row][col]=wstick; } } } } } /* free memory */ Free2DArray((void **)intensity,nrow+2*ARMLEN); return(0); } /* 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;rownrow || kcol>ncol){ return(array1); } /* mirror reflect edges */ for(row=0;row=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. */ 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); } /* 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 */ 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){ /* make sure the hangup signal doesn't revert to default behavior */ signal(SIGHUP,SetDump); /* print a nice message, and set the dump variable */ 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); } /* done */ return; } /* 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){ 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); /* done */ return; } /* function: SignalExit() * ---------------------- * Signal hanlder that prints message about the signal received, then exits. */ 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); /* done */ return; } /* function: StartTimers() * ----------------------- * Starts the wall clock and CPU timers for use in conjunction with * DisplayElapsedTime(). */ 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)); } } /* done */ return(0); } /* 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. */ 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); } /* done */ return(0); } /* function: LongCompare() * ----------------------- * Compares two long integers. For use with qsort(). */ int LongCompare(const void *c1, const void *c2){ return((*((long *)c1))-(*((long *)c2))); } snaphu-v2.0.6/src/PaxHeader/snaphu_io.c000644 777777 777777 00000000043 14423062415 017616 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/src/snaphu_io.c000644 Ho)00000354350 14423062415 017062 0ustar00curtis000000 000000 /************************************************************************* snaphu input/output 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "snaphu.h" /* static (local) function prototypes */ static int ParseConfigLine(char *buf, char *conffile, long nlines, infileT *infiles, outfileT *outfiles, long *linelenptr, paramT *params); static int LogStringParam(FILE *fp, char *key, char *value); static int LogBoolParam(FILE *fp, char *key, signed char boolvalue); static int LogFileFormat(FILE *fp, char *key, signed char fileformat); static int WriteAltLineFile(float **mag, float **phase, char *outfile, long nrow, long ncol); static int WriteAltSampFile(float **arr1, float **arr2, char *outfile, long nrow, long ncol); /* function: SetDefaults() * ----------------------- * Sets all parameters to their initial default values. */ int SetDefaults(infileT *infiles, outfileT *outfiles, paramT *params){ /* initialize to all zero to start for extra robustness */ memset(infiles,0,sizeof(infileT)); memset(outfiles,0,sizeof(outfileT)); memset(params,0,sizeof(paramT)); /* input files */ StrNCopy(infiles->weightfile,DEF_WEIGHTFILE,MAXSTRLEN); StrNCopy(infiles->corrfile,DEF_CORRFILE,MAXSTRLEN); StrNCopy(infiles->ampfile,DEF_AMPFILE,MAXSTRLEN); StrNCopy(infiles->ampfile2,DEF_AMPFILE2,MAXSTRLEN); StrNCopy(infiles->estfile,DEF_ESTFILE,MAXSTRLEN); StrNCopy(infiles->magfile,DEF_MAGFILE,MAXSTRLEN); StrNCopy(infiles->costinfile,DEF_COSTINFILE,MAXSTRLEN); StrNCopy(infiles->bytemaskfile,DEF_BYTEMASKFILE,MAXSTRLEN); StrNCopy(infiles->dotilemaskfile,DEF_DOTILEMASKFILE,MAXSTRLEN); /* output and dump files */ StrNCopy(outfiles->initfile,DEF_INITFILE,MAXSTRLEN); StrNCopy(outfiles->flowfile,DEF_FLOWFILE,MAXSTRLEN); StrNCopy(outfiles->eifile,DEF_EIFILE,MAXSTRLEN); StrNCopy(outfiles->rowcostfile,DEF_ROWCOSTFILE,MAXSTRLEN); StrNCopy(outfiles->colcostfile,DEF_COLCOSTFILE,MAXSTRLEN); StrNCopy(outfiles->mstrowcostfile,DEF_MSTROWCOSTFILE,MAXSTRLEN); StrNCopy(outfiles->mstcolcostfile,DEF_MSTCOLCOSTFILE,MAXSTRLEN); StrNCopy(outfiles->mstcostsfile,DEF_MSTCOSTSFILE,MAXSTRLEN); StrNCopy(outfiles->corrdumpfile,DEF_CORRDUMPFILE,MAXSTRLEN); StrNCopy(outfiles->rawcorrdumpfile,DEF_RAWCORRDUMPFILE,MAXSTRLEN); StrNCopy(outfiles->costoutfile,DEF_COSTOUTFILE,MAXSTRLEN); StrNCopy(outfiles->conncompfile,DEF_CONNCOMPFILE,MAXSTRLEN); StrNCopy(outfiles->outfile,DEF_OUTFILE,MAXSTRLEN); StrNCopy(outfiles->logfile,DEF_LOGFILE,MAXSTRLEN); /* file formats */ infiles->infileformat=DEF_INFILEFORMAT; infiles->unwrappedinfileformat=DEF_UNWRAPPEDINFILEFORMAT; infiles->magfileformat=DEF_MAGFILEFORMAT; infiles->corrfileformat=DEF_CORRFILEFORMAT; infiles->estfileformat=DEF_ESTFILEFORMAT; infiles->ampfileformat=DEF_AMPFILEFORMAT; outfiles->outfileformat=DEF_OUTFILEFORMAT; /* options and such */ params->unwrapped=DEF_UNWRAPPED; params->regrowconncomps=DEF_REGROWCONNCOMPS; params->eval=DEF_EVAL; params->initonly=DEF_INITONLY; params->initmethod=DEF_INITMETHOD; params->costmode=DEF_COSTMODE; params->amplitude=DEF_AMPLITUDE; params->verbose=DEF_VERBOSE; /* SAR and geometry parameters */ params->orbitradius=DEF_ORBITRADIUS; params->altitude=DEF_ALTITUDE; params->earthradius=DEF_EARTHRADIUS; params->bperp=DEF_BPERP; params->transmitmode=DEF_TRANSMITMODE; params->baseline=DEF_BASELINE; params->baselineangle=DEF_BASELINEANGLE; params->nlooksrange=DEF_NLOOKSRANGE; params->nlooksaz=DEF_NLOOKSAZ; params->nlooksother=DEF_NLOOKSOTHER; params->ncorrlooks=DEF_NCORRLOOKS; params->ncorrlooksrange=DEF_NCORRLOOKSRANGE; params->ncorrlooksaz=DEF_NCORRLOOKSAZ; params->nearrange=DEF_NEARRANGE; params->dr=DEF_DR; params->da=DEF_DA; params->rangeres=DEF_RANGERES; params->azres=DEF_AZRES; params->lambda=DEF_LAMBDA; /* scattering model parameters */ params->kds=DEF_KDS; params->specularexp=DEF_SPECULAREXP; params->dzrcritfactor=DEF_DZRCRITFACTOR; params->shadow=DEF_SHADOW; params->dzeimin=DEF_DZEIMIN; params->laywidth=DEF_LAYWIDTH; params->layminei=DEF_LAYMINEI; params->sloperatiofactor=DEF_SLOPERATIOFACTOR; params->sigsqei=DEF_SIGSQEI; /* decorrelation model parameters */ params->drho=DEF_DRHO; params->rhosconst1=DEF_RHOSCONST1; params->rhosconst2=DEF_RHOSCONST2; params->cstd1=DEF_CSTD1; params->cstd2=DEF_CSTD2; params->cstd3=DEF_CSTD3; params->defaultcorr=DEF_DEFAULTCORR; params->rhominfactor=DEF_RHOMINFACTOR; /* pdf model parameters */ params->dzlaypeak=DEF_DZLAYPEAK; params->azdzfactor=DEF_AZDZFACTOR; params->dzeifactor=DEF_DZEIFACTOR; params->dzeiweight=DEF_DZEIWEIGHT; params->dzlayfactor=DEF_DZLAYFACTOR; params->layconst=DEF_LAYCONST; params->layfalloffconst=DEF_LAYFALLOFFCONST; params->sigsqshortmin=DEF_SIGSQSHORTMIN; params->sigsqlayfactor=DEF_SIGSQLAYFACTOR; /* deformation mode parameters */ params->defoazdzfactor=DEF_DEFOAZDZFACTOR; params->defothreshfactor=DEF_DEFOTHRESHFACTOR; params->defomax=DEF_DEFOMAX; params->sigsqcorr=DEF_SIGSQCORR; params->defolayconst=DEF_DEFOLAYCONST; /* algorithm parameters */ params->flipphasesign=DEF_FLIPPHASESIGN; params->onetilereopt=DEF_ONETILEREOPT; params->rmtileinit=DEF_RMTILEINIT; params->initmaxflow=DEF_INITMAXFLOW; params->arcmaxflowconst=DEF_ARCMAXFLOWCONST; params->maxflow=DEF_MAXFLOW; params->krowei=DEF_KROWEI; params->kcolei=DEF_KCOLEI; params->kperpdpsi=DEF_KPERPDPSI; params->kpardpsi=DEF_KPARDPSI; params->threshold=DEF_THRESHOLD; params->initdzr=DEF_INITDZR; params->initdzstep=DEF_INITDZSTEP; params->maxcost=DEF_MAXCOST; params->costscale=DEF_COSTSCALE; params->costscaleambight=DEF_COSTSCALEAMBIGHT; params->dnomincangle=DEF_DNOMINCANGLE; params->srcrow=DEF_SRCROW; params->srccol=DEF_SRCCOL; params->p=DEF_P; params->bidirlpn=DEF_BIDIRLPN; params->nshortcycle=DEF_NSHORTCYCLE; params->maxnewnodeconst=DEF_MAXNEWNODECONST; params->maxcyclefraction=DEF_MAXCYCLEFRACTION; params->nconnnodemin=DEF_NCONNNODEMIN; params->maxnflowcycles=DEF_MAXNFLOWCYCLES; params->dumpall=DEF_DUMPALL; params->cs2scalefactor=DEF_CS2SCALEFACTOR; params->nmajorprune=DEF_NMAJORPRUNE; params->prunecostthresh=DEF_PRUNECOSTTHRESH; params->edgemasktop=DEF_EDGEMASKTOP; params->edgemaskbot=DEF_EDGEMASKBOT; params->edgemaskleft=DEF_EDGEMASKLEFT; params->edgemaskright=DEF_EDGEMASKRIGHT; params->parentpid=(long )getpid(); /* tile parameters */ params->ntilerow=DEF_NTILEROW; params->ntilecol=DEF_NTILECOL; params->rowovrlp=DEF_ROWOVRLP; params->colovrlp=DEF_COLOVRLP; params->piecefirstrow=DEF_PIECEFIRSTROW; params->piecefirstcol=DEF_PIECEFIRSTCOL; params->piecenrow=DEF_PIECENROW; params->piecencol=DEF_PIECENCOL; params->tilecostthresh=DEF_TILECOSTTHRESH; params->minregionsize=DEF_MINREGIONSIZE; params->nthreads=DEF_NTHREADS; params->scndryarcflowmax=DEF_SCNDRYARCFLOWMAX; StrNCopy(params->tiledir,DEF_TILEDIR,MAXSTRLEN); params->assembleonly=DEF_ASSEMBLEONLY; params->rmtmptile=DEF_RMTMPTILE; params->tileedgeweight=DEF_TILEEDGEWEIGHT; /* connected component parameters */ params->minconncompfrac=DEF_MINCONNCOMPFRAC; params->conncompthresh=DEF_CONNCOMPTHRESH; params->maxncomps=DEF_MAXNCOMPS; params->conncompouttype=DEF_CONNCOMPOUTTYPE; /* done */ return(0); } /* function: ProcessArgs() * ----------------------- * Parses command line inputs passed to main(). */ int ProcessArgs(int argc, char *argv[], infileT *infiles, outfileT *outfiles, long *linelenptr, paramT *params){ long i,j; signed char noarg_exit; /* required inputs */ noarg_exit=FALSE; StrNCopy(infiles->infile,"",MAXSTRLEN); *linelenptr=0; /* loop over inputs */ if(argc<2){ /* catch zero arguments in */ fprintf(sp1,OPTIONSHELPBRIEF); exit(ABNORMAL_EXIT); } for(i=1;iunwrapped=TRUE; }else if(argv[i][j]=='t'){ params->costmode=TOPO; }else if(argv[i][j]=='d'){ params->costmode=DEFO; }else if(argv[i][j]=='s'){ params->costmode=SMOOTH; params->defomax=0.0; }else if(argv[i][j]=='q'){ params->eval=TRUE; params->unwrapped=TRUE; }else if(argv[i][j]=='C'){ if(++ioutfile,argv[i],MAXSTRLEN); break; }else{ noarg_exit=TRUE; } }else if(argv[i][j]=='c'){ if(++icorrfile,argv[i],MAXSTRLEN); break; }else{ noarg_exit=TRUE; } }else if(argv[i][j]=='m'){ if(++imagfile,argv[i],MAXSTRLEN); break; }else{ noarg_exit=TRUE; } }else if(argv[i][j]=='M'){ if(++ibytemaskfile,argv[i],MAXSTRLEN); break; }else{ noarg_exit=TRUE; } }else if(argv[i][j]=='a'){ if(++iampfile,argv[i],MAXSTRLEN); params->amplitude=TRUE; break; }else{ noarg_exit=TRUE; } }else if(argv[i][j]=='A'){ if(++iampfile,argv[i],MAXSTRLEN); params->amplitude=FALSE; break; }else{ noarg_exit=TRUE; } }else if(argv[i][j]=='e'){ if(++iestfile,argv[i],MAXSTRLEN); break; }else{ noarg_exit=TRUE; } }else if(argv[i][j]=='w'){ if(++iweightfile,argv[i],MAXSTRLEN); break; }else{ noarg_exit=TRUE; } }else if(argv[i][j]=='g'){ if(++iconncompfile,argv[i],MAXSTRLEN); break; }else{ noarg_exit=TRUE; } }else if(argv[i][j]=='G'){ params->regrowconncomps=TRUE; if(++iconncompfile,argv[i],MAXSTRLEN); break; }else{ noarg_exit=TRUE; } }else if(argv[i][j]=='b'){ if(++ibperp)) || !(params->bperp)){ fflush(NULL); fprintf(sp0,"option -%c requires non-zero decimal argument\n", argv[i-1][j]); exit(ABNORMAL_EXIT); } break; }else{ noarg_exit=TRUE; } }else if(argv[i][j]=='p'){ if(++ip))){ fflush(NULL); fprintf(sp0,"option -%c requires decimal argument\n", argv[i-1][j]); exit(ABNORMAL_EXIT); } break; }else{ noarg_exit=TRUE; } }else if(argv[i][j]=='i'){ params->initonly=TRUE; }else if(argv[i][j]=='S'){ params->onetilereopt=TRUE; }else if(argv[i][j]=='k'){ params->rmtmptile=FALSE; params->rmtileinit=FALSE; }else if(argv[i][j]=='n'){ params->costmode=NOSTATCOSTS; }else if(argv[i][j]=='v'){ params->verbose=TRUE; }else if(argv[i][j]=='l'){ if(++ilogfile,argv[i],MAXSTRLEN); break; }else{ noarg_exit=TRUE; } }else{ fflush(NULL); fprintf(sp0,"unrecognized option -%c\n",argv[i][j]); exit(ABNORMAL_EXIT); } if(noarg_exit){ fflush(NULL); fprintf(sp0,"option -%c requires an argument\n",argv[i-1][j]); exit(ABNORMAL_EXIT); } } }else{ /* argument is a "--" option */ if(!strcmp(argv[i],"--costinfile")){ if(++icostinfile,argv[i],MAXSTRLEN); }else{ noarg_exit=TRUE; } }else if(!strcmp(argv[i],"--costoutfile")){ if(++icostoutfile,argv[i],MAXSTRLEN); }else{ noarg_exit=TRUE; } }else if(!strcmp(argv[i],"--debug") || !strcmp(argv[i],"--dumpall")){ params->dumpall=TRUE; }else if(!strcmp(argv[i],"--mst")){ params->initmethod=MSTINIT; }else if(!strcmp(argv[i],"--mcf")){ params->initmethod=MCFINIT; }else if(!strcmp(argv[i],"--aa")){ if(i+2ampfile,argv[++i],MAXSTRLEN); StrNCopy(infiles->ampfile2,argv[++i],MAXSTRLEN); infiles->ampfileformat=FLOAT_DATA; params->amplitude=TRUE; }else{ noarg_exit=TRUE; } }else if(!strcmp(argv[i],"--AA")){ if(++i+1ampfile,argv[i++],MAXSTRLEN); StrNCopy(infiles->ampfile2,argv[i],MAXSTRLEN); infiles->ampfileformat=FLOAT_DATA; params->amplitude=FALSE; }else{ noarg_exit=TRUE; } }else if(!strcmp(argv[i],"--tile")){ if(++i+3ntilerow)) || StringToLong(argv[i++],&(params->ntilecol)) || StringToLong(argv[i++],&(params->rowovrlp)) || StringToLong(argv[i],&(params->colovrlp))){ fflush(NULL); fprintf(sp0,"option %s requires four integer arguments\n", argv[i-4]); exit(ABNORMAL_EXIT); } }else{ noarg_exit=TRUE; } }else if(!strcmp(argv[i],"--piece")){ if(++i+3piecefirstrow)) || StringToLong(argv[i++],&(params->piecefirstcol)) || StringToLong(argv[i++],&(params->piecenrow)) || StringToLong(argv[i],&(params->piecencol))){ fflush(NULL); fprintf(sp0,"option %s requires four integer arguments\n", argv[i-4]); exit(ABNORMAL_EXIT); } }else{ noarg_exit=TRUE; } }else if(!strcmp(argv[i],"--nproc")){ if(++inthreads))){ fflush(NULL); fprintf(sp0,"option %s requires an integer arguemnt\n", argv[i-1]); exit(ABNORMAL_EXIT); } }else{ noarg_exit=TRUE; } }else if(!strcmp(argv[i],"--tiledir")){ if(++itiledir,argv[i],MAXSTRLEN); }else{ noarg_exit=TRUE; } }else if(!strcmp(argv[i],"--assemble")){ params->assembleonly=TRUE; }else if(!strcmp(argv[i],"--copyright") || !strcmp(argv[i],"--info")){ fprintf(sp1,COPYRIGHT); exit(ABNORMAL_EXIT); }else if(!strcmp(argv[i],"--help")){ fflush(NULL); fprintf(sp1,OPTIONSHELPFULL); exit(ABNORMAL_EXIT); }else{ fflush(NULL); fprintf(sp0,"unrecognized option %s\n",argv[i]); exit(ABNORMAL_EXIT); } if(noarg_exit){ fflush(NULL); fprintf(sp0,"incorrect number of arguments for option %s\n", argv[i-1]); exit(ABNORMAL_EXIT); } } }else{ /* argument is not an option */ if(!strlen(infiles->infile)){ StrNCopy(infiles->infile,argv[i],MAXSTRLEN); }else if(*linelenptr==0){ if(StringToLong(argv[i],linelenptr) || *linelenptr<=0){ fflush(NULL); fprintf(sp0,"line length must be positive integer\n"); exit(ABNORMAL_EXIT); } }else{ fflush(NULL); fprintf(sp0,"multiple input files: %s and %s\n", infiles->infile,argv[i]); exit(ABNORMAL_EXIT); } } } /* end for loop over arguments */ /* check to make sure we have required arguments */ if(!strlen(infiles->infile) || !(*linelenptr)){ fflush(NULL); fprintf(sp0,"not enough input arguments. type %s -h for help\n", PROGRAMNAME); exit(ABNORMAL_EXIT); } /* done */ return(0); } /* end of ProcessArgs */ /* function: CheckParams() * ----------------------- * Checks all parameters to make sure they are valid. This is just a boring * function with lots of checks in it. */ int CheckParams(infileT *infiles, outfileT *outfiles, long linelen, long nlines, paramT *params){ long ni, nj, n; FILE *fp; /* make sure output file is writable (try opening in append mode) */ /* file will be opened in write mode later, clobbering existing file */ if((fp=fopen(outfiles->outfile,"a"))==NULL){ fflush(NULL); fprintf(sp0,"file %s is not writable\n",outfiles->outfile); exit(ABNORMAL_EXIT); }else{ if(ftell(fp)){ fclose(fp); }else{ fclose(fp); remove(outfiles->outfile); } if(!strcmp(outfiles->outfile,infiles->infile) && !params->eval && !params->regrowconncomps){ fflush(NULL); fprintf(sp0,"WARNING: output will overwrite input\n"); } } /* make sure options aren't contradictory */ if(params->initonly && params->unwrapped){ fflush(NULL); fprintf(sp0,"cannot use initialize-only mode with unwrapped input\n"); exit(ABNORMAL_EXIT); } if(params->initonly && params->p>=0){ fflush(NULL); fprintf(sp0,"cannot use initialize-only mode with Lp costs\n"); exit(ABNORMAL_EXIT); } if(params->costmode==NOSTATCOSTS && !(params->initonly || params->p>=0)){ fflush(NULL); fprintf(sp0,"no-statistical-costs option can only be used in\n"); fprintf(sp0," initialize-only or Lp-norm modes\n"); exit(ABNORMAL_EXIT); } if(strlen(infiles->costinfile) && params->costmode==NOSTATCOSTS){ fflush(NULL); fprintf(sp0,"no-statistical-costs option cannot be given\n"); fprintf(sp0," if input cost file is specified\n"); exit(ABNORMAL_EXIT); } if(strlen(outfiles->costoutfile) && params->costmode==NOSTATCOSTS){ fflush(NULL); fprintf(sp0,"no-statistical-costs option cannot be given\n"); fprintf(sp0," if output cost file is specified\n"); exit(ABNORMAL_EXIT); } /* check geometry parameters */ if(params->earthradius<=0){ fflush(NULL); fprintf(sp0,"earth radius must be nonnegative\n"); exit(ABNORMAL_EXIT); } if(params->altitude){ if(params->altitude>0){ params->orbitradius=params->earthradius+params->altitude; }else{ fflush(NULL); fprintf(sp0,"platform altitude must be positive\n"); exit(ABNORMAL_EXIT); } }else if(params->orbitradius < params->earthradius){ fflush(NULL); fprintf(sp0,"platform orbit radius must be greater than earth radius\n"); exit(ABNORMAL_EXIT); } if(params->costmode==TOPO && params->baseline<0){ fflush(NULL); fprintf(sp0,"baseline length must be nonnegative\n"); exit(ABNORMAL_EXIT); } if(params->costmode==TOPO && params->baseline==0){ fflush(NULL); fprintf(sp0,"WARNING: zero baseline may give unpredictable results\n"); } if(params->ncorrlooks<=0){ fflush(NULL); fprintf(sp0,"number of looks ncorrlooks must be positive\n"); exit(ABNORMAL_EXIT); } if(params->nearrange<=0){ fflush(NULL); fprintf(sp0,"slant range parameter nearrange must be positive (meters)\n"); exit(ABNORMAL_EXIT); } if(params->dr<=0 || params->da<=0){ fflush(NULL); fprintf(sp0,"pixel spacings dr and da must be positive (meters)\n"); exit(ABNORMAL_EXIT); } /* dr and da after multilooking can be larger than rangeres, azres */ /* if(params->rangeres<=(params->dr) || params->azres<=(params->da)){ fflush(NULL); fprintf(sp0,"resolutions parameters must be larger than pixel spacings\n"); exit(ABNORMAL_EXIT); } */ if(params->lambda<=0){ fflush(NULL); fprintf(sp0,"wavelength lambda must be positive (meters)\n"); exit(ABNORMAL_EXIT); } /* check scattering model defaults */ if(params->kds<=0){ fflush(NULL); fprintf(sp0,"scattering model parameter kds must be positive\n"); exit(ABNORMAL_EXIT); } if(params->specularexp<=0){ fflush(NULL); fprintf(sp0,"scattering model parameter SPECULAREXP must be positive\n"); exit(ABNORMAL_EXIT); } if(params->dzrcritfactor<0){ fflush(NULL); fprintf(sp0,"dzrcritfactor must be nonnegative\n"); exit(ABNORMAL_EXIT); } if(params->laywidth<1){ fflush(NULL); fprintf(sp0,"layover window width laywidth must be positive\n"); exit(ABNORMAL_EXIT); } if(params->layminei<0){ fflush(NULL); fprintf(sp0,"layover minimum brightness must be nonnegative\n"); exit(ABNORMAL_EXIT); } if(params->sloperatiofactor<0){ fflush(NULL); fprintf(sp0,"slope ratio fudge factor must be nonnegative\n"); exit(ABNORMAL_EXIT); } if(params->sigsqei<=0){ fflush(NULL); fprintf(sp0,"intensity estimate variance must be positive\n"); exit(ABNORMAL_EXIT); } /* check decorrelation model defaults */ if(params->drho<=0){ fflush(NULL); fprintf(sp0,"correlation step size drho must be positive\n"); exit(ABNORMAL_EXIT); } if(params->rhosconst1<=0 || params->rhosconst2<=0){ fflush(NULL); fprintf(sp0,"parameters rhosconst1 and rhosconst2 must be positive\n"); exit(ABNORMAL_EXIT); } if(!strlen(infiles->corrfile) && (params->defaultcorr<0 || params->defaultcorr>1)){ fflush(NULL); fprintf(sp0,"default correlation must be between 0 and 1\n"); exit(ABNORMAL_EXIT); } if(params->rhominfactor<0){ fflush(NULL); fprintf(sp0,"parameter rhominfactor must be nonnegative\n"); exit(ABNORMAL_EXIT); } if(params->ncorrlooksaz<1 || params->ncorrlooksrange<1 || params->nlooksaz<1 || params->nlooksrange<1 || params->nlooksother<1){ fflush(NULL); fprintf(sp0,"numbers of looks must be positive integer\n"); exit(ABNORMAL_EXIT); } if(!strlen(infiles->corrfile)){ if(params->ncorrlooksaznlooksaz){ fflush(NULL); fprintf(sp0,"NCORRLOOKSAZ cannot be smaller than NLOOKSAZ\n"); fprintf(sp0," setting NCORRLOOKSAZ to equal NLOOKSAZ\n"); params->ncorrlooksaz=params->nlooksaz; } if(params->ncorrlooksrangenlooksrange){ fflush(NULL); fprintf(sp0,"NCORRLOOKSRANGE cannot be smaller than NLOOKSRANGE\n"); fprintf(sp0," setting NCORRLOOKSRANGE to equal NLOOKSRANGE\n"); params->ncorrlooksrange=params->nlooksrange; } } /* check pdf model parameters */ if(params->azdzfactor<0){ fflush(NULL); fprintf(sp0,"parameter azdzfactor must be nonnegative\n"); exit(ABNORMAL_EXIT); } if(params->dzeifactor<0){ fflush(NULL); fprintf(sp0,"parameter dzeifactor must be nonnegative\n"); exit(ABNORMAL_EXIT); } if(params->dzeiweight<0 || params->dzeiweight>1.0){ fflush(NULL); fprintf(sp0,"parameter dzeiweight must be between 0 and 1\n"); exit(ABNORMAL_EXIT); } if(params->dzlayfactor<0){ fflush(NULL); fprintf(sp0,"parameter dzlayfactor must be nonnegative\n"); exit(ABNORMAL_EXIT); } if(params->layconst<=0){ fflush(NULL); fprintf(sp0,"parameter layconst must be positive\n"); exit(ABNORMAL_EXIT); } if(params->layfalloffconst<0){ fflush(NULL); fprintf(sp0,"parameter layfalloffconst must be nonnegative\n"); exit(ABNORMAL_EXIT); } if(params->sigsqshortmin<=0){ fflush(NULL); fprintf(sp0,"parameter sigsqshortmin must be positive\n"); exit(ABNORMAL_EXIT); } if(params->sigsqlayfactor<0){ fflush(NULL); fprintf(sp0,"parameter sigsqlayfactor must be nonnegative\n"); exit(ABNORMAL_EXIT); } /* check deformation mode parameters */ if(params->defoazdzfactor<0){ fflush(NULL); fprintf(sp0,"parameter defoazdzfactor must be nonnegative\n"); exit(ABNORMAL_EXIT); } if(params->defothreshfactor<0){ fflush(NULL); fprintf(sp0,"parameter defothreshfactor must be nonnegative\n"); exit(ABNORMAL_EXIT); } if(params->defomax<0){ fflush(NULL); fprintf(sp0,"parameter defomax must be nonnegative\n"); exit(ABNORMAL_EXIT); } if(params->sigsqcorr<0){ fflush(NULL); fprintf(sp0,"parameter sigsqcorr must be nonnegative\n"); exit(ABNORMAL_EXIT); } if(params->defolayconst<=0){ fflush(NULL); fprintf(sp0,"parameter defolayconst must be positive\n"); exit(ABNORMAL_EXIT); } /* check algorithm parameters */ /* be sure to check for things that will cause type overflow */ /* or floating point exception */ if((params->initmaxflow)<1 && (params->initmaxflow)!=AUTOCALCSTATMAX){ fflush(NULL); fprintf(sp0,"initialization maximum flow must be positive\n"); exit(ABNORMAL_EXIT); } if((params->arcmaxflowconst)<1){ fflush(NULL); fprintf(sp0,"arcmaxflowconst must be positive\n"); exit(ABNORMAL_EXIT); } if((params->maxflow)<1){ fflush(NULL); fprintf(sp0,"maxflow must be positive\n"); exit(ABNORMAL_EXIT); } if(params->krowei<=0 || params->kcolei<=0){ fflush(NULL); fprintf(sp0,"averaging window sizes krowei and kcolei must be positive\n"); exit(ABNORMAL_EXIT); } if(params->kperpdpsi<=0 || params->kpardpsi<=0){ fflush(NULL); fprintf(sp0, "averaging window sizes kperpdpsi and kpardpsi must be positive\n"); exit(ABNORMAL_EXIT); } if(params->threshold<=0){ fflush(NULL); fprintf(sp0,"numerical solver threshold must be positive\n"); exit(ABNORMAL_EXIT); } if(params->initdzr<=0){ fflush(NULL); fprintf(sp0,"initdzr must be positive\n"); exit(ABNORMAL_EXIT); } if(params->initdzstep<=0){ fflush(NULL); fprintf(sp0,"initdzstep must be positive\n"); exit(ABNORMAL_EXIT); } if(params->maxcost>POSSHORTRANGE || params->maxcost<=0){ fflush(NULL); fprintf(sp0,"maxcost must be positive and within range or short int\n"); exit(ABNORMAL_EXIT); } if(params->costscale<=0){ fflush(NULL); fprintf(sp0,"cost scale factor costscale must be positive\n"); exit(ABNORMAL_EXIT); } if(params->p<0 && params->p!=PROBCOSTP){ fflush(NULL); fprintf(sp0,"Lp-norm parameter p should be nonnegative\n"); exit(ABNORMAL_EXIT); } if(params->costmode==TOPO && (params->maxflow*params->nshortcycle) >POSSHORTRANGE){ fflush(NULL); fprintf(sp0,"maxflow exceeds range of short int for given nshortcycle\n"); exit(ABNORMAL_EXIT); } if(params->costmode==DEFO && ceil(params->defomax*params->nshortcycle) >POSSHORTRANGE){ fflush(NULL); fprintf(sp0,"defomax exceeds range of short int for given nshortcycle\n"); exit(ABNORMAL_EXIT); } if(params->nshortcycle < 1 || params->nshortcycle > MAXNSHORTCYCLE){ fflush(NULL); fprintf(sp0,"illegal value for nshortcycle\n"); exit(ABNORMAL_EXIT); } if(params->maxnewnodeconst<=0 || params->maxnewnodeconst>1){ fflush(NULL); fprintf(sp0,"maxnewnodeconst must be between 0 and 1\n"); exit(ABNORMAL_EXIT); } if(params->nconnnodemin<0){ fflush(NULL); fprintf(sp0,"nconnnodemin must be nonnegative\n"); exit(ABNORMAL_EXIT); } if(infiles->infileformat!=FLOAT_DATA || strlen(infiles->magfile)){ params->havemagnitude=TRUE; }else{ params->havemagnitude=FALSE; } if(params->maxnflowcycles==USEMAXCYCLEFRACTION){ params->maxnflowcycles=LRound(params->maxcyclefraction *nlines/(double )params->ntilerow *linelen/(double )params->ntilecol); } if(params->initmaxflow==AUTOCALCSTATMAX && !(params->ntilerow==1 && params->ntilecol==1)){ fflush(NULL); fprintf(sp0,"initial maximum flow cannot be calculated automatically in " "tile mode\n"); exit(ABNORMAL_EXIT); } #ifdef NO_CS2 if(params->initmethod==MCFINIT && !params->unwrapped){ fflush(NULL); fprintf(sp0,"program not compiled with cs2 MCF solver module\n"); exit(ABNORMAL_EXIT); } #endif /* masking parameters */ if(strlen(infiles->bytemaskfile) || params->edgemasktop || params->edgemaskbot || params->edgemaskleft || params->edgemaskright){ if(params->initonly){ fflush(NULL); fprintf(sp0,"masking not applicable for initialize-only mode\n"); exit(ABNORMAL_EXIT); } } if(params->edgemasktop<0 || params->edgemaskbot<0 || params->edgemaskleft<0 || params->edgemaskright<0){ fflush(NULL); fprintf(sp0,"edgemask parameters cannot be negative\n"); exit(ABNORMAL_EXIT); } if(params->edgemasktop+params->edgemaskbot>=nlines || params->edgemaskleft+params->edgemaskright>=linelen){ fflush(NULL); fprintf(sp0,"edge masks cannot exceed input array size\n"); exit(ABNORMAL_EXIT); } /* tile parameters */ if(params->ntilerow<1 || params->ntilecol<1){ fflush(NULL); fprintf(sp0,"numbers of tile rows and columns must be positive\n"); exit(ABNORMAL_EXIT); } if(params->rowovrlp<0 || params->colovrlp<0){ fflush(NULL); fprintf(sp0,"tile overlaps must be nonnegative\n"); exit(ABNORMAL_EXIT); } if(params->ntilerow>1 || params->ntilecol>1){ ni=ceil((nlines+(params->ntilerow-1)*params->rowovrlp) /(double )params->ntilerow); nj=ceil((linelen+(params->ntilecol-1)*params->colovrlp) /(double )params->ntilecol); if(params->ntilerow+params->rowovrlp > nlines || params->ntilecol+params->colovrlp > linelen || params->ntilerow*params->ntilerow > nlines || params->ntilecol*params->ntilecol > linelen){ fflush(NULL); fprintf(sp0,"tiles too small or overlap too large for given input\n"); exit(ABNORMAL_EXIT); } if(params->minregionsize > ((nlines-(params->ntilerow-1)*(ni-params->rowovrlp)) *(linelen-(params->ntilecol-1)*(nj-params->colovrlp)))){ fflush(NULL); fprintf(sp0,"minimum region size too large for given tile parameters\n"); exit(ABNORMAL_EXIT); } if(TMPTILEOUTFORMAT!=ALT_LINE_DATA && TMPTILEOUTFORMAT!=FLOAT_DATA){ fflush(NULL); fprintf(sp0,"unsupported TMPTILEOUTFORMAT value in complied binary\n"); exit(ABNORMAL_EXIT); } if(TMPTILEOUTFORMAT==FLOAT_DATA && outfiles->outfileformat!=FLOAT_DATA){ fflush(NULL); fprintf(sp0,"precompiled tile format precludes given output format\n"); exit(ABNORMAL_EXIT); } if(params->scndryarcflowmax<1){ fflush(NULL); fprintf(sp0,"parameter scndryarcflowmax too small\n"); exit(ABNORMAL_EXIT); } if(params->initonly){ fflush(NULL); fprintf(sp0, "initialize-only mode and tile mode are mutually exclusive\n"); exit(ABNORMAL_EXIT); } if(params->assembleonly){ n=strlen(params->tiledir); while(--n>0 && params->tiledir[n]=='/'){ params->tiledir[n]='\0'; } if(!strlen(params->tiledir)){ fflush(NULL); fprintf(sp0,"tile directory name must be specified\n"); exit(ABNORMAL_EXIT); } if(!strcmp(params->tiledir,"/")){ StrNCopy(params->tiledir,"",MAXSTRLEN); } params->rmtmptile=FALSE; /* cowardly avoid removing tile dir input */ } if(params->piecefirstrow!=DEF_PIECEFIRSTROW || params->piecefirstcol!=DEF_PIECEFIRSTCOL || params->piecenrow!=DEF_PIECENROW || params->piecencol!=DEF_PIECENCOL){ fflush(NULL); fprintf(sp0,"piece-only mode cannot be used with multiple tiles\n"); exit(ABNORMAL_EXIT); } if(params->costmode==NOSTATCOSTS){ fflush(NULL); fprintf(sp0,"no-statistical-costs option cannot be used in tile mode\n"); exit(ABNORMAL_EXIT); } if(params->rowovrlpcolovrlpassembleonly){ fflush(NULL); fprintf(sp0,"assemble-only mode can only be used with multiple tiles\n"); exit(ABNORMAL_EXIT); } if(params->nthreads>1){ fflush(NULL); fprintf(sp0,"only one tile--disregarding multiprocessor option\n"); } if(params->rowovrlp || params->colovrlp){ fflush(NULL); fprintf(sp0,"only one tile--disregarding tile overlap values\n"); } if(params->onetilereopt){ fprintf(sp0, "cannot do single-tile reoptimization without tiling params\n"); exit(ABNORMAL_EXIT); } } if(params->nthreads<1){ fflush(NULL); fprintf(sp0,"number of processors must be at least one\n"); exit(ABNORMAL_EXIT); }else if(params->nthreads>MAXTHREADS){ fflush(NULL); fprintf(sp0,"number of processors exceeds precomplied limit of %d\n", MAXTHREADS); exit(ABNORMAL_EXIT); } /* piece params */ params->piecefirstrow--; /* index from 0 instead of 1 */ params->piecefirstcol--; /* index from 0 instead of 1 */ if(!params->piecenrow){ params->piecenrow=nlines; } if(!params->piecencol){ params->piecencol=linelen; } if(params->piecefirstrow<0 || params->piecefirstcol<0 || params->piecenrow<1 || params->piecencol<1 || params->piecefirstrow+params->piecenrow>nlines || params->piecefirstcol+params->piecencol>linelen){ fflush(NULL); fprintf(sp0,"illegal values for piece of interferogram to unwrap\n"); exit(ABNORMAL_EXIT); } /* connected component parameters */ if(params->regrowconncomps){ if(!strlen(outfiles->conncompfile)){ fflush(NULL); fprintf(sp0,"no connected component output file specified\n"); exit(ABNORMAL_EXIT); } params->unwrapped=TRUE; } if(params->minconncompfrac<0 || params->minconncompfrac>1){ fflush(NULL); fprintf(sp0,"illegal value for minimum connected component fraction\n"); exit(ABNORMAL_EXIT); } if(params->maxncomps<=0){ fflush(NULL); fprintf(sp0,"illegal value for maximum number of connected components\n"); exit(ABNORMAL_EXIT); } if(params->maxncomps>UCHAR_MAX && params->conncompouttype==CONNCOMPOUTTYPEUCHAR){ fflush(NULL); fprintf(sp0,"WARNING: clipping max num conn comps to fit uchar out type\n"); params->maxncomps=UCHAR_MAX; } if(params->maxncomps>UINT_MAX && params->conncompouttype==CONNCOMPOUTTYPEUINT){ fflush(NULL); fprintf(sp0,"WARNING: clipping max num conn comps to fit uint out type\n"); params->maxncomps=UINT_MAX; } if(strlen(outfiles->conncompfile)){ if(params->initonly){ fflush(NULL); fprintf(sp0,"WARNING: connected component mask cannot be generated " "in initialize-only mode\n mask will not be output\n"); StrNCopy(outfiles->conncompfile,"",MAXSTRLEN); } if(params->costmode==NOSTATCOSTS){ fflush(NULL); fprintf(sp0,"WARNING: connected component mask cannot be generated " "without statistical costs\n mask will not be output\n"); StrNCopy(outfiles->conncompfile,"",MAXSTRLEN); } } /* done */ return(0); } /* function: ReadConfigFile() * -------------------------- * Read in parameter values from a file, overriding existing parameters. */ int ReadConfigFile(char *conffile, infileT *infiles, outfileT *outfiles, long *linelenptr, paramT *params){ int parsestatus; long nlines, nparams; char *ptr; char buf[MAXLINELEN]; FILE *fp; /* open input config file */ if(strlen(conffile)){ if((fp=fopen(conffile,"r"))==NULL){ /* abort if we were given a non-zero length name that is unreadable */ fflush(NULL); fprintf(sp0,"unable to read configuration file %s\n",conffile); exit(ABNORMAL_EXIT); } }else{ /* if we were given a zero-length name, just ignore it and go on */ return(0); } /* read each line and convert the first two fields */ nlines=0; nparams=0; while(TRUE){ /* read a line from the file and store it in buffer buf */ buf[0]='\0'; ptr=fgets(buf,MAXLINELEN,fp); /* break when we read EOF without reading any text */ if(ptr==NULL && !strlen(buf)){ break; } nlines++; /* make sure we got the whole line */ if(strlen(buf)>=MAXLINELEN-1){ fflush(NULL); fprintf(sp0,"line %ld in file %s exceeds maximum line length\n", nlines,conffile); exit(ABNORMAL_EXIT); } /* parse config line */ parsestatus=ParseConfigLine(buf,conffile,nlines, infiles,outfiles,linelenptr,params); if(parsestatus>0){ nparams++; } } /* finish up */ fclose(fp); if(nparams>1){ fprintf(sp1,"%ld parameters input from file %s (%ld lines total)\n", nparams,conffile,nlines); }else{ if(nlines>1){ fprintf(sp1,"%ld parameter input from file %s (%ld lines total)\n", nparams,conffile,nlines); }else{ fprintf(sp1,"%ld parameter input from file %s (%ld line total)\n", nparams,conffile,nlines); } } /* done */ return(0); } /* function: ParseConfigLine() * --------------------------- * Parse config line from passed buffer. */ static int ParseConfigLine(char *buf, char *conffile, long nlines, infileT *infiles, outfileT *outfiles, long *linelenptr, paramT *params){ int nparams; long nfields; char str1[MAXLINELEN], str2[MAXLINELEN]; signed char badparam; /* set up */ nparams=0; badparam=FALSE; /* read the first two fields */ /* (str1, str2 same size as buf, so can't overflow them */ nfields=sscanf(buf,"%s %s",str1,str2); /* if only one field is read, and it is not a comment, we have an error */ if(nfields==1 && isalnum(str1[0])){ fflush(NULL); fprintf(sp0,"unrecognized configuration parameter '%s' (%s:%ld)\n", str1,conffile,nlines); exit(ABNORMAL_EXIT); } /* if we have (at least) two non-comment fields */ if(nfields==2 && isalnum(str1[0])){ /* do the conversions */ nparams++; if(!strcmp(str1,"INFILE")){ StrNCopy(infiles->infile,str2,MAXSTRLEN); }else if(!strcmp(str1,"OUTFILE")){ StrNCopy(outfiles->outfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"WEIGHTFILE")){ StrNCopy(infiles->weightfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"AMPFILE") || !strcmp(str1,"AMPFILE1")){ if(strlen(infiles->ampfile2) && !params->amplitude){ fflush(NULL); fprintf(sp0,"cannot specify both amplitude and power\n"); exit(ABNORMAL_EXIT); } StrNCopy(infiles->ampfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"AMPFILE2")){ if(strlen(infiles->ampfile) && !params->amplitude){ fflush(NULL); fprintf(sp0,"cannot specify both amplitude and power\n"); exit(ABNORMAL_EXIT); } StrNCopy(infiles->ampfile2,str2,MAXSTRLEN); infiles->ampfileformat=FLOAT_DATA; }else if(!strcmp(str1,"PWRFILE") || !strcmp(str1,"PWRFILE1")){ if(strlen(infiles->ampfile2) && params->amplitude){ fflush(NULL); fprintf(sp0,"cannot specify both amplitude and power\n"); exit(ABNORMAL_EXIT); } StrNCopy(infiles->ampfile,str2,MAXSTRLEN); params->amplitude=FALSE; }else if(!strcmp(str1,"PWRFILE2")){ if(strlen(infiles->ampfile) && params->amplitude){ fflush(NULL); fprintf(sp0,"cannot specify both amplitude and power\n"); exit(ABNORMAL_EXIT); } StrNCopy(infiles->ampfile2,str2,MAXSTRLEN); params->amplitude=FALSE; infiles->ampfileformat=FLOAT_DATA; }else if(!strcmp(str1,"MAGFILE")){ StrNCopy(infiles->magfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"CORRFILE")){ StrNCopy(infiles->corrfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"ESTIMATEFILE")){ StrNCopy(infiles->estfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"LINELENGTH") || !strcmp(str1,"LINELEN")){ badparam=StringToLong(str2,linelenptr); }else if(!strcmp(str1,"STATCOSTMODE")){ if(!strcmp(str2,"TOPO")){ params->costmode=TOPO; }else if(!strcmp(str2,"DEFO")){ params->costmode=DEFO; }else if(!strcmp(str2,"SMOOTH")){ params->costmode=SMOOTH; }else if(!strcmp(str2,"NOSTATCOSTS")){ params->costmode=NOSTATCOSTS; }else{ badparam=TRUE; } }else if(!strcmp(str1,"INITONLY")){ badparam=SetBooleanSignedChar(&(params->initonly),str2); }else if(!strcmp(str1,"UNWRAPPED_IN")){ badparam=SetBooleanSignedChar(&(params->unwrapped),str2); }else if(!strcmp(str1,"DEBUG") || !strcmp(str1,"DUMPALL")){ badparam=SetBooleanSignedChar(&(params->dumpall),str2); }else if(!strcmp(str1,"VERBOSE")){ badparam=SetBooleanSignedChar(&(params->verbose),str2); }else if(!strcmp(str1,"INITMETHOD")){ if(!strcmp(str2,"MST") || !strcmp(str2,"mst")){ params->initmethod=MSTINIT; }else if(!strcmp(str2,"MCF") || !strcmp(str2,"mcf") || !strcmp(str2,"CS2") || !strcmp(str2,"cs2")){ params->initmethod=MCFINIT; }else{ badparam=TRUE; } }else if(!strcmp(str1,"ORBITRADIUS")){ if(!(badparam=StringToDouble(str2,&(params->orbitradius)))){ params->altitude=0; } }else if(!strcmp(str1,"ALTITUDE")){ if(!(badparam=StringToDouble(str2,&(params->altitude)))){ params->orbitradius=0; } }else if(!strcmp(str1,"EARTHRADIUS")){ badparam=StringToDouble(str2,&(params->earthradius)); }else if(!strcmp(str1,"BPERP")){ badparam=StringToDouble(str2,&(params->bperp)); }else if(!strcmp(str1,"TRANSMITMODE")){ if(!strcmp(str2,"PINGPONG") || !strcmp(str2,"REPEATPASS")){ params->transmitmode=PINGPONG; }else if(!strcmp(str2,"SINGLEANTENNATRANSMIT") || !strcmp(str2,"SAT") || !strcmp(str2,"SINGLEANTTRANSMIT")){ params->transmitmode=SINGLEANTTRANSMIT; }else{ badparam=TRUE; } }else if(!strcmp(str1,"BASELINE")){ if(!(badparam=StringToDouble(str2,&(params->baseline)))){ params->bperp=0; } }else if(!strcmp(str1,"BASELINEANGLE_RAD")){ if(!(badparam=StringToDouble(str2,&(params->baselineangle)))){ params->bperp=0; } }else if(!strcmp(str1,"BASELINEANGLE_DEG")){ if(!(badparam=StringToDouble(str2,&(params->baselineangle)))){ (params->baselineangle)*=(PI/180.0); params->bperp=0; } }else if(!strcmp(str1,"NLOOKSRANGE")){ badparam=StringToLong(str2,&(params->nlooksrange)); }else if(!strcmp(str1,"NLOOKSAZ")){ badparam=StringToLong(str2,&(params->nlooksaz)); }else if(!strcmp(str1,"NLOOKSOTHER")){ badparam=StringToLong(str2,&(params->nlooksother)); }else if(!strcmp(str1,"NCORRLOOKS")){ badparam=StringToDouble(str2,&(params->ncorrlooks)); }else if(!strcmp(str1,"NCORRLOOKSRANGE")){ badparam=StringToLong(str2,&(params->ncorrlooksrange)); }else if(!strcmp(str1,"NCORRLOOKSAZ")){ badparam=StringToLong(str2,&(params->ncorrlooksaz)); }else if(!strcmp(str1,"NEARRANGE") || !strcmp(str1,"NOMRANGE")){ badparam=StringToDouble(str2,&(params->nearrange)); }else if(!strcmp(str1,"DR")){ badparam=StringToDouble(str2,&(params->dr)); }else if(!strcmp(str1,"DA")){ badparam=StringToDouble(str2,&(params->da)); }else if(!strcmp(str1,"RANGERES")){ badparam=StringToDouble(str2,&(params->rangeres)); }else if(!strcmp(str1,"AZRES")){ badparam=StringToDouble(str2,&(params->azres)); }else if(!strcmp(str1,"LAMBDA")){ badparam=StringToDouble(str2,&(params->lambda)); }else if(!strcmp(str1,"KDS") || !strcmp(str1,"KSD")){ if(!strcmp(str1,"KSD")){ fflush(NULL); fprintf(sp0,"WARNING: parameter KSD interpreted as KDS (%s:%ld)\n", conffile,nlines); } badparam=StringToDouble(str2,&(params->kds)); }else if(!strcmp(str1,"SPECULAREXP") || !strcmp(str1,"N")){ badparam=StringToDouble(str2,&(params->specularexp)); }else if(!strcmp(str1,"DZRCRITFACTOR")){ badparam=StringToDouble(str2,&(params->dzrcritfactor)); }else if(!strcmp(str1,"SHADOW")){ badparam=SetBooleanSignedChar(&(params->shadow),str2); }else if(!strcmp(str1,"DZEIMIN")){ badparam=StringToDouble(str2,&(params->dzeimin)); }else if(!strcmp(str1,"LAYWIDTH")){ badparam=StringToLong(str2,&(params->laywidth)); }else if(!strcmp(str1,"LAYMINEI")){ badparam=StringToDouble(str2,&(params->layminei)); }else if(!strcmp(str1,"SLOPERATIOFACTOR")){ badparam=StringToDouble(str2,&(params->sloperatiofactor)); }else if(!strcmp(str1,"SIGSQEI")){ badparam=StringToDouble(str2,&(params->sigsqei)); }else if(!strcmp(str1,"DRHO")){ badparam=StringToDouble(str2,&(params->drho)); }else if(!strcmp(str1,"RHOSCONST1")){ badparam=StringToDouble(str2,&(params->rhosconst1)); }else if(!strcmp(str1,"RHOSCONST2")){ badparam=StringToDouble(str2,&(params->rhosconst2)); }else if(!strcmp(str1,"CSTD1")){ badparam=StringToDouble(str2,&(params->cstd1)); }else if(!strcmp(str1,"CSTD2")){ badparam=StringToDouble(str2,&(params->cstd2)); }else if(!strcmp(str1,"CSTD3")){ badparam=StringToDouble(str2,&(params->cstd3)); }else if(!strcmp(str1,"DEFAULTCORR")){ badparam=StringToDouble(str2,&(params->defaultcorr)); }else if(!strcmp(str1,"RHOMINFACTOR")){ badparam=StringToDouble(str2,&(params->rhominfactor)); }else if(!strcmp(str1,"DZLAYPEAK")){ badparam=StringToDouble(str2,&(params->dzlaypeak)); }else if(!strcmp(str1,"AZDZFACTOR")){ badparam=StringToDouble(str2,&(params->azdzfactor)); }else if(!strcmp(str1,"DZEIFACTOR")){ badparam=StringToDouble(str2,&(params->dzeifactor)); }else if(!strcmp(str1,"DZEIWEIGHT")){ badparam=StringToDouble(str2,&(params->dzeiweight)); }else if(!strcmp(str1,"DZLAYFACTOR")){ badparam=StringToDouble(str2,&(params->dzlayfactor)); }else if(!strcmp(str1,"LAYCONST")){ badparam=StringToDouble(str2,&(params->layconst)); }else if(!strcmp(str1,"LAYFALLOFFCONST")){ badparam=StringToDouble(str2,&(params->layfalloffconst)); }else if(!strcmp(str1,"SIGSQSHORTMIN")){ badparam=StringToLong(str2,&(params->sigsqshortmin)); }else if(!strcmp(str1,"SIGSQLAYFACTOR")){ badparam=StringToDouble(str2,&(params->sigsqlayfactor)); }else if(!strcmp(str1,"DEFOAZDZFACTOR")){ badparam=StringToDouble(str2,&(params->defoazdzfactor)); }else if(!strcmp(str1,"DEFOTHRESHFACTOR")){ badparam=StringToDouble(str2,&(params->defothreshfactor)); }else if(!strcmp(str1,"DEFOMAX_CYCLE")){ badparam=StringToDouble(str2,&(params->defomax)); }else if(!strcmp(str1,"DEFOMAX_RAD")){ if(!(badparam=StringToDouble(str2,&(params->defomax)))){ params->defomax/=TWOPI; } }else if(!strcmp(str1,"SIGSQCORR")){ badparam=StringToDouble(str2,&(params->sigsqcorr)); }else if(!strcmp(str1,"DEFOLAYCONST") || !strcmp(str1,"DEFOCONST")){ badparam=StringToDouble(str2,&(params->defolayconst)); }else if(!strcmp(str1,"INITMAXFLOW")){ badparam=StringToLong(str2,&(params->initmaxflow)); }else if(!strcmp(str1,"ARCMAXFLOWCONST")){ badparam=StringToLong(str2,&(params->arcmaxflowconst)); }else if(!strcmp(str1,"MAXFLOW")){ badparam=StringToLong(str2,&(params->maxflow)); }else if(!strcmp(str1,"KROWEI") || !strcmp(str1,"KROW")){ badparam=StringToLong(str2,&(params->krowei)); }else if(!strcmp(str1,"KCOLEI") || !strcmp(str1,"KCOL")){ badparam=StringToLong(str2,&(params->kcolei)); }else if(!strcmp(str1,"KPERPDPSI")){ badparam=StringToLong(str2,&(params->kperpdpsi)); }else if(!strcmp(str1,"KPARDPSI")){ badparam=StringToLong(str2,&(params->kpardpsi)); }else if(!strcmp(str1,"THRESHOLD")){ badparam=StringToDouble(str2,&(params->threshold)); }else if(!strcmp(str1,"INITDZR")){ badparam=StringToDouble(str2,&(params->initdzr)); }else if(!strcmp(str1,"INITDZSTEP")){ badparam=StringToDouble(str2,&(params->initdzstep)); }else if(!strcmp(str1,"MAXCOST")){ badparam=StringToDouble(str2,&(params->maxcost)); }else if(!strcmp(str1,"COSTSCALE")){ badparam=StringToDouble(str2,&(params->costscale)); }else if(!strcmp(str1,"COSTSCALEAMBIGHT")){ badparam=StringToDouble(str2,&(params->costscaleambight)); }else if(!strcmp(str1,"DNOMINCANGLE")){ badparam=StringToDouble(str2,&(params->dnomincangle)); }else if(!strcmp(str1,"CS2SCALEFACTOR")){ badparam=StringToLong(str2,&(params->cs2scalefactor)); }else if(!strcmp(str1,"NMAJORPRUNE")){ badparam=StringToLong(str2,&(params->nmajorprune)); }else if(!strcmp(str1,"PRUNECOSTTHRESH")){ badparam=StringToLong(str2,&(params->prunecostthresh)); }else if(!strcmp(str1,"PLPN")){ badparam=StringToDouble(str2,&(params->p)); }else if(!strcmp(str1,"BIDIRLPN")){ badparam=SetBooleanSignedChar(&(params->bidirlpn),str2); }else if(!strcmp(str1,"EDGEMASKTOP")){ badparam=StringToLong(str2,&(params->edgemasktop)); }else if(!strcmp(str1,"EDGEMASKBOT")){ badparam=StringToLong(str2,&(params->edgemaskbot)); }else if(!strcmp(str1,"EDGEMASKLEFT")){ badparam=StringToLong(str2,&(params->edgemaskleft)); }else if(!strcmp(str1,"EDGEMASKRIGHT")){ badparam=StringToLong(str2,&(params->edgemaskright)); }else if(!strcmp(str1,"PIECEFIRSTROW")){ badparam=StringToLong(str2,&(params->piecefirstrow)); }else if(!strcmp(str1,"PIECEFIRSTCOL")){ badparam=StringToLong(str2,&(params->piecefirstcol)); }else if(!strcmp(str1,"PIECENROW")){ badparam=StringToLong(str2,&(params->piecenrow)); }else if(!strcmp(str1,"PIECENCOL")){ badparam=StringToLong(str2,&(params->piecencol)); }else if(!strcmp(str1,"NTILEROW")){ badparam=StringToLong(str2,&(params->ntilerow)); }else if(!strcmp(str1,"NTILECOL")){ badparam=StringToLong(str2,&(params->ntilecol)); }else if(!strcmp(str1,"ROWOVRLP")){ badparam=StringToLong(str2,&(params->rowovrlp)); }else if(!strcmp(str1,"COLOVRLP")){ badparam=StringToLong(str2,&(params->colovrlp)); }else if(!strcmp(str1,"TILECOSTTHRESH")){ badparam=StringToLong(str2,&(params->tilecostthresh)); }else if(!strcmp(str1,"MINREGIONSIZE")){ badparam=StringToLong(str2,&(params->minregionsize)); }else if(!strcmp(str1,"TILEEDGEWEIGHT")){ badparam=StringToDouble(str2,&(params->tileedgeweight)); }else if(!strcmp(str1,"SCNDRYARCFLOWMAX")){ badparam=StringToLong(str2,&(params->scndryarcflowmax)); }else if(!strcmp(str1,"TILEDIR")){ StrNCopy(params->tiledir,str2,MAXSTRLEN); }else if(!strcmp(str1,"ASSEMBLEONLY")){ badparam=SetBooleanSignedChar(&(params->assembleonly),str2); }else if(!strcmp(str1,"SINGLETILEREOPTIMIZE")){ badparam=SetBooleanSignedChar(&(params->onetilereopt),str2); }else if(!strcmp(str1,"RMTMPTILE")){ badparam=SetBooleanSignedChar(&(params->rmtmptile),str2); params->rmtileinit=params->rmtmptile; }else if(!strcmp(str1,"MINCONNCOMPFRAC")){ badparam=StringToDouble(str2,&(params->minconncompfrac)); }else if(!strcmp(str1,"CONNCOMPTHRESH")){ badparam=StringToLong(str2,&(params->conncompthresh)); }else if(!strcmp(str1,"MAXNCOMPS")){ badparam=StringToLong(str2,&(params->maxncomps)); }else if(!strcmp(str1,"CONNCOMPOUTTYPE")){ if(!strcmp(str2,"UCHAR")){ params->conncompouttype=CONNCOMPOUTTYPEUCHAR; }else if(!strcmp(str2,"UINT")){ params->conncompouttype=CONNCOMPOUTTYPEUINT; }else{ badparam=TRUE; } }else if(!strcmp(str1,"NSHORTCYCLE")){ badparam=StringToLong(str2,&(params->nshortcycle)); }else if(!strcmp(str1,"MAXNEWNODECONST")){ badparam=StringToDouble(str2,&(params->maxnewnodeconst)); }else if(!strcmp(str1,"MAXNFLOWCYCLES")){ badparam=StringToLong(str2,&(params->maxnflowcycles)); }else if(!strcmp(str1,"MAXCYCLEFRACTION")){ badparam=StringToDouble(str2,&(params->maxcyclefraction)); params->maxnflowcycles=USEMAXCYCLEFRACTION; }else if(!strcmp(str1,"SOURCEMODE")){ fflush(NULL); fprintf(sp0, "WARNING: SOURCEMODE keyword no longer supported--ignoring\n"); }else if(!strcmp(str1,"NCONNNODEMIN")){ badparam=StringToLong(str2,&(params->nconnnodemin)); }else if(!strcmp(str1,"NPROC") || !strcmp(str1,"NTHREADS")){ badparam=StringToLong(str2,&(params->nthreads)); }else if(!strcmp(str1,"COSTINFILE")){ StrNCopy(infiles->costinfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"BYTEMASKFILE")){ StrNCopy(infiles->bytemaskfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"DOTILEMASKFILE")){ StrNCopy(infiles->dotilemaskfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"COSTOUTFILE")){ StrNCopy(outfiles->costoutfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"LOGFILE")){ StrNCopy(outfiles->logfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"INFILEFORMAT")){ if(!strcmp(str2,"COMPLEX_DATA")){ infiles->infileformat=COMPLEX_DATA; }else if(!strcmp(str2,"FLOAT_DATA")){ infiles->infileformat=FLOAT_DATA; }else if(!strcmp(str2,"ALT_LINE_DATA")){ infiles->infileformat=ALT_LINE_DATA; }else if(!strcmp(str2,"ALT_SAMPLE_DATA")){ infiles->infileformat=ALT_SAMPLE_DATA; }else{ badparam=TRUE; } }else if(!strcmp(str1,"UNWRAPPEDINFILEFORMAT")){ if(!strcmp(str2,"ALT_LINE_DATA")){ infiles->unwrappedinfileformat=ALT_LINE_DATA; }else if(!strcmp(str2,"ALT_SAMPLE_DATA")){ infiles->unwrappedinfileformat=ALT_SAMPLE_DATA; }else if(!strcmp(str2,"FLOAT_DATA")){ infiles->unwrappedinfileformat=FLOAT_DATA; }else{ badparam=TRUE; } }else if(!strcmp(str1,"MAGFILEFORMAT")){ if(!strcmp(str2,"ALT_LINE_DATA")){ infiles->magfileformat=ALT_LINE_DATA; }else if(!strcmp(str2,"ALT_SAMPLE_DATA")){ infiles->magfileformat=ALT_SAMPLE_DATA; }else if(!strcmp(str2,"FLOAT_DATA")){ infiles->magfileformat=FLOAT_DATA; }else if(!strcmp(str2,"COMPLEX_DATA")){ infiles->magfileformat=COMPLEX_DATA; }else{ badparam=TRUE; } }else if(!strcmp(str1,"OUTFILEFORMAT")){ if(!strcmp(str2,"ALT_LINE_DATA")){ outfiles->outfileformat=ALT_LINE_DATA; }else if(!strcmp(str2,"ALT_SAMPLE_DATA")){ outfiles->outfileformat=ALT_SAMPLE_DATA; }else if(!strcmp(str2,"FLOAT_DATA")){ outfiles->outfileformat=FLOAT_DATA; }else{ badparam=TRUE; } }else if(!strcmp(str1,"CORRFILEFORMAT")){ if(!strcmp(str2,"ALT_LINE_DATA")){ infiles->corrfileformat=ALT_LINE_DATA; }else if(!strcmp(str2,"ALT_SAMPLE_DATA")){ infiles->corrfileformat=ALT_SAMPLE_DATA; }else if(!strcmp(str2,"FLOAT_DATA")){ infiles->corrfileformat=FLOAT_DATA; }else{ badparam=TRUE; } }else if(!strcmp(str1,"AMPFILEFORMAT")){ if(!strcmp(str2,"ALT_LINE_DATA")){ infiles->ampfileformat=ALT_LINE_DATA; }else if(!strcmp(str2,"ALT_SAMPLE_DATA")){ infiles->ampfileformat=ALT_SAMPLE_DATA; }else if(!strcmp(str2,"FLOAT_DATA")){ infiles->ampfileformat=FLOAT_DATA; }else{ badparam=TRUE; } }else if(!strcmp(str1,"ESTFILEFORMAT")){ if(!strcmp(str2,"ALT_LINE_DATA")){ infiles->estfileformat=ALT_LINE_DATA; }else if(!strcmp(str2,"ALT_SAMPLE_DATA")){ infiles->estfileformat=ALT_SAMPLE_DATA; }else if(!strcmp(str2,"FLOAT_DATA")){ infiles->estfileformat=FLOAT_DATA; }else{ badparam=TRUE; } }else if(!strcmp(str1,"INITFILE")){ StrNCopy(outfiles->initfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"FLOWFILE")){ StrNCopy(outfiles->flowfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"EIFILE")){ StrNCopy(outfiles->eifile,str2,MAXSTRLEN); }else if(!strcmp(str1,"ROWCOSTFILE")){ StrNCopy(outfiles->rowcostfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"COLCOSTFILE")){ StrNCopy(outfiles->colcostfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"MSTROWCOSTFILE")){ StrNCopy(outfiles->mstrowcostfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"MSTCOLCOSTFILE")){ StrNCopy(outfiles->mstcolcostfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"MSTCOSTSFILE")){ StrNCopy(outfiles->mstcostsfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"CORRDUMPFILE")){ StrNCopy(outfiles->corrdumpfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"RAWCORRDUMPFILE")){ StrNCopy(outfiles->rawcorrdumpfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"CONNCOMPFILE")){ StrNCopy(outfiles->conncompfile,str2,MAXSTRLEN); }else if(!strcmp(str1,"REGROWCONNCOMPS")){ badparam=SetBooleanSignedChar(&(params->regrowconncomps),str2); }else{ fflush(NULL); fprintf(sp0,"unrecognized configuration parameter '%s' (%s:%ld)\n", str1,conffile,nlines); exit(ABNORMAL_EXIT); } /* give an error if we had trouble interpreting the line */ if(badparam){ fflush(NULL); fprintf(sp0,"illegal argument %s for parameter %s (%s:%ld)\n", str2,str1,conffile,nlines); exit(ABNORMAL_EXIT); } } /* return number of parameters successfully parsed */ return(nparams); } /* function: WriteConfigLogFile() * ------------------------------ * Writes a text log file of configuration parameters and other * information. The log file is in a format compatible to be used as * a configuration file. */ int WriteConfigLogFile(int argc, char *argv[], infileT *infiles, outfileT *outfiles, long linelen, paramT *params){ FILE *fp; time_t t[1]; long k; char buf[MAXSTRLEN], *ptr; char hostnamestr[MAXSTRLEN]; /* see if we need to write a log file */ if(strlen(outfiles->logfile)){ /* open the log file */ if((fp=fopen(outfiles->logfile,"w"))==NULL){ fflush(NULL); fprintf(sp0,"unable to write to log file %s\n",outfiles->logfile); exit(ABNORMAL_EXIT); } fprintf(sp1,"Logging run-time parameters to file %s\n",outfiles->logfile); /* print some run-time environment information */ fprintf(fp,"# %s v%s\n",PROGRAMNAME,VERSION); time(t); fprintf(fp,"# Log file generated %s",ctime(t)); if(gethostname(hostnamestr,MAXSTRLEN)){ fprintf(fp,"# Could not determine host name\n"); }else{ fprintf(fp,"# Host name: %s\n",hostnamestr); } fprintf(fp,"# PID %ld\n",params->parentpid); ptr=getcwd(buf,MAXSTRLEN); if(ptr!=NULL){ fprintf(fp,"# Current working directory: %s\n",buf); }else{ fprintf(fp,"# Could not determine current working directory\n"); } fprintf(fp,"# Command line call:"); for(k=0;kinfile); fprintf(fp,"LINELENGTH %ld\n",linelen); LogStringParam(fp,"OUTFILE",outfiles->outfile); LogStringParam(fp,"WEIGHTFILE",infiles->weightfile); if(params->amplitude){ if(strlen(infiles->ampfile2)){ LogStringParam(fp,"AMPFILE1",infiles->ampfile); LogStringParam(fp,"AMPFILE2",infiles->ampfile2); }else{ LogStringParam(fp,"AMPFILE",infiles->ampfile); } }else{ if(strlen(infiles->ampfile2)){ LogStringParam(fp,"PWRFILE1",infiles->ampfile); LogStringParam(fp,"PWRFILE2",infiles->ampfile2); }else{ LogStringParam(fp,"PWRFILE",infiles->ampfile); } } LogStringParam(fp,"MAGFILE",infiles->magfile); LogStringParam(fp,"CORRFILE",infiles->corrfile); LogStringParam(fp,"ESTIMATEFILE",infiles->estfile); LogStringParam(fp,"COSTINFILE",infiles->costinfile); LogStringParam(fp,"COSTOUTFILE",outfiles->costoutfile); LogStringParam(fp,"BYTEMASKFILE",infiles->bytemaskfile); LogStringParam(fp,"LOGFILE",outfiles->logfile); if(params->costmode==TOPO){ fprintf(fp,"STATCOSTMODE TOPO\n"); }else if(params->costmode==DEFO){ fprintf(fp,"STATCOSTMODE DEFO\n"); }else if(params->costmode==SMOOTH){ fprintf(fp,"STATCOSTMODE SMOOTH\n"); }else if(params->costmode==NOSTATCOSTS){ fprintf(fp,"STATCOSTMODE NOSTATCOSTS\n"); } LogBoolParam(fp,"INITONLY",params->initonly); LogBoolParam(fp,"UNWRAPPED_IN",params->unwrapped); LogBoolParam(fp,"DEBUG",params->dumpall); if(params->initmethod==MSTINIT){ fprintf(fp,"INITMETHOD MST\n"); }else if(params->initmethod==MCFINIT){ fprintf(fp,"INITMETHOD MCF\n"); } LogBoolParam(fp,"VERBOSE",params->verbose); /* file formats */ fprintf(fp,"\n# File Formats\n"); LogFileFormat(fp,"INFILEFORMAT",infiles->infileformat); LogFileFormat(fp,"OUTFILEFORMAT",outfiles->outfileformat); LogFileFormat(fp,"AMPFILEFORMAT",infiles->ampfileformat); LogFileFormat(fp,"MAGFILEFORMAT",infiles->magfileformat); LogFileFormat(fp,"CORRFILEFORMAT",infiles->corrfileformat); LogFileFormat(fp,"ESTFILEFORMAT",infiles->estfileformat); LogFileFormat(fp,"UNWRAPPEDINFILEFORMAT",infiles->unwrappedinfileformat); /* SAR and geometry parameters */ fprintf(fp,"\n# SAR and Geometry Parameters\n"); fprintf(fp,"ALTITUDE %.8f\n", params->orbitradius-params->earthradius); fprintf(fp,"# ORBITRADIUS %.8f\n",params->orbitradius); fprintf(fp,"EARTHRADIUS %.8f\n",params->earthradius); if(params->bperp){ fprintf(fp,"BPERP %.8f\n",params->bperp); }else{ fprintf(fp,"BASELINE %.8f\n",params->baseline); fprintf(fp,"BASELINEANGLE_DEG %.8f\n", params->baselineangle*(180.0/PI)); } if(params->transmitmode==PINGPONG){ fprintf(fp,"TRANSMITMODE REPEATPASS\n"); }else if(params->transmitmode==SINGLEANTTRANSMIT){ fprintf(fp,"TRANSMITMODE SINGLEANTENNATRANSMIT\n"); } fprintf(fp,"NEARRANGE %.8f\n",params->nearrange); fprintf(fp,"DR %.8f\n",params->dr); fprintf(fp,"DA %.8f\n",params->da); fprintf(fp,"RANGERES %.8f\n",params->rangeres); fprintf(fp,"AZRES %.8f\n",params->azres); fprintf(fp,"LAMBDA %.8f\n",params->lambda); fprintf(fp,"NLOOKSRANGE %ld\n",params->nlooksrange); fprintf(fp,"NLOOKSAZ %ld\n",params->nlooksaz); fprintf(fp,"NLOOKSOTHER %ld\n",params->nlooksother); fprintf(fp,"NCORRLOOKS %.8f\n",params->ncorrlooks); fprintf(fp,"NCORRLOOKSRANGE %ld\n",params->ncorrlooksrange); fprintf(fp,"NCORRLOOKSAZ %ld\n",params->ncorrlooksaz); /* scattering model parameters */ fprintf(fp,"\n# Scattering model parameters\n"); fprintf(fp,"KDS %.8f\n",params->kds); fprintf(fp,"SPECULAREXP %.8f\n",params->specularexp); fprintf(fp,"DZRCRITFACTOR %.8f\n",params->dzrcritfactor); LogBoolParam(fp,"SHADOW",params->shadow); fprintf(fp,"DZEIMIN %.8f\n",params->dzeimin); fprintf(fp,"LAYWIDTH %ld\n",params->laywidth); fprintf(fp,"LAYMINEI %.8f\n",params->layminei); fprintf(fp,"SLOPERATIOFACTOR %.8f\n",params->sloperatiofactor); fprintf(fp,"SIGSQEI %.8f\n",params->sigsqei); /* decorrelation model paramters */ fprintf(fp,"\n# Decorrelation model parameters\n"); fprintf(fp,"DRHO %.8f\n",params->drho); fprintf(fp,"RHOSCONST1 %.8f\n",params->rhosconst1); fprintf(fp,"RHOSCONST2 %.8f\n",params->rhosconst2); fprintf(fp,"CSTD1 %.8f\n",params->cstd1); fprintf(fp,"CSTD2 %.8f\n",params->cstd2); fprintf(fp,"CSTD3 %.8f\n",params->cstd3); fprintf(fp,"DEFAULTCORR %.8f\n",params->defaultcorr); fprintf(fp,"RHOMINFACTOR %.8f\n",params->rhominfactor); /* PDF model paramters */ fprintf(fp,"\n# PDF model parameters\n"); fprintf(fp,"DZLAYPEAK %.8f\n",params->dzlaypeak); fprintf(fp,"AZDZFACTOR %.8f\n",params->azdzfactor); fprintf(fp,"DZEIFACTOR %.8f\n",params->dzeifactor); fprintf(fp,"DZEIWEIGHT %.8f\n",params->dzeiweight); fprintf(fp,"DZLAYFACTOR %.8f\n",params->dzlayfactor); fprintf(fp,"LAYCONST %.8f\n",params->layconst); fprintf(fp,"LAYFALLOFFCONST %.8f\n",params->layfalloffconst); fprintf(fp,"SIGSQSHORTMIN %ld\n",params->sigsqshortmin); fprintf(fp,"SIGSQLAYFACTOR %.8f\n",params->sigsqlayfactor); /* deformation mode paramters */ fprintf(fp,"\n# Deformation mode parameters\n"); fprintf(fp,"DEFOAZDZFACTOR %.8f\n",params->defoazdzfactor); fprintf(fp,"DEFOTHRESHFACTOR %.8f\n",params->defothreshfactor); fprintf(fp,"DEFOMAX_CYCLE %.8f\n",params->defomax); fprintf(fp,"SIGSQCORR %.8f\n",params->sigsqcorr); fprintf(fp,"DEFOCONST %.8f\n",params->defolayconst); /* algorithm parameters */ fprintf(fp,"\n# Algorithm parameters\n"); fprintf(fp,"INITMAXFLOW %ld\n",params->initmaxflow); fprintf(fp,"ARCMAXFLOWCONST %ld\n",params->arcmaxflowconst); fprintf(fp,"MAXFLOW %ld\n",params->maxflow); fprintf(fp,"KROWEI %ld\n",params->krowei); fprintf(fp,"KCOLEI %ld\n",params->kcolei); fprintf(fp,"KPARDPSI %ld\n",params->kpardpsi); fprintf(fp,"KPERPDPSI %ld\n",params->kperpdpsi); fprintf(fp,"THRESHOLD %.8f\n",params->threshold); fprintf(fp,"INITDZR %.8f\n",params->initdzr); fprintf(fp,"INITDZSTEP %.8f\n",params->initdzstep); fprintf(fp,"MAXCOST %.8f\n",params->maxcost); fprintf(fp,"COSTSCALE %.8f\n",params->costscale); fprintf(fp,"COSTSCALEAMBIGHT %.8f\n",params->costscaleambight); fprintf(fp,"DNOMINCANGLE %.8f\n",params->dnomincangle); fprintf(fp,"NSHORTCYCLE %ld\n",params->nshortcycle); fprintf(fp,"MAXNEWNODECONST %.8f\n",params->maxnewnodeconst); if(params->maxnflowcycles==USEMAXCYCLEFRACTION){ fprintf(fp,"MAXCYCLEFRACTION %.8f\n",params->maxcyclefraction); }else{ fprintf(fp,"MAXNFLOWCYCLES %ld\n",params->maxnflowcycles); } fprintf(fp,"NCONNNODEMIN %ld\n",params->nconnnodemin); fprintf(fp,"CS2SCALEFACTOR %ld\n",params->cs2scalefactor); fprintf(fp,"NMAJORPRUNE %ld\n",params->nmajorprune); fprintf(fp,"PRUNECOSTTHRESH %ld\n",params->prunecostthresh); if(params->p!=PROBCOSTP){ fprintf(fp,"PLPN %.8g\n",params->p); LogBoolParam(fp,"BIDIRLPN",params->bidirlpn); }else{ fprintf(fp,"# PLPN %.8g (not set)\n",params->p); LogBoolParam(fp,"# BIDIRLPN",params->bidirlpn); } /* file names for dumping intermediate arrays */ fprintf(fp,"\n# File names for dumping intermediate arrays\n"); LogStringParam(fp,"INITFILE",outfiles->initfile); LogStringParam(fp,"FLOWFILE",outfiles->flowfile); LogStringParam(fp,"EIFILE",outfiles->eifile); LogStringParam(fp,"ROWCOSTFILE",outfiles->rowcostfile); LogStringParam(fp,"COLCOSTFILE",outfiles->colcostfile); LogStringParam(fp,"MSTROWCOSTFILE",outfiles->mstrowcostfile); LogStringParam(fp,"MSTCOLCOSTFILE",outfiles->mstcolcostfile); LogStringParam(fp,"MSTCOSTSFILE",outfiles->mstcostsfile); LogStringParam(fp,"RAWCORRDUMPFILE",outfiles->rawcorrdumpfile); LogStringParam(fp,"CORRDUMPFILE",outfiles->corrdumpfile); /* edge masking parameters */ fprintf(fp,"\n# Edge masking parameters\n"); fprintf(fp,"EDGEMASKTOP %ld\n",params->edgemasktop); fprintf(fp,"EDGEMASKBOT %ld\n",params->edgemaskbot); fprintf(fp,"EDGEMASKLEFT %ld\n",params->edgemaskleft); fprintf(fp,"EDGEMASKRIGHT %ld\n",params->edgemaskright); /* piece extraction parameters */ if(params->ntilerow==1 && params->ntilecol==1){ fprintf(fp,"\n# Piece extraction parameters\n"); fprintf(fp,"PIECEFIRSTROW %ld\n",params->piecefirstrow+1); fprintf(fp,"PIECEFIRSTCOL %ld\n",params->piecefirstcol+1); fprintf(fp,"PIECENROW %ld\n",params->piecenrow); fprintf(fp,"PIECENCOL %ld\n",params->piecencol); }else{ fprintf(fp,"\n# Piece extraction parameters\n"); fprintf(fp,"# Parameters ignored because of tile mode\n"); fprintf(fp,"# PIECEFIRSTROW %ld\n",params->piecefirstrow); fprintf(fp,"# PIECEFIRSTCOL %ld\n",params->piecefirstcol); fprintf(fp,"# PIECENROW %ld\n",params->piecenrow); fprintf(fp,"# PIECENCOL %ld\n",params->piecencol); } /* tile control */ fprintf(fp,"\n# Tile control\n"); fprintf(fp,"NTILEROW %ld\n",params->ntilerow); fprintf(fp,"NTILECOL %ld\n",params->ntilecol); fprintf(fp,"ROWOVRLP %ld\n",params->rowovrlp); fprintf(fp,"COLOVRLP %ld\n",params->colovrlp); fprintf(fp,"NPROC %ld\n",params->nthreads); fprintf(fp,"TILECOSTTHRESH %ld\n",params->tilecostthresh); fprintf(fp,"MINREGIONSIZE %ld\n",params->minregionsize); fprintf(fp,"TILEEDGEWEIGHT %.8f\n",params->tileedgeweight); fprintf(fp,"SCNDRYARCFLOWMAX %ld\n",params->scndryarcflowmax); LogBoolParam(fp,"RMTMPTILE",params->rmtmptile); LogStringParam(fp,"DOTILEMASKFILE",infiles->dotilemaskfile); LogStringParam(fp,"TILEDIR",params->tiledir); LogBoolParam(fp,"ASSEMBLEONLY",params->assembleonly); LogBoolParam(fp,"SINGLETILEREOPTIMIZE",params->onetilereopt); /* connected component control */ fprintf(fp,"\n# Connected component control\n"); LogStringParam(fp,"CONNCOMPFILE",outfiles->conncompfile); LogBoolParam(fp,"REGROWCONNCOMPS",params->regrowconncomps); fprintf(fp,"MINCONNCOMPFRAC %.8f\n",params->minconncompfrac); fprintf(fp,"CONNCOMPTHRESH %ld\n",params->conncompthresh); fprintf(fp,"MAXNCOMPS %ld\n",params->maxncomps); if(params->conncompouttype==CONNCOMPOUTTYPEUCHAR){ fprintf(fp,"CONNCOMPOUTTYPE UCHAR\n"); }else if(params->conncompouttype==CONNCOMPOUTTYPEUINT){ fprintf(fp,"CONNCOMPOUTTYPE UINT\n"); }else{ fflush(NULL); fprintf(sp0,"ERROR: bad value of params->conncompouttype\n"); exit(ABNORMAL_EXIT); } /* close the log file */ if(fclose(fp)){ fflush(NULL); fprintf(sp0,"ERROR in closing log file %s (disk full?)\nAbort\n", outfiles->logfile); exit(ABNORMAL_EXIT); } } /* done */ return(0); } /* function: LogStringParam() * -------------------------- * Writes a line to the log file stream for the given keyword/value * pair. */ static int LogStringParam(FILE *fp, char *key, char *value){ /* see if we were passed a zero length value string */ if(strlen(value)){ fprintf(fp,"%s %s\n",key,value); fflush(fp); }else{ fprintf(fp,"# Empty value for parameter %s\n",key); } return(0); } /* LogBoolParam() * -------------- * Writes a line to the log file stream for the given keyword/bool * pair. */ static int LogBoolParam(FILE *fp, char *key, signed char boolvalue){ if(boolvalue){ fprintf(fp,"%s TRUE\n",key); }else{ fprintf(fp,"%s FALSE\n",key); } return(0); } /* LogFileFormat() * --------------- * Writes a line to the log file stream for the given keyword/ * file format pair. */ static int LogFileFormat(FILE *fp, char *key, signed char fileformat){ if(fileformat==COMPLEX_DATA){ fprintf(fp,"%s COMPLEX_DATA\n",key); }else if(fileformat==FLOAT_DATA){ fprintf(fp,"%s FLOAT_DATA\n",key); }else if(fileformat==ALT_LINE_DATA){ fprintf(fp,"%s ALT_LINE_DATA\n",key); }else if(fileformat==ALT_SAMPLE_DATA){ fprintf(fp,"%s ALT_SAMPLE_DATA\n",key); } return(0); } /* function: GetNLines() * --------------------- * Gets the number of lines of data in the input file based on the file * size. */ long GetNLines(infileT *infiles, long linelen, paramT *params){ FILE *fp; long filesize, datasize; /* get size of input file in rows and columns */ if((fp=fopen(infiles->infile,"r"))==NULL){ fflush(NULL); fprintf(sp0,"can't open file %s\n",infiles->infile); exit(ABNORMAL_EXIT); } fseek(fp,0,SEEK_END); filesize=ftell(fp); fclose(fp); if((!params->unwrapped && infiles->infileformat==FLOAT_DATA) || (params->unwrapped && infiles->unwrappedinfileformat==FLOAT_DATA)){ datasize=sizeof(float); }else{ datasize=2*sizeof(float); } if(filesize % (datasize*linelen)){ fflush(NULL); fprintf(sp0,"extra data in file %s (bad linelength?)\n", infiles->infile); exit(ABNORMAL_EXIT); } return(filesize/(datasize*linelen)); /* implicit floor */ } /* function: WriteOutputFile() * --------------------------- * Writes the unwrapped phase to the output file specified, in the * format given in the parameter structure. */ int WriteOutputFile(float **mag, float **unwrappedphase, char *outfile, outfileT *outfiles, long nrow, long ncol){ if(outfiles->outfileformat==ALT_LINE_DATA){ WriteAltLineFile(mag,unwrappedphase,outfile,nrow,ncol); }else if(outfiles->outfileformat==ALT_SAMPLE_DATA){ WriteAltSampFile(mag,unwrappedphase,outfile,nrow,ncol); }else if(outfiles->outfileformat==FLOAT_DATA){ Write2DArray((void **)unwrappedphase,outfile, nrow,ncol,sizeof(float)); }else{ fflush(NULL); fprintf(sp0,"WARNING: Illegal format specified for output file\n"); fprintf(sp0," using default floating-point format\n"); Write2DArray((void **)unwrappedphase,outfile, nrow,ncol,sizeof(float)); } return(0); } /* function: OpenOutputFile() * -------------------------- * Opens a file for writing. If unable to open the file, tries to * open a file in a dump path. The name of the opened output file * is written into the string realoutfile, for which at least * MAXSTRLEN bytes should already be allocated. */ FILE *OpenOutputFile(char *outfile, char *realoutfile){ char path[MAXSTRLEN], basename[MAXSTRLEN], dumpfile[MAXSTRLEN]; FILE *fp; if((fp=fopen(outfile,"w"))==NULL){ /* if we can't write to the out file, get the file name from the path */ /* and dump to the default path */ ParseFilename(outfile,path,basename); StrNCopy(dumpfile,DUMP_PATH,MAXSTRLEN); strcat(dumpfile,basename); if((fp=fopen(dumpfile,"w"))!=NULL){ fflush(NULL); fprintf(sp0,"WARNING: Can't write to file %s. Dumping to file %s\n", outfile,dumpfile); StrNCopy(realoutfile,dumpfile,MAXSTRLEN); }else{ fflush(NULL); fprintf(sp0,"Unable to write to file %s or dump to file %s\nAbort\n", outfile,dumpfile); exit(ABNORMAL_EXIT); } }else{ StrNCopy(realoutfile,outfile,MAXSTRLEN); } return(fp); } /* function: WriteAltLineFile() * ---------------------------- * Writes magnitude and phase data from separate arrays to file. * Data type is float. For each line of data, a full line of magnitude data * is written, then a full line of phase data. Dumps the file to a * default directory if the file name/path passed in cannot be used. */ static int WriteAltLineFile(float **mag, float **phase, char *outfile, long nrow, long ncol){ int row; FILE *fp; char realoutfile[MAXSTRLEN]; fp=OpenOutputFile(outfile,realoutfile); for(row=0; rownrow; ncol=tileparams->ncol; /* check data size */ if(tileparams->ncol>LARGESHORT || tileparams->nrow>LARGESHORT){ fflush(NULL); fprintf(sp0,"one or more interferogram dimensions too large\n"); exit(ABNORMAL_EXIT); } if(tileparams->ncol<2 || tileparams->nrow<2){ fflush(NULL); fprintf(sp0,"input interferogram must be at least 2x2\n"); exit(ABNORMAL_EXIT); } /* is the input file already unwrapped? */ if(!params->unwrapped){ /* read wrapped phase and possibly interferogram magnitude data */ fprintf(sp1,"Reading wrapped phase from file %s\n",infiles->infile); if(infiles->infileformat==COMPLEX_DATA){ ReadComplexFile(&mag,&wrappedphase,infiles->infile, linelen,nlines,tileparams); }else if(infiles->infileformat==ALT_LINE_DATA){ ReadAltLineFile(&mag,&wrappedphase,infiles->infile, linelen,nlines,tileparams); }else if(infiles->infileformat==ALT_SAMPLE_DATA){ ReadAltSampFile(&mag,&wrappedphase,infiles->infile, linelen,nlines,tileparams); }else if(infiles->infileformat==FLOAT_DATA){ Read2DArray((void ***)&wrappedphase,infiles->infile,linelen,nlines, tileparams,sizeof(float *),sizeof(float)); }else{ fflush(NULL); fprintf(sp0,"illegal input file format specification\n"); exit(ABNORMAL_EXIT); } /* check to make sure the input data doesn't contain NaNs or infs */ if(!ValidDataArray(wrappedphase,nrow,ncol) || (mag!=NULL && !ValidDataArray(mag,nrow,ncol))){ fflush(NULL); fprintf(sp0,"NaN or infinity found in input float data\nAbort\n"); exit(ABNORMAL_EXIT); } if(mag!=NULL && !NonNegDataArray(mag,nrow,ncol)){ fflush(NULL); fprintf(sp0,"Negative magnitude found in input magnitude data\nAbort\n"); exit(ABNORMAL_EXIT); } /* flip the sign of the wrapped phase if flip flag is set */ FlipPhaseArraySign(wrappedphase,params,nrow,ncol); /* make sure the wrapped phase is properly wrapped */ WrapPhase(wrappedphase,nrow,ncol); }else{ /* read unwrapped phase input */ fprintf(sp1,"Reading unwrapped phase from file %s\n",infiles->infile); if(infiles->unwrappedinfileformat==ALT_LINE_DATA){ ReadAltLineFile(&mag,&unwrappedphase,infiles->infile, linelen,nlines,tileparams); }else if(infiles->unwrappedinfileformat==ALT_SAMPLE_DATA){ ReadAltSampFile(&mag,&unwrappedphase,infiles->infile, linelen,nlines,tileparams); }else if(infiles->unwrappedinfileformat==FLOAT_DATA){ Read2DArray((void ***)&unwrappedphase,infiles->infile,linelen,nlines, tileparams,sizeof(float *),sizeof(float)); }else{ fflush(NULL); fprintf(sp0,"Illegal input file format specification\nAbort\n"); exit(ABNORMAL_EXIT); } /* check to make sure the input data doesn't contain NaNs or infs */ if(!ValidDataArray(unwrappedphase,nrow,ncol) || (mag!=NULL && !ValidDataArray(mag,nrow,ncol))){ fflush(NULL); fprintf(sp0,"NaN or infinity found in input float data\nAbort\n"); exit(ABNORMAL_EXIT); } if(mag!=NULL && !NonNegDataArray(mag,nrow,ncol)){ fflush(NULL); fprintf(sp0,"Negative magnitude found in input magnitude data\nAbort\n"); exit(ABNORMAL_EXIT); } /* flip the sign of the input unwrapped phase if flip flag is set */ FlipPhaseArraySign(unwrappedphase,params,nrow,ncol); /* parse flows of unwrapped phase */ wrappedphase=ExtractFlow(unwrappedphase,&flows,nrow,ncol); /* free unwrapped phase array to save memory */ Free2DArray((void **)unwrappedphase,nrow); } /* show which pixels read if tiling */ if(tileparams->nrow!=nlines || tileparams->ncol!=linelen){ fprintf(sp2, "Read %ldx%ld array of pixels starting at row,col %ld,%ld\n", tileparams->nrow,tileparams->ncol, tileparams->firstrow,tileparams->firstcol); } /* get memory for mag (power) image and set to unity if not passed */ if(mag==NULL){ mag=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float)); for(row=0;rowmagfile)){ fprintf(sp1,"Reading interferogram magnitude from file %s\n", infiles->magfile); if(infiles->magfileformat==FLOAT_DATA){ Read2DArray((void ***)&mag,infiles->magfile,linelen,nlines,tileparams, sizeof(float *),sizeof(float)); }else if(infiles->magfileformat==COMPLEX_DATA){ ReadComplexFile(&mag,&dummy,infiles->magfile,linelen,nlines, tileparams); }else if(infiles->magfileformat==ALT_LINE_DATA){ ReadAltLineFile(&mag,&dummy,infiles->magfile,linelen,nlines, tileparams); }else if(infiles->magfileformat==ALT_SAMPLE_DATA){ ReadAltSampFile(&mag,&dummy,infiles->magfile,linelen,nlines, tileparams); } } if(dummy!=NULL){ Free2DArray((void **)dummy,tileparams->nrow); } return(0); } /* function: ReadByteMask() * ------------------------ * Read signed byte mask value; set magnitude to zero where byte mask * is zero or where pixel is close enough to edge as defined by * edgemask parameters; leave magnitude unchanged otherwise. */ int ReadByteMask(float **mag, infileT *infiles, long linelen, long nlines, tileparamT *tileparams, paramT *params){ long row, col, nrow, ncol, fullrow, fullcol; signed char **bytemask; /* set up */ nrow=tileparams->nrow; ncol=tileparams->ncol; /* read byte mask (memory allocated by read function) */ bytemask=NULL; if(strlen(infiles->bytemaskfile)){ fprintf(sp1,"Reading byte mask from file %s\n",infiles->bytemaskfile); Read2DArray((void ***)&bytemask,infiles->bytemaskfile,linelen,nlines, tileparams,sizeof(signed char *),sizeof(signed char)); } /* loop over rows and columns and zero out magnitude where mask is zero */ /* also mask edges according to edgemask parameters */ for(row=0;rowfirstrow+row; fullcol=tileparams->firstcol+col; if((bytemask!=NULL && bytemask[row][col]==0) || fullrowedgemasktop || fullcoledgemaskleft || fullrow>=nlines-params->edgemaskbot || fullcol>=linelen-params->edgemaskright){ mag[row][col]=0; } } } /* free bytemask memory */ if(bytemask!=NULL){ Free2DArray((void **)bytemask,nrow); } /* done */ return(0); } /* function: ReadUnwrappedEstimateFile() * ------------------------------------- * Reads the unwrapped-phase estimate from a file (assumes file name exists). */ int ReadUnwrappedEstimateFile(float ***unwrappedestptr, infileT *infiles, long linelen, long nlines, paramT *params, tileparamT *tileparams){ float **dummy; long nrow, ncol; /* initialize */ dummy=NULL; nrow=tileparams->nrow; ncol=tileparams->ncol; /* read data */ fprintf(sp1,"Reading coarse unwrapped estimate from file %s\n", infiles->estfile); if(infiles->estfileformat==ALT_LINE_DATA){ ReadAltLineFilePhase(unwrappedestptr,infiles->estfile, linelen,nlines,tileparams); }else if(infiles->estfileformat==FLOAT_DATA){ Read2DArray((void ***)unwrappedestptr,infiles->estfile,linelen,nlines, tileparams,sizeof(float *),sizeof(float)); }else if(infiles->estfileformat==ALT_SAMPLE_DATA){ ReadAltSampFile(&dummy,unwrappedestptr,infiles->estfile, linelen,nlines,tileparams); }else{ fflush(NULL); fprintf(sp0,"Illegal file format specification for file %s\nAbort\n", infiles->estfile); } if(dummy!=NULL){ Free2DArray((void **)dummy,nrow); } /* make sure data is valid */ if(!ValidDataArray(*unwrappedestptr,nrow,ncol)){ fflush(NULL); fprintf(sp0,"Infinity or NaN found in file %s\nAbort\n",infiles->estfile); exit(ABNORMAL_EXIT); } /* flip the sign of the unwrapped estimate if the flip flag is set */ FlipPhaseArraySign(*unwrappedestptr,params,nrow,ncol); /* done */ return(0); } /* function: ReadWeightsFile() * --------------------------- * Read in weights form rowcol format file of short ints. */ int ReadWeightsFile(short ***weightsptr,char *weightfile, long linelen, long nlines, tileparamT *tileparams){ long row, col, nrow, ncol; short **rowweight, **colweight; signed char printwarning; /* set up and read data */ nrow=tileparams->nrow; ncol=tileparams->ncol; if(strlen(weightfile)){ fprintf(sp1,"Reading weights from file %s\n",weightfile); Read2DRowColFile((void ***)weightsptr,weightfile,linelen,nlines, tileparams,sizeof(short)); rowweight=*weightsptr; colweight=&(*weightsptr)[nrow-1]; printwarning=FALSE; for(row=0;rownrow; ncol=tileparams->ncol; pwr=NULL; pwr1=NULL; pwr2=NULL; /* read the data */ if(strlen(infiles->ampfile2)){ /* data is given in two separate files */ fprintf(sp1,"Reading brightness data from files %s and %s\n", infiles->ampfile,infiles->ampfile2); if(infiles->ampfileformat==FLOAT_DATA){ Read2DArray((void ***)&pwr1,infiles->ampfile,linelen,nlines,tileparams, sizeof(float *),sizeof(float)); Read2DArray((void ***)&pwr2,infiles->ampfile2,linelen,nlines,tileparams, sizeof(float *),sizeof(float)); }else{ fflush(NULL); fprintf(sp0,"Illegal file formats specified for files %s, %s\nAbort\n", infiles->ampfile,infiles->ampfile2); exit(ABNORMAL_EXIT); } }else{ /* data is in single file */ fprintf(sp1,"Reading brightness data from file %s\n",infiles->ampfile); if(infiles->ampfileformat==ALT_SAMPLE_DATA){ ReadAltSampFile(&pwr1,&pwr2,infiles->ampfile,linelen,nlines, tileparams); }else if(infiles->ampfileformat==ALT_LINE_DATA){ ReadAltLineFile(&pwr1,&pwr2,infiles->ampfile,linelen,nlines, tileparams); }else if(infiles->ampfileformat==FLOAT_DATA){ Read2DArray((void ***)&pwr,infiles->ampfile,linelen,nlines,tileparams, sizeof(float *),sizeof(float)); pwr1=NULL; pwr2=NULL; }else{ fflush(NULL); fprintf(sp0,"Illegal file format specified for file %s\nAbort\n", infiles->ampfile); exit(ABNORMAL_EXIT); } } /* check data validity */ if((pwr1!=NULL && !ValidDataArray(pwr1,nrow,ncol)) || (pwr2!=NULL && !ValidDataArray(pwr2,nrow,ncol)) || (pwr!=NULL && !ValidDataArray(pwr,nrow,ncol))){ fflush(NULL); fprintf(sp0,"Infinity or NaN found in amplitude or power data\nAbort\n"); exit(ABNORMAL_EXIT); } if((pwr1!=NULL && !NonNegDataArray(pwr1,nrow,ncol)) || (pwr2!=NULL && !NonNegDataArray(pwr2,nrow,ncol)) || (pwr!=NULL && !NonNegDataArray(pwr,nrow,ncol))){ fflush(NULL); fprintf(sp0,"Negative value found in amplitude or power data\nAbort\n"); exit(ABNORMAL_EXIT); } /* if data is amplitude, square to get power */ if(params->amplitude){ for(row=0;rownrow; dummy=NULL; corr=NULL; /* read the data */ fprintf(sp1,"Reading correlation data from file %s\n",infiles->corrfile); if(infiles->corrfileformat==ALT_SAMPLE_DATA){ ReadAltSampFile(&dummy,&corr,infiles->corrfile,linelen,nlines,tileparams); }else if(infiles->corrfileformat==ALT_LINE_DATA){ ReadAltLineFilePhase(&corr,infiles->corrfile,linelen,nlines,tileparams); }else if(infiles->corrfileformat==FLOAT_DATA){ Read2DArray((void ***)&corr,infiles->corrfile,linelen,nlines,tileparams, sizeof(float *),sizeof(float)); }else{ fflush(NULL); fprintf(sp0,"Illegal file format specified for file %s\nAbort\n", infiles->corrfile); exit(ABNORMAL_EXIT); } /* set output pointer and free memory */ if(dummy!=NULL){ Free2DArray((void **)dummy,nrow); } *corrptr=corr; /* done */ return(0); } /* function: ReadAltLineFile() * --------------------------- * Read in the data from a file containing magnitude and phase * data. File should have one line of magnitude data, one line * of phase data, another line of magnitude data, etc. * ncol refers to the number of complex elements in one line of * data. */ int ReadAltLineFile(float ***mag, float ***phase, char *alfile, long linelen, long nlines, tileparamT *tileparams){ FILE *fp; long filesize,row,nrow,ncol,padlen; /* open the file */ if((fp=fopen(alfile,"r"))==NULL){ fflush(NULL); fprintf(sp0,"Can't open file %s\nAbort\n",alfile); exit(ABNORMAL_EXIT); } /* get number of lines based on file size and line length */ fseek(fp,0,SEEK_END); filesize=ftell(fp); if(filesize!=(2*nlines*linelen*sizeof(float))){ fflush(NULL); fprintf(sp0,"File %s wrong size (%ldx%ld array expected)\nAbort\n", alfile,nlines,linelen); exit(ABNORMAL_EXIT); } fseek(fp,0,SEEK_SET); /* get memory */ nrow=tileparams->nrow; ncol=tileparams->ncol; if(*mag==NULL){ (*mag)=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float)); } if(*phase==NULL){ (*phase)=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float)); } /* read the data */ fseek(fp,(tileparams->firstrow*2*linelen+tileparams->firstcol) *sizeof(float),SEEK_CUR); padlen=(linelen-ncol)*sizeof(float); for(row=0; rownrow; ncol=tileparams->ncol; if(*phase==NULL){ (*phase)=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float)); } /* read the phase data */ fseek(fp,(tileparams->firstrow*2*linelen+linelen +tileparams->firstcol)*sizeof(float),SEEK_CUR); padlen=(2*linelen-ncol)*sizeof(float); for(row=0; rownrow; ncol=tileparams->ncol; if(*mag==NULL){ (*mag)=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float)); } if(*phase==NULL){ (*phase)=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float)); } inpline=(float *)MAlloc(2*ncol*sizeof(float)); /* read the data and convert to magnitude and phase */ fseek(fp,(tileparams->firstrow*linelen+tileparams->firstcol) *2*sizeof(float),SEEK_CUR); padlen=(linelen-ncol)*2*sizeof(float); for(row=0; row=TWOPI){ (*phase)[row][col]-=TWOPI; } } fseek(fp,padlen,SEEK_CUR); } free(inpline); fclose(fp); /* done */ return(0); } /* function: Read2DArray() * ------------------------- * Reads file of real data of size elsize. Assumes the native byte order * of the platform. */ int Read2DArray(void ***arr, char *infile, long linelen, long nlines, tileparamT *tileparams, size_t elptrsize, size_t elsize){ FILE *fp; long filesize,row,nrow,ncol,padlen; /* open the file */ if((fp=fopen(infile,"r"))==NULL){ fflush(NULL); fprintf(sp0,"Can't open file %s\nAbort\n",infile); exit(ABNORMAL_EXIT); } /* get number of lines based on file size and line length */ fseek(fp,0,SEEK_END); filesize=ftell(fp); if(filesize!=(nlines*linelen*elsize)){ fflush(NULL); fprintf(sp0,"File %s wrong size (%ldx%ld array expected)\nAbort\n", infile,nlines,linelen); exit(ABNORMAL_EXIT); } fseek(fp,0,SEEK_SET); /* get memory */ nrow=tileparams->nrow; ncol=tileparams->ncol; if(*arr==NULL){ (*arr)=(void **)Get2DMem(nrow,ncol,elptrsize,elsize); } /* read the data */ fseek(fp,(linelen*tileparams->firstrow+tileparams->firstcol) *elsize,SEEK_CUR); padlen=(linelen-ncol)*elsize; for(row=0; rownrow; ncol=tileparams->ncol; if(*arr1==NULL){ (*arr1)=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float)); } if(*arr2==NULL){ (*arr2)=(float **)Get2DMem(nrow,ncol,sizeof(float *),sizeof(float)); } inpline=(float *)MAlloc(2*ncol*sizeof(float)); /* read the data */ fseek(fp,(tileparams->firstrow*linelen+tileparams->firstcol) *2*sizeof(float),SEEK_CUR); padlen=(linelen-ncol)*2*sizeof(float); for(row=0; rownrow; ncol=tileparams->ncol; if(*arr==NULL){ (*arr)=Get2DRowColMem(nrow,ncol,sizeof(void *),size); } /* read arrays */ fseek(fp,(linelen*tileparams->firstrow+tileparams->firstcol) *size,SEEK_SET); padlen=(linelen-ncol)*size; for(row=0; rowfirstrow +tileparams->firstcol)*size,SEEK_SET); for(row=nrow-1; row<2*nrow-1; row++){ if(fread((*arr)[row],size,ncol-1,fp)!=ncol-1){ fflush(NULL); fprintf(sp0,"Error while reading from file %s\nAbort\n",filename); exit(ABNORMAL_EXIT); } fseek(fp,padlen,SEEK_CUR); } fclose(fp); /* done */ return(0); } /* function: Read2DRowColFileRows() * -------------------------------- * Similar to Read2DRowColFile(), except reads only row (horizontal) data * at specified locations. tileparams->nrow is treated as the number of * rows of data to be read from the RowCol file, not the number of * equivalent rows in the orginal pixel file (whose arcs are represented * in the RowCol file). */ int Read2DRowColFileRows(void ***arr, char *filename, long linelen, long nlines, tileparamT *tileparams, size_t size){ FILE *fp; long row, nel, nrow, ncol, padlen, filelen; /* open the file */ if((fp=fopen(filename,"r"))==NULL){ fflush(NULL); fprintf(sp0,"Can't open file %s\nAbort\n",filename); exit(ABNORMAL_EXIT); } /* get number of data elements in file */ fseek(fp,0,SEEK_END); filelen=ftell(fp); fseek(fp,0,SEEK_SET); nel=(long )(filelen/size); /* check file size */ if(2*linelen*nlines-nlines-linelen != nel || (filelen % size)){ fflush(NULL); fprintf(sp0,"File %s wrong size (%ld elements expected)\nAbort\n", filename,2*linelen*nlines-nlines-linelen); exit(ABNORMAL_EXIT); } /* get memory if passed pointer is NULL */ nrow=tileparams->nrow; ncol=tileparams->ncol; if(*arr==NULL){ (*arr)=Get2DMem(nrow,ncol,sizeof(void *),size); } /* read arrays */ fseek(fp,(linelen*tileparams->firstrow+tileparams->firstcol) *size,SEEK_SET); padlen=(linelen-ncol)*size; for(row=0; rowdumpall){ if(!strlen(outfiles->initfile)){ StrNCopy(outfiles->initfile,DUMP_INITFILE,MAXSTRLEN); } if(!strlen(outfiles->flowfile)){ StrNCopy(outfiles->flowfile,DUMP_FLOWFILE,MAXSTRLEN); } if(!strlen(outfiles->eifile)){ StrNCopy(outfiles->eifile,DUMP_EIFILE,MAXSTRLEN); } if(!strlen(outfiles->rowcostfile)){ StrNCopy(outfiles->rowcostfile,DUMP_ROWCOSTFILE,MAXSTRLEN); } if(!strlen(outfiles->colcostfile)){ StrNCopy(outfiles->colcostfile,DUMP_COLCOSTFILE,MAXSTRLEN); } if(!strlen(outfiles->mstrowcostfile)){ StrNCopy(outfiles->mstrowcostfile,DUMP_MSTROWCOSTFILE,MAXSTRLEN); } if(!strlen(outfiles->mstcolcostfile)){ StrNCopy(outfiles->mstcolcostfile,DUMP_MSTCOLCOSTFILE,MAXSTRLEN); } if(!strlen(outfiles->mstcostsfile)){ StrNCopy(outfiles->mstcostsfile,DUMP_MSTCOSTSFILE,MAXSTRLEN); } if(!strlen(outfiles->corrdumpfile)){ StrNCopy(outfiles->corrdumpfile,DUMP_CORRDUMPFILE,MAXSTRLEN); } if(!strlen(outfiles->rawcorrdumpfile)){ StrNCopy(outfiles->rawcorrdumpfile,DUMP_RAWCORRDUMPFILE,MAXSTRLEN); } } return(0); } /* function: SetStreamPointers() * ----------------------------- * Sets the default stream pointers (global variables). */ int SetStreamPointers(void){ fflush(NULL); if((sp0=DEF_ERRORSTREAM)==NULL){ if((sp0=fopen(NULLFILE,"w"))==NULL){ fflush(NULL); fprintf(sp0,"unable to open null file %s\n",NULLFILE); exit(ABNORMAL_EXIT); } } if((sp1=DEF_OUTPUTSTREAM)==NULL){ if((sp1=fopen(NULLFILE,"w"))==NULL){ fflush(NULL); fprintf(sp0,"unable to open null file %s\n",NULLFILE); exit(ABNORMAL_EXIT); } } if((sp2=DEF_VERBOSESTREAM)==NULL){ if((sp2=fopen(NULLFILE,"w"))==NULL){ fflush(NULL); fprintf(sp0,"unable to open null file %s\n",NULLFILE); exit(ABNORMAL_EXIT); } } if((sp3=DEF_COUNTERSTREAM)==NULL){ if((sp3=fopen(NULLFILE,"w"))==NULL){ fflush(NULL); fprintf(sp0,"unable to open null file %s\n",NULLFILE); exit(ABNORMAL_EXIT); } } return(0); } /* function: SetVerboseOut() * ------------------------- * Set the global stream pointer sp2 to be stdout if the verbose flag * is set in the parameter data type. */ int SetVerboseOut(paramT *params){ fflush(NULL); if(params->verbose){ if(sp2!=stdout && sp2!=stderr && sp2!=stdin && sp2!=NULL){ fclose(sp2); } sp2=stdout; if(sp3!=stdout && sp3!=stderr && sp3!=stdin && sp3!=NULL){ fclose(sp3); } sp3=stdout; } return(0); } /* function: ChildResetStreamPointers() * ----------------------------------- * Reset the global stream pointers for a child. Streams equal to stdout * are directed to a log file, and errors are written to the screen. */ int ChildResetStreamPointers(pid_t pid, long tilerow, long tilecol, paramT *params){ FILE *logfp; char logfile[MAXSTRLEN], cwd[MAXSTRLEN]; fflush(NULL); sprintf(logfile,"%s/%s%ld_%ld",params->tiledir,LOGFILEROOT,tilerow,tilecol); if((logfp=fopen(logfile,"w"))==NULL){ fflush(NULL); fprintf(sp0,"Unable to open log file %s\nAbort\n",logfile); exit(ABNORMAL_EXIT); } fprintf(logfp,"%s (pid %ld): unwrapping tile at row %ld, column %ld\n\n", PROGRAMNAME,(long )pid,tilerow,tilecol); if(getcwd(cwd,MAXSTRLEN)!=NULL){ fprintf(logfp,"Current working directory is %s\n",cwd); } if(sp2==stdout || sp2==stderr){ sp2=logfp; } if(sp1==stdout || sp1==stderr){ sp1=logfp; } if(sp0==stdout || sp0==stderr){ sp0=logfp; } if(sp3!=stdout && sp3!=stderr && sp3!=stdin && sp3!=NULL){ fclose(sp3); } if((sp3=fopen(NULLFILE,"w"))==NULL){ fflush(NULL); fprintf(sp0,"Unable to open null file %s\n",NULLFILE); exit(ABNORMAL_EXIT); } return(0); } /* function: DumpIncrCostFiles() * ----------------------------- * Dumps incremental cost arrays, creating file names for them. */ int DumpIncrCostFiles(incrcostT **incrcosts, long iincrcostfile, long nflow, long nrow, long ncol){ long row, col, maxcol; char incrcostfile[MAXSTRLEN]; char tempstr[MAXSTRLEN]; short **tempcosts; /* get memory for tempcosts */ tempcosts=(short **)Get2DRowColMem(nrow,ncol,sizeof(short *),sizeof(short)); /* create the file names and dump the files */ /* snprintf() is more elegant, but its unavailable on some machines */ for(row=0;row<2*nrow-1;row++){ if(rowtiledir)){ ParseFilename(outfiles->outfile,path,basename); sprintf(params->tiledir,"%s%s%ld",path,TMPTILEDIRROOT,params->parentpid); } /* return if directory exists */ /* this is a hack; tiledir could be file or could give other stat() error */ /* but if there is a problem, the error will be caught later */ if(!stat(params->tiledir,statbuf)){ return(0); } /* create tile directory */ fprintf(sp1,"Creating temporary directory %s\n",params->tiledir); if(mkdir(params->tiledir,TILEDIRMODE)){ fflush(NULL); fprintf(sp0,"Error creating directory %s\nAbort\n",params->tiledir); exit(ABNORMAL_EXIT); } /* done */ return(0); } /* function: SetTileInitOutfile() * ------------------------------ * Set name of temporary tile-mode output assuming nominal output file * name is in string passed. Write new name in string memory pointed * to by input. */ int SetTileInitOutfile(char *outfile, long pid){ char path[MAXSTRLEN], basename[MAXSTRLEN]; struct stat statbuf[1]; /* initialize, including statubf for good measure even though not used */ memset(path,0,MAXSTRLEN); memset(basename,0,MAXSTRLEN); memset(statbuf,0,sizeof(struct stat)); /* create name for output file (use pid to make unique) */ ParseFilename(outfile,path,basename); sprintf(outfile,"%s%s%ld_%s",path,TILEINITFILEROOT,pid,basename); /* see if file already exists and exit if so */ if(!stat(outfile,statbuf)){ fprintf(sp0, "ERROR: refusing to write tile init to existing file %s\n",outfile); exit(ABNORMAL_EXIT); } /* done */ return(0); } /* function: ParseFilename() * ------------------------- * Given a filename, separates it into path and base filename. Output * buffers should be at least MAXSTRLEN characters, and filename buffer * should be no more than MAXSTRLEN characters. The output path * has a trailing "/" character. */ int ParseFilename(char *filename, char *path, char *basename){ char tempstring[MAXSTRLEN]; char *tempouttok; /* make sure we have a nonzero filename */ if(!strlen(filename)){ fflush(NULL); fprintf(sp0,"Zero-length filename passed to ParseFilename()\nAbort\n"); exit(ABNORMAL_EXIT); } /* initialize path */ if(filename[0]=='/'){ StrNCopy(path,"/",MAXSTRLEN); }else{ StrNCopy(path,"",MAXSTRLEN); } /* parse the filename */ StrNCopy(tempstring,filename,MAXSTRLEN); tempouttok=strtok(tempstring,"/"); while(TRUE){ StrNCopy(basename,tempouttok,MAXSTRLEN); if((tempouttok=strtok(NULL,"/"))==NULL){ break; } strcat(path,basename); strcat(path,"/"); } /* make sure we have a nonzero base filename */ if(!strlen(basename)){ fflush(NULL); fprintf(sp0,"Zero-length base filename found in ParseFilename()\nAbort\n"); exit(ABNORMAL_EXIT); } /* done */ return(0); } snaphu-v2.0.6/src/PaxHeader/snaphu.h000644 777777 777777 00000000043 14423062415 017134 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/src/snaphu.h000644 Ho)00000136625 14423062415 016403 0ustar00curtis000000 000000 /************************************************************************* snaphu header 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. *************************************************************************/ /**********************/ /* defined constants */ /**********************/ #define PROGRAMNAME "snaphu" #define VERSION "2.0.6" #define BUGREPORTEMAIL "snaphu@gmail.com" #ifdef PI #undef PI #endif #define PI 3.14159265358979323846 #define TWOPI 6.28318530717958647692 #define SQRTHALF 0.70710678118654752440 #define MAXSTRLEN 512 #define MAXTMPSTRLEN 1024 #define MAXLINELEN 2048 #define TRUE 1 #define FALSE 0 #define LARGESHORT 32000 #define LARGEINT 2000000000 #define LARGEFLOAT 1.0e35 #define VERYFAR LARGEINT #define GROUNDROW -2 #define GROUNDCOL -2 #define BOUNDARYROW -4 #define BOUNDARYCOL -4 #define MAXGROUPBASE LARGEINT #define ONTREE -1 #define INBUCKET -2 #define NOTINBUCKET -3 #define PRUNED -4 #define MASKED -5 #define BOUNDARYPTR -6 #define BOUNDARYCANDIDATE -7 #define BOUNDARYLEVEL LARGEINT #define INTERIORLEVEL (BOUNDARYLEVEL-1) #define MINBOUNDARYSIZE 100 #define POSINCR 0 #define NEGINCR 1 #define NOCOSTSHELF -LARGESHORT #define MINSCALARCOST 1 #define INITARRSIZE 500 #define NEWNODEBAGSTEP 500 #define CANDIDATEBAGSTEP 500 #define NEGBUCKETFRACTION 1.0 #define POSBUCKETFRACTION 1.0 #define CLIPFACTOR 0.6666666667 #define NSOURCELISTMEMINCR 1024 #define NLISTMEMINCR 1024 #define DEF_OUTFILE "snaphu.out" #define DEF_SYSCONFFILE "" /* "/usr/local/snaphu/snaphu.conf" */ #define DEF_WEIGHTFILE "" /* "snaphu.weight" */ #define DEF_AMPFILE "" /* "snaphu.amp" */ #define DEF_AMPFILE2 "" /* "snaphu.amp" */ #define DEF_MAGFILE "" /* "snaphu.mag" */ #define DEF_CORRFILE "" /* "snaphu.corr" */ #define DEF_ESTFILE "" /* "snaphu.est" */ #define DEF_COSTINFILE "" #define DEF_BYTEMASKFILE "" #define DEF_DOTILEMASKFILE "" #define DEF_INITFILE "" #define DEF_FLOWFILE "" #define DEF_EIFILE "" #define DEF_ROWCOSTFILE "" #define DEF_COLCOSTFILE "" #define DEF_MSTROWCOSTFILE "" #define DEF_MSTCOLCOSTFILE "" #define DEF_MSTCOSTSFILE "" #define DEF_CORRDUMPFILE "" #define DEF_RAWCORRDUMPFILE "" #define DEF_CONNCOMPFILE "" #define DEF_COSTOUTFILE "" #define DEF_LOGFILE "" #define MAXITERATION 5000 #define NEGSHORTRANGE SHRT_MIN #define POSSHORTRANGE SHRT_MAX #define MAXRES SCHAR_MAX #define MINRES SCHAR_MIN #define PROBCOSTP (-99.999) #define NULLFILE "/dev/null" #define DEF_ERRORSTREAM stderr #define DEF_OUTPUTSTREAM stdout #define DEF_VERBOSESTREAM NULL #define DEF_COUNTERSTREAM NULL #define DEF_INITONLY FALSE #define DEF_INITMETHOD MSTINIT #define DEF_UNWRAPPED FALSE #define DEF_REGROWCONNCOMPS FALSE #define DEF_EVAL FALSE #define DEF_WEIGHT 1 #define DEF_COSTMODE TOPO #define DEF_VERBOSE FALSE #define DEF_AMPLITUDE TRUE #define AUTOCALCSTATMAX 0 #define MAXNSHORTCYCLE 8192 #define USEMAXCYCLEFRACTION (-123) #define COMPLEX_DATA 1 /* file format */ #define FLOAT_DATA 2 /* file format */ #define ALT_LINE_DATA 3 /* file format */ #define ALT_SAMPLE_DATA 4 /* file format */ #define TILEINITFILEFORMAT ALT_LINE_DATA #define TILEINITFILEROOT "snaphu_tileinit_" #define ABNORMAL_EXIT 1 /* exit code */ #define NORMAL_EXIT 0 /* exit code */ #define DUMP_PATH "/tmp/" /* default location for writing dumps */ #define NARMS 8 /* number of arms for Despeckle() */ #define ARMLEN 5 /* length of arms for Despeckle() */ #define KEDGE 5 /* length of edge detection window */ #define ARCUBOUND 200 /* capacities for cs2 */ #define MSTINIT 1 /* initialization method */ #define MCFINIT 2 /* initialization method */ #define BIGGESTDZRHOMAX 10000.0 #define SECONDSPERPIXEL 0.000001 /* for delay between thread creations */ #define MAXTHREADS 64 #define TMPTILEDIRROOT "snaphu_tiles_" #define TILEDIRMODE 511 #define TMPTILEROOT "tmptile_" #define TMPTILECOSTSUFFIX "cost_" #define TMPTILEOUTFORMAT ALT_LINE_DATA #define REGIONSUFFIX "_regions" #define LOGFILEROOT "tmptilelog_" #define RIGHT 1 #define DOWN 2 #define LEFT 3 #define UP 4 #define TILEDPSICOLFACTOR 0.8 #define TILEOVRLPWARNTHRESH 400 #define ZEROCOSTARC -LARGEINT #define PINGPONG 2 #define SINGLEANTTRANSMIT 1 #define NOSTATCOSTS 0 #define TOPO 1 #define DEFO 2 #define SMOOTH 3 #define CONNCOMPOUTTYPEUCHAR 1 #define CONNCOMPOUTTYPEUINT 4 /* SAR and geometry parameter defaults */ #define DEF_ORBITRADIUS 7153000.0 #define DEF_ALTITUDE 0.0 #define DEF_EARTHRADIUS 6378000.0 #define DEF_BASELINE 150.0 #define DEF_BASELINEANGLE (1.25*PI) #define DEF_BPERP 0 #define DEF_TRANSMITMODE PINGPONG #define DEF_NLOOKSRANGE 1 #define DEF_NLOOKSAZ 5 #define DEF_NLOOKSOTHER 1 #define DEF_NCORRLOOKS 23.8 #define DEF_NCORRLOOKSRANGE 3 #define DEF_NCORRLOOKSAZ 15 #define DEF_NEARRANGE 831000.0 #define DEF_DR 8.0 #define DEF_DA 20.0 #define DEF_RANGERES 10.0 #define DEF_AZRES 6.0 #define DEF_LAMBDA 0.0565647 /* scattering model defaults */ #define DEF_KDS 0.02 #define DEF_SPECULAREXP 8.0 #define DEF_DZRCRITFACTOR 2.0 #define DEF_SHADOW FALSE #define DEF_DZEIMIN -4.0 #define DEF_LAYWIDTH 16 #define DEF_LAYMINEI 1.25 #define DEF_SLOPERATIOFACTOR 1.18 #define DEF_SIGSQEI 100.0 /* decorrelation model parameters */ #define DEF_DRHO 0.005 #define DEF_RHOSCONST1 1.3 #define DEF_RHOSCONST2 0.14 #define DEF_CSTD1 0.4 #define DEF_CSTD2 0.35 #define DEF_CSTD3 0.06 #define DEF_DEFAULTCORR 0.01 #define DEF_RHOMINFACTOR 1.3 /* pdf model parameters */ #define DEF_DZLAYPEAK -2.0 #define DEF_AZDZFACTOR 0.99 #define DEF_DZEIFACTOR 4.0 #define DEF_DZEIWEIGHT 0.5 #define DEF_DZLAYFACTOR 1.0 #define DEF_LAYCONST 0.9 #define DEF_LAYFALLOFFCONST 2.0 #define DEF_SIGSQSHORTMIN 1 #define DEF_SIGSQLAYFACTOR 0.1 /* deformation mode parameters */ #define DEF_DEFOAZDZFACTOR 1.0 #define DEF_DEFOTHRESHFACTOR 1.2 #define DEF_DEFOMAX 1.2 #define DEF_SIGSQCORR 0.05 #define DEF_DEFOLAYCONST 0.9 /* algorithm parameters */ #define DEF_FLIPPHASESIGN FALSE #define DEF_ONETILEREOPT FALSE #define DEF_RMTILEINIT TRUE #define DEF_MAXFLOW 4 #define DEF_KROWEI 65 #define DEF_KCOLEI 257 #define DEF_KPARDPSI 7 #define DEF_KPERPDPSI 7 #define DEF_THRESHOLD 0.001 #define DEF_INITDZR 2048.0 #define DEF_INITDZSTEP 100.0 #define DEF_MAXCOST 1000.0 #define DEF_COSTSCALE 100.0 #define DEF_COSTSCALEAMBIGHT 80.0 #define DEF_DNOMINCANGLE 0.01 #define DEF_SRCROW -1 #define DEF_SRCCOL -1 #define DEF_P PROBCOSTP #define DEF_BIDIRLPN TRUE #define DEF_NSHORTCYCLE 200 #define DEF_MAXNEWNODECONST 0.0008 #define DEF_MAXCYCLEFRACTION 0.00001 #define DEF_NCONNNODEMIN 0 #define DEF_MAXNFLOWCYCLES USEMAXCYCLEFRACTION #define DEF_INITMAXFLOW 9999 #define INITMAXCOSTINCR 200 #define NOSTATINITMAXFLOW 15 #define DEF_ARCMAXFLOWCONST 3 #define DEF_DUMPALL FALSE #define DUMP_INITFILE "snaphu.init" #define DUMP_FLOWFILE "snaphu.flow" #define DUMP_EIFILE "snaphu.ei" #define DUMP_ROWCOSTFILE "snaphu.rowcost" #define DUMP_COLCOSTFILE "snaphu.colcost" #define DUMP_MSTROWCOSTFILE "snaphu.mstrowcost" #define DUMP_MSTCOLCOSTFILE "snaphu.mstcolcost" #define DUMP_MSTCOSTSFILE "snaphu.mstcosts" #define DUMP_CORRDUMPFILE "snaphu.corr" #define DUMP_RAWCORRDUMPFILE "snaphu.rawcorr" #define INCRCOSTFILEPOS "snaphu.incrcostpos" #define INCRCOSTFILENEG "snaphu.incrcostneg" #define DEF_CS2SCALEFACTOR 8 #define DEF_NMAJORPRUNE LARGEINT #define DEF_PRUNECOSTTHRESH LARGEINT #define DEF_EDGEMASKTOP 0 #define DEF_EDGEMASKBOT 0 #define DEF_EDGEMASKLEFT 0 #define DEF_EDGEMASKRIGHT 0 #define CONNCOMPMEMINCR 1024 /* default tile parameters */ #define DEF_NTILEROW 1 #define DEF_NTILECOL 1 #define DEF_ROWOVRLP 0 #define DEF_COLOVRLP 0 #define DEF_PIECEFIRSTROW 1 #define DEF_PIECEFIRSTCOL 1 #define DEF_PIECENROW 0 #define DEF_PIECENCOL 0 #define DEF_TILECOSTTHRESH 500 #define DEF_MINREGIONSIZE 100 #define DEF_NTHREADS 1 #define DEF_SCNDRYARCFLOWMAX 8 #define DEF_TILEEDGEWEIGHT 2.5 #define DEF_TILEDIR "" #define DEF_ASSEMBLEONLY FALSE #define DEF_RMTMPTILE TRUE /* default connected component parameters */ #define DEF_MINCONNCOMPFRAC 0.01 #define DEF_CONNCOMPTHRESH 300 #define DEF_MAXNCOMPS 32 #define DEF_CONNCOMPOUTTYPE CONNCOMPOUTTYPEUCHAR /* default file formats */ #define DEF_INFILEFORMAT COMPLEX_DATA #define DEF_UNWRAPPEDINFILEFORMAT ALT_LINE_DATA #define DEF_MAGFILEFORMAT FLOAT_DATA #define DEF_OUTFILEFORMAT ALT_LINE_DATA #define DEF_CORRFILEFORMAT ALT_LINE_DATA #define DEF_ESTFILEFORMAT ALT_LINE_DATA #define DEF_AMPFILEFORMAT ALT_SAMPLE_DATA /* command-line usage help strings */ #define OPTIONSHELPFULL\ "usage: snaphu [options] infile linelength [options]\n"\ "options:\n"\ " -t use topography mode costs (default)\n"\ " -d use deformation mode costs\n"\ " -s use smooth-solution mode costs\n"\ " -C parse argument string as config line as from conf file\n"\ " -f read configuration parameters from file\n"\ " -o write output to file\n"\ " -a read amplitude data from file\n"\ " -A read power data from file\n"\ " -m read interferogram magnitude data from file\n"\ " -M read byte mask data from file\n"\ " -c read correlation data from file\n"\ " -e read coarse unwrapped-phase estimate from file\n"\ " -w read scalar weights from file\n"\ " -b perpendicular baseline (meters, topo mode only)\n"\ " -p Lp-norm parameter p\n"\ " -i do initialization and exit\n"\ " -n do not use statistical costs (with -p or -i)\n"\ " -u infile is already unwrapped; initialization not needed\n"\ " -q quantify cost of unwrapped input file then exit\n"\ " -g grow connected components mask and write to file\n"\ " -G grow connected components mask for unwrapped input\n"\ " -S single-tile reoptimization after multi-tile init\n"\ " -k keep temporary tile outputs\n"\ " -l log runtime parameters to file\n"\ " -v give verbose output\n"\ " --mst use MST algorithm for initialization (default)\n"\ " --mcf use MCF algorithm for initialization\n"\ " --aa read amplitude from next two files\n"\ " --AA read power from next two files\n"\ " --costinfile read statistical costs from file\n"\ " --costoutfile write statistical costs to file\n"\ " --tile unwrap as nrow x ncol tiles\n"\ " --nproc number of processors used in tile mode\n"\ " --tiledir use specified directory for tiles\n"\ " --assemble assemble unwrapped tiles in tiledir\n"\ " --piece unwrap subset of image\n" \ " --debug, --dumpall dump all intermediate data arrays\n"\ " --copyright, --info print copyright and bug report info\n"\ " -h, --help print this help text\n"\ "\n" #define OPTIONSHELPBRIEF\ "usage: snaphu [options] infile linelength [options]\n"\ "most common options:\n"\ " -t use topography mode costs (default)\n"\ " -d use deformation mode costs\n"\ " -s use smooth-solution mode costs\n"\ " -C parse argument string as config line as from conf file\n"\ " -f read configuration parameters from file\n"\ " -o write output to file\n"\ " -a read amplitude data from file\n"\ " -c read correlation data from file\n"\ " -M read byte mask data from file\n"\ " -b perpendicular baseline (meters)\n"\ " -i do initialization and exit\n"\ " -S single-tile reoptimization after multi-tile init\n"\ " -l log runtime parameters to file\n"\ " -u infile is already unwrapped; initialization not needed\n"\ " -v give verbose output\n"\ " --mst use MST algorithm for initialization (default)\n"\ " --mcf use MCF algorithm for initialization\n"\ " --tile unwrap as nrow x ncol tiles\n"\ " --nproc number of processors used in tile mode\n"\ "\n"\ "type snaphu -h for a complete list of options\n"\ "\n" #define COPYRIGHT\ "Written by Curtis W. Chen\n"\ "Copyright 2002,2017 Board of Trustees, Leland Stanford Jr. University\n"\ "\n"\ "Except as noted below, permission to use, copy, modify, and\n"\ "distribute, this software and its documentation for any purpose is\n"\ "hereby granted without fee, provided that the above copyright notice\n"\ "appear in all copies and that both that copyright notice and this\n"\ "permission notice appear in supporting documentation, and that the\n"\ "name of the copyright holders be used in advertising or publicity\n"\ "pertaining to distribution of the software with specific, written\n"\ "prior permission, and that no fee is charged for further distribution\n"\ "of this software, or any modifications thereof. The copyright holder\n"\ "makes no representations about the suitability of this software for\n"\ "any purpose. It is provided \"as is\" without express or implied\n"\ "warranty.\n"\ "\n"\ "THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS\n"\ "SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND\n"\ "FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY\n"\ "SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER\n"\ "RESULTING FROM LOSS OF USE, DATA, PROFITS, QPA OR GPA, WHETHER IN AN\n"\ "ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT\n"\ "OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n"\ "\n"\ "The parts of this software derived from the CS2 minimum cost flow\n"\ "solver written by A. V. Goldberg and B. Cherkassky are governed by the\n"\ "terms of the copyright holder of that software. Permission has been\n"\ "granted to use and distrubute that software for strictly noncommercial\n"\ "purposes as part of this package, provided that the following\n"\ "copyright notice from the original distribution and URL accompany the\n"\ "software:\n"\ "\n"\ " COPYRIGHT C 1995 IG Systems, Inc. Permission to use for\n"\ " evaluation purposes is granted provided that proper\n"\ " acknowledgments are given. For a commercial licence, contact\n"\ " igsys@eclipse.net (http://www.igsystems.com/cs2).\n"\ "\n"\ " This software comes with NO WARRANTY, expressed or implied. By way\n"\ " of example, but not limitation, we make no representations of\n"\ " warranties of merchantability or fitness for any particular\n"\ " purpose or that the use of the software components or\n"\ " documentation will not infringe any patents, copyrights,\n"\ " trademarks, or other rights.\n"\ "\n"\ "\n"\ "Please send snaphu bug reports to " BUGREPORTEMAIL "\n"\ "\n" /********************/ /* type definitions */ /********************/ /* node data structure */ typedef struct nodeST{ int row,col; /* row, col of this node */ struct nodeST *next; /* ptr to next node in thread or bucket */ struct nodeST *prev; /* ptr to previous node in thread or bucket */ struct nodeST *pred; /* parent node in tree */ unsigned int level; /* tree level */ int group; /* for marking label */ int incost,outcost; /* costs to, from root of tree */ }nodeT; /* boundary neighbor structure */ typedef struct neighborST{ nodeT *neighbor; /* neighbor node pointer */ int arcrow; /* row of arc to neighbor */ int arccol; /* col of arc to neighbor */ int arcdir; /* direction of arc to neighbor */ }neighborT; /* boundary data structure */ typedef struct boundaryST{ nodeT node[1]; /* ground node pointed to by this boundary */ neighborT* neighborlist; /* list of neighbors of common boundary */ nodeT **boundarylist; /* list of nodes covered by common boundary */ long nneighbor; /* number of neighbor nodes of boundary */ long nboundary; /* number of nodes covered by boundary */ }boundaryT; /* arc cost data structure */ typedef struct costST{ short offset; /* offset of wrapped phase gradient from 0 */ short sigsq; /* variance due to decorrelation */ short dzmax; /* largest discontinuity on shelf */ short laycost; /* cost of layover discontinuity shelf */ }costT; /* arc cost data structure for smooth costs */ typedef struct smoothcostST{ short offset; /* offset of wrapped phase gradient from 0 */ short sigsq; /* variance due to decorrelation */ }smoothcostT; /* arc cost data structure for bidirectional scalar costs */ typedef struct bidircostST{ short posweight; /* weight for positive flows */ short negweight; /* weight for negative flows */ }bidircostT; /* incremental cost data structure */ typedef struct incrcostST{ short poscost; /* cost for positive flow increment */ short negcost; /* cost for negative flow increment */ }incrcostT; /* arc candidate data structure */ typedef struct candidateST{ nodeT *from, *to; /* endpoints of candidate arc */ long violation; /* magnitude of arc violation */ int arcrow,arccol; /* indexes into arc arrays */ signed char arcdir; /* direction of arc (1=fwd, -1=rev) */ }candidateT; /* bucket data structure */ typedef struct bucketST{ long size; /* number of buckets in list */ long curr; /* current bucket index */ long maxind; /* maximum bucket index */ long minind; /* smallest (possibly negative) bucket index */ nodeT **bucket; /* array of first nodes in each bucket */ nodeT **bucketbase; /* real base of bucket array */ signed char wrapped; /* flag denoting wrapped circular buckets */ }bucketT; /* secondary arc data structure */ typedef struct scndryarcST{ int arcrow; /* row of arc in secondary network array */ int arccol; /* col of arc in secondary network array */ nodeT *from; /* secondary node at tail of arc */ nodeT *to; /* secondary node at head of arc */ signed char fromdir; /* direction from which arc enters head */ }scndryarcT; /* supplementary data structure for secondary nodes */ typedef struct nodesuppST{ int row; /* row of node in primary network problem */ int col; /* col of node in primary network problem */ nodeT **neighbornodes; /* pointers to neighboring secondary nodes */ scndryarcT **outarcs; /* pointers to secondary arcs to neighbors */ int noutarcs; /* number of arcs from this node */ }nodesuppT; /* run-time parameter data structure */ typedef struct paramST{ /* SAR and geometry parameters */ double orbitradius; /* radius of platform orbit (meters) */ double altitude; /* SAR altitude (meters) */ double earthradius; /* radius of earth (meters) */ double bperp; /* nominal perpendiuclar baseline (meters) */ signed char transmitmode; /* transmit mode (PINGPONG or SINGLEANTTRANSMIT) */ double baseline; /* baseline length (meters, always postive) */ double baselineangle; /* baseline angle above horizontal (rad) */ long nlooksrange; /* number of looks in range for input data */ long nlooksaz; /* number of looks in azimuth for input data */ long nlooksother; /* number of nonspatial looks for input data */ double ncorrlooks; /* number of independent looks in correlation est */ long ncorrlooksrange; /* number of looks in range for correlation */ long ncorrlooksaz; /* number of looks in azimuth for correlation */ double nearrange; /* slant range to near part of swath (meters) */ double dr; /* range bin spacing (meters) */ double da; /* azimuth bin spacing (meters) */ double rangeres; /* range resolution (meters) */ double azres; /* azimuth resolution (meters) */ double lambda; /* wavelength (meters) */ /* scattering model parameters */ double kds; /* ratio of diffuse to specular scattering */ double specularexp; /* power specular scattering component */ double dzrcritfactor; /* fudge factor for linearizing scattering model */ signed char shadow; /* allow discontinuities from shadowing */ double dzeimin; /* lower limit for backslopes (if shadow = FALSE) */ long laywidth; /* width of window for summing layover brightness */ double layminei; /* threshold brightness for assuming layover */ double sloperatiofactor;/* fudge factor for linearized scattering slopes */ double sigsqei; /* variance (dz, meters) due to uncertainty in EI */ /* decorrelation model parameters */ double drho; /* step size of correlation-slope lookup table */ double rhosconst1,rhosconst2;/* for calculating rho0 in biased rho */ double cstd1,cstd2,cstd3;/* for calculating correlation power given nlooks */ double defaultcorr; /* default correlation if no correlation file */ double rhominfactor; /* threshold for setting unbiased correlation to 0 */ /* pdf model parameters */ double dzlaypeak; /* range pdf peak for no discontinuity when bright */ double azdzfactor; /* fraction of dz in azimuth vs. rnage */ double dzeifactor; /* nonlayover dz scale factor */ double dzeiweight; /* weight to give dz expected from intensity */ double dzlayfactor; /* layover regime dz scale factor */ double layconst; /* normalized constant pdf of layover edge */ double layfalloffconst; /* factor of sigsq for layover cost increase */ long sigsqshortmin; /* min short value for costT variance */ double sigsqlayfactor; /* fration of ambiguityheight^2 for layover sigma */ /* deformation mode parameters */ double defoazdzfactor; /* scale for azimuth ledge in defo cost function */ double defothreshfactor;/* factor of rho0 for discontinuity threshold */ double defomax; /* max discontinuity (cycles) from deformation */ double sigsqcorr; /* variance in measured correlation */ double defolayconst; /* layconst for deformation mode */ /* algorithm parameters */ signed char eval; /* evaluate unwrapped input file if TRUE */ signed char unwrapped; /* input file is unwrapped if TRUE */ signed char regrowconncomps;/* grow connected components and exit if TRUE */ signed char initonly; /* exit after initialization if TRUE */ signed char initmethod; /* MST or MCF initialization */ signed char costmode; /* statistical cost mode */ signed char dumpall; /* dump intermediate files */ signed char verbose; /* print verbose output */ signed char amplitude; /* intensity data is amplitude, not power */ signed char havemagnitude; /* flag: create correlation from other inputs */ signed char flipphasesign; /* flag: flip phase and flow array signs */ signed char onetilereopt; /* flag: reoptimize full input after tile init */ signed char rmtileinit; /* flag to remove temporary tile unw init soln */ long initmaxflow; /* maximum flow for initialization */ long arcmaxflowconst; /* units of flow past dzmax to use for initmaxflow */ long maxflow; /* max flow for tree solve looping */ long krowei, kcolei; /* size of boxcar averaging window for mean ei */ long kpardpsi; /* length of boxcar for mean wrapped gradient */ long kperpdpsi; /* width of boxcar for mean wrapped gradient */ double threshold; /* thershold for numerical dzrcrit calculation */ double initdzr; /* initial dzr for numerical dzrcrit calc. (m) */ double initdzstep; /* initial stepsize for spatial decor slope calc. */ double maxcost; /* min and max float values for cost arrays */ double costscale; /* scale factor for discretizing to integer costs */ double costscaleambight;/* ambiguity height for auto costs caling */ double dnomincangle; /* step size for range-varying param lookup table */ long srcrow,srccol; /* source node location */ double p; /* power for Lp-norm solution (less than 0 is MAP) */ signed char bidirlpn; /* use bidirectional Lp costs if TRUE */ long nshortcycle; /* number of points for one cycle in short int dz */ double maxnewnodeconst; /* number of nodes added to tree on each iteration */ long maxnflowcycles; /* max number of cycles to consider nflow done */ double maxcyclefraction;/* ratio of max cycles to pixels */ long nconnnodemin; /* min number of nodes to keep in connected set */ long cs2scalefactor; /* scale factor for cs2 initialization (eg, 3-30) */ long nmajorprune; /* number of major iterations between tree pruning */ long prunecostthresh; /* cost threshold for pruning */ long edgemasktop; /* number of pixels to mask at top edge of input */ long edgemaskbot; /* number of pixels to mask at bottom edge */ long edgemaskleft; /* number of pixels to mask at left edge */ long edgemaskright; /* number of pixels to mask at right edge */ long parentpid; /* process identification number of parent */ /* tiling parameters */ long ntilerow; /* number of tiles in azimuth */ long ntilecol; /* number of tiles in range */ long rowovrlp; /* pixels of overlap between row tiles */ long colovrlp; /* pixels of overlap between column tiles */ long piecefirstrow; /* first row (indexed from 1) for piece mode */ long piecefirstcol; /* first column (indexed from 1) for piece mode */ long piecenrow; /* number of rows for piece mode */ long piecencol; /* number of cols for piece mode */ long tilecostthresh; /* maximum cost within single reliable tile region */ long minregionsize; /* minimum number of pixels in a region */ long nthreads; /* number of parallel processes to run */ long scndryarcflowmax; /* max flow increment for which to keep cost data */ double tileedgeweight; /* weight applied to tile-edge secondary arc costs */ signed char assembleonly; /* flag for assemble-only (no unwrap) mode */ signed char rmtmptile; /* flag for removing temporary tile files */ char tiledir[MAXSTRLEN];/* directory for temporary tile files */ /* connected component parameters */ double minconncompfrac; /* min fraction of pixels in connected component */ long conncompthresh; /* cost threshold for connected component */ long maxncomps; /* max number of connected components */ int conncompouttype; /* flag for type of connected component output file */ }paramT; /* input file name data structure */ typedef struct infileST{ char infile[MAXSTRLEN]; /* input interferogram */ char magfile[MAXSTRLEN]; /* interferogram magnitude (optional) */ char ampfile[MAXSTRLEN]; /* image amplitude or power file */ char ampfile2[MAXSTRLEN]; /* second amplitude or power file */ char weightfile[MAXSTRLEN]; /* arc weights */ char corrfile[MAXSTRLEN]; /* correlation file */ char estfile[MAXSTRLEN]; /* unwrapped estimate */ char costinfile[MAXSTRLEN]; /* file from which cost data is read */ char bytemaskfile[MAXSTRLEN]; /* signed char valid pixel mask */ char dotilemaskfile[MAXSTRLEN]; /* signed char tile unwrap mask file */ signed char infileformat; /* input file format */ signed char unwrappedinfileformat; /* input file format if unwrapped */ signed char magfileformat; /* interferogram magnitude file format */ signed char corrfileformat; /* correlation file format */ signed char weightfileformat; /* weight file format */ signed char ampfileformat; /* amplitude file format */ signed char estfileformat; /* unwrapped-estimate file format */ }infileT; /* output file name data structure */ typedef struct outfileST{ char outfile[MAXSTRLEN]; /* unwrapped output */ char initfile[MAXSTRLEN]; /* unwrapped initialization */ char flowfile[MAXSTRLEN]; /* flows of unwrapped solution */ char eifile[MAXSTRLEN]; /* despckled, normalized intensity */ char rowcostfile[MAXSTRLEN]; /* statistical azimuth cost array */ char colcostfile[MAXSTRLEN]; /* statistical range cost array */ char mstrowcostfile[MAXSTRLEN]; /* scalar initialization azimuth costs */ char mstcolcostfile[MAXSTRLEN]; /* scalar initialization range costs */ char mstcostsfile[MAXSTRLEN]; /* scalar initialization costs (all) */ char corrdumpfile[MAXSTRLEN]; /* correlation coefficient magnitude */ char rawcorrdumpfile[MAXSTRLEN]; /* correlation coefficient magnitude */ char conncompfile[MAXSTRLEN]; /* connected component map or mask */ char costoutfile[MAXSTRLEN]; /* file to which cost data is written */ char logfile[MAXSTRLEN]; /* file to which parmeters are logged */ signed char outfileformat; /* output file format */ }outfileT; /* tile parameter data structure */ typedef struct tileparamST{ long firstcol; /* first column of tile to process (index from 0) */ long ncol; /* number of columns in tile to process */ long firstrow; /* first row of tile to process (index from 0) */ long nrow; /* number of rows in tile to process */ }tileparamT; /* connectected component size structure */ typedef struct conncompsizeST{ unsigned int tilenum; /* tile index */ unsigned int icomptile; /* conn comp index in tile */ unsigned int icompfull; /* conn comp index in full array */ long npix; /* number of pixels in conn comp */ }conncompsizeT; /* type for total cost of solution (may overflow long) */ typedef double totalcostT; #define INITTOTALCOST LARGEFLOAT /***********************/ /* function prototypes */ /***********************/ /* functions in snaphu_tile.c */ int SetupTile(long nlines, long linelen, paramT *params, tileparamT *tileparams, outfileT *outfiles, outfileT *tileoutfiles, long tilerow, long tilecol); signed char **SetUpDoTileMask(infileT *infiles, long ntilerow, long ntilecol); int GrowRegions(void **costs, short **flows, long nrow, long ncol, incrcostT **incrcosts, outfileT *outfiles, tileparamT *tileparams, paramT *params); int GrowConnCompsMask(void **costs, short **flows, long nrow, long ncol, incrcostT **incrcosts, outfileT *outfiles, paramT *params); int AssembleTiles(outfileT *outfiles, paramT *params, long nlines, long linelen); /* functions in snaphu_solver.c */ int SetGridNetworkFunctionPointers(void); int SetNonGridNetworkFunctionPointers(void); long TreeSolve(nodeT **nodes, nodesuppT **nodesupp, nodeT *ground, nodeT *source, candidateT **candidatelistptr, candidateT **candidatebagptr, long *candidatelistsizeptr, long *candidatebagsizeptr, bucketT *bkts, short **flows, void **costs, incrcostT **incrcosts, nodeT ***apexes, signed char **iscandidate, long ngroundarcs, long nflow, float **mag, float **wrappedphase, char *outfile, long nnoderow, int *nnodesperrow, long narcrow, int *narcsperrow, long nrow, long ncol, outfileT *outfiles, long nconnected, paramT *params); int InitNetwork(short **flows, long *ngroundarcsptr, long *ncycleptr, long *nflowdoneptr, long *mostflowptr, long *nflowptr, long *candidatebagsizeptr, candidateT **candidatebagptr, long *candidatelistsizeptr, candidateT **candidatelistptr, signed char ***iscandidateptr, nodeT ****apexesptr, bucketT **bktsptr, long *iincrcostfileptr, incrcostT ***incrcostsptr, nodeT ***nodesptr, nodeT *ground, long *nnoderowptr, int **nnodesperrowptr, long *narcrowptr, int **narcsperrowptr, long nrow, long ncol, signed char *notfirstloopptr, totalcostT *totalcostptr, paramT *params); long SetupTreeSolveNetwork(nodeT **nodes, nodeT *ground, nodeT ***apexes, signed char **iscandidate, long nnoderow, int *nnodesperrow, long narcrow, int *narcsperrow, long nrow, long ncol); signed char CheckMagMasking(float **mag, long nrow, long ncol); int MaskNodes(long nrow, long ncol, nodeT **nodes, nodeT *ground, float **mag); long MaxNonMaskFlow(short **flows, float **mag, long nrow, long ncol); int InitNodeNums(long nrow, long ncol, nodeT **nodes, nodeT *ground); int InitNodes(long nrow, long ncol, nodeT **nodes, nodeT *ground); void BucketInsert(nodeT *node, long ind, bucketT *bkts); void BucketRemove(nodeT *node, long ind, bucketT *bkts); nodeT *ClosestNode(bucketT *bkts); long SelectSources(nodeT **nodes, float **mag, nodeT *ground, long nflow, short **flows, long ngroundarcs, long nrow, long ncol, paramT *params, nodeT ***sourcelistptr, long **nconnectedarrptr); long ReCalcCost(void **costs, incrcostT **incrcosts, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params); int SetupIncrFlowCosts(void **costs, incrcostT **incrcosts, short **flows, long nflow, long nrow, long narcrow, int *narcsperrow, paramT *params); totalcostT EvaluateTotalCost(void **costs, short **flows, long nrow, long ncol, int *narcsperrow,paramT *params); int MSTInitFlows(float **wrappedphase, short ***flowsptr, short **mstcosts, long nrow, long ncol, nodeT ***nodes, nodeT *ground, long maxflow); int MCFInitFlows(float **wrappedphase, short ***flowsptr, short **mstcosts, long nrow, long ncol, long cs2scalefactor); /* functions in snaphu_cost.c */ int BuildCostArrays(void ***costsptr, short ***mstcostsptr, float **mag, float **wrappedphase, float **unwrappedest, long linelen, long nlines, long nrow, long ncol, paramT *params, tileparamT *tileparams, infileT *infiles, outfileT *outfiles); void CalcCostTopo(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr); void CalcCostDefo(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr); void CalcCostSmooth(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr); void CalcCostL0(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr); void CalcCostL1(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr); void CalcCostL2(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr); void CalcCostLP(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr); void CalcCostL0BiDir(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr); void CalcCostL1BiDir(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr); void CalcCostL2BiDir(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr); void CalcCostLPBiDir(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr); void CalcCostNonGrid(void **costs, long flow, long arcrow, long arccol, long nflow, long nrow, paramT *params, long *poscostptr, long *negcostptr); long EvalCostTopo(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params); long EvalCostDefo(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params); long EvalCostSmooth(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params); long EvalCostL0(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params); long EvalCostL1(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params); long EvalCostL2(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params); long EvalCostLP(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params); long EvalCostL0BiDir(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params); long EvalCostL1BiDir(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params); long EvalCostL2BiDir(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params); long EvalCostLPBiDir(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params); long EvalCostNonGrid(void **costs, short **flows, long arcrow, long arccol, long nrow, paramT *params); /* functions in snaphu_util.c */ signed char SetBooleanSignedChar(signed char *boolptr, char *str); int WrapPhase(float **wrappedphase, long nrow, long ncol); int CalcWrappedRangeDiffs(float **dpsi, float **avgdpsi, float **wrappedphase, long kperpdpsi, long kpardpsi, long nrow, long ncol); int CalcWrappedAzDiffs(float **dpsi, float **avgdpsi, float **wrappedphase, long kperpdpsi, long kpardpsi, long nrow, long ncol); int CycleResidue(float **phase, signed char **residue, int nrow, int ncol); int NodeResidue(float **wphase, long row, long col); int CalcFlow(float **phase, short ***flowsptr, long nrow, long ncol); int IntegratePhase(float **psi, float **phi, short **flows, long nrow, long ncol); float **ExtractFlow(float **unwrappedphase, short ***flowsptr, long nrow, long ncol); int FlipPhaseArraySign(float **arr, paramT *params, long nrow, long ncol); int FlipFlowArraySign(short **arr, paramT *params, long nrow, long ncol); void **Get2DMem(int nrow, int ncol, int psize, size_t size); void **Get2DRowColMem(long nrow, long ncol, int psize, size_t size); void **Get2DRowColZeroMem(long nrow, long ncol, int psize, size_t size); void *MAlloc(size_t size); void *CAlloc(size_t nitems, size_t size); void *ReAlloc(void *ptr, size_t size); int Free2DArray(void **array, unsigned int nrow); int Set2DShortArray(short **arr, long nrow, long ncol, long value); signed char ValidDataArray(float **arr, long nrow, long ncol); signed char NonNegDataArray(float **arr, long nrow, long ncol); signed char IsFinite(double d); long LRound(double a); long LMin(long a, long b); long LClip(long a, long minval, long maxval); long Short2DRowColAbsMax(short **arr, long nrow, long ncol); float LinInterp1D(float *arr, double index, long nelem); float LinInterp2D(float **arr, double rowind, double colind , long nrow, long ncol); int Despeckle(float **mag, float ***ei, long nrow, long ncol); float **MirrorPad(float **array1, long nrow, long ncol, long krow, long kcol); int BoxCarAvg(float **avgarr, float **padarr, long nrow, long ncol, long krow, long kcol); char *StrNCopy(char *dest, const char *src, size_t n); int FlattenWrappedPhase(float **wrappedphase, float **unwrappedest, long nrow, long ncol); int Add2DFloatArrays(float **arr1, float **arr2, long nrow, long ncol); int StringToDouble(char *str, double *d); int StringToLong(char *str, long *l); int CatchSignals(void (*SigHandler)(int)); void SetDump(int signum); void KillChildrenExit(int signum); void SignalExit(int signum); int StartTimers(time_t *tstart, double *cputimestart); int DisplayElapsedTime(time_t tstart, double cputimestart); int LongCompare(const void *c1, const void *c2); /* functions in snaphu_io.c */ int SetDefaults(infileT *infiles, outfileT *outfiles, paramT *params); int ProcessArgs(int argc, char *argv[], infileT *infiles, outfileT *outfiles, long *ncolptr, paramT *params); int CheckParams(infileT *infiles, outfileT *outfiles, long linelen, long nlines, paramT *params); int ReadConfigFile(char *conffile, infileT *infiles, outfileT *outfiles, long *ncolptr, paramT *params); int WriteConfigLogFile(int argc, char *argv[], infileT *infiles, outfileT *outfiles, long linelen, paramT *params); long GetNLines(infileT *infiles, long linelen, paramT *params); int WriteOutputFile(float **mag, float **unwrappedphase, char *outfile, outfileT *outfiles, long nrow, long ncol); FILE *OpenOutputFile(char *outfile, char *realoutfile); int Write2DArray(void **array, char *filename, long nrow, long ncol, size_t size); int Write2DRowColArray(void **array, char *filename, long nrow, long ncol, size_t size); int ReadInputFile(infileT *infiles, float ***magptr, float ***wrappedphaseptr, short ***flowsptr, long linelen, long nlines, paramT *params, tileparamT *tileparams); int ReadMagnitude(float **mag, infileT *infiles, long linelen, long nlines, tileparamT *tileparams); int ReadByteMask(float **mag, infileT *infiles, long linelen, long nlines, tileparamT *tileparams, paramT *params); int ReadUnwrappedEstimateFile(float ***unwrappedestptr, infileT *infiles, long linelen, long nlines, paramT *params, tileparamT *tileparams); int ReadWeightsFile(short ***weightsptr,char *weightfile, long linelen, long nlines, tileparamT *tileparams); int ReadIntensity(float ***pwrptr, float ***pwr1ptr, float ***pwr2ptr, infileT *infiles, long linelen, long nlines, paramT *params, tileparamT *tileparams); int ReadCorrelation(float ***corrptr, infileT *infiles, long linelen, long nlines, tileparamT *tileparams); int ReadAltLineFile(float ***mag, float ***phase, char *alfile, long linelen, long nlines, tileparamT *tileparams); int ReadAltLineFilePhase(float ***phase, char *alfile, long linelen, long nlines, tileparamT *tileparams); int ReadComplexFile(float ***mag, float ***phase, char *rifile, long linelen, long nlines, tileparamT *tileparams); int Read2DArray(void ***arr, char *infile, long linelen, long nlines, tileparamT *tileparams, size_t elptrsize, size_t elsize); int ReadAltSampFile(float ***arr1, float ***arr2, char *infile, long linelen, long nlines, tileparamT *tileparams); int Read2DRowColFile(void ***arr, char *filename, long linelen, long nlines, tileparamT *tileparams, size_t size); int Read2DRowColFileRows(void ***arr, char *filename, long linelen, long nlines, tileparamT *tileparams, size_t size); int SetDumpAll(outfileT *outfiles, paramT *params); int SetStreamPointers(void); int SetVerboseOut(paramT *params); int ChildResetStreamPointers(pid_t pid, long tilerow, long tilecol, paramT *params); int DumpIncrCostFiles(incrcostT **incrcosts, long iincrcostfile, long nflow, long nrow, long ncol); int MakeTileDir(paramT *params, outfileT *outfiles); int ParseFilename(char *filename, char *path, char *basename); int SetTileInitOutfile(char *outfile, long pid); /* functions in snaphu_cs2.c */ void SolveCS2(signed char **residue, short **mstcosts, long nrow, long ncol, long cs2scalefactor, short ***flowsptr); /*******************************************/ /* global (external) variable declarations */ /*******************************************/ /* flags used for signal handling */ extern char dumpresults_global; extern char requestedstop_global; /* ouput stream pointers */ /* sp0=error messages, sp1=status output, sp2=verbose, sp3=verbose counter */ extern FILE *sp0, *sp1, *sp2, *sp3; /* node pointer for marking arc not on tree in apex array */ /* this should be treat as a constant */ extern nodeT NONTREEARC[1]; /* pointers to functions which calculate arc costs */ extern void (*CalcCost)(void **, long, long, long, long, long, paramT *, long *, long *); extern long (*EvalCost)(void **, short **, long, long, long, paramT *); /* end of snaphu.h */ snaphu-v2.0.6/src/PaxHeader/snaphu_cs2parse.c000644 777777 777777 00000000043 14423062415 020731 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/src/snaphu_cs2parse.c000644 Ho)00000035731 14423062415 020174 0ustar00curtis000000 000000 /************************************************************************* This code is derived from cs2 v3.7 Written by Andrew V. Goldberg and Boris Cherkassky Modifications for use in snaphu by Curtis W. Chen Parser for cs2 minimum cost flow solver. Originally written to read DIMACS format (text) input files. Modified to parse passed data from snaphu. This file is included with a #include from snaphu_cs2.c. The cs2 code is used here with permission for strictly noncommerical use. The original cs2 source code can be downloaded from http://www.igsystems.com/cs2 The original cs2 copyright is stated as follows: COPYRIGHT C 1995 IG Systems, Inc. Permission to use for evaluation purposes is granted provided that proper acknowledgments are given. For a commercial licence, contact igsys@eclipse.net. This software comes with NO WARRANTY, expressed or implied. By way of example, but not limitation, we make no representations of warranties of merchantability or fitness for any particular purpose or that the use of the software components or documentation will not infringe any patents, copyrights, trademarks, or other rights. Copyright 2002 Board of Trustees, Leland Stanford Jr. University *************************************************************************/ int cs2mcfparse(residue, rowcost, colcost, nNrow, nNcol, n_ad, m_ad, nodes_ad, arcs_ad, node_min_ad, m_c_ad, cap_ad ) /* parameters passed to set up network */ signed char **residue; /* 2D array of residues */ short **rowcost; /* 2D array of row arc costs */ short **colcost; /* 2D array of col arc costs */ long nNrow; /* number of nodes per row */ long nNcol; /* number of nodes per column */ /* these parameters are output */ long *n_ad; /* address of the number of nodes */ long *m_ad; /* address of the number of arcs */ node **nodes_ad; /* address of the array of nodes */ arc **arcs_ad; /* address of the array of arcs */ long *node_min_ad; /* address of the minimal node */ double *m_c_ad; /* maximal arc cost */ short **cap_ad; /* array of capacities (changed to short) */ { #define ABS( x ) ( (x) >= 0 ) ? (x) : -(x) /* variables added for unwrapping parse */ unsigned int row, col, dir; unsigned long narcs, nnodes, nodectr, arcctr, nresidues; long cumsupply, temp; long inf_cap = 0; long n, /* internal number of nodes */ node_min, /* minimal no of node */ node_max, /* maximal no of nodes */ *arc_first, /* internal array for holding - node degree - position of the first outgoing arc */ *arc_tail, /* internal array: tails of the arcs */ /* temporary variables carrying no of nodes */ head, tail, i; long m, /* internal number of arcs */ /* temporary variables carrying no of arcs */ last, arc_num, arc_new_num; node *nodes, /* pointers to the node structure */ *head_p, *ndp, *in, *jn; arc *arcs, /* pointers to the arc structure */ *arc_current, *arc_new, *arc_tmp; long excess, /* supply/demand of the node */ low, /* lowest flow through the arc */ acap; /* capacity */ long cost; /* arc cost */ double dcost, /* arc cost in double mode */ m_c; /* maximal arc cost */ short *cap; /* array of capacities (changed to short) */ double total_p, /* total supply */ total_n, /* total demand */ cap_out, /* sum of outgoing capacities */ cap_in; /* sum of incoming capacities */ long no_lines=0, /* no of current input line */ /* no_plines=0, */ /* no of problem-lines */ /* no_nlines=0, */ /* no of node lines */ no_alines=0, /* no of arc-lines */ pos_current=0; /* 2*no_alines */ int /* k, */ /* temporary */ err_no; /* no of detected error */ /* -------------- error numbers & error messages ---------------- */ #define EN1 0 #define EN2 1 #define EN3 2 #define EN4 3 #define EN6 4 #define EN10 5 #define EN7 6 #define EN8 7 #define EN9 8 #define EN11 9 #define EN12 10 #define EN13 11 #define EN14 12 #define EN16 13 #define EN15 14 #define EN17 15 #define EN18 16 #define EN21 17 #define EN19 18 #define EN20 19 #define EN22 20 static char *err_message[] = { /* 0*/ "more than one problem line", /* 1*/ "wrong number of parameters in the problem line", /* 2*/ "it is not a Min-cost problem line", /* 3*/ "bad value of a parameter in the problem line", /* 4*/ "can't obtain enough memory to solve this problem", /* 5*/ "", /* 6*/ "can't read problem name", /* 7*/ "problem description must be before node description", /* 8*/ "wrong capacity bounds", /* 9*/ "wrong number of parameters in the node line", /*10*/ "wrong value of parameters in the node line", /*11*/ "unbalanced problem", /*12*/ "node descriptions must be before arc descriptions", /*13*/ "too many arcs in the input", /*14*/ "wrong number of parameters in the arc line", /*15*/ "wrong value of parameters in the arc line", /*16*/ "unknown line type in the input", /*17*/ "read error", /*18*/ "not enough arcs in the input", /*19*/ "warning: capacities too big - excess overflow possible", /*20*/ "can't read anything from the input file", /*21*/ "warning: infinite capacity replaced by BIGGEST_FLOW" }; /* --------------------------------------------------------------- */ /* set up */ nnodes=nNrow*nNcol+1; /* add one for ground node */ narcs=2*((nNrow+1)*nNcol+nNrow*(nNcol+1)); /* 2x for two directional arcs */ cumsupply=0; nresidues=0; /* get memory (formerly case 'p' in DIMACS file read) */ fprintf(sp2,"Setting up data structures for cs2 MCF solver\n"); n=nnodes; m=narcs; if ( n <= 0 || m <= 0 ) /*wrong value of no of arcs or nodes*/ { err_no = EN4; goto error; } /* allocating memory for 'nodes', 'arcs' and internal arrays */ nodes = (node*) CAlloc ( n+2, sizeof(node) ); arcs = (arc*) CAlloc ( 2*m+1, sizeof(arc) ); cap = (short*) CAlloc ( 2*m, sizeof(short) ); /* changed to short */ arc_tail = (long*) CAlloc ( 2*m, sizeof(long) ); arc_first= (long*) CAlloc ( n+2, sizeof(long) ); /* arc_first [ 0 .. n+1 ] = 0 - initialized by calloc */ for ( in = nodes; in <= nodes + n; in ++ ) in -> excess = 0; if ( nodes == NULL || arcs == NULL || arc_first == NULL || arc_tail == NULL ) /* memory is not allocated */ { err_no = EN6; goto error; } /* setting pointer to the first arc */ arc_current = arcs; node_max = 0; node_min = n; m_c = 0; total_p = total_n = 0; for ( ndp = nodes; ndp < nodes + n; ndp ++ ) ndp -> excess = 0; /* end of former case 'p' */ /* load supply/demand info into arrays (case 'n' in former loop) */ for(col=0; col excess = excess; if ( excess > 0 ) total_p += (double)excess; if ( excess < 0 ) total_n -= (double)excess; nresidues++; cumsupply+=residue[row][col]; } } } /* give ground node excess of -cumsupply */ ( nodes + nnodes ) -> excess = -cumsupply; if (cumsupply < 0) total_p -= (double)cumsupply; if (cumsupply > 0) total_n += (double)cumsupply; /* load arc info into arrays (case 'a' in former loop) */ low=0; acap=ARCUBOUND; /* horizontal (row) direction arcs first */ for(arcctr=1;arcctr<=2*nNrow*nNcol+nNrow+nNcol;arcctr++){ if(arcctr<=nNrow*(nNcol+1)){ /* row (horizontal) arcs first */ nodectr=arcctr; if(nodectr<=nNrow*nNcol){ tail=nodectr; }else{ tail=nnodes; } if(nodectr<=nNrow){ head=nnodes; }else{ head=nodectr-nNrow; } cost=rowcost[((nodectr-1) % nNrow)][(int )((nodectr-1)/nNrow)]; }else{ /* column (vertical) arcs */ nodectr=arcctr-nNrow*(nNcol+1); if(nodectr % (nNrow+1)==0){ tail=nnodes; }else{ tail=(int )(nodectr-ceil(nodectr/(nNrow+1.0))+1); } if(nodectr % (nNrow+1)==1){ head=nnodes; }else{ head=(int )(nodectr-ceil(nodectr/(nNrow+1.0))); } cost=colcost[((nodectr-1) % (nNrow+1))][(int )((nodectr-1)/(nNrow+1))]; } if ( tail < 0 || tail > n || head < 0 || head > n ) /* wrong value of nodes */ { err_no = EN17; goto error; } if ( acap < 0 ) { acap = BIGGEST_FLOW; if (!inf_cap) { inf_cap = 1; fprintf ( sp0, "\ncs2 solver: %s\n", err_message[21] ); } } if ( low < 0 || low > acap ) { err_no = EN9; goto error; } for(dir=0;dir<=1;dir++){ if(dir){ /* switch head and tail and loop for two directional arcs */ temp=tail; tail=head; head=temp; } /* no of arcs incident to node i is placed in arc_first[i+1] */ arc_first[tail + 1] ++; arc_first[head + 1] ++; in = nodes + tail; jn = nodes + head; dcost = (double)cost; /* storing information about the arc */ arc_tail[pos_current] = tail; arc_tail[pos_current+1] = head; arc_current -> head = jn; arc_current -> r_cap = acap - low; cap[pos_current] = acap; arc_current -> cost = dcost; arc_current -> sister = arc_current + 1; ( arc_current + 1 ) -> head = nodes + tail; ( arc_current + 1 ) -> r_cap = 0; cap[pos_current+1] = 0; ( arc_current + 1 ) -> cost = -dcost; ( arc_current + 1 ) -> sister = arc_current; in -> excess -= low; jn -> excess += low; /* searching for minimum and maximum node */ if ( head < node_min ) node_min = head; if ( tail < node_min ) node_min = tail; if ( head > node_max ) node_max = head; if ( tail > node_max ) node_max = tail; if ( dcost < 0 ) dcost = -dcost; if ( dcost > m_c && acap > 0 ) m_c = dcost; no_alines ++; arc_current += 2; pos_current += 2; }/* end of for loop over arc direction */ }/* end of for loop over arcss */ /* ----- all is red or error while reading ----- */ if ( ABS( total_p - total_n ) > 0.5 ) /* unbalanced problem */ { err_no = EN13; goto error; } /********** ordering arcs - linear time algorithm ***********/ /* first arc from the first node */ ( nodes + node_min ) -> first = arcs; /* before below loop arc_first[i+1] is the number of arcs outgoing from i; after this loop arc_first[i] is the position of the first outgoing from node i arcs after they would be ordered; this value is transformed to pointer and written to node.first[i] */ for ( i = node_min + 1; i <= node_max + 1; i ++ ) { arc_first[i] += arc_first[i-1]; ( nodes + i ) -> first = arcs + arc_first[i]; } for ( i = node_min; i < node_max; i ++ ) /* scanning all the nodes exept the last*/ { last = ( ( nodes + i + 1 ) -> first ) - arcs; /* arcs outgoing from i must be cited from position arc_first[i] to the position equal to initial value of arc_first[i+1]-1 */ for ( arc_num = arc_first[i]; arc_num < last; arc_num ++ ) { tail = arc_tail[arc_num]; while ( tail != i ) /* the arc no arc_num is not in place because arc cited here must go out from i; we'll put it to its place and continue this process until an arc in this position would go out from i */ { arc_new_num = arc_first[tail]; arc_current = arcs + arc_num; arc_new = arcs + arc_new_num; /* arc_current must be cited in the position arc_new swapping these arcs: */ head_p = arc_new -> head; arc_new -> head = arc_current -> head; arc_current -> head = head_p; acap = cap[arc_new_num]; cap[arc_new_num] = cap[arc_num]; cap[arc_num] = acap; acap = arc_new -> r_cap; arc_new -> r_cap = arc_current -> r_cap; arc_current -> r_cap = acap; dcost = arc_new -> cost; arc_new -> cost = arc_current -> cost; arc_current -> cost = dcost; if ( arc_new != arc_current -> sister ) { arc_tmp = arc_new -> sister; arc_new -> sister = arc_current -> sister; arc_current -> sister = arc_tmp; ( arc_current -> sister ) -> sister = arc_current; ( arc_new -> sister ) -> sister = arc_new; } arc_tail[arc_num] = arc_tail[arc_new_num]; arc_tail[arc_new_num] = tail; /* we increase arc_first[tail] */ arc_first[tail] ++ ; tail = arc_tail[arc_num]; } } /* all arcs outgoing from i are in place */ } /* ----------------------- arcs are ordered ------------------------- */ /*------------ testing network for possible excess overflow ---------*/ for ( ndp = nodes + node_min; ndp <= nodes + node_max; ndp ++ ) { cap_in = ( ndp -> excess ); cap_out = - ( ndp -> excess ); for ( arc_current = ndp -> first; arc_current != (ndp+1) -> first; arc_current ++ ) { arc_num = arc_current - arcs; if ( cap[arc_num] > 0 ) cap_out += cap[arc_num]; if ( cap[arc_num] == 0 ) cap_in += cap[( arc_current -> sister )-arcs]; } /* if (cap_in > BIGGEST_FLOW || cap_out > BIGGEST_FLOW) { fprintf ( sp0, "\ncs2 solver: %s\n", err_message[EN20] ); break; } */ } /* ----------- assigning output values ------------*/ *m_ad = m; *n_ad = node_max - node_min + 1; *node_min_ad = node_min; *nodes_ad = nodes + node_min; *arcs_ad = arcs; *m_c_ad = m_c; *cap_ad = cap; /* free internal memory */ free ( arc_first ); free ( arc_tail ); /* Thanks God! All is done! */ return (0); /* ---------------------------------- */ error: /* error found reading input */ fprintf ( sp0, "\ncs2 solver: line %ld of input - %s\n", no_lines, err_message[err_no] ); exit (ABNORMAL_EXIT); /* this is a needless return statement so the compiler doesn't complain */ return(1); } /* -------------------- end of parser -------------------*/ snaphu-v2.0.6/config/PaxHeader/snaphu.conf.brief000644 777777 777777 00000000043 14423062415 021376 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/config/snaphu.conf.brief000644 Ho)00000041056 14423062415 020636 0ustar00curtis000000 000000 # snaphu configuration file # # Lines with fewer than two fields and lines whose first non-whitespace # characters are not alphnumeric are ignored. For the remaining lines, # anything after the first two fields (delimited by whitespace) is # also ignored. Inputs are converted in the order they appear in the file; # if multiple assignments are made to the same parameter, the last one # given is the one used. Parameters in this file will be superseded by # parameters given on the command line after the -f flag specifying this # file. Multiple configuration files may be given on the command line. ############################################# # File input and output and runtime options # ############################################# # See section below for file format configuration options. # Input file name # INFILE snaphu.in # Input file line length # LINELENGTH 1000 # Output file name # OUTFILE snaphu.out # Amplitude file name # AMPFILE snaphu.amp.in # Single file containing amplitude images # Correlation file name # CORRFILE snaphu.corr.in # Input file of signed binary byte (signed char) values. # BYTEMASKFILE snaphu.bytemask # Text file to which runtime parameters will be logged. # LOGFILE snaph.logfile # Statistical-cost mode (TOPO, DEFO, SMOOTH, or NOSTATCOSTS) # STATCOSTMODE TOPO # Initialize-only mode (TRUE or FALSE) # INITONLY FALSE # Unwrapped-input mode (TRUE or FALSE) # UNWRAPPED_IN FALSE # Algorithm used for initialization of wrapped phase values. Possible # values are MST and MCF. # INITMETHOD MST # Verbose-output mode (TRUE or FALSE) # VERBOSE FALSE ################ # File formats # ################ # Valid data formats: # # COMPLEX_DATA: complex values: real, imag, real, imag # ALT_LINE_DATA: real values from different arrays, alternating by line # ALT_SAMPLE_DATA: real values from different arrays, alternating by sample # FLOAT_DATA: single array of floating-point data # # The ALT_SAMPLE_DATA format is sometimes known as .amp or sample- # interleaved format; the ALT_LINE_DATA format is sometimes known as # .hgt or line-interleaved format. For the ALT_LINE_DATA format, the # first array is always assumed to be the interferogram magnitude. All # formats assume single-precision (32-bit) floating-point data (real*4 # and complex*8 in Fortran) in the native byte order (big vs. little # endian) of the system. # Input file format # Allowable formats: # If the data are not complex, the phase should be in radians from 0 to 2pi. # COMPLEX_DATA (default) # ALT_LINE_DATA (magnitude in channel 1, phase in radians in channel 2) # ALT_SAMPLE_DATA (magnitude in channel 1, phase in radians in channel 2) # FLOAT_DATA (phase in radians) # #INFILEFORMAT COMPLEX_DATA # Output file format # Allowable formats: # ALT_LINE_DATA (masked interferogram magnitude in channel 1, # unwrapped phase in radians in channel 2; default) # ALT_SAMPLE_DATA (masked interferogram magnitude in channel 1, # unwrapped phase in radians in channel 2) # FLOAT_DATA (unwrapped phase in radians) # #OUTFILEFORMAT ALT_LINE_DATA # Amplitude or power file format # Units should be consistent with interferogram. Allowable formats: # ALT_LINE_DATA (first image amplitude in channel 1, # second image amplitude in channel 2) # ALT_SAMPLE_DATA (first image amplitude in channel 1, # second image amplitude in channel 2; default) # FLOAT_DATA (square root of average power of two images) # #AMPFILEFORMAT ALT_SAMPLE_DATA # Correlation file format # Allowable formats: # ALT_LINE_DATA (channel 1 ignored; correlation values # between 0 and 1 in channel 2; default) # ALT_SAMPLE_DATA (channel 1 ignored; correlation values # between 0 and 1 in channel 2) # FLOAT_DATA (correlation values between 0 and 1) # #CORRFILEFORMAT ALT_LINE_DATA # Unwrapped input file format # Allowable formats: # ALT_LINE_DATA (interferogram magnitude in channel 1, # unwrapped phase in radians in channel 2; default) # ALT_SAMPLE_DATA (interferogram magnitude in channel 1, # unwrapped phase in radians in channel 2) # FLOAT_DATA (unwrapped phase in radians) # #UNWRAPPEDINFILEFORMAT ALT_LINE_DATA ############################### # SAR and geometry parameters # ############################### # Orbital radius (double, meters) or altitude (double, meters). The # radius should be the local radius if the orbit is not circular. The # altitude is just defined as the orbit radius minus the earth radius. # Only one of these two parameters should be given. ORBITRADIUS 7153000.0 #ALTITUDE 775000.0 # Local earth radius (double, meters). A spherical-earth model is # used. EARTHRADIUS 6378000.0 # The baseline parameters are not used in deformation mode, but they # are very important in topography mode. The parameter BASELINE # (double, meters) is the physical distance (always positive) between # the antenna phase centers. The along-track componenet of the # baseline is assumed to be zero. The parameter BASELINEANGLE_DEG # (double, degrees) is the angle between the antenna phase centers # with respect to the local horizontal. Suppose the interferogram is # s1*conj(s2). The baseline angle is defined as the angle of antenna2 # above the horizontal line extending from antenna1 towards the side # of the SAR look direction. Thus, if the baseline angle minus the # look angle is less than -pi/2 or greater than pi/2, the topographic # height increases with increasing elevation. The units of # BASELINEANGLE_RAD are radians. BASELINE 150.0 BASELINEANGLE_DEG 225.0 #BASELINEANGLE_RAD 3.92699 # If the BPERP parameter is given, the baseline angle is taken to be # equal to the look angle (mod pi) at midswath, and the length of the # baseline is set accordingly. Particular attention must be paid to # the sign of this parameter--it should be negative if increasing # phase implies increasing topographic height. #BPERP -150.0 # The transmit mode should be either REPEATPASS or PINGPONG if both # antennas transmitted and both received (REPEATPASS and PINGPONG have # the same effect); the transmit mode should be SINGLEANTENNATRANSMIT # if only one antenna was used to transmit while both antennas # received. In single-antenna-transmit mode, the baseline is # effectively halved. This parameter is ignored for cost modes other # than topography. TRANSMITMODE REPEATPASS # Slant range from platform to first range bin in input data file # (double, meters). Be sure to modify this parameter if the input # file is extracted from a larger scene. The parameter does not need # to be modified is snaphu is unwrapping only a subset of the input file. NEARRANGE 831000.0 # Slant range and azimuth pixel spacings of input interferogram after # any multilook averaging. This is not the same as the resolution. # (double, meters). DR 8.0 DA 20.0 # Single-look slant range and azimuth resolutions. This is not the # same as the pixel spacing. (double, meters). RANGERES 10.0 AZRES 6.0 # Wavelength (double, meters). LAMBDA 0.0565647 # Number of real (not necessarily independent) looks taken in range and # azimuth to form the input interferogram (long). NLOOKSRANGE 1 NLOOKSAZ 5 # Number of looks (assumed independent) from nonspatial averaging (long). NLOOKSOTHER 1 # Equivalent number of independent looks (double, dimensionless) that were # used to generate correlation file if one is specified. This parameter # is ignored if the correlation data are generated by the interferogram # and amplitude data. # # The equivalent number of independent looks is approximately equal to the # real number of looks divided by the product of range and azimuth # resolutions, and multiplied by the product of the single-look range and # azimuth pixel spacings. It is about 0.53 times the number of real looks # for ERS data processed without windowing. NCORRLOOKS 23.8 # Number of looks that should be taken in range and azimuth for estimating # the correlation coefficient from the interferogram and the amplitude # data. These numbers must be larger than NLOOKSRANGE and NLOOKSAZ. # The actual numbers used may be different since we prefer odd integer # multiples of NLOOKSRANGE and NLOOKSAZ (long). These numbers are ignored # if a separate correlation file is given as input. NCORRLOOKSRANGE 3 NCORRLOOKSAZ 15 ############################### # Scattering model parameters # ############################### # Threshold brightness (normalized) for layover height integration # (double, dimensionless) LAYMINEI 1.25 ################################## # Decorrelation model parameters # ################################## # Here, rho is the magnitude of the complex correlation coefficient # between the two observations forming the interferogram (0<=rho<=1) # See Zebker & Villasenor, 1992 # Default value to use uniformly for true, unbiased correlation if no # correlation file is specified and correlation cannot be generated # from the available data (double). DEFAULTCORR 0.01 # Factor applied to expected minimum measured (biased) correlation. # Values smaller than the threshold rhominfactor*rho0 are assumed to # come from zero statistical correlation because of estimator bias (double). # This is used only in topo mode; for defo mode, use DEFOTHRESHFACTOR. RHOMINFACTOR 1.3 ######################## # PDF model parameters # ######################## # Algorithm costs are based on the negative log pdf: # # cost = -log(f(phi | EI, rho)) # Factor applied to range layover probability density to get azimuth # layover probability density (double). AZDZFACTOR 0.99 # Ratio of layover probability density to peak probability density # for non-layover slopes expected (double). LAYCONST 0.9 ############################### # Deformation mode parameters # ############################### # Factor applied to range discontinuity probability density to get # corresponding value for azimuth (double). DEFOAZDZFACTOR 1.0 # Factor applied to rho0 to get threshold for whether or not phase # discontinuity is possible (double). rho0 is the expected, biased # correlation measure if true correlation is 0. DEFOTHRESHFACTOR 1.2 # Maximum phase discontinuity likely (double). Units are radians or cycles. # If abrupt phase discontinuities are not expected, this paramter can be # set to zero. DEFOMAX_CYCLE 1.2 #DEFOMAX_RAD 7.5398 # Ratio of phase discontinuity probability density to peak probability # density expected for discontinuity-possible pixel differences (double). # Value of 1 means zero cost for discontinuity, 0 means infinite cost. DEFOCONST 0.9 ######################## # Algorithm parameters # ######################## # Maximum flow increment (long) for solver. Not the same as maximum # flow possible. MAXFLOW 4 # Scaling constant factor applied to double precision costs to get # integer costs (double). COSTSCALE 100.0 # Integer spacing that represents one unit of flow or one cycle of phase # when storing costs as short integer types (long). NSHORTCYCLE 200 # Gives the minimum number of connected nodes to consider for # unwrapping. If masking separates the input data into disconnected # sets of pixels, a source is selected for each connected set, # provided that the number of nodes in the set is greater than # NCONNNODEMIN. If NCONNNODEMIN is zero, all possible unmasked pixels # will be uwnrapped. NCONNNODEMIN should be nonnegative. NCONNNODEMIN 0 ########################### # Edge masking parameters # ########################### # These parameters (long, dimensionless) are used to mask out pixels # near the edges of the input array. EDGEMASKTOP, EDGEMASKBOT, # EDGEMASKLEFT, and EDGEMASKRIGHT specify the numbers of pixels from the # top, bottom, left, and right edges respectively that should be # masked out. Masking is only applied during the nonlinear solver # stage (not the initialization). # EDGEMASKTOP 0 # EDGEMASKBOT 0 # EDGEMASKLEFT 0 # EDGEMASKRIGHT 0 ############################### # Piece extraction parameters # ############################### # These parameters (long, dimensionless) allow only a subset of the # input data files to be read and unwrapped. The upper left corner of # the subset is at row PIECEFIRSTROW and column PIECEFIRSTCOL, with # both indexed from 1 (that is, the upper left corner is pixel 1,1). # The output will be PIECENROW rows x PIECENCOL columns in size. # These parameters cannot be used in tile mode. If PIECENROW or # PIECENCOL is zero, the full depth or width of the input is # unwrapped. # PIECEFIRSTROW 1 # PIECEFIRSTCOL 1 # PIECENROW 0 # PIECENCOL 0 ################ # Tile control # ################ # Parameters in this section describe how the input files will be # tiled. This is mainly used for tiling, in which different # patches of the interferogram are unwrapped separately. # Number of rows and columns of tiles into which the data files are # to be broken up. # NTILEROW 1 # NTILECOL 1 # Overlap, in pixels, between neighboring tiles. # ROWOVRLP 0 # COLOVRLP 0 # Maximum number of child processes to start for parallel tile # unwrapping. # NPROC 1 # Cost threshold to use for determining boundaries of reliable regions # (long, dimensionless; scaled according to other cost constants). # Larger cost threshold implies smaller regions---safer, but # more expensive computationally. # TILECOSTTHRESH 500 # Minimum size (long, pixels) of a reliable region in tile mode. # MINREGIONSIZE 100 # Extra weight applied to secondary arcs on tile edges. # TILEEDGEWEIGHT 2.5 # Maximum flow magnitude (long) whose cost will be stored in the secondary # cost lookup table. Secondary costs larger than this will be approximated # by a quadratic function. # SCNDRYARCFLOWMAX 8 # The program will remove temporary tile files if this is set. # RMTMPTILE FALSE # This is the name (string) of a file of signed character data types # which serve as a mask for which tiles will be unwrapped. The file # should be a raster array with NTILEROW rows and NTILECOL columns. # Where the array element is nonzero, the corresponding tile will be # unwrapped; where the array element is zero, the tile will not be # unwrapped and no output for that tile will be written. This option # is used for reprocessing only certain tiles of a run. # DOTILEMASKFILE snaphu.dotilemaskfile.in # This is the name of the tile directory. Tiles will be stored # temporarily in the tile directory. If in assemble only mode, # unwrapped tiles are assumed to reside in this directory. The # directory is create if it does not exist. # TILEDIR snaphu_tiledir # If this is set to TRUE, the program will skip the unwrapping step # and only assemble temporary tile files from a previous invocation # saved in the directory whose name is given by the TILEDIR keyword. # The tile size parameters and file names must be the same. # ASSEMBLEONLY FALSE # Repotimize as single tile after using tile mode for intialization if # this is set to TRUE. This is equivalent to unwrapping with multiple # tiles, then using the unwrapped output as the input to a new, single-tile run # of snaphu with the -u option. The purpose is for speed. #SINGLETILEREOPTIMIZE FALSE ############################### # Connected component control # ############################### # Grow connected components mask and write to the output file whose # name is specified here as a string. The mask is a file of unsigned # integer values with the same number of rows and columns as the # unwrapped interferogram. The type of integer (1 byte vs. 4 byte) is # specified by the CONNCOMPOUTTYPE keyword, with 1-byte integers being # the default. # CONNCOMPFILE snaphu.conncomp # Type of integer that the connected-component output, if requested, # will be written as (see the CONNCOMPFILE keyword). The value here # may be either UCHAR or UINT, which specify unsigned character # (1-byte integer) or unsigned integer (4-byte integer) values, # respectively. # CONNCOMPOUTTYPE UCHAR # Grow connected components mask from unwrapped input then exit if TRUE. # Output is written to the file specified by CONNCOMPFILE. # REGROWCONNCOMPS FALSE # Minimum size of a single connected component, as a fraction (double) # of the total number of pixels in tile. # MINCONNCOMPFRAC 0.01 # Cost threshold for connected components (long). Higher threshold will # give smaller connected components. # CONNCOMPTHRESH 300 # Maximum number of connected components per tile (long). # MAXNCOMPS 32 # End of snaphu configuration file snaphu-v2.0.6/config/PaxHeader/snaphu.conf.full000644 777777 777777 00000000043 14423062415 021251 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/config/snaphu.conf.full000644 Ho)00000066711 14423062415 020516 0ustar00curtis000000 000000 # snaphu configuration file # # Lines with fewer than two fields and lines whose first non-whitespace # characters are not alphnumeric are ignored. For the remaining lines, # anything after the first two fields (delimited by whitespace) is # also ignored. Inputs are converted in the order they appear in the file; # if multiple assignments are made to the same parameter, the last one # given is the one used. Parameters in this file will be superseded by # parameters given on the command line after the -f flag specifying this # file. Multiple configuration files may be given on the command line. ############################################# # File input and output and runtime options # ############################################# # See section below for file format configuration options. # Input file name (see possible file formats below) # INFILE snaphu.in # Input file line length # LINELENGTH 1000 # Output file name (see possible file formats below). The output # array will have the same dimensions as the input unless the PIECE # parameters are specified. # OUTFILE snaphu.out # Weight file name. Weights are specified on arcs, not pixel values. # WEIGHTFILE snaphu.weights.in # Amplitude file name(s); (see possible file formats below). The # array(s) should have the same dimensions as the input wrapped phase # array. The values should be in linear units. # AMPFILE snaphu.amp.in # Single file containing amplitude images # # AMPFILE1 snaphu.amp1.in # Pair of separate files for amplitude images # AMPFILE2 snaphu.amp2.in # Power file name(s); (see possible file formats below) The array(s) # should have the same dimensions as the input wrapped phase array. # The values should be in linear units (not dB). # PWRFILE snaphu.amp.in # Single file containing power images # # PWRFILE1 snaphu.amp1.in # Pair of separate files for power images # PWRFILE2 snaphu.amp2.in # Interferogram magnitude file (see possible file formats below). The # array should have the same dimensions as the input wrapped phase # array. The magnitude should be in linear units. # MAGFILE snaphu.mag.in # Correlation file name (see possible file formats below). The array # should have the same dimensions as the input wrapped phase array. # CORRFILE snaphu.corr.in # Coarse unwrapped-phase estimate file name (see possible file formats # below). The array should have the same dimensions as the input # wrapped phase array. # ESTIMATEFILE snaphu.est.in # Input cost file (for statistical costs). If costs are read from this # file, many of the other parameters will be ignored (string). # COSTINFILE snaphu.costinfile # Output cost file to which statistical costs will be dumped (string). # Costs are not dumped if no file is given. # COSTOUTFILE snaphu.costoutfile # Input file of signed binary byte (signed char) values. Values in # the file should be either 0 or 1, with 0 denoting interferogram # pixels that should be masked out and 1 denoting valid pixels. The # array should have the same dimensions as the input wrapped phase # array. # BYTEMASKFILE snaphu.bytemask # Text file to which runtime parameters will be logged. The format of # that file will be suitable so that it can also be used as a # configuration file. # LOGFILE snaph.logfile # Statistical-cost mode (TOPO, DEFO, SMOOTH, or NOSTATCOSTS) # STATCOSTMODE TOPO # Initialize-only mode (TRUE or FALSE) # INITONLY FALSE # Unwrapped-input mode (TRUE or FALSE) # UNWRAPPED_IN FALSE # Debug mode, dumps all intermediate arrays (TRUE or FALSE) # DEBUG FALSE # Algorithm used for initialization of wrapped phase values. Possible # values are MST and MCF. # INITMETHOD MST # Verbose-output mode (TRUE or FALSE) # VERBOSE FALSE ################ # File formats # ################ # Valid data formats: # # COMPLEX_DATA: complex values: real, imag, real, imag # ALT_LINE_DATA: real values from different arrays, alternating by line # ALT_SAMPLE_DATA: real values from different arrays, alternating by sample # FLOAT_DATA: single array of floating-point data # # The ALT_SAMPLE_DATA format is sometimes known as .amp or sample- # interleaved format; the ALT_LINE_DATA format is sometimes known as # .hgt or line-interleaved format. For the ALT_LINE_DATA format, the # first array is always assumed to be the interferogram magnitude. All # formats assume single-precision (32-bit) floating-point data (real*4 # and complex*8 in Fortran) in the native byte order (big vs. little # endian) of the system. # Input file format # Allowable formats: # If the data are not complex, the phase should be in radians from 0 to 2pi. # COMPLEX_DATA (default) # ALT_LINE_DATA (magnitude in channel 1, phase in radians in channel 2) # ALT_SAMPLE_DATA (magnitude in channel 1, phase in radians in channel 2) # FLOAT_DATA (phase in radians) # #INFILEFORMAT COMPLEX_DATA # Output file format # Allowable formats: # ALT_LINE_DATA (masked interferogram magnitude in channel 1, # unwrapped phase in radians in channel 2; default) # ALT_SAMPLE_DATA (masked interferogram magnitude in channel 1, # unwrapped phase in radians in channel 2) # FLOAT_DATA (unwrapped phase in radians) # #OUTFILEFORMAT ALT_LINE_DATA # Amplitude or power file format # Units should be consistent with interferogram. Allowable formats: # ALT_LINE_DATA (first image amplitude in channel 1, # second image amplitude in channel 2) # ALT_SAMPLE_DATA (first image amplitude in channel 1, # second image amplitude in channel 2; default) # FLOAT_DATA (square root of average power of two images) # #AMPFILEFORMAT ALT_SAMPLE_DATA # Magnitude file format # Allowable formats: # ALT_LINE_DATA (interferogram magnitude in channel 1, # channel 2 ignored) # ALT_SAMPLE_DATA (interferogram magnitude in channel 1, # channel 2 ignored) # FLOAT_DATA (interferogram magnitude; default) # #MAGFILEFORMAT FLOAT_DATA # Correlation file format # Allowable formats: # ALT_LINE_DATA (channel 1 ignored; correlation values # between 0 and 1 in channel 2; default) # ALT_SAMPLE_DATA (channel 1 ignored; correlation values # between 0 and 1 in channel 2) # FLOAT_DATA (correlation values between 0 and 1) # #CORRFILEFORMAT ALT_LINE_DATA # Unwrapped estimate file format # Allowable formats: # ALT_LINE_DATA (interferogram magnitude in channel 1, # unwrapped phase in radians in channel 2; default) # ALT_SAMPLE_DATA (interferogram magnitude in channel 1, # unwrapped phase in radians in channel 2) # FLOAT_DATA (unwrapped phase in radians) # #ESTFILEFORMAT ALT_LINE_DATA # Unwrapped input file format # Allowable formats: # ALT_LINE_DATA (interferogram magnitude in channel 1, # unwrapped phase in radians in channel 2; default) # ALT_SAMPLE_DATA (interferogram magnitude in channel 1, # unwrapped phase in radians in channel 2) # FLOAT_DATA (unwrapped phase in radians) # #UNWRAPPEDINFILEFORMAT ALT_LINE_DATA ############################### # SAR and geometry parameters # ############################### # Orbital radius (double, meters) or altitude (double, meters). The # radius should be the local radius if the orbit is not circular. The # altitude is just defined as the orbit radius minus the earth radius. # Only one of these two parameters should be given. ORBITRADIUS 7153000.0 #ALTITUDE 775000.0 # Local earth radius (double, meters). A spherical-earth model is # used. EARTHRADIUS 6378000.0 # The baseline parameters are not used in deformation mode, but they # are very important in topography mode. The parameter BASELINE # (double, meters) is the physical distance (always positive) between # the antenna phase centers. The along-track componenet of the # baseline is assumed to be zero. The parameter BASELINEANGLE_DEG # (double, degrees) is the angle between the antenna phase centers # with respect to the local horizontal. Suppose the interferogram is # s1*conj(s2). The baseline angle is defined as the angle of antenna2 # above the horizontal line extending from antenna1 towards the side # of the SAR look direction. Thus, if the baseline angle minus the # look angle is less than -pi/2 or greater than pi/2, the topographic # height increases with increasing elevation. The units of # BASELINEANGLE_RAD are radians. BASELINE 150.0 BASELINEANGLE_DEG 225.0 #BASELINEANGLE_RAD 3.92699 # If the BPERP parameter is given, the baseline angle is taken to be # equal to the look angle (mod pi) at midswath, and the length of the # baseline is set accordingly. Particular attention must be paid to # the sign of this parameter--it should be negative if increasing # phase implies increasing topographic height. #BPERP -150.0 # The transmit mode should be either REPEATPASS or PINGPONG if both # antennas transmitted and both received (REPEATPASS and PINGPONG have # the same effect); the transmit mode should be SINGLEANTENNATRANSMIT # if only one antenna was used to transmit while both antennas # received. In single-antenna-transmit mode, the baseline is # effectively halved. This parameter is ignored for cost modes other # than topography. TRANSMITMODE REPEATPASS # Slant range from platform to first range bin in input data file # (double, meters). Be sure to modify this parameter if the input # file is extracted from a larger scene. The parameter does not need # to be modified is snaphu is unwrapping only a subset of the input file. NEARRANGE 831000.0 # Slant range and azimuth pixel spacings of input interferogram after # any multilook averaging. This is not the same as the resolution. # (double, meters). DR 8.0 DA 20.0 # Single-look slant range and azimuth resolutions. This is not the # same as the pixel spacing. (double, meters). RANGERES 10.0 AZRES 6.0 # Wavelength (double, meters). LAMBDA 0.0565647 # Number of real (not necessarily independent) looks taken in range and # azimuth to form the input interferogram (long). NLOOKSRANGE 1 NLOOKSAZ 5 # Number of looks (assumed independent) from nonspatial averaging (long). NLOOKSOTHER 1 # Equivalent number of independent looks (double, dimensionless) that were # used to generate correlation file if one is specified. This parameter # is ignored if the correlation data are generated by the interferogram # and amplitude data. # # The equivalent number of independent looks is approximately equal to the # real number of looks divided by the product of range and azimuth # resolutions, and multiplied by the product of the single-look range and # azimuth pixel spacings. It is about 0.53 times the number of real looks # for ERS data processed without windowing. NCORRLOOKS 23.8 # Number of looks that should be taken in range and azimuth for estimating # the correlation coefficient from the interferogram and the amplitude # data. These numbers must be larger than NLOOKSRANGE and NLOOKSAZ. # The actual numbers used may be different since we prefer odd integer # multiples of NLOOKSRANGE and NLOOKSAZ (long). These numbers are ignored # if a separate correlation file is given as input. NCORRLOOKSRANGE 3 NCORRLOOKSAZ 15 ############################### # Scattering model parameters # ############################### # The scattering model: brightness proportional to # # sigma0 = C * (kds*cos(thetai) + (cos(2thetai))^n) * cos(thetai) # # kds (input parameter KDS) is the ratio of diffuse to specular # scattering. n (input parameter SPECULAREXP) is the power to which # speclar cosine term is rasied. Larger n implies a sharper peak for # specular scatter (both doubles, dimensionless). KDS 0.02 SPECULAREXP 8.0 # Multiplicative factor applied to diffuse scatter term in evaluating # crossover point between diffuse and specular scatter in terms of # range slope (double, dimensionless). DZRCRITFACTOR 2.0 # Allow shadow discontinuities (TRUE,FALSE)? (not yet enabled) SHADOW FALSE # Minimum slope expected in the absence of layover (double, # meters per slant-range pixel). DZEIMIN -4.0 # Number of pixels towards in increasing range that should be included in # layover height estimation (long, dimensionless). LAYWIDTH 16 # Threshold brightness (normalized) for layover height integration # (double, dimensionless) LAYMINEI 1.25 # Multiplicative factor applied to kds (see scattering model) in order # to get ratio of slopes for linearized scattering model. The term improves # agreement of the piecewise-linear model with the cosine model near the # transition point (dzrcrit) at the expense of poorer agreement at very # large slopes (double, dimensionless). SLOPERATIOFACTOR 1.18 # Variance (sigma squared) of range slopes due to uncertainties in slope # estimation from brightness (double, (meters/pixel)^2) SIGSQEI 100.0 ################################## # Decorrelation model parameters # ################################## # Here, rho is the magnitude of the complex correlation coefficient # between the two observations forming the interferogram (0<=rho<=1) # See Zebker & Villasenor, 1992 # Step size for calculating lookup table of maximum layover slope based # on measured correlation (double, dimensionless). DRHO 0.005 # Constants (double) for modeling biased measured correlation expected for # zero statistical correlation: # # rho0 ~= rhosconst1/ncorrlooks + rhosconst2 # # Approximately matches curves of Touzi, Lopes, Bruniquel, & Vachon 1999 # (double). RHOSCONST1 1.3 RHOSCONST2 0.14 # Constants (double) for modeling phase standard deviation as a function # of rho: # # sigma ~= rho ^ ( cstd1 + cstd2*log(nlooks) + cstd3*nlooks ) # # Approximately matches curves of Lee, Hoppel, Mango, & Miller, 1994. CSTD1 0.4 CSTD2 0.35 CSTD3 0.06 # Default value to use uniformly for true, unbiased correlation if no # correlation file is specified and correlation cannot be generated # from the available data (double). DEFAULTCORR 0.01 # Factor applied to expected minimum measured (biased) correlation. # Values smaller than the threshold rhominfactor*rho0 are assumed to # come from zero statistical correlation because of estimator bias (double). # This is used only in topo mode; for defo mode, use DEFOTHRESHFACTOR. RHOMINFACTOR 1.3 ######################## # PDF model parameters # ######################## # Algorithm costs are based on the negative log pdf: # # cost = -log(f(phi | EI, rho)) # Layover peak location (meters/pixel) DZLAYPEAK -2.0 # Factor applied to range layover probability density to get azimuth # layover probability density (double). AZDZFACTOR 0.99 # Factor applied to slope expected from brightness without layover (double). # Can account for underestimation of brightness from averaging with # neighboring dark pixels when despeckling. DZEIFACTOR 4.0 # Weight applied to slope expected from brightness without layover (double). # Must be between zero and one. Can reduce influence of intensity on # nonlayover slope. This is useful if there are lots of nontopographic # variations in brightness (ie, changes in surface relfectivity). DZEIWEIGHT 0.5 # Factor applied to slope expected from brightness with layover (double). # Can account for underestimation of brightness from averaging with # neighboring dark pixels when despeckling. DZLAYFACTOR 1.0 # Ratio of layover probability density to peak probability density # for non-layover slopes expected (double). LAYCONST 0.9 # Factor applied to slope varinace for nonlayover to get falloff of # probability density after the upper layover slope limit has been # exceeded (double). LAYFALLOFFCONST 2.0 # Minimum value of variance when cast to short integer data type (long). # Must be greater than 0 to avoid divide-by-zero. SIGSQSHORTMIN 1 # Fraction of (ambiguity height)^2 to use for slope variance in the # presence of layover. Should usually be less than (1/2)^2 = 0.25. SIGSQLAYFACTOR 0.1 ############################### # Deformation mode parameters # ############################### # Factor applied to range discontinuity probability density to get # corresponding value for azimuth (double). DEFOAZDZFACTOR 1.0 # Factor applied to rho0 to get threshold for whether or not phase # discontinuity is possible (double). rho0 is the expected, biased # correlation measure if true correlation is 0. DEFOTHRESHFACTOR 1.2 # Maximum phase discontinuity likely (double). Units are radians or cycles. # If abrupt phase discontinuities are not expected, this paramter can be # set to zero. DEFOMAX_CYCLE 1.2 #DEFOMAX_RAD 7.5398 # Phase variance (cycles^2) reflecting uncertainty in measurement of # actual statistical correlation (double). SIGSQCORR 0.05 # Ratio of phase discontinuity probability density to peak probability # density expected for discontinuity-possible pixel differences (double). # Value of 1 means zero cost for discontinuity, 0 means infinite cost. DEFOCONST 0.9 ######################## # Algorithm parameters # ######################## # Maximum flow (long) to allow in initialization. If this is zero, # then the maximum is calculated automatically from the statistical # cost functions. To disable, set it to a large value like 9999, but # do not overflow the long integer data type. INITMAXFLOW 9999 # Constant (long) to add to maximum flow expected from statistical # cost functions for automatically determining initial maximum # flow (see above). ARCMAXFLOWCONST 3 # Maximum flow increment (long) for solver. Not the same as maximum # flow possible. MAXFLOW 4 # Number of pixels in row and column dimensions to use in sliding average # window used for normalizing intensity values (long). KROWEI 65 KCOLEI 257 # Number of pixels to use in sliding window average used for averaging # wrapped gradients to get mean non-layover slope, in directions parallel # and perpendicular to the examined phase difference (long). KPARDPSI 7 KPERPDPSI 7 # Threshold precision for iterative numerical calculations (double). THRESHOLD 0.001 # Initial value of range slope for dzrcrit numerical solution (double, # meters/pixel) INITDZR 2048.0 # Initial range slope stepsize in dzrhomax numerical solution (double, # meters/pixel) INITDZSTEP 100.0 # Maximum cost allowd for scalar MST costs and for estimating number of # buckets needed for solver routine (double). MAXCOST 1000.0 # Scaling constant factor applied to double precision costs to get # integer costs (double). COSTSCALE 100.0 # Ambiguity height for autoscaling COSTSCALE to equal 100 (double, # meters). COSTSCALE is automatically adjusted to be inversely # proportional to the midswath ambigutiy height in topography mode. COSTSCALEAMBIGHT 80.0 # Step size (double, radians) for dzrhomax lookup table. The index is # on the local flat-earth incidence angle; this is the sample spacing # in the table. DNOMINCANGLE 0.01 # Integer spacing that represents one unit of flow or one cycle of phase # when storing costs as short integer types (long). NSHORTCYCLE 200 # Fraction of total number of nodes to add in each tree expansion # phase of solver algorithm (double). MAXNEWNODECONST 0.0008 # Number of cycles to allow for a call to solver with a specific flow # increment delta and still consider that increment done. Ideally # it would be zero, but scaling for different deltas may leave some # negative cycles that won't affect solution much. Comment this out # to automatically determine the number based on the size of the # interferogram. #MAXNFLOWCYCLES 10 # Fraction of the number of pixels to use as the maximum number of # cycles allowed for a specific flow increment if MAXNFLOWCYCLES # is not given. MAXCYCLEFRACTION 0.00001 # Gives the minimum number of connected nodes to consider for # unwrapping. If masking separates the input data into disconnected # sets of pixels, a source is selected for each connected set, # provided that the number of nodes in the set is greater than # NCONNNODEMIN. If NCONNNODEMIN is zero, all possible unmasked pixels # will be uwnrapped. NCONNNODEMIN should be nonnegative. NCONNNODEMIN 0 # Scale factor (long) for cs2 MCF initializations. A larger number # gives greater speed, but uses more memory. CS2SCALEFACTOR 8 # Number of major iterations between tree pruning operations. A # smaller number causes pruning operations to occur more frequently. # This is experimental. NMAJORPRUNE 2000000000 # Cost threshold for pruning tree. A lower threshold prunes more # aggressively. This is experimental. PRUNECOSTTHRESH 2000000000 # If this parameters is set, the cost functions are approximated by # L^p cost functions with parameter p. That is, the cost functions # are parameterized as (flow)^(PLPN), where p can be any nonnegative # decimal. Statistical costs are generated in order to weight the Lp # cost functions by default. # PLPN 1 # If this parameter is set to TRUE, bidirectional Lp costs are assumed # if PLPN is set. This implies that the scalar weight of an Lp arc # may be different depending on the direction of net flow on the arc. # If this parameter is FALSE, the weight is the same regardless of the # arc direction. # BIDIRLPN TRUE ############################################## # File names for dumping intermediate arrays # ############################################## # If the following file names are given, the corresponding intermediate # array will be dumped to that file. Otherwise, the array is not dumped. # These filenames override the default file names assigned when # DEBUG is TRUE. # Unwrapped initialization # INITFILE snaphu.init # Flow corresponding to unwrapped solution # FLOWFILE snaphu.flow # Normalized, despeckled SAR image intensity # EIFILE snaphu.ei # Statistical costs for azimuth # ROWCOSTFILE snaphu.rowcost # Statistical costs for range # COLCOSTFILE snaphu.colcost # Scalar initialization costs for azimuth # MSTROWCOSTFILE snaphu.mstrowcost # Scalar initialization costs for range # MSTCOLCOSTFILE snaphu.mstcolcost # Scalar initialization costs for both azimuth and range, concatenated # MSTCOSTSFILE snaphu.mstcosts # Correlation coefficient magnitude (before clipping into [0,1] interval) # RAWCORRDUMPFILE snaphu.rawcorr # Correlation coefficient magnitude (after clipping into [0,1] interval) # CORRDUMPFILE snaphu.corr ########################### # Edge masking parameters # ########################### # These parameters (long, dimensionless) are used to mask out pixels # near the edges of the input array. EDGEMASKTOP, EDGEMASKBOT, # EDGEMASKLEFT, and EDGEMASKRIGHT specify the numbers of pixels from the # top, bottom, left, and right edges respectively that should be # masked out. Masking is only applied during the nonlinear solver # stage (not the initialization). # EDGEMASKTOP 0 # EDGEMASKBOT 0 # EDGEMASKLEFT 0 # EDGEMASKRIGHT 0 ############################### # Piece extraction parameters # ############################### # These parameters (long, dimensionless) allow only a subset of the # input data files to be read and unwrapped. The upper left corner of # the subset is at row PIECEFIRSTROW and column PIECEFIRSTCOL, with # both indexed from 1 (that is, the upper left corner is pixel 1,1). # The output will be PIECENROW rows x PIECENCOL columns in size. # These parameters cannot be used in tile mode. If PIECENROW or # PIECENCOL is zero, the full depth or width of the input is # unwrapped. # PIECEFIRSTROW 1 # PIECEFIRSTCOL 1 # PIECENROW 0 # PIECENCOL 0 ################ # Tile control # ################ # Parameters in this section describe how the input files will be # tiled. This is mainly used for tiling, in which different # patches of the interferogram are unwrapped separately. # Number of rows and columns of tiles into which the data files are # to be broken up. # NTILEROW 1 # NTILECOL 1 # Overlap, in pixels, between neighboring tiles. # ROWOVRLP 0 # COLOVRLP 0 # Maximum number of child processes to start for parallel tile # unwrapping. # NPROC 1 # Cost threshold to use for determining boundaries of reliable regions # (long, dimensionless; scaled according to other cost constants). # Larger cost threshold implies smaller regions---safer, but # more expensive computationally. # TILECOSTTHRESH 500 # Minimum size (long, pixels) of a reliable region in tile mode. # MINREGIONSIZE 100 # Extra weight applied to secondary arcs on tile edges. # TILEEDGEWEIGHT 2.5 # Maximum flow magnitude (long) whose cost will be stored in the secondary # cost lookup table. Secondary costs larger than this will be approximated # by a quadratic function. # SCNDRYARCFLOWMAX 8 # The program will remove temporary tile files if this is set. # RMTMPTILE FALSE # This is the name (string) of a file of signed character data types # which serve as a mask for which tiles will be unwrapped. The file # should be a raster array with NTILEROW rows and NTILECOL columns. # Where the array element is nonzero, the corresponding tile will be # unwrapped; where the array element is zero, the tile will not be # unwrapped and no output for that tile will be written. This option # is used for reprocessing only certain tiles of a run. # DOTILEMASKFILE snaphu.dotilemaskfile.in # This is the name of the tile directory. Tiles will be stored # temporarily in the tile directory. If in assemble only mode, # unwrapped tiles are assumed to reside in this directory. The # directory is create if it does not exist. # TILEDIR snaphu_tiledir # If this is set to TRUE, the program will skip the unwrapping step # and only assemble temporary tile files from a previous invocation # saved in the directory whose name is given by the TILEDIR keyword. # The tile size parameters and file names must be the same. # ASSEMBLEONLY FALSE # Repotimize as single tile after using tile mode for intialization if # this is set to TRUE. This is equivalent to unwrapping with multiple # tiles, then using the unwrapped output as the input to a new, single-tile run # of snaphu with the -u option. The purpose is for speed. #SINGLETILEREOPTIMIZE FALSE ############################### # Connected component control # ############################### # Grow connected components mask and write to the output file whose # name is specified here as a string. The mask is a file of unsigned # integer values with the same number of rows and columns as the # unwrapped interferogram. The type of integer (1 byte vs. 4 byte) is # specified by the CONNCOMPOUTTYPE keyword, with 1-byte integers being # the default. # CONNCOMPFILE snaphu.conncomp # Type of integer that the connected-component output, if requested, # will be written as (see the CONNCOMPFILE keyword). The value here # may be either UCHAR or UINT, which specify unsigned character # (1-byte integer) or unsigned integer (4-byte integer) values, # respectively. # CONNCOMPOUTTYPE UCHAR # Grow connected components mask from unwrapped input then exit if TRUE. # Output is written to the file specified by CONNCOMPFILE. # REGROWCONNCOMPS FALSE # Minimum size of a single connected component, as a fraction (double) # of the total number of pixels in tile. # MINCONNCOMPFRAC 0.01 # Cost threshold for connected components (long). Higher threshold will # give smaller connected components. # CONNCOMPTHRESH 300 # Maximum number of connected components per tile (long). # MAXNCOMPS 32 # Type to use for connected component output file. The value should # either be UCHAR for unsigned character (8 bit) or UINT for unsigned # integer (32 bit for common systems). # CONNCOMPOUTTYPE UCHAR # End of snaphu configuration file snaphu-v2.0.6/man/PaxHeader/snaphu_man1.txt000644 777777 777777 00000000043 14423062415 020424 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/man/snaphu_man1.txt000644 Ho)00000077407 14423062415 017675 0ustar00curtis000000 000000 snaphu(1) General Commands Manual snaphu(1) NAME snaphu - phase unwrapping algorithm for SAR interferometry SYNOPSIS snaphu [options] [infile] [linelength] [options] DESCRIPTION snaphu is a statistical-cost network-flow algorithm for phase unwrapping. Given an input interferogram and other observable data, snaphu attempts to compute congruent phase-unwrapped solutions that are maximally probable in an approximate a posteriori sense. The algorithm's solver routine is based on network optimization. By default, snaphu assumes that its input is a synthetic aperture radar (SAR) interferogram measuring surface topography. Deformation measurements are assumed if the -d option is given. Smooth, generic data are assumed if the -s option is given. This man page documents only the syntax and usage of snaphu. Its theoretical foundations are discussed in the references cited below. The most common input parameters may be given on the command line, while many other twiddle parameters are handled via the -f option and configuration files. At the very least, the name of a wrapped-phase input file and its line length must be specified. For topography interferograms, range should increase towards the right in the interferogram, and the flat-earth phase ramp should be removed from the input interferogram before snaphu is run. For deformation interferograms, phase variations due to topography should be removed as well. Except for the input file name and the line length, all input parameters take default values if not specified. However, these parameters should be customized whenever possible since the accuracy of the solution depends on how well the statistics of the estimation problem are modeled. To avoid poor-quality solutions, users are strongly encouraged to provide their best estimates of the relevant problem parameters. Parameters are set in the order in which they are given on the command line, so multiple configuration files or options may be given, with later values overriding earlier ones. Allowable file formats are detailed below. The default format for the input file is COMPLEX_DATA, but any of the described formats may be used. If either of the ALT_LINE_DATA or ALT_SAMPLE_DATA formats are used, the magnitude and phase (in radians from 0 to 2pi) of the interferogram should be in the first and second channels of the file, respectively. If the FLOAT_DATA format is used, the input file should contain only the phase of the interferogram (in radians from 0 to 2pi); the magnitude may be passed with the -m option. OPTIONS -a ampfile Read brightness data from the file ampfile. The file should contain the amplitudes (not powers) of the two individual SAR images forming the interferogram if the formats ALT_SAMPLE_DATA (default) or ALT_LINE_DATA are used. It should contain an average of those two images if the FLOAT_DATA format is used. If (1) the amplitudes of both images are available, (2) the interferogram magnitude is also available, and (3) the -c option is not used, then a coherence estimate is automatically formed from the available data. The number of looks used for this estimate can be set in a configuration file. If no amplitude or power data are specified, then the magnitude of the input interferogram is used as the average amplitude, and no coherence estimate is formed. Note that the magnitude of the interferogram is not equal to the average amplitude of the SAR images. The amplitude data should be in the same system of units used for the input interferogram, and also coregistered to it. -A pwrfile Similar to the -a option, except the data in the specified file is assumed to represent the powers of the two individual SAR images. -b Bperp For topography mode, use Bperp (decimal value, in meters) as the value of the perpendicular component of the interferometric baseline. The sign is defined such that Bperp is negative if the unwrapped phase increases with the elevation. By default, repeat-pass or ping-pong mode is assumed; for single-antenna- transmit data, the value of Bperp should be halved, or the transmit mode should be set accordingly in a configuration file (see the -f option). The baseline value is only used in topography mode. -c corrfile Read correlation data from the file corrfile. The correlation data should be the same size as, and registered to, the input interferogram. Consequently, a raw correlation estimate may need to be upsampled if it incorporates more looks than the interferogram. If the -c option is not given, a coherence estimate is formed from the available data if possible. Otherwise, a uniform default coherence is assumed for the entire interferogram. If the ALT_LINE_DATA (default) or ALT_SAMPLE_DATA formats are used, the correlation data should be in the second data channel of the file; the first channel is ignored. The FLOAT_DATA format may also be used. The correlation values should be between zero and one, inclusive. -C configstr Parse the string configstr as if it were a line from a configuration file containing a keyword-value pair (see the -f option). Configuration lines generally have whitespace between the keyword and the value, so configstr will usually need to be surrounded by quotation marks on a command line so that the shell does not split it into separate arguments (snaphu itself does not require or allow quotation marks, however). The syntax for how quotation marks are handled is defined by the shell. Multiple instances of the -C option may be used in order to specify multiple configuration inputs. Later instances of the -C option take precedence over both earlier instances of the -C option and the configurations specified by earlier instances of the -f option. -d Run in deformation mode. The problem statistics and resulting cost functions are based on the assumption that the true unwrapped phase represents surface displacement rather than elevation. -e estimatefile Flatten using the unwrapped phase estimate in the file estimatefile. The estimate is subtracted from the input interferogram before unwrapping, and is inserted back into the solution just before the output is written. The estimate also affects the cost functions used, since subtracting a constant from a random variable shifts the probability density function of the random variable. If the formats ALT_LINE_DATA (default) or ALT_SAMPLE_DATA are used, the unwrapped estimate (in radians) should be in the second data channel of the file; the first channel is ignored. The FLOAT_DATA format may also be used. -f configfile Read configuration parameters from file configfile. The file is parsed line by line for key-value pairs. Template configuration files are included with the snaphu source code: snaphu.conf.full contains all valid key-value pairs; snaphu.conf.brief contains the most important parameters. Lines not beginning with alphanumeric characters are treated as comment lines. Command line options specified after -f will override parameters specified in the configfile and vice versa. The -f option may be given multiple times with different configuration files, with parameters in later-specified files overriding those in earlier ones. -g maskfile Grow a connected component mask for the unwrapped solution and write the mask to the file maskfile. A connected component is a region of pixels in the solution that is believed to have been unwrapped in a relative, internally self-consistent manner according to the statistical costs used. Regions that are smaller than a preselected threshold are masked out. Parameters for this option can be set in the configuration file. The connected component file is composed of unsigned characters by default, with all pixels of the same value belonging to the same connected component and zero corresponding to masked pixels. -G maskfile Grow a connected component mask (see the -g option) for the input data array, assuming that it is already unwrapped, and write the mask to the file maskfile. Statistical cost functions are computed for forming the mask, but a new unwrapped solution is not computed. -h, --help Print a help message summarizing command-line options and exit. -i Run in initialize-only mode. Normally, snaphu uses either an approximate minimum spanning tree (MST) algorithm or a minimum cost flow (MCF) algorithm for generating the initialization to its iterative, modified network-simplex solver. If -i is given, the initialization is written to the output and the program exits without running the iterative solver. -k Keep temporary tile outputs. If this option is specified when snaphu runs in tile mode, the temporary directory where tile outputs are stored will be left in place rather than deleted. The tile-mode initialization of the -S option will also be left in place rather than deleted. -l logfile Log all runtime parameters and some other environment information into the specified file. The log file is a text file in the same format as a configuration file. -m magfile Read interferogram magnitude data from the specified file. This option is useful mainly if the wrapped-phase input file is given as a set of real phase values rather than complex interferogram values. The interferogram magnitude is used to form a coherence estimate if appropriate amplitude data are given as well. The default file format is FLOAT_DATA. If the formats ALT_LINE_DATA or ALT_SAMPLE_DATA are used, the magnitude should be in the first data channel of the file; the second channel is ignored. If the COMPLEX_DATA format is used, the phase information is ignored. Areas where the magnitude is zero are treated as masked areas (see the -M option). -M bytemaskfile Read a byte mask from the specified file. The mask file should be the same size as the input array to be unwrapped. The mask should have the binary (not ASCII) value 0 where pixels of the input array are to be ignored during the primary optimization stage of the program. Values elsewhere should be binary 1. Masking is not applied until after the initialization stage of snaphu. Masked areas are treated as areas in which the solution phase value is irrelevant to the solution cost. The magnitude of the interferogram is set to zero in masked areas in the output file. Areas with zero magnitude in the input data are treated as masked areas as well. Areas near the edges of the input may also be masked via options in a configuration file. -n Run in no-statistical-costs mode. If the -i or -p options are given, snaphu will not use statistical costs. Information from a weight file (-w option) will still be used if given. -o outfile Write the unwrapped output to a file called outfile. If the file formats ALT_LINE_DATA (default) or ALT_SAMPLE_DATA are used, the unwrapped phase is written into the second data channel, while the interferogram magnitude is written into the first channel. The format FLOAT_DATA may also be used. -p value Run in Lp-norm mode with p=value, where value is a nonnegative decimal. Instead of statistical cost functions, the program uses Lp cost functions with statistically based weights (unless -n is also given). Solutions are still always congruent. Moreover, congruence is enforced within the solver routine, not as a post-optimization processing step. Therefore, if p=2, for example, least-squares cost functions are used, but the solution will probably be more accurate than one generated from a transform-based least-squares algorithm. -q Run in quantify-only mode. The input data are assumed to be unwrapped already, and the total cost of this solution is calculated and printed. The unwrapped phase is wrapped assuming congruence for the cost calculation. Round-off errors may limit the precision of the quantified cost. See the -u option for allowable file formats. -s Run in smooth-solution mode. The problem statistics and resulting cost functions are based on the assumption that the true unwrapped phase represents a generic surface with no discontinuities. This is the same as deformation mode with the DEFOMAX parameter set to zero. -S Do single-tile re-optimization after tile-mode initialization. If this option is specified, snaphu will run in tile mode to generate an unwrapped solution, which is then used as the initialization to a single-tile optimization that produces the final unwrapped output. The tile-mode initialization may itself be initialized by the MST or MCF algorithms (or an input unwrapped phase file) as normal. This option is equivalent to running an instance of snaphu in tile mode, then running another instance of snaphu taking the tile-mode output as an unwrapped input via the -u option. Tile parameters must be specified when using this option. This approach is often faster than unwrapping an interferogram as a single tile from an MST initialization, especially if multiple processors are used. -t Run in topography mode. The problem statistics and resulting cost functions are based on the assumption that the true unwrapped phase represents surface elevation. This is the default. -u Assume that the input file is unwrapped rather than wrapped. The algorithm makes iterative improvements to this solution instead of using an initialization routine. The input file may be in the formats ALT_LINE_DATA (default) or ALT_SAMPLE_DATA; the interferogram magnitude should be in the first data channel and the unwrapped phase should be in the second data channel. The format FLOAT_DATA may also be used. -v Run in verbose mode. Extra information on the algorithm's progress is printed to the standard output. -w weightfile Read external, scalar weights from file weightfile. The weights, which should be positive short integers, are applied to whichever cost functions are used. There is one weight value for each arc in the network, so weightfile should be the concatenation of raster horizontal-flow and vertical-flow arc weights. Thus, for an N row by M column interferogram, weightfile would consist of a rasterized (N-1) by M array followed by a rasterized N by (M-1) array of short integer data. This option is not well tested. --aa ampfile1 ampfile2 Amplitude data are read from the files specified. The data from the two individual SAR images forming the interferogram are assumed to be separately stored in files ampfile1 and ampfile2. These files should be in the format FLOAT_DATA. This option is similar to the -a option. --AA pwrfile1 pwrfile2 Similar to the --aa option, but power data are read from the specified files. --assemble Assemble the tile-mode temporary files from a previous tile-mode run of snaphu, possibly with different secondary optimization parameters, to produce a new unwrapped solution. The tile directory name must be specified with the --tiledir option. Most configuration options (from the command line and any configuration files) must be specified similar to the previous run, including the output file name from which the names of temporary tile files are derived. The previous output file may hence be overwritten by the new output file. This option is useful if the user wishes to modify tile-assembly parameters without unwrapping the individual tiles over again. --copyright, --info Print the software copyright notice and bug report info, then exit. --costinfile costfile Read statistical cost arrays from file costfile. This file should be in the format written by the --costoutfile option. The cost file does not control whether snaphu runs in topography, deformation, or smooth-solution mode; the latter two must be specified explicitly even if costfile was generated while running in those modes. --costoutfile costfile Write statistical cost arrays to file costfile. This option can be used with the --costinfile option to save the time of generating statistical costs if the same costs are used multiple times. --debug, --dumpall Dump all sorts of intermediate arrays to files. --mst Use a minimum spanning tree (MST) algorithm for the initialization. This is the default. --mcf Use a minimum cost flow (MCF) algorithm for the initialization. The cs2 solver by Goldberg and Cherkassky is used. The modified network-simplex solver in L1 mode may give different results than the cs2 solver, though in principle both should be L1 optimal. --nproc n Use n parallel processes when in tile mode. The program forks a new process for each tile so that tiles can be unwrapped in parallel; at most n processes will run concurrently. Forking is done before data are read. The standard output streams of child processes are directed to log files in the temporary tile directory. --piece firstrow firstcol nrow ncol Read and unwrap only a subset or part of the input interferogram. The read piece is the nrow by ncol rectangle whose upper left corner is the pixel at row firstrow and column firstcol (indexed from 1). All input files (such as amplitude, coherence, etc.) are assumed to be the same size as the input phase file. All output files are nrow by ncol. --tile ntilerow ntilecol rowovrlp colovrlp Unwrap the interferogram in tile mode. The interferogram is partitioned into ntilerow by ntilecol tiles, each of which is unwrapped independently. Tiles overlap by rowovrlp and colovrlp pixels in the row and column directions. The tiles are then segmented into reliable regions based on the cost functions, and the regions are reassembled. The program creates a subdirectory for temporary files in the directory of the eventual output file (see the --tiledir and -k options). Tiles can be unwrapped in parallel (see the --nproc option). --tiledir dirname Use dirname as the name of the directory in which temporary tile-model outputs are written and/or read. The directory is created if it does not exist, and it is removed at the end of the run unless the -k or --assemble options are specified. FILE FORMATS The formats of input files may be specified in a configuration file. All of these formats are composed of raster, single-precision (float, real*4, or complex*8) floating-point data types in the platform's native byte order. Data are read line by line in row-major order (across then down, with the column index varying faster than the row index). Regardless of the file format, all input data arrays should have the same number of samples in width and depth and should be coregistered to one another. Note that weight files and cost files have their own formats. The allowable formats for other data files are described below. COMPLEX_DATA Alternating floats correspond to the real (in-phase) and imaginary (quadrature) components of complex data samples. The specified line length should be the number of complex samples (pairs of real and imaginary samples) per line. ALT_LINE_DATA Alternating lines (rows) of data correspond to lines of purely real data from two separate arrays. The first array is often the magnitude of the interferogram, and the second may be unwrapped phase, coherence, etc. This is also sometimes called hgt, rmg, or line-interleaved format. ALT_SAMPLE_DATA Alternating samples correspond to purely real samples from two separate arrays. This format is sometimes used for the amplitudes of the two SAR images. FLOAT_DATA The file contains data for only one channel or array, and the data are purely real. EXAMPLES Unwrap a wrapped topographic interferogram called ``wrappedfile'' whose line length is 1024 complex samples (output will be written to a file whose name is compiled into the program): snaphu wrappedfile 1024 Unwrap the same file as above, but use brightness information from the file ``ampfile,'' set the perpendicular baseline to -165 m at midswath, and place the output in a file called ``unwrappedfile'' (coherence data are generated automatically if ``wrappedfile'' contains complex data and ``ampfile'' contains amplitude data from both SAR images): snaphu wrappedfile 1024 -a ampfile \ -b -165 -o unwrappedfile Unwrap the interferogram as above, but read correlation information from the file ``corrfile'' instead of generating it from the interferogram and amplitude data: snaphu wrappedfile 1024 -a ampfile -c corrfile \ -b -165 -o unwrappedfile The following is equivalent to the previous example, but input parameters are read from a configuration file, and verbose output is displayed: cat > configfile # This is a comment line which will be ignored AMPFILE ampfile CORRFILE corrfile BPERP -165 OUTFILE unwrappedfile EOF (ie, Ctrl-D) snaphu -v -f configfile wrappedfile 1024 Unwrap the same interferogram, but use only the MST initialization (with scalar statistical weights) and write the output to ``mstfile'': snaphu -f configfile -i wrappedfile 1024 -o mstfile Read the unwrapped data in ``mstfile'' and use that as the initialization to the modified network-simplex solver: snaphu -f configfile -u mstfile 1024 -o unwrappedfile Note that in the previous two examples, the output file name in the configuration file is overrided by the one given on the command line. The previous two commands together are in principle equivalent to the preceding one, although round-off errors in flow-to-phase conversions may cause minor differences Unwrap the interferogram as above, but use the MCF algorithm for initialization: snaphu -f configfile wrappedfile 1024 --mcf Unwrap the interferogram once again, but first flatten it with the unwrapped data in ``estfile,'' then reinsert the subtracted phase after unwrapping: snaphu -f configfile wrappedfile 1024 -e estfile The following assumes that the wrapped input interferogram measures deformation, not topography. Unwrap the interferogram with the given correlation data: snaphu -d wrappedfile 1024 -c corrfile Unwrap the input interferogram by minimizing the unweighted congruent L2 norm: snaphu -p 2 -n wrappedfile 1024 Unwrap the interferogram as a three-by-four set of tiles that overlap by 30 pixels, with the specified configuration file, using two processors: snaphu wrappedfile 1024 -f configfile \ --tile 3 4 30 30 --nproc 2 HINTS AND TIPS The program may print a warning message about costs being clipped to avoid overflow. If too many costs are clipped, the value of COSTSCALE may need to be decreased in a configuration file (via the -f option). If the program prints a warning message about an unexpected increase in the total solution cost, this is an indication that too many costs are clipped. It is usually okay if just a few costs are clipped. In topography mode, if the unwrapped result contains too many discontinuities, try increasing the value of LAYMINEI or decreasing the value of LAYCONST. The former determines the normalized intensity threshold for layover, and the latter is the relative layover probability. If there are too many discontinuities running in azimuth, try decreasing the value of AZDZFACTOR, which affects the ratio of azimuth to range costs. If the baseline is not known, take a guess at it and be sure its sign is correct. Specify the SAR imaging geometry parameters as well as possible. The defaults assume ERS data with five looks taken in azimuth. In deformation mode, if the unwrapped result contains too many discontinuities, try increasing the value of DEFOTHRESHFACTOR or decreasing the value of DEFOCONST. If the surface displacement varies slowly and true discontinuities are not expected at all, DEFOMAX_CYCLE can be set to zero. This behavior is also invoked with the -s option. The resulting cost functions will be similar to correlation-weighted L2 cost functions, though the former are not necessarily centered on the wrapped gradients. Congruence is still enforced during rather than after optimization. The program can be run in initialize-only (-i) mode for quick down-and- dirty MST or MCF solutions. SIGNALS Once the iterative solver has started, snaphu traps the interrupt (INT) and hangup (HUP) signals. Upon receiving an interrupt, for example if the user types Ctrl-C, the program finishes a minor iteration, dumps its current solution to the output, and exits. If a second interrupt is given after the first (caught) interrupt, the program exits immediately. If a hangup signal is received, the program dumps its current solution then continues to execute normally. EXIT STATUS Upon successful termination, the program exits with code 0. Errors result in exit code 1. FILES The following files may be useful for reference, but are not required. They are included in the program source distribution and may be installed somewhere on the system. snaphu.conf.full Template configuration file setting all valid input parameters (though some may be commented out). snaphu.conf.brief General-purpose template configuration file setting the most important or commonly modified input parameters. In addition to parameters read from configuration files specified on the command line, default parameters may be read from a system-wide configuration file if such a file is named when the program is compiled. BUGS The -w option has not been tested exhaustively. Extreme shadow discontinuities (i.e., abrupt elevation drops in increasing range due to cliffs facing away from the radar) are not modeled that well in the cost functions for topography mode. Abrupt changes in surface reflectivity, such as those of coastlines between bright land and dark water, might be misinterpreted as layover and assigned inappropriate costs. The algorithm's behavior may be unpredictable if the costs are badly scaled and excessively clipped to fit into their short-integer data types. There is no error checking that ensures that the network node potentials (incost and outcost) do not overflow their integer data types. Automatic flow clipping is built into the MST initialization, but it can give erratic results and may loop infinitely for certain input data sets. It is consequently turned off by default. Dedicated programs for specific Lp objective functions may work better than snaphu in Lp mode. Note that snaphu enforces congruence as part of the problem formulation, however, not as a post-optimization processing step. A tree pruning capability is built into the code and can be enabled from a configuration file, but this functionality is experimental and not well tested. REFERENCES C. W. Chen and H. A. Zebker, ``Two-dimensional phase unwrapping with use of statistical models for cost functions in nonlinear optimization,'' Journal of the Optical Society of America A, 18, 338-351 (2001). C. W. Chen and H. A. Zebker, ``Network approaches to two-dimensional phase unwrapping: intractability and two new algorithms,'' Journal of the Optical Society of America A, 17, 401-414 (2000). C. W. Chen and H. A. Zebker, ``Phase unwrapping for large SAR interferograms: Statistical segmentation and generalized network models,'' IEEE Transactions on Geoscience and Remote Sensing, 40, 1709-1719 (2002). snaphu(1) snaphu-v2.0.6/man/PaxHeader/man1000755 777777 777777 00000000043 14423062415 016233 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/man/man1/000755 Ho)00000000000 14423062415 015537 5ustar00curtis000000 000000 snaphu-v2.0.6/man/PaxHeader/snaphu_man1.html000644 777777 777777 00000000043 14423062415 020551 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/man/snaphu_man1.html000644 Ho)00000110765 14423062415 020015 0ustar00curtis000000 000000 snaphu

snaphu

NAME
SYNOPSIS
DESCRIPTION
OPTIONS
FILE FORMATS
EXAMPLES
HINTS AND TIPS
SIGNALS
EXIT STATUS
FILES
BUGS
REFERENCES

NAME

snaphu − phase unwrapping algorithm for SAR interferometry

SYNOPSIS

snaphu [options] [infile] [linelength] [options]

DESCRIPTION

snaphu is a statistical-cost network-flow algorithm for phase unwrapping. Given an input interferogram and other observable data, snaphu attempts to compute congruent phase-unwrapped solutions that are maximally probable in an approximate a posteriori sense. The algorithm’s solver routine is based on network optimization. By default, snaphu assumes that its input is a synthetic aperture radar (SAR) interferogram measuring surface topography. Deformation measurements are assumed if the −d option is given. Smooth, generic data are assumed if the −s option is given.

This man page documents only the syntax and usage of snaphu. Its theoretical foundations are discussed in the references cited below.

The most common input parameters may be given on the command line, while many other twiddle parameters are handled via the −f option and configuration files. At the very least, the name of a wrapped-phase input file and its line length must be specified. For topography interferograms, range should increase towards the right in the interferogram, and the flat-earth phase ramp should be removed from the input interferogram before snaphu is run. For deformation interferograms, phase variations due to topography should be removed as well.

Except for the input file name and the line length, all input parameters take default values if not specified. However, these parameters should be customized whenever possible since the accuracy of the solution depends on how well the statistics of the estimation problem are modeled. To avoid poor-quality solutions, users are strongly encouraged to provide their best estimates of the relevant problem parameters. Parameters are set in the order in which they are given on the command line, so multiple configuration files or options may be given, with later values overriding earlier ones.

Allowable file formats are detailed below. The default format for the input file is COMPLEX_DATA, but any of the described formats may be used. If either of the ALT_LINE_DATA or ALT_SAMPLE_DATA formats are used, the magnitude and phase (in radians from 0 to 2pi) of the interferogram should be in the first and second channels of the file, respectively. If the FLOAT_DATA format is used, the input file should contain only the phase of the interferogram (in radians from 0 to 2pi); the magnitude may be passed with the −m option.

OPTIONS

−a ampfile

Read brightness data from the file ampfile. The file should contain the amplitudes (not powers) of the two individual SAR images forming the interferogram if the formats ALT_SAMPLE_DATA (default) or ALT_LINE_DATA are used. It should contain an average of those two images if the FLOAT_DATA format is used. If (1) the amplitudes of both images are available, (2) the interferogram magnitude is also available, and (3) the −c option is not used, then a coherence estimate is automatically formed from the available data. The number of looks used for this estimate can be set in a configuration file. If no amplitude or power data are specified, then the magnitude of the input interferogram is used as the average amplitude, and no coherence estimate is formed. Note that the magnitude of the interferogram is not equal to the average amplitude of the SAR images. The amplitude data should be in the same system of units used for the input interferogram, and also coregistered to it.

−A pwrfile

Similar to the −a option, except the data in the specified file is assumed to represent the powers of the two individual SAR images.

−b Bperp

For topography mode, use Bperp (decimal value, in meters) as the value of the perpendicular component of the interferometric baseline. The sign is defined such that Bperp is negative if the unwrapped phase increases with the elevation. By default, repeat-pass or ping-pong mode is assumed; for single-antenna-transmit data, the value of Bperp should be halved, or the transmit mode should be set accordingly in a configuration file (see the −f option). The baseline value is only used in topography mode.

−c corrfile

Read correlation data from the file corrfile. The correlation data should be the same size as, and registered to, the input interferogram. Consequently, a raw correlation estimate may need to be upsampled if it incorporates more looks than the interferogram. If the −c option is not given, a coherence estimate is formed from the available data if possible. Otherwise, a uniform default coherence is assumed for the entire interferogram. If the ALT_LINE_DATA (default) or ALT_SAMPLE_DATA formats are used, the correlation data should be in the second data channel of the file; the first channel is ignored. The FLOAT_DATA format may also be used. The correlation values should be between zero and one, inclusive.

−C configstr

Parse the string configstr as if it were a line from a configuration file containing a keyword-value pair (see the -f option). Configuration lines generally have whitespace between the keyword and the value, so configstr will usually need to be surrounded by quotation marks on a command line so that the shell does not split it into separate arguments (snaphu itself does not require or allow quotation marks, however). The syntax for how quotation marks are handled is defined by the shell. Multiple instances of the -C option may be used in order to specify multiple configuration inputs. Later instances of the -C option take precedence over both earlier instances of the -C option and the configurations specified by earlier instances of the -f option.

−d

Run in deformation mode. The problem statistics and resulting cost functions are based on the assumption that the true unwrapped phase represents surface displacement rather than elevation.

−e estimatefile

Flatten using the unwrapped phase estimate in the file estimatefile. The estimate is subtracted from the input interferogram before unwrapping, and is inserted back into the solution just before the output is written. The estimate also affects the cost functions used, since subtracting a constant from a random variable shifts the probability density function of the random variable. If the formats ALT_LINE_DATA (default) or ALT_SAMPLE_DATA are used, the unwrapped estimate (in radians) should be in the second data channel of the file; the first channel is ignored. The FLOAT_DATA format may also be used.

−f configfile

Read configuration parameters from file configfile. The file is parsed line by line for key-value pairs. Template configuration files are included with the snaphu source code: snaphu.conf.full contains all valid key-value pairs; snaphu.conf.brief contains the most important parameters. Lines not beginning with alphanumeric characters are treated as comment lines. Command line options specified after −f will override parameters specified in the configfile and vice versa. The −f option may be given multiple times with different configuration files, with parameters in later-specified files overriding those in earlier ones.

−g maskfile

Grow a connected component mask for the unwrapped solution and write the mask to the file maskfile. A connected component is a region of pixels in the solution that is believed to have been unwrapped in a relative, internally self-consistent manner according to the statistical costs used. Regions that are smaller than a preselected threshold are masked out. Parameters for this option can be set in the configuration file. The connected component file is composed of unsigned characters by default, with all pixels of the same value belonging to the same connected component and zero corresponding to masked pixels.

−G maskfile

Grow a connected component mask (see the −g option) for the input data array, assuming that it is already unwrapped, and write the mask to the file maskfile. Statistical cost functions are computed for forming the mask, but a new unwrapped solution is not computed.

−h, −−help

Print a help message summarizing command-line options and exit.

−i

Run in initialize-only mode. Normally, snaphu uses either an approximate minimum spanning tree (MST) algorithm or a minimum cost flow (MCF) algorithm for generating the initialization to its iterative, modified network-simplex solver. If −i is given, the initialization is written to the output and the program exits without running the iterative solver.

−k

Keep temporary tile outputs. If this option is specified when snaphu runs in tile mode, the temporary directory where tile outputs are stored will be left in place rather than deleted. The tile-mode initialization of the -S option will also be left in place rather than deleted.

−l logfile

Log all runtime parameters and some other environment information into the specified file. The log file is a text file in the same format as a configuration file.

−m magfile

Read interferogram magnitude data from the specified file. This option is useful mainly if the wrapped-phase input file is given as a set of real phase values rather than complex interferogram values. The interferogram magnitude is used to form a coherence estimate if appropriate amplitude data are given as well. The default file format is FLOAT_DATA. If the formats ALT_LINE_DATA or ALT_SAMPLE_DATA are used, the magnitude should be in the first data channel of the file; the second channel is ignored. If the COMPLEX_DATA format is used, the phase information is ignored. Areas where the magnitude is zero are treated as masked areas (see the −M option).

−M bytemaskfile

Read a byte mask from the specified file. The mask file should be the same size as the input array to be unwrapped. The mask should have the binary (not ASCII) value 0 where pixels of the input array are to be ignored during the primary optimization stage of the program. Values elsewhere should be binary 1. Masking is not applied until after the initialization stage of snaphu. Masked areas are treated as areas in which the solution phase value is irrelevant to the solution cost. The magnitude of the interferogram is set to zero in masked areas in the output file. Areas with zero magnitude in the input data are treated as masked areas as well. Areas near the edges of the input may also be masked via options in a configuration file.

−n

Run in no-statistical-costs mode. If the −i or −p options are given, snaphu will not use statistical costs. Information from a weight file (−w option) will still be used if given.

−o outfile

Write the unwrapped output to a file called outfile. If the file formats ALT_LINE_DATA (default) or ALT_SAMPLE_DATA are used, the unwrapped phase is written into the second data channel, while the interferogram magnitude is written into the first channel. The format FLOAT_DATA may also be used.

−p value

Run in Lp-norm mode with p=value, where value is a nonnegative decimal. Instead of statistical cost functions, the program uses Lp cost functions with statistically based weights (unless −n is also given). Solutions are still always congruent. Moreover, congruence is enforced within the solver routine, not as a post-optimization processing step. Therefore, if p=2, for example, least-squares cost functions are used, but the solution will probably be more accurate than one generated from a transform-based least-squares algorithm.

−q

Run in quantify-only mode. The input data are assumed to be unwrapped already, and the total cost of this solution is calculated and printed. The unwrapped phase is wrapped assuming congruence for the cost calculation. Round-off errors may limit the precision of the quantified cost. See the −u option for allowable file formats.

−s

Run in smooth-solution mode. The problem statistics and resulting cost functions are based on the assumption that the true unwrapped phase represents a generic surface with no discontinuities. This is the same as deformation mode with the DEFOMAX parameter set to zero.

−S

Do single-tile re-optimization after tile-mode initialization. If this option is specified, snaphu will run in tile mode to generate an unwrapped solution, which is then used as the initialization to a single-tile optimization that produces the final unwrapped output. The tile-mode initialization may itself be initialized by the MST or MCF algorithms (or an input unwrapped phase file) as normal. This option is equivalent to running an instance of snaphu in tile mode, then running another instance of snaphu taking the tile-mode output as an unwrapped input via the -u option. Tile parameters must be specified when using this option. This approach is often faster than unwrapping an interferogram as a single tile from an MST initialization, especially if multiple processors are used.

−t

Run in topography mode. The problem statistics and resulting cost functions are based on the assumption that the true unwrapped phase represents surface elevation. This is the default.

−u

Assume that the input file is unwrapped rather than wrapped. The algorithm makes iterative improvements to this solution instead of using an initialization routine. The input file may be in the formats ALT_LINE_DATA (default) or ALT_SAMPLE_DATA; the interferogram magnitude should be in the first data channel and the unwrapped phase should be in the second data channel. The format FLOAT_DATA may also be used.

−v

Run in verbose mode. Extra information on the algorithm’s progress is printed to the standard output.

−w weightfile

Read external, scalar weights from file weightfile. The weights, which should be positive short integers, are applied to whichever cost functions are used. There is one weight value for each arc in the network, so weightfile should be the concatenation of raster horizontal-flow and vertical-flow arc weights. Thus, for an N row by M column interferogram, weightfile would consist of a rasterized (N-1) by M array followed by a rasterized N by (M-1) array of short integer data. This option is not well tested.

−−aa ampfile1 ampfile2

Amplitude data are read from the files specified. The data from the two individual SAR images forming the interferogram are assumed to be separately stored in files ampfile1 and ampfile2. These files should be in the format FLOAT_DATA. This option is similar to the −a option.

−−AA pwrfile1 pwrfile2

Similar to the −−aa option, but power data are read from the specified files.

−−assemble

Assemble the tile-mode temporary files from a previous tile-mode run of snaphu, possibly with different secondary optimization parameters, to produce a new unwrapped solution. The tile directory name must be specified with the −−tiledir option. Most configuration options (from the command line and any configuration files) must be specified similar to the previous run, including the output file name from which the names of temporary tile files are derived. The previous output file may hence be overwritten by the new output file. This option is useful if the user wishes to modify tile-assembly parameters without unwrapping the individual tiles over again.

−−copyright, −−info

Print the software copyright notice and bug report info, then exit.

−−costinfile costfile

Read statistical cost arrays from file costfile. This file should be in the format written by the −−costoutfile option. The cost file does not control whether snaphu runs in topography, deformation, or smooth-solution mode; the latter two must be specified explicitly even if costfile was generated while running in those modes.

−−costoutfile costfile

Write statistical cost arrays to file costfile. This option can be used with the −−costinfile option to save the time of generating statistical costs if the same costs are used multiple times.

−−debug, −−dumpall

Dump all sorts of intermediate arrays to files.

−−mst

Use a minimum spanning tree (MST) algorithm for the initialization. This is the default.

−−mcf

Use a minimum cost flow (MCF) algorithm for the initialization. The cs2 solver by Goldberg and Cherkassky is used. The modified network-simplex solver in L1 mode may give different results than the cs2 solver, though in principle both should be L1 optimal.

−−nproc n

Use n parallel processes when in tile mode. The program forks a new process for each tile so that tiles can be unwrapped in parallel; at most n processes will run concurrently. Forking is done before data are read. The standard output streams of child processes are directed to log files in the temporary tile directory.

−−piece firstrow firstcol nrow ncol

Read and unwrap only a subset or part of the input interferogram. The read piece is the nrow by ncol rectangle whose upper left corner is the pixel at row firstrow and column firstcol (indexed from 1). All input files (such as amplitude, coherence, etc.) are assumed to be the same size as the input phase file. All output files are nrow by ncol.

−−tile ntilerow ntilecol rowovrlp colovrlp

Unwrap the interferogram in tile mode. The interferogram is partitioned into ntilerow by ntilecol tiles, each of which is unwrapped independently. Tiles overlap by rowovrlp and colovrlp pixels in the row and column directions. The tiles are then segmented into reliable regions based on the cost functions, and the regions are reassembled. The program creates a subdirectory for temporary files in the directory of the eventual output file (see the −−tiledir and -k options). Tiles can be unwrapped in parallel (see the −−nproc option).

−−tiledir dirname

Use dirname as the name of the directory in which temporary tile-model outputs are written and/or read. The directory is created if it does not exist, and it is removed at the end of the run unless the -k or −−assemble options are specified.

FILE FORMATS

The formats of input files may be specified in a configuration file. All of these formats are composed of raster, single-precision (float, real*4, or complex*8) floating-point data types in the platform’s native byte order. Data are read line by line in row-major order (across then down, with the column index varying faster than the row index). Regardless of the file format, all input data arrays should have the same number of samples in width and depth and should be coregistered to one another. Note that weight files and cost files have their own formats. The allowable formats for other data files are described below.
COMPLEX_DATA

Alternating floats correspond to the real (in-phase) and imaginary (quadrature) components of complex data samples. The specified line length should be the number of complex samples (pairs of real and imaginary samples) per line.

ALT_LINE_DATA

Alternating lines (rows) of data correspond to lines of purely real data from two separate arrays. The first array is often the magnitude of the interferogram, and the second may be unwrapped phase, coherence, etc. This is also sometimes called hgt, rmg, or line-interleaved format.

ALT_SAMPLE_DATA

Alternating samples correspond to purely real samples from two separate arrays. This format is sometimes used for the amplitudes of the two SAR images.

FLOAT_DATA

The file contains data for only one channel or array, and the data are purely real.

EXAMPLES

Unwrap a wrapped topographic interferogram called ‘‘wrappedfile’’ whose line length is 1024 complex samples (output will be written to a file whose name is compiled into the program):

snaphu wrappedfile 1024

Unwrap the same file as above, but use brightness information from the file ‘‘ampfile,’’ set the perpendicular baseline to -165 m at midswath, and place the output in a file called ‘‘unwrappedfile’’ (coherence data are generated automatically if ‘‘wrappedfile’’ contains complex data and ‘‘ampfile’’ contains amplitude data from both SAR images):

snaphu wrappedfile 1024 -a ampfile \
-b -165 -o unwrappedfile

Unwrap the interferogram as above, but read correlation information from the file ‘‘corrfile’’ instead of generating it from the interferogram and amplitude data:

snaphu wrappedfile 1024 -a ampfile -c corrfile \
-b -165 -o unwrappedfile

The following is equivalent to the previous example, but input parameters are read from a configuration file, and verbose output is displayed:

cat > configfile
# This is a comment line which will be ignored
AMPFILE ampfile
CORRFILE corrfile
BPERP -165
OUTFILE unwrappedfile
EOF (ie, Ctrl-D)

snaphu -v -f configfile wrappedfile 1024

Unwrap the same interferogram, but use only the MST initialization (with scalar statistical weights) and write the output to ‘‘mstfile’’:

snaphu -f configfile -i wrappedfile 1024 -o mstfile

Read the unwrapped data in ‘‘mstfile’’ and use that as the initialization to the modified network-simplex solver:

snaphu -f configfile -u mstfile 1024 -o unwrappedfile

Note that in the previous two examples, the output file name in the configuration file is overrided by the one given on the command line. The previous two commands together are in principle equivalent to the preceding one, although round-off errors in flow-to-phase conversions may cause minor differences

Unwrap the interferogram as above, but use the MCF algorithm for initialization:

snaphu -f configfile wrappedfile 1024 --mcf

Unwrap the interferogram once again, but first flatten it with the unwrapped data in ‘‘estfile,’’ then reinsert the subtracted phase after unwrapping:

snaphu -f configfile wrappedfile 1024 -e estfile

The following assumes that the wrapped input interferogram measures deformation, not topography. Unwrap the interferogram with the given correlation data:

snaphu -d wrappedfile 1024 -c corrfile

Unwrap the input interferogram by minimizing the unweighted congruent L2 norm:

snaphu -p 2 -n wrappedfile 1024

Unwrap the interferogram as a three-by-four set of tiles that overlap by 30 pixels, with the specified configuration file, using two processors:

snaphu wrappedfile 1024 -f configfile \
--tile 3 4 30 30 --nproc 2

HINTS AND TIPS

The program may print a warning message about costs being clipped to avoid overflow. If too many costs are clipped, the value of COSTSCALE may need to be decreased in a configuration file (via the −f option). If the program prints a warning message about an unexpected increase in the total solution cost, this is an indication that too many costs are clipped. It is usually okay if just a few costs are clipped.

In topography mode, if the unwrapped result contains too many discontinuities, try increasing the value of LAYMINEI or decreasing the value of LAYCONST. The former determines the normalized intensity threshold for layover, and the latter is the relative layover probability. If there are too many discontinuities running in azimuth, try decreasing the value of AZDZFACTOR, which affects the ratio of azimuth to range costs. If the baseline is not known, take a guess at it and be sure its sign is correct. Specify the SAR imaging geometry parameters as well as possible. The defaults assume ERS data with five looks taken in azimuth.

In deformation mode, if the unwrapped result contains too many discontinuities, try increasing the value of DEFOTHRESHFACTOR or decreasing the value of DEFOCONST. If the surface displacement varies slowly and true discontinuities are not expected at all, DEFOMAX_CYCLE can be set to zero. This behavior is also invoked with the −s option. The resulting cost functions will be similar to correlation-weighted L2 cost functions, though the former are not necessarily centered on the wrapped gradients. Congruence is still enforced during rather than after optimization.

The program can be run in initialize-only (−i) mode for quick down-and-dirty MST or MCF solutions.

SIGNALS

Once the iterative solver has started, snaphu traps the interrupt (INT) and hangup (HUP) signals. Upon receiving an interrupt, for example if the user types Ctrl-C, the program finishes a minor iteration, dumps its current solution to the output, and exits. If a second interrupt is given after the first (caught) interrupt, the program exits immediately. If a hangup signal is received, the program dumps its current solution then continues to execute normally.

EXIT STATUS

Upon successful termination, the program exits with code 0. Errors result in exit code 1.

FILES

The following files may be useful for reference, but are not required. They are included in the program source distribution and may be installed somewhere on the system.
snaphu.conf.full

Template configuration file setting all valid input parameters (though some may be commented out).

snaphu.conf.brief

General-purpose template configuration file setting the most important or commonly modified input parameters.

In addition to parameters read from configuration files specified on the command line, default parameters may be read from a system-wide configuration file if such a file is named when the program is compiled.

BUGS

The −w option has not been tested exhaustively.

Extreme shadow discontinuities (i.e., abrupt elevation drops in increasing range due to cliffs facing away from the radar) are not modeled that well in the cost functions for topography mode.

Abrupt changes in surface reflectivity, such as those of coastlines between bright land and dark water, might be misinterpreted as layover and assigned inappropriate costs.

The algorithm’s behavior may be unpredictable if the costs are badly scaled and excessively clipped to fit into their short-integer data types.

There is no error checking that ensures that the network node potentials (incost and outcost) do not overflow their integer data types.

Automatic flow clipping is built into the MST initialization, but it can give erratic results and may loop infinitely for certain input data sets. It is consequently turned off by default.

Dedicated programs for specific Lp objective functions may work better than snaphu in Lp mode. Note that snaphu enforces congruence as part of the problem formulation, however, not as a post-optimization processing step.

A tree pruning capability is built into the code and can be enabled from a configuration file, but this functionality is experimental and not well tested.

REFERENCES

C. W. Chen and H. A. Zebker, ‘‘Two-dimensional phase unwrapping with use of statistical models for cost functions in nonlinear optimization,’’ Journal of the Optical Society of America A, 18, 338-351 (2001).

C. W. Chen and H. A. Zebker, ‘‘Network approaches to two-dimensional phase unwrapping: intractability and two new algorithms,’’ Journal of the Optical Society of America A, 17, 401-414 (2000).

C. W. Chen and H. A. Zebker, ‘‘Phase unwrapping for large SAR interferograms: Statistical segmentation and generalized network models,’’ IEEE Transactions on Geoscience and Remote Sensing, 40, 1709-1719 (2002).


snaphu-v2.0.6/man/man1/PaxHeader/snaphu.1000644 777777 777777 00000000043 14423062415 017665 xustar00curtis000000 000000 17 gid=703763885 18 uid=1220510063 snaphu-v2.0.6/man/man1/snaphu.1000644 Ho)00000067553 14423062415 017137 0ustar00curtis000000 000000 .TH "snaphu" 1 .SH NAME snaphu \- phase unwrapping algorithm for SAR interferometry .SH SYNOPSIS .B snaphu [options] [infile] [linelength] [options] .SH DESCRIPTION \fBsnaphu\fR is a \fBs\fRtatistical-cost \fBn\fRetwork-flow \fBa\fRlgorithm for \fBph\fRase \fBu\fRnwrapping. Given an input interferogram and other observable data, \fBsnaphu\fR attempts to compute congruent phase-unwrapped solutions that are maximally probable in an approximate \fIa posteriori\fR sense. The algorithm's solver routine is based on network optimization. By default, \fBsnaphu\fR assumes that its input is a synthetic aperture radar (SAR) interferogram measuring surface topography. Deformation measurements are assumed if the \fB\-d\fR option is given. Smooth, generic data are assumed if the \fB\-s\fR option is given. .PP This man page documents only the syntax and usage of \fBsnaphu\fR. Its theoretical foundations are discussed in the references cited below. .PP The most common input parameters may be given on the command line, while many other twiddle parameters are handled via the \fB\-f\fR option and configuration files. At the very least, the name of a wrapped-phase input file and its line length must be specified. For topography interferograms, range should increase towards the right in the interferogram, and the flat-earth phase ramp should be removed from the input interferogram before \fBsnaphu\fR is run. For deformation interferograms, phase variations due to topography should be removed as well. .PP Except for the input file name and the line length, all input parameters take default values if not specified. However, these parameters should be customized whenever possible since the accuracy of the solution depends on how well the statistics of the estimation problem are modeled. To avoid poor-quality solutions, users are strongly encouraged to provide their best estimates of the relevant problem parameters. Parameters are set in the order in which they are given on the command line, so multiple configuration files or options may be given, with later values overriding earlier ones. .PP Allowable file formats are detailed below. The default format for the input file is COMPLEX_DATA, but any of the described formats may be used. If either of the ALT_LINE_DATA or ALT_SAMPLE_DATA formats are used, the magnitude and phase (in radians from 0 to 2pi) of the interferogram should be in the first and second channels of the file, respectively. If the FLOAT_DATA format is used, the input file should contain only the phase of the interferogram (in radians from 0 to 2pi); the magnitude may be passed with the \fB\-m\fR option. .SH OPTIONS .TP \fB\-a\fP \fIampfile\fP Read brightness data from the file \fIampfile\fP. The file should contain the amplitudes (not powers) of the two individual SAR images forming the interferogram if the formats ALT_SAMPLE_DATA (default) or ALT_LINE_DATA are used. It should contain an average of those two images if the FLOAT_DATA format is used. If (1) the amplitudes of both images are available, (2) the interferogram magnitude is also available, and (3) the \fB\-c\fP option is not used, then a coherence estimate is automatically formed from the available data. The number of looks used for this estimate can be set in a configuration file. If no amplitude or power data are specified, then the magnitude of the input interferogram is used as the average amplitude, and no coherence estimate is formed. Note that the magnitude of the interferogram is not equal to the average amplitude of the SAR images. The amplitude data should be in the same system of units used for the input interferogram, and also coregistered to it. .TP \fB\-A\fP \fIpwrfile\fP Similar to the \fB\-a\fP option, except the data in the specified file is assumed to represent the powers of the two individual SAR images. .TP \fB\-b\fP \fIBperp\fP For topography mode, use \fIBperp\fP (decimal value, in meters) as the value of the perpendicular component of the interferometric baseline. The sign is defined such that \fIBperp\fP is negative if the unwrapped phase increases with the elevation. By default, repeat-pass or ping-pong mode is assumed; for single-antenna-transmit data, the value of \fIBperp\fP should be halved, or the transmit mode should be set accordingly in a configuration file (see the \fB\-f\fP option). The baseline value is only used in topography mode. .TP \fB\-c\fP \fIcorrfile\fP Read correlation data from the file \fIcorrfile\fP. The correlation data should be the same size as, and registered to, the input interferogram. Consequently, a raw correlation estimate may need to be upsampled if it incorporates more looks than the interferogram. If the \fB\-c\fP option is not given, a coherence estimate is formed from the available data if possible. Otherwise, a uniform default coherence is assumed for the entire interferogram. If the ALT_LINE_DATA (default) or ALT_SAMPLE_DATA formats are used, the correlation data should be in the second data channel of the file; the first channel is ignored. The FLOAT_DATA format may also be used. The correlation values should be between zero and one, inclusive. .TP \fB\-C\fP \fIconfigstr\fP Parse the string \fIconfigstr\fP as if it were a line from a configuration file containing a keyword-value pair (see the \fB-f\fP option). Configuration lines generally have whitespace between the keyword and the value, so \fIconfigstr\fP will usually need to be surrounded by quotation marks on a command line so that the shell does not split it into separate arguments (\fBsnaphu\fR itself does not require or allow quotation marks, however). The syntax for how quotation marks are handled is defined by the shell. Multiple instances of the \fB-C\fP option may be used in order to specify multiple configuration inputs. Later instances of the \fB-C\fP option take precedence over both earlier instances of the \fB-C\fP option and the configurations specified by earlier instances of the \fB-f\fP option. .TP .B \-d Run in deformation mode. The problem statistics and resulting cost functions are based on the assumption that the true unwrapped phase represents surface displacement rather than elevation. .TP \fB\-e\fP \fIestimatefile\fP Flatten using the unwrapped phase estimate in the file \fIestimatefile\fP. The estimate is subtracted from the input interferogram before unwrapping, and is inserted back into the solution just before the output is written. The estimate also affects the cost functions used, since subtracting a constant from a random variable shifts the probability density function of the random variable. If the formats ALT_LINE_DATA (default) or ALT_SAMPLE_DATA are used, the unwrapped estimate (in radians) should be in the second data channel of the file; the first channel is ignored. The FLOAT_DATA format may also be used. .TP \fB\-f\fP \fIconfigfile\fP Read configuration parameters from file \fIconfigfile\fP. The file is parsed line by line for key-value pairs. Template configuration files are included with the \fBsnaphu\fP source code: \fIsnaphu.conf.full\fP contains all valid key-value pairs; \fIsnaphu.conf.brief\fP contains the most important parameters. Lines not beginning with alphanumeric characters are treated as comment lines. Command line options specified after \fB\-f\fP will override parameters specified in the \fIconfigfile\fP and vice versa. The \fB\-f\fP option may be given multiple times with different configuration files, with parameters in later-specified files overriding those in earlier ones. .TP .B \-g \fImaskfile\fP Grow a connected component mask for the unwrapped solution and write the mask to the file \fImaskfile\fP. A connected component is a region of pixels in the solution that is believed to have been unwrapped in a relative, internally self-consistent manner according to the statistical costs used. Regions that are smaller than a preselected threshold are masked out. Parameters for this option can be set in the configuration file. The connected component file is composed of unsigned characters by default, with all pixels of the same value belonging to the same connected component and zero corresponding to masked pixels. .TP .B \-G \fImaskfile\fP Grow a connected component mask (see the \fB\-g\fP option) for the input data array, assuming that it is already unwrapped, and write the mask to the file \fImaskfile\fP. Statistical cost functions are computed for forming the mask, but a new unwrapped solution is not computed. .TP .B \-h, \-\-help Print a help message summarizing command-line options and exit. .TP .B \-i Run in initialize-only mode. Normally, \fBsnaphu\fP uses either an approximate minimum spanning tree (MST) algorithm or a minimum cost flow (MCF) algorithm for generating the initialization to its iterative, modified network-simplex solver. If \fB\-i\fP is given, the initialization is written to the output and the program exits without running the iterative solver. .TP .B \-k Keep temporary tile outputs. If this option is specified when \fBsnaphu\fP runs in tile mode, the temporary directory where tile outputs are stored will be left in place rather than deleted. The tile-mode initialization of the \fB-S\fP option will also be left in place rather than deleted. .TP \fB\-l\fP \fIlogfile\fP Log all runtime parameters and some other environment information into the specified file. The log file is a text file in the same format as a configuration file. .TP \fB\-m\fP \fImagfile\fP Read interferogram magnitude data from the specified file. This option is useful mainly if the wrapped-phase input file is given as a set of real phase values rather than complex interferogram values. The interferogram magnitude is used to form a coherence estimate if appropriate amplitude data are given as well. The default file format is FLOAT_DATA. If the formats ALT_LINE_DATA or ALT_SAMPLE_DATA are used, the magnitude should be in the first data channel of the file; the second channel is ignored. If the COMPLEX_DATA format is used, the phase information is ignored. Areas where the magnitude is zero are treated as masked areas (see the \fB\-M\fP option). .TP \fB\-M\fP \fIbytemaskfile\fP Read a byte mask from the specified file. The mask file should be the same size as the input array to be unwrapped. The mask should have the binary (not ASCII) value 0 where pixels of the input array are to be ignored during the primary optimization stage of the program. Values elsewhere should be binary 1. Masking is not applied until after the initialization stage of \fBsnaphu\fP. Masked areas are treated as areas in which the solution phase value is irrelevant to the solution cost. The magnitude of the interferogram is set to zero in masked areas in the output file. Areas with zero magnitude in the input data are treated as masked areas as well. Areas near the edges of the input may also be masked via options in a configuration file. .TP .B \-n Run in no-statistical-costs mode. If the \fB\-i\fP or \fB\-p\fP options are given, \fBsnaphu\fP will not use statistical costs. Information from a weight file (\fB\-w\fP option) will still be used if given. .TP \fB\-o\fP \fIoutfile\fP Write the unwrapped output to a file called \fIoutfile\fP. If the file formats ALT_LINE_DATA (default) or ALT_SAMPLE_DATA are used, the unwrapped phase is written into the second data channel, while the interferogram magnitude is written into the first channel. The format FLOAT_DATA may also be used. .TP \fB\-p\fP \fIvalue\fP Run in Lp-norm mode with p=\fIvalue\fP, where \fIvalue\fP is a nonnegative decimal. Instead of statistical cost functions, the program uses Lp cost functions with statistically based weights (unless \fB\-n\fP is also given). Solutions are still always congruent. Moreover, congruence is enforced within the solver routine, not as a post-optimization processing step. Therefore, if p=2, for example, least-squares cost functions are used, but the solution will probably be more accurate than one generated from a transform-based least-squares algorithm. .TP .B \-q Run in quantify-only mode. The input data are assumed to be unwrapped already, and the total cost of this solution is calculated and printed. The unwrapped phase is wrapped assuming congruence for the cost calculation. Round-off errors may limit the precision of the quantified cost. See the \fB\-u\fP option for allowable file formats. .TP .B \-s Run in smooth-solution mode. The problem statistics and resulting cost functions are based on the assumption that the true unwrapped phase represents a generic surface with no discontinuities. This is the same as deformation mode with the DEFOMAX parameter set to zero. .TP .B \-S Do single-tile re-optimization after tile-mode initialization. If this option is specified, \fBsnaphu\fP will run in tile mode to generate an unwrapped solution, which is then used as the initialization to a single-tile optimization that produces the final unwrapped output. The tile-mode initialization may itself be initialized by the MST or MCF algorithms (or an input unwrapped phase file) as normal. This option is equivalent to running an instance of \fBsnaphu\fP in tile mode, then running another instance of \fBsnaphu\fP taking the tile-mode output as an unwrapped input via the \fB-u\fP option. Tile parameters must be specified when using this option. This approach is often faster than unwrapping an interferogram as a single tile from an MST initialization, especially if multiple processors are used. .TP .B \-t Run in topography mode. The problem statistics and resulting cost functions are based on the assumption that the true unwrapped phase represents surface elevation. This is the default. .TP .B \-u Assume that the input file is unwrapped rather than wrapped. The algorithm makes iterative improvements to this solution instead of using an initialization routine. The input file may be in the formats ALT_LINE_DATA (default) or ALT_SAMPLE_DATA; the interferogram magnitude should be in the first data channel and the unwrapped phase should be in the second data channel. The format FLOAT_DATA may also be used. .TP .B \-v Run in verbose mode. Extra information on the algorithm's progress is printed to the standard output. .TP \fB\-w\fP \fIweightfile\fP Read external, scalar weights from file \fIweightfile\fP. The weights, which should be positive short integers, are applied to whichever cost functions are used. There is one weight value for each arc in the network, so \fIweightfile\fP should be the concatenation of raster horizontal-flow and vertical-flow arc weights. Thus, for an N row by M column interferogram, \fIweightfile\fP would consist of a rasterized (N-1) by M array followed by a rasterized N by (M-1) array of short integer data. This option is not well tested. .TP \fB\-\-aa\fP \fIampfile1 ampfile2\fP Amplitude data are read from the files specified. The data from the two individual SAR images forming the interferogram are assumed to be separately stored in files \fIampfile1\fP and \fIampfile2\fP. These files should be in the format FLOAT_DATA. This option is similar to the \fB\-a\fP option. .TP \fB\-\-AA\fP \fIpwrfile1 pwrfile2\fP Similar to the \fB\-\-aa\fP option, but power data are read from the specified files. .TP \fB\-\-assemble Assemble the tile-mode temporary files from a previous tile-mode run of \fBsnaphu\fP, possibly with different secondary optimization parameters, to produce a new unwrapped solution. The tile directory name must be specified with the \fB\-\-tiledir\fP option. Most configuration options (from the command line and any configuration files) must be specified similar to the previous run, including the output file name from which the names of temporary tile files are derived. The previous output file may hence be overwritten by the new output file. This option is useful if the user wishes to modify tile-assembly parameters without unwrapping the individual tiles over again. .TP .B \-\-copyright, \-\-info Print the software copyright notice and bug report info, then exit. .TP \fB\-\-costinfile\fP \fIcostfile\fP Read statistical cost arrays from file \fIcostfile\fP. This file should be in the format written by the \fB\-\-costoutfile\fP option. The cost file does not control whether \fBsnaphu\fP runs in topography, deformation, or smooth-solution mode; the latter two must be specified explicitly even if \fIcostfile\fP was generated while running in those modes. .TP \fB\-\-costoutfile\fP \fIcostfile\fP Write statistical cost arrays to file \fIcostfile\fP. This option can be used with the \fB\-\-costinfile\fP option to save the time of generating statistical costs if the same costs are used multiple times. .TP .B \-\-debug, \-\-dumpall Dump all sorts of intermediate arrays to files. .TP .B \-\-mst Use a minimum spanning tree (MST) algorithm for the initialization. This is the default. .TP .B \-\-mcf Use a minimum cost flow (MCF) algorithm for the initialization. The cs2 solver by Goldberg and Cherkassky is used. The modified network-simplex solver in L1 mode may give different results than the cs2 solver, though in principle both should be L1 optimal. .TP .B \-\-nproc \fIn\fP Use \fIn\fP parallel processes when in tile mode. The program forks a new process for each tile so that tiles can be unwrapped in parallel; at most \fIn\fP processes will run concurrently. Forking is done before data are read. The standard output streams of child processes are directed to log files in the temporary tile directory. .TP .B \-\-piece \fIfirstrow firstcol nrow ncol\fP Read and unwrap only a subset or part of the input interferogram. The read piece is the \fInrow\fP by \fIncol\fP rectangle whose upper left corner is the pixel at row \fIfirstrow\fP and column \fIfirstcol\fP (indexed from 1). All input files (such as amplitude, coherence, etc.) are assumed to be the same size as the input phase file. All output files are \fInrow\fP by \fIncol\fP. .TP .B \-\-tile \fIntilerow ntilecol rowovrlp colovrlp\fP Unwrap the interferogram in tile mode. The interferogram is partitioned into \fIntilerow\fP by \fIntilecol\fP tiles, each of which is unwrapped independently. Tiles overlap by \fIrowovrlp\fP and \fIcolovrlp\fP pixels in the row and column directions. The tiles are then segmented into reliable regions based on the cost functions, and the regions are reassembled. The program creates a subdirectory for temporary files in the directory of the eventual output file (see the \fB\-\-tiledir\fP and \fB-k\fP options). Tiles can be unwrapped in parallel (see the \fB\-\-nproc\fP option). .TP .B \-\-tiledir \fIdirname\fP Use \fIdirname\fP as the name of the directory in which temporary tile-model outputs are written and/or read. The directory is created if it does not exist, and it is removed at the end of the run unless the \fB-k\fP or \fB\-\-assemble\fP options are specified. .SH FILE FORMATS The formats of input files may be specified in a configuration file. All of these formats are composed of raster, single-precision (float, real*4, or complex*8) floating-point data types in the platform's native byte order. Data are read line by line in row-major order (across then down, with the column index varying faster than the row index). Regardless of the file format, all input data arrays should have the same number of samples in width and depth and should be coregistered to one another. Note that weight files and cost files have their own formats. The allowable formats for other data files are described below. .TP COMPLEX_DATA Alternating floats correspond to the real (in-phase) and imaginary (quadrature) components of complex data samples. The specified line length should be the number of complex samples (pairs of real and imaginary samples) per line. .TP ALT_LINE_DATA Alternating lines (rows) of data correspond to lines of purely real data from two separate arrays. The first array is often the magnitude of the interferogram, and the second may be unwrapped phase, coherence, etc. This is also sometimes called \fBhgt\fP, \fBrmg\fP, or line-interleaved format. .TP ALT_SAMPLE_DATA Alternating samples correspond to purely real samples from two separate arrays. This format is sometimes used for the amplitudes of the two SAR images. .TP FLOAT_DATA The file contains data for only one channel or array, and the data are purely real. .SH EXAMPLES Unwrap a wrapped topographic interferogram called ``wrappedfile'' whose line length is 1024 complex samples (output will be written to a file whose name is compiled into the program): .PP .nf snaphu wrappedfile 1024 .fi .PP Unwrap the same file as above, but use brightness information from the file ``ampfile,'' set the perpendicular baseline to -165 m at midswath, and place the output in a file called ``unwrappedfile'' (coherence data are generated automatically if ``wrappedfile'' contains complex data and ``ampfile'' contains amplitude data from both SAR images): .PP .nf snaphu wrappedfile 1024 -a ampfile \e -b -165 -o unwrappedfile .fi .PP Unwrap the interferogram as above, but read correlation information from the file ``corrfile'' instead of generating it from the interferogram and amplitude data: .PP .nf snaphu wrappedfile 1024 -a ampfile -c corrfile \e -b -165 -o unwrappedfile .fi .PP The following is equivalent to the previous example, but input parameters are read from a configuration file, and verbose output is displayed: .PP .nf cat > configfile # This is a comment line which will be ignored AMPFILE ampfile CORRFILE corrfile BPERP -165 OUTFILE unwrappedfile EOF (ie, Ctrl-D) snaphu -v -f configfile wrappedfile 1024 .fi .PP Unwrap the same interferogram, but use only the MST initialization (with scalar statistical weights) and write the output to ``mstfile'': .PP .nf snaphu -f configfile -i wrappedfile 1024 -o mstfile .fi .PP Read the unwrapped data in ``mstfile'' and use that as the initialization to the modified network-simplex solver: .PP .nf snaphu -f configfile -u mstfile 1024 -o unwrappedfile .fi .PP Note that in the previous two examples, the output file name in the configuration file is overrided by the one given on the command line. The previous two commands together are in principle equivalent to the preceding one, although round-off errors in flow-to-phase conversions may cause minor differences .PP Unwrap the interferogram as above, but use the MCF algorithm for initialization: .PP .nf snaphu -f configfile wrappedfile 1024 --mcf .fi .PP Unwrap the interferogram once again, but first flatten it with the unwrapped data in ``estfile,'' then reinsert the subtracted phase after unwrapping: .PP .nf snaphu -f configfile wrappedfile 1024 -e estfile .fi .PP The following assumes that the wrapped input interferogram measures deformation, not topography. Unwrap the interferogram with the given correlation data: .PP .nf snaphu -d wrappedfile 1024 -c corrfile .fi .PP Unwrap the input interferogram by minimizing the unweighted congruent L2 norm: .PP .nf snaphu -p 2 -n wrappedfile 1024 .fi .PP Unwrap the interferogram as a three-by-four set of tiles that overlap by 30 pixels, with the specified configuration file, using two processors: .PP .nf snaphu wrappedfile 1024 -f configfile \e --tile 3 4 30 30 --nproc 2 .fi .PP .SH "HINTS AND TIPS" The program may print a warning message about costs being clipped to avoid overflow. If too many costs are clipped, the value of COSTSCALE may need to be decreased in a configuration file (via the \fB\-f\fR option). If the program prints a warning message about an unexpected increase in the total solution cost, this is an indication that too many costs are clipped. It is usually okay if just a few costs are clipped. .PP In topography mode, if the unwrapped result contains too many discontinuities, try increasing the value of LAYMINEI or decreasing the value of LAYCONST. The former determines the normalized intensity threshold for layover, and the latter is the relative layover probability. If there are too many discontinuities running in azimuth, try decreasing the value of AZDZFACTOR, which affects the ratio of azimuth to range costs. If the baseline is not known, take a guess at it and be sure its sign is correct. Specify the SAR imaging geometry parameters as well as possible. The defaults assume ERS data with five looks taken in azimuth. .PP In deformation mode, if the unwrapped result contains too many discontinuities, try increasing the value of DEFOTHRESHFACTOR or decreasing the value of DEFOCONST. If the surface displacement varies slowly and true discontinuities are not expected at all, DEFOMAX_CYCLE can be set to zero. This behavior is also invoked with the \fB\-s\fR option. The resulting cost functions will be similar to correlation-weighted L2 cost functions, though the former are not necessarily centered on the wrapped gradients. Congruence is still enforced during rather than after optimization. .PP The program can be run in initialize-only (\fB\-i\fR) mode for quick down-and-dirty MST or MCF solutions. .SH SIGNALS Once the iterative solver has started, \fBsnaphu\fR traps the interrupt (INT) and hangup (HUP) signals. Upon receiving an interrupt, for example if the user types Ctrl-C, the program finishes a minor iteration, dumps its current solution to the output, and exits. If a second interrupt is given after the first (caught) interrupt, the program exits immediately. If a hangup signal is received, the program dumps its current solution then continues to execute normally. .SH "EXIT STATUS" Upon successful termination, the program exits with code 0. Errors result in exit code 1. .SH FILES The following files may be useful for reference, but are not required. They are included in the program source distribution and may be installed somewhere on the system. .TP \fIsnaphu.conf.full\fP Template configuration file setting all valid input parameters (though some may be commented out). .TP \fIsnaphu.conf.brief\fP General-purpose template configuration file setting the most important or commonly modified input parameters. .PP In addition to parameters read from configuration files specified on the command line, default parameters may be read from a system-wide configuration file if such a file is named when the program is compiled. .SH BUGS The \fB\-w\fR option has not been tested exhaustively. .PP Extreme shadow discontinuities (i.e., abrupt elevation drops in increasing range due to cliffs facing away from the radar) are not modeled that well in the cost functions for topography mode. .PP Abrupt changes in surface reflectivity, such as those of coastlines between bright land and dark water, might be misinterpreted as layover and assigned inappropriate costs. .PP The algorithm's behavior may be unpredictable if the costs are badly scaled and excessively clipped to fit into their short-integer data types. .PP There is no error checking that ensures that the network node potentials (incost and outcost) do not overflow their integer data types. .PP Automatic flow clipping is built into the MST initialization, but it can give erratic results and may loop infinitely for certain input data sets. It is consequently turned off by default. .PP Dedicated programs for specific Lp objective functions may work better than \fBsnaphu\fR in Lp mode. Note that \fBsnaphu\fR enforces congruence as part of the problem formulation, however, not as a post-optimization processing step. .PP A tree pruning capability is built into the code and can be enabled from a configuration file, but this functionality is experimental and not well tested. .SH REFERENCES C. W. Chen and H. A. Zebker, ``Two-dimensional phase unwrapping with use of statistical models for cost functions in nonlinear optimization,'' \fIJournal of the Optical Society of America A\fP, \fB18\fP, 338-351 (2001). .PP C. W. Chen and H. A. Zebker, ``Network approaches to two-dimensional phase unwrapping: intractability and two new algorithms,'' \fIJournal of the Optical Society of America A\fP, \fB17\fP, 401-414 (2000). .PP C. W. Chen and H. A. Zebker, ``Phase unwrapping for large SAR interferograms: Statistical segmentation and generalized network models,'' \fIIEEE Transactions on Geoscience and Remote Sensing\fP, \fB40\fP, 1709-1719 (2002).