
    Zfѿ                        d Z ddlZddlZddlZddlZdZdZdZd Z	d7dZ
d8dZd	 Zd9d
Zd Zd:dZd Zd Zd Zd Zd Zd Zd;dZd Zd Zd<dZd Zd=dZd=dZd=dZd>dZd Zd Z d?dZ!dejD                  z  ejD                  gfd Z#d! Z$d@d"Z%dAd#Z&d9d$Z'dBd%Z(d& Z)d' Z*d( Z+d) Z,d* Z-d+ Z.dCd,Z/d- Z0dDd.Z1dEd/Z2d:d0Z3d1 Z4d2 Z5d3 Z6d4 Z7dFd5Z8d6 Z9y)Gz&Miscellaneous utilities - independent.    NiJxg3333MXAgHz'D@c                     t        j                  |       }t        | t         j                        r
d|| dkD  <   |S | dkD  rd}|S )a  Calculate the resulting coherence due to mis-registration (coregistration error).

    Reference:
      Equation (30) in Just and Bamler (1994); Equation (4.4.27) in Hanssen (2001).

    Parameters: mu  - float / np.ndarray, mis-registration in the unit of resolution cell
                      NOTE: the unit is resolution cell, NOT pixel size/spacing.
                      Applicable to both SAR range and azimuth directions.
    Returns:    coh - float / np.ndarray, coherence.
    r      )npsinc
isinstancendarray)mucohs     L/home/exouser/operations/rsmas_insar/tools/MintPy/src/mintpy/utils/utils0.pymisregistration2coherencer   !   sH     ''"+C "bjj!BF
 J 6CJ    c                    d| j                         v r|dkD  rd}|rt        d       t        | d         t        | d         }}t        | d         t        | d         }}|||dz
  z  z   }||z   d	z  }|r*t        d
|z         t        d|z         t        d|z         |dk(  r$t	        j
                  |t        j                        S t	        j                  |||      }	|dk(  r$t	        j
                  |	t        j                        S t	        j                  |	|df      }
t	        j
                  |
t        j                        S )a  Calculate slant range distance from input attribute dict
    Parameters: atr : dict, including the following ROI_PAC attributes:
                    STARTING_RANGE
                    RANGE_PIXEL_SIZE
                    LENGTH
                    WIDTH
                dimension : int, choices = [0,1,2]
                    2 for 2d matrix, vary in range direction, constant in az direction,
                        for radar coord only
                    1 for 1d matrix, in range direction, for radar coord file
                    0 for center value
    Returns:    np.array (0, 1 or 2 D) : range distance between antenna and ground target in meters
    Y_FIRSTr   zGinput file is geocoded, return center range distance for the whole areaSTARTING_RANGERANGE_PIXEL_SIZELENGTHWIDTHr          @znear   range : %.2f mzcenter range : %.2f mzfar    range : %.2f m)num)	keysprintfloatintr   arrayfloat32linspacetile)atr	dimension	print_msgrange_ndRlengthwidthrange_frange_crange_xrange_xys              r   range_distancer)   :   s$    CHHJ9q=	[\,-.c:L6M0NRGH&CL(9EFE!G$G #%G%12%12%12A~xx,,kk'76GA~xx,,777VQK0xx"**--r   c           	      >   |rt         nd }d| j                         v r|dkD  r
d} |d       |dk(  r/d| j                         v rt        | d         } |d|dd       |S t        | d	         }t        | d
         }t        | j                  dt                    }t        | d         }	t        | d         }
|||
z  z   }t        j                  t        j                  |dz  |dz  z   ||	z   dz  z
  d|z  |z  z        z
  dz  t        j                  z  }t        j                  t        j                  |dz  |dz  z   ||	z   dz  z
  d|z  |z  z        z
  dz  t        j                  z  }||z   dz  } |d|dd        |d|dd        |d|dd       |dk(  r|}|S |dk(  r*t        j                  |||
dt        j                        }|S |dk(  rt        | d         }|kt        | dd      }t        j                  t        j                  ||z   dz  |dz  z   ||	z   dz  z
  d||z   z  |z  z        z
  dz  t        j                  z  }|S t        j                  t        j                  |||
dt        j                        |df      }|S t        d|       )a  Calculate 2D matrix of incidence angle from ROI_PAC attributes, very accurate.
    Parameters: atr : dict - ROI_PAC attributes including the following items:
                     STARTING_RANGE
                     RANGE_PIXEL_SIZE
                     EARTH_RADIUS
                     HEIGHT
                     WIDTH
                     LENGTH                  #for dimension=2
                     CENTER_INCIDENCE_ANGLE  #for dimension=0
                dem : 2D array for height to calculate local incidence angle
                dimension : int,
                            2 for 2d matrix
                            1 for 1d array
                            0 for one center value
                print_msg : bool
    Returns:    inc_angle : 2D np.array, incidence angle in degree for each pixel
    Example:    dem = readfile.read('hgt.rdr')[0]
                atr = readfile.read_attribute('filt_fine.unw')
                inc_angle = ut.incidence_angle(atr, dem=dem)
    c                       y N )argskwargss     r   <lambda>z!incidence_angle.<locals>.<lambda>x   s    r   r   r   z9input file is geocoded, return center incident angle onlyCENTER_INCIDENCE_ANGLEzcenter incidence angle : z.4fz( degree (grabbed from metadata directly)r   r   EARTH_RADIUSHEIGHTr           f@r   znear   incidence angle : z degreezfar    incidence angle : r   FALSE)r   endpointdtyper   Fr   r    zun-supported dimension input: )r   r   r   getr2   r   r   piarccosr   r   r)   r   	Exception)r   demr   r    vprint	inc_angler!   r"   rHr$   r%   inc_angle_ninc_angle_finc_angle_cr#   
range_dists                    r   incidence_anglerG   c   s   *  U%AF CHHJ9q=	JK A~2chhj@#678	*9S/9abc C()*G	s%&	'Bcggnl34Ac(mAGE U
"G55299adWaZ&71Q3(&BQqS[%QRRV[[\^\a\aaK55299adWaZ&71Q3(&BQqS[%QRRV[[\^\a\aaK,3K
&{3&7w?@
&{3&7w?@
&{3&7w?@A~	& # 
aKK[e)0

D	   
aS]# ?'qEJJQsUQJQ,F!A#PQ,Q,-quIj,@,B "C CFKLLNEERI 	 K%5<BJJ!PRXZ[Q\^I  8DEEr   c                    t        |t              rt        |      }t        j                  |t        j
                        dz  t        j                  z  }t        | d         }t        | d         }||z   t        j                  t        j                  |z
        z  }t        j                  ||z        }||z
  }|t        j                  |      z  }|S )a  Calculate the corresponding slant range distance given an incidence angle

    Law of sines:
               r + H                   r               range_dist
       --------------------- = ----------------- = ------------------ = 2R
        sin(pi - inc_angle)     sin(look_angle)     sin(range_angle)

    where range_angle = inc_angle - look_angle
          R is the radius of the circumcircle.

    link: http://www.ambrsoft.com/TrigoCalc/Triangle/BasicLaw/BasicTriangle.htm

    Parameters: atr         - dict, metadata including the following items:
                                  EARTH_RADIUS
                                  HEIGHT
                inc_angle   - float / np.ndarray, incidence angle in degree
    Returns:    slant_range - float, slant range distance
    r8      r2   r3   )	r   strr   r   r   r   r;   sinarcsin)r   r@   rA   rB   R2
look_anglerange_anglerF   s           r   $incidence_angle2slant_range_distancerQ      s    & )S!)$	"**5;beeCIc.!"Ac(mA a%266"%%)+,	,BAF$Jj(Kbff[))Jr   c                     d| j                         v rt        d       yt        | d|      }t        | d         t	        j
                  |dz  t        j                  z        z  }|S )zkGet range resolution on the ground in meters,
        from ROI_PAC attributes, for file in radar coord
    X_FIRSTz5Input file is in geo coord, no range resolution info.Nr   r9   r   r5   )r   r   rG   r   r   rL   r;   )r   r    r@   rg_steps       r   range_ground_resolutionrU      s\     CHHJEFqIFIC*+,RVVIeOBEE4I-JJGNr   c                     d| j                         v rt        d       y| j                  dd      }|dv r5t        | d         }t        | d         }t        | d	         |z  ||z   z  }|S |d
k(  rt        | d	         }S )zmGet azimuth resolution on the ground in meters,
        from ROI_PAC attributes, for file in radar coord
    rS   z7Input file is in geo coord, no azimuth resolution info.N	PROCESSORisce)roipacrX   r2   r3   AZIMUTH_PIXEL_SIZEgamma)r   r   r:   r   )r   procReheightaz_steps        r   azimuth_ground_resolutionr`      s     CHHJGH77;'D!!3~&'s8}%012R72;G N 
012Nr   c                 ^   | syt        | t              r| g} | D cg c]  }||	 } }| D ][  }t        j                  j	                  |      s#t        |d      5  t        j                  ||       t        d|z          ddd       ] t        |       dk(  r| d   } | S c c}w # 1 sw Y   xY w)a  python equivalent function to Unix utility - touch
    It sets the modification and access times of files to the current time of day.
    If the file doesn't exist, it is created with default permissions.
    Inputs/Output:
        fname_list - string / list of string
    Naztouch r   r   )	r   rK   ospathisfileopenutimer   len)
fname_listtimesxfnames       r   touchrm      s     *c" \
'91=!9J9 &77>>% eS! &&hun%& && :!]
 :& &s   BB%B##B,	c                     ddl m} |j                  dt        | dd       | d   j	                         dk(  d      }|j                         d   }|S )	a  Convert UTM Zone string to EPSG code.

    Reference:
        https://docs.up42.com/data/reference/utm#utm-wgs84
        https://pyproj4.github.io/pyproj/stable/examples.html#initializing-crs

    Parameters: utm_zone  - str, atr['UTM_ZONE'], comprises a zone number
                            and a hemisphere, e.g. 11N, 36S, etc.
    Returns:    epsg_code - str, EPSG code
    Examples:   epsg_code = utm_zone2epsg_code('11N')
    r   CRSutmNS)projzonesouthr   )pyprojrp   	from_dictr   upperto_authority)utm_zonerp   crs	epsg_codes       r   utm_zone2epsg_coder~     s[     
--HSbM""##%, C
   "1%Ir   c                 n    ddl m} |j                  |       }|j                  }|st	        d|  d       |S )a  Convert EPSG code to UTM Zone string.

    Reference:
        https://docs.up42.com/data/reference/utm#utm-wgs84
        https://pyproj4.github.io/pyproj/stable/examples.html#initializing-crs

    Parameters: epsg_code - str / int, EPSG code
    Returns:    utm_zone  - str, atr['UTM_ZONE'], comprises a zone number
                            and a hemisphere, e.g. 11N, 36S, etc. None for
                            a EPSG code not in a UTM coordnate system
    Examples:   utm_zone = epsg_code2utm_zone('32736')
    r   ro   zWARNING: input EPSG code (z.) is NOT a UTM zone, return None and continue.)rw   rp   	from_epsgr{   r   )r}   rp   r|   r{   s       r   epsg_code2utm_zoner   $  s9     
--	
"C||H*9+5cdeOr   c                 B   ddl m} ddlm}m} |j                  |       }|j                         }|j                         s|j                  d      dk(  r||fS  ||j                               } |d      }	|j                  ||	      }
|
j                  ||      \  }}||fS )a  Convert x, y in the projection coordinates of the file to lat/lon in degree.

    Similar functionality also exists in utm.to_latlon() at:
        https://github.com/Turbo87/utm#utm-to-latitudelongitude

    Parameters: infile - str, GDAL supported file path
                x/y    - scalar or 1/2D np.ndarray, coordinates in x and y direction
    Returns:    y/x    - scalar or 1/2D np.ndarray, coordinates in latitutde and longitude
    r   )gdal)ProjTransformerunitdegreez	epsg:4326)osgeor   rw   r   r   OpenGetSpatialRefIsProjectedGetAttrValueGetProjection	from_proj	transform)infilerk   yr   r   r   dssrsp_inp_outtransformers              r   	to_latlonr   9  s     ( 
6	B



C OOC$4$4V$<$H!t   "#DE''e4K  A&DAqa4Kr   c                 L   ddl }t        | d   dd       }| d   d   j                         dk(  }|j                  t	        j
                  |      t	        j
                  |      ||d      \  }}t        d ||fD              r |j                         }|j                         }||fS )	a)  Convert UTM easting/northing in meters to lat/lon in degrees.

    Parameters: meta     - dict, mintpy attributes that includes:
                           UTM_ZONE
                easting  - scalar/list/tuple/1-2D np.ndarray, UTM    coordinates in x direction
                northing - scalar/list/tuple/1-2D np.ndarray, UTM    coordinates in y direction
    Returns:    lat      - scalar/list/tuple/1-2D np.ndarray, WGS 84 coordinates in y direction
                lon      - scalar/list/tuple/1-2D np.ndarray, WGS 84 coordinates in x direction
    r   NUTM_ZONErr   NF)northernstrictc              3   H   K   | ]  }t        |t        t        f        y wr,   r   listtuple.0rk   s     r   	<genexpr>zutm2latlon.<locals>.<genexpr>l  s     
EA:a$'
E    ")rq   r   ry   r   r   r   anytolist)metaeastingnorthingrq   zone_numr   latlons           r   
utm2latlonr   W  s     4
#CR()HJ#))+s2H
 }}RXXg.0BH&.u  >HC 
E'81D
EEjjljjl8Or   c                    ddl }t        | d   dd       }|j                  t        j                  |      t        j                  |      |      dd \  }}t        d ||fD              r |j                         }|j                         }||fS )a4  Convert latitude/longitude in degrees to UTM easting/northing in meters.

    Parameters: meta     - dict, mintpy attributes that includes:
                           UTM_ZONE
                lat      - scalar/list/tuple/1-2D np.ndarray, WGS 84 coordinates in y direction
                lon      - scalar/list/tuple/1-2D np.ndarray, WGS 84 coordinates in x direction
    Returns:    easting  - scalar/list/tuple/1-2D np.ndarray, UTM    coordinates in x direction
                northing - scalar/list/tuple/1-2D np.ndarray, UTM    coordinates in y direction
    r   Nr   rr   )force_zone_numberr4   c              3   H   K   | ]  }t        |t        t        f        y wr,   r   r   s     r   r   zlatlon2utm.<locals>.<genexpr>  s     
<A:a$'
<r   )rq   r   from_latlonr   r   r   r   )r   r   r   rq   r   r   r   s          r   
latlon2utmr   s  s      4
#CR()Hrxx}X`abdcdeGX 
<#s
<<.."??$Wr   c           
          | \  }}}}|||||g}|||||g}ddj                  t        ||      D cg c]  \  }}| d|  c}}      z   dz   }	|	S c c}}w )zConvert the input bounding box in SNWE into WKT format POLYGON.

    Parameters: snwe    - list of 4 float, south, north, west and east in degrees/meters
    Returns:    polygon - str, WKT format POLYGON
    z	POLYGON((, z)))joinzip)
snwers   r   WElatslonsr   r   polygons
             r   snwe_to_wkt_polygonr     sr     JAq!Qq!Q?Dq!Q?DCHHSt_%UcQsen%UVVZ^^GN &Vs   Ac                    t        | d         t        | d         }}|dd||f}g }|8t        j                  |d      5 }	t        |	j	                               }ddd       d|v rUt        j                  |d      5 }	|	d   |d   |d   |d   |d	   f   }
|	d
   |d   |d   |d   |d	   f   }ddd       nTd| j	                         v r/t        | d         }t        | d         }t        | d         ||d   dz   z  z   }t        | d         ||d   dz   z  z   }|d   |d   z
  }|d	   |d   z
  }|||dz
  z  z   }|||dz
  z  z   }|d	k(  r%t        j                  |||dz  |||dz  f   \  }
}nF|dk(  r3t        j                  |||d      }
t        j                  |||d      }nt        d|       | d   j                  d      sAd| j	                         v r/t        d       t        | ||
      \  }
}nd}|dz  }t        |      t        j                  
t        j                        }
t        j                  t        j                        }||z  dkD  rL|
j                  dk(  r|
dd|   }
|dd|   }|
|fS |
j                  d	k(  r|
dd|dd|f   }
|dd|dd|f   }|
|fS # 1 sw Y   YxY w# 1 sw Y   xY w)a  Extract precise pixel-wise lat/lon.

    For meta dict in geo-coordinates OR geom_file with latitude/longitude dataset

    Returned lat/lon are corresponds to the pixel center

    Parameters: meta      - dict, including LENGTH, WIDTH and Y/X_FIRST/STEP
                box       - 4-tuple of int for (x0, y0, x1, y1)
                dimension - int, output lat/lon matrix dimension, 1 or 2
                y/xstep   - int, number of pixels to skip for each output pixel
    Returns:    lats      - 1/2D np.array for latitude  in size of (length, _width_)
                lons      - 1/2D np.array for longitude in size of (_length_, width)
    r   r   Nr   rA   latituder      r4   	longituder   Y_STEPX_STEP      ?rS   y              ?T)r   r7   zun-supported dimension = Y_UNITdegr   z2UTM coordinates detected, convert UTM into lat/lon)r   r   zCan not get pixel-wise lat/lon!z]
meta dict is not geocoded and/or geometry file does not contains latitude/longitude dataset.rI   )r   h5pyFiler   r   r   r   mgridr   
ValueError
startswithr   r   r   r   ndim)r   	geom_fileboxr   ystepxstepr#   r$   ds_listfr   r   lat_steplon_steplat0lon0lat_numlon_numlat1lon1msgs                        r   get_lat_lonr     s:    X'T']);EF
{!UF#GYYy#& 	%!1668nG	% WYYy#& 	@!Z=QAAs1v!=>D[>#a&Q-QA">?D	@ 	@ 
diik	!h(h(T)_%CFSL(AAT)_%CFSL(AAa&3q6/a&3q6/h'A+..h'A+.. >$tGBJ"6"&tGBJ"6#7 8JD$ !^;;tTwFD;;tTwFD 8DEE H~((/J$))+4MFG#D$FJD$ 0ooo88D

+D88D

+D u}q99>%=D%=D
 :	 YY!^%5()D%5()D:q	% 	%
	@ 	@s   J0;5J=0J:=Kc                    d| j                         v rt        d      t        | d         t        | d         }}dD cg c]  }t        | d|           }}dD cg c]  }t        | d|           }}t	        j
                  ||ft        j                        }t	        j
                  ||ft        j                        }t        |      D ]n  }t        |      D ]^  }|d	   ||d
   |d	   z
  z  |z  z   ||d   |d	   z
  z  |z  z   |||f<   |d	   ||d
   |d	   z
  z  |z  z   ||d   |d	   z
  z  |z  z   |||f<   ` p ||fS c c}w c c}w )ab  Get 2D array of lat and lon for metadata dict in radar-coord.

    WARNING: This is a rough lat/lon value, NOT accurate!

    Parameters: meta : dict, including LENGTH, WIDTH and LAT/LON_REF1/2/3/4
    Returns:    lats : 2D np.array for latitude  in size of (length, width)
                lons : 2D np.array for longitude in size of (length, width)
    r   zJInput file is in geo-coordinates, use more accurate get_lat_lon() instead.r   r   )r   r4   r      LAT_REFLON_REFrI   r   r   r4   )r   r=   r   r   r   zerosr   range)	r   r#   r$   ir   r   r   r   js	            r   get_lat_lon_rdcr     s    DIIKdeeX'T']);EF09:1E$}%&:D:09:1E$}%&:D:
((F5>"**
5C
((F5>"**
5C6] \u 	\AAwDGd1g$5!6u!<<q$q'DQRGBS?TU[?[[C!HAwDGd1g$5!6u!<<q$q'DQRGBS?TU[?[[C!H	\\ 8O ;:s   EE	c                     t        | d         }t        | d         }t        | d         }t        | d         }t        | d         }t        | d         }|||z  z   }|||z  z   }||||fS )a	  Get the 4 corners coordinates from metadata dict in geo-coordinates.
    Parameters: atr - dict
    Returns:    south, north, west, east - float, in degrees or meters
    Examples:   S, N, W, E = ut.four_corners(atr)
                SNWE = ut.four_corners(atr)
    r   r   r   r   rS   r   )r   r   )	r   r$   r#   r   r   westnorthrv   easts	            r   four_cornersr     s     WEXFS]#HS]#H#i.!D#i.!EHv%%EHu$$D%t##r   c                     |j                  d      rd}|S ddg}ddg}t         fd|D              r/t        |D cg c]  }t        t	         |                c}      }not         fd|D              rYt	         d         t        j                  t        j                  d	            z  }t	         d         d
z  }t        ||g      dz  }nd}|dk\  rd}|S |dk\  rd}|S |dk\  rd}|S |dk\  rd}|S d}|S c c}w )a  Get the digit of the decimal place for the lat/lon info for display (e.g., at the status bar).

    Parameters: meta       - dict, metadata for the following attributes:
                             X_STEP
                             Y_STEP
                             RANGE_PIXEL_SIZE
                             AZIMUTH_PIXEL_SIZE
                coord_unit - str, coordinate unit, degree or meter
    Returns:    digit      - int, the digit for the decimal places of lat/lon
    meterr4   r   r   r   rZ   c              3   B   K   | ]  }|j                         v   y wr,   r   r   rk   r   s     r   r   z)get_lalo_digit4display.<locals>.<genexpr>(  s     7AqDIIK7   c              3   B   K   | ]  }|j                         v   y wr,   r   r   s     r   r   z)get_lalo_digit4display.<locals>.<genexpr>+  s     9adiik!9r      g?g     ^@g߼xV42?g{Gz?r   gMb`?r   g-C6*?   gh㈵>      )r   allminabsr   r   cosdeg2rad)	r   
coord_unitdigitgeo_step_keysrdr_step_keysrk   min_steprg_pix_sizeaz_pix_sizes	   `        r   get_lalo_digit4displayr    s2    W%4 L/ "8,+-AB 777GACd1g/GHH9=99%7 89BFF2::b><RRK%9 :;cAKK56>H "H  L 
 L	  L  L )*L% Hs   C9c                    d}d}|dz  }|dz  }dgdz  }t        t        |             D cg c]  }dgdz  
 }}| d   dz  | d   dz  z   }||z  }	d|z
  | d   dz  z  |z  }
|	|
z   |z
  dz  }||	z  |
z  d	|dz  z  z  }d|z   t        j                  |d
|z   z        z   dz  }|d|z   d|z  z   z  }t        j                  |dz  ||
z  z         }|||z   |
z
  z  d
|z  z  }t        j                  ||z   |dz  z         |z
  }|t        j                  |      z  ||z   z  }t        j                  | d   |      |d<   t        j                  | d   | d         |d<   ||z   dz
  t        j                  |dz  | d   dz  z         z  |z  |d<   t        j
                  |d         |d<   t        j
                  |d         |d<   |d   |d<   |d   }|d|z
  dz  z  }t        j                  t        j                  t        j                  |d               |dz  z  |dz  z        }t        j                  |      dz  |dz  z  t        j                  |      dz  |dz  z  z   }dt        j                  |      z  }||fS c c}w )a  Calculate satellite height and ellipsoid local radius from orbital state vector.

    This is a simplified version of the following functions from ISCE-2:
    + isce.isceobj.Planet.xyz_to_llh()
    + isce.isceobj.Ellipsoid.localRadius()

    Parameters: xyz    - tuple of 3 float, orbital state vector
    Reference:  height - float, satellite altitude in m
                radius - float, Earth radius in m
    g   @TXAgk{?r4   r   r   r   g      ?g      @g      @r   gUUUUUU?r   )r   rh   mathsqrtatan2degreesatantanradiansr   rL   )xyzrb   e2a2e4r_llhr   d_llhxy2pqrA   stuvwkDr^   blatgargradiuss                           r   xyz_to_local_radiusr   ?  s    	A	B 
AB	QBSUE!#c(O,qaSU,E,
a&!)c!fai
C	
A	bCFAI"A	
QrA
Q
b1a4i A	a$))AaL)	)g6A	R!Vbd]A		!Q$a- A
a!eaiBF#A		!a%!Q$,!#A	DIIcNa"f%Azz#a&!$E!Hzz#a&#a&)E!HBtyyAA	)9::Q>E!H||E!H%E!H||E!H%E!HQxE!H1XF 	
S2XOA99dhht||E!H56A=1DFD88D>1q!t#(9AqD(@
AC499S>!F6>5 -s   I9c                 b    |dk(  r| dz
  }n| dz   }|t        j                  |dz        dz  z  }|S )a3  Convert the azimuth angle of the LOS vector to the one of the orbit flight vector.
    Parameters: los_az_angle - np.ndarray or float, azimuth angle of the LOS vector from the ground to the SAR platform
                               measured from the north with anti-clockwise direction as positive, in the unit of degrees
    Returns:    orb_az_angle - np.ndarray or float, azimuth angle of the SAR platform along track/orbit direction
                               measured from the north with anti-clockwise direction as positive, in the unit of degrees
    rightZ        v@r   round)los_az_anglelook_directionorb_az_angles      r   los2orbit_azimuth_angler*    sC      #b(#b(BHH\D01D88Lr   c                 n    |dk(  r	| dz
  dz  }n| dz   dz  }|t        j                  |dz        dz  z  }|S )a  Convert azimuth angle from ISCE los.rdr band2 into satellite orbit heading angle

    ISCE-2 los.* file band2 is azimuth angle of LOS vector from ground target to the satellite
        measured from the north in anti-clockwise as positive

    Below are typical values in deg for satellites with near-polar orbit:
        ascending  orbit: heading angle of -12  and azimuth angle of 102
        descending orbit: heading angle of -168 and azimuth angle of -102
    r"  r#  rr   r$  r%  )az_angler(  
head_angles      r   azimuth2heading_angler.    sK      mr)
mr)
"((:,-44Jr   c                 n    |dk(  r	| dz
  dz  }n| dz   dz  }|t        j                  |dz        dz  z  }|S )zNConvert satellite orbit heading angle into azimuth angle as defined in ISCE-2.r"  r#  rr   r$  r%  )r-  r(  r,  s      r   heading2azimuth_angler0    sG     Or)Or)D)D00HOr   c                    ||t        |      }nt        d| d      | t        j                  t        j                  |            z  t        j                  t        j                  |            z  dz  |t        j                  t        j                  |            z  t        j
                  t        j                  |            z  z   |t        j
                  t        j                  |            z  z   }|S )a  Project east/north/up motion into the line-of-sight (LOS) direction defined by incidence/azimuth angle.
    Parameters: v_e        - np.ndarray or float, displacement in east-west   direction, east  as positive
                v_n        - np.ndarray or float, displacement in north-south direction, north as positive
                v_u        - np.ndarray or float, displacement in vertical    direction, up    as positive
                inc_angle  - np.ndarray or float, incidence angle from vertical, in the unit of degrees
                head_angle - np.ndarray or float, azimuth angle of the SAR platform along track direction
                             measured from the north with clockwise direction as positive, in the unit of degrees
                az_angle   - np.ndarray or float, azimuth angle of the LOS vector from the ground to the SAR platform
                             measured from the north with anti-clockwise direction as positive, in the unit of degrees
                             head_angle = 90 - az_angle
    Returns:    v_los      - np.ndarray or float, displacement in LOS direction, motion toward satellite as positive
    zinvalid az_angle: !rr   )r0  r   r   rL   r   r   )v_ev_nv_ur@   r-  r,  v_loss          r   enu2losr7    s     !,Z8H1(1=>> RVVBJJy122RVVBJJx<P5QQTVVRVVBJJy122RVVBJJx<P5QQRRVVBJJy1223E Lr   c                     | t        j                  t        j                  |            z  dz  |t        j                  t        j                  |            z  z   }|S )a  Project east/north motion into the radar azimuth direction.
    Parameters: v_e          - np.ndarray or float, displacement in east-west   direction, east  as positive
                v_n          - np.ndarray or float, displacement in north-south direction, north as positive
                orb_az_angle - np.ndarray or float, azimuth angle of the SAR platform along track/orbit direction
                               measured from the north with anti-clockwise direction as positive, in the unit of degrees
                               orb_az_angle = los_az_angle - 90 for right-looking radar.
    Returns:    v_az         - np.ndarray or float, displacement in azimuth direction,
                               motion along flight direction as positive
    rr   )r   rL   r   r   )r3  r4  r)  v_azs       r   en2azr:    sI     BFF2::l344r9BFF2::l3445DKr   c                 d    dt        j                  t        j                  | |            z  dz  }|S )aL  Calculate the azimuth angle of the given horizontal observation (in east and north)

    Parameters: east     - float,  eastward motion
                north    - float, northward motion
    Returns:    az_angle - float, azimuth angle in degree
                           measured from the north with anti-clockwise as positive
    rr   ih  )r   rad2degarctan2)r   r   r,  s      r    calc_azimuth_from_east_north_obsr>    s,     BJJrzz$677#=HOr   c                 
   g d}||vrt        d| d|       |dk(  r|t        d      d}|dv rt        j                  t        j                  |             t        j                  t        j                  |            z  dz  t        j                  t        j                  |             t        j                  t        j                  |            z  t        j                  t        j                  |             g}|S |d	v rt        j                  t        j                  |             t        j                  t        j                  |            z  dz  t        j                  t        j                  |             t        j                  t        j                  |            z  t        j
                  |       g}|S |d
v rSt        j
                  |       t        j
                  |       t        j                  t        j                  |             g}|S |dv rtt        |      }t        j                  t        j                  |            dz  t        j                  t        j                  |            t        j
                  |      g}|S |dv rg d}|S |dv rgt        j                  t        j                  |            dz  t        j                  t        j                  |            t        j
                  |      g}|S )a  Get the unit vector for the component of interest.
    Parameters: los_inc_angle - np.ndarray or float, incidence angle from vertical, in the unit of degrees
                los_az_angle  - np.ndarray or float, azimuth angle of the LOS vector from the ground to the SAR platform
                                measured from the north with anti-clockwise direction as positive, in the unit of degrees
                comp          - str, component of interest, choose among the following values:
                                enu2los, en2los, hz2los, u2los, up2los, orb(it)_az, vert, horz
                horz_az_angle - np.ndarray or float, azimuth angle of the horizontal direction of interest
                                measured from the north with anti-clockwise direction as positive, in the unit of degrees
    Returns:    unit_vec      - list(np.ndarray/float), unit vector of the ENU component for the component of interest
    )r7  en2loshz2loshorz2losu2losvert2losr:  hz2azorb_azorbit_azvertverticalhorz
horizontalzun-recognized comp input: z.
choose from: rJ  Nz'comp=horz requires horz_az_angle input!)r7  rr   )r@  rA  rB  )rC  rD  )r:  rE  rF  rG  )rH  rI  )r   r   r   )rJ  rK  )r   r   rL   r   r   
zeros_liker*  )los_inc_angler'  comphorz_az_anglecompsunit_vecr)  s          r   %get_unit_vector4component_of_interestrR    si   E 55dV;KE7STTv~-/BCC H{FF2::m,-rzz,7O0PPSUUFF2::m,-rzz,7O0PPFF2::m,-
L OA 
1	1FF2::m,-rzz,7O0PPSUUFF2::m,-rzz,7O0PPMM-(
> O3 
&	&MM-(MM-(FF2::m,-
0 O% 
9	9.|<FF2::l+,r1FF2::l+,MM,'
  O 
%	% O 
'	'FF2::m,-2FF2::m,-MM-(
 Or   g      c                 x    |\  }}t        j                  |       }|t        j                  ||z
  ||z
        z   }|S )zWrap data into a range.
    Parameters: data_in    : np.array, array to be wrapped
                wrap_range : list of 2 float, range to be wrapped into
    Returns:    data       : np.array, data after wrapping
    )r   r   mod)data_in
wrap_rangew0w1datas        r   wraprZ  .  s=     FB88GDtby"r'**DKr   c           	          t        j                  t        j                  d| z        t        j                  t        j                  d|z              z        }|S )a  Calculate the difference between two input wrapped phase.

    Parameters: pha1     - np.ndarray, (un)wrapped phase
                pha2     - np.ndarray / float, (un)wrapped phase
    Returns:    pha_diff - np.ndarray, wrapped phase difference for (pha1 - pha2)
    y             )r   angleexpconj)pha1pha2pha_diffs      r   diff_wrapped_phaserb  :  s?     xxsTz*RWWRVVC$J5G-HHIHOr   c                     t        j                  |       } g }t        | d      }t        j                  |       s:|j	                  |       | |z  } t        | d      }t        j                  |       s:|S )aH  Get all connected component with number of pixels larger than threshold
    Parameters: mask_in  : 2D np.array with zero as background and non-zero as foreground
                min_num_pixel : int/float, minimum number of pixels to be identified and output
    Returns:    mask_out : list of 2D np.array in np.bool_ format
         @)min_num_pixel)r   r   get_largest_conn_componentr   append)mask_inre  mask_outmask_ccs       r   get_all_conn_componentsrk  E  sj     hhwGH(DGffgX 7,WCH ffgX Or   c                 x   ddl m} ddlm} t	        j
                  | j                  t        j                        }|j                  |       d   }t	        j                  t	        j                  |j                               dd       }||k  r|S t	        j                  t	        j                  |j                               dd       dz   }||k(  }|rh|j                  ddddg      \  }	}
|
d   j                  |        |
d   j                  |       |
d	   j                  | |z         |j                          |S )
a  Extract the largest connected component from an 2D array
       with zero as background value
    Parameters: mask_in  : 2D np.array with zero as background and non-zero as foreground
                min_num_pixel : int/float, minimum number of pixels to be identified and output
                display : bool, display the result or not.
    Returns:    mask_out : 2D np.array in np.bool_ format
    r   N)ndimager   r      r   )nrowsncolsfigsizer4   )matplotlib.pyplotpyplotscipyrm  r   r   shapebool_labelmaxbincountflattenargmaxsubplotsimshowshow)rh  re  displaypltrm  ri  labels	num_pixel	max_label_axs              r   rf  rf  U  s     $xxrxx0H]]7#A&Fr{{6>>#34QR89I= 		"++fnn&67;<q@I"H1AAw?2
1W
1X
1Wx'(
Or   c                    ddl m} ddlm} t	        j
                  | dk7        \  }}t	        j                  |j                  dd      |j                  dd      f      } ||      }t	        j
                  |dk7        \  }}t	        j                  |j                  dd      |j                  dd      f      }	|j                  |	      \  }
}t	        j                  |
      }|	|   }|||      }|
|   }|r]|j                          |j                  | dz  |dz  z          |j                  |d   |d   g|d   |d   gd       |j                          |||fS )at  Calculate the min distance between two regions of pixels marked by mask1 and mask2
    Parameters: mask1/2 : 2D np.array in size of (length, width) in np.bool_ format
    Returns:    pts1 : tuple of 2 int, bridge point in mask1, in (x, y)
                pts2 : tuple of 2 int, bridge point in mask2, in (x, y)
                min_dist : float, min euclidean distance
    r   N)cKDTreerr   r   r4   z-o)rr  rs  scipy.spatialr  r   wherehstackreshapequeryargminfigurer}  plotr~  )mask1mask2r  r  r  r   rk   pts1treepts2distidxidx_minr  xy1min_dists                   r   min_region_distancer  q  s5    $%88EQJDAq99aiiA&		"a(89:D4=D88EQJDAq99aiiA&		"a(89:D

4 ID#iioG
w-C
s7|
CG}H



519uqy()#a&#a&!CFCF#3T:
Xr   c           	         ddl m} | j                  }t        j                  |d         t        j                  |d         f} ||| |d      }t        j
                  t        j                  d|d   dz
  |d   d      t        j                  d|d   dz
  |d   d            \  }}t        j                  |j                  dd      |j                  dd      f      }	 ||	      j                  |      }
|
S )a  Interpolate input 2D matrix into different shape.

    Used to get full resolution perp baseline from ISCE coarse grid baseline file.

    Parameters: in_data       : 2D np.ndarray
                out_shape     : tuple of 2 int in (length, width)
                interp_method : string, choose in [nearest, linear, cubic]
    Returns:    out_data      : 2D np.ndarray in out_shape
    r   )RegularGridInterpolatorr   F)methodbounds_error)r7   rr   )	scipy.interpolater  ru  r   arangemeshgridr   r  r  )in_data	out_shapeinterp_methodr  in_shapein_ptsinterp_funcxxyyout_ptsout_datas              r   interpolate_datar    s     : }}Hii$bii&<=F)	K [[QAy|eTQAy|eTVFBiiB*BJJr1,=>?G 7#++I6HOr   c                     ddl m}m} |\  }}|j                  d||fd      }|j	                  |      j                  | dd       t        j                  |t        j                        }|S )ar  Create a 2D mask (numpy array in binary) from a polygon.

    Link: https://stackoverflow.com/questions/3654289/scipy-create-2d-polygon-mask
    Parameters: polygon - list of tuples of 2 int, e.g. [(x1, y1), (x2, y2), ...]
                shape   - list/tuple of 2 int, for length and width
    Returns:    mask    - 2D np.ndarray in bool in size of (length, width)
    r   )Image	ImageDrawLr   )outlinefillrI   )	PILr  r  newDrawr   r   r   rv  )r   ru  r  r  r#   r$   imgmasks           r   polygon2maskr    s]     %MFE
))C%!
,CNN3;88Crxx(DKr   c                 z    |\  }}t         j                  | ||z
  |  || z
  f   \  }}|dz  |dz  z   |dz  k  }|S )z5Get mask of pixels within circle defined by (x, y, r)r4   )r   ogrid)	rk   r   r  ru  r#   r$   r  r  cmasks	            r   get_circular_maskr    sZ    MFEXXqbkbqj! "FBURU]fai'ELr   c                    t        | d         }t        | d         }t        |t              r|}n3t        |t              r|}n |j	                  dd      j                         }|D cg c]  }t        |       }}	 t        |d         }t        |d         }t        t        |d               }t        d|||fz         t        j                  | ||z
  | ||z
  f   \  }}|dz  |dz  z   |dz  k  }|S c c}w #  	 t        |d         }	t        |d         }
t        t        |d               }t        j                  |	t        | d	         z
  t        | d
         z        }t        j                  |
t        | d         z
  t        | d         z        }t        dj                  |	|
|             n7#  t        d|z          t        d       t        d       t        d       Y Y yxY wY /xY w)a  Return Index of Elements within a Circle centered at input pixel
    Parameters: atr : dictionary
                    containing the following attributes:
                    WIDT
                    LENGTH
                circle_par : string in the format of 'y,x,radius'
                    i.e. '200,300,20'          for radar coord
                         '31.0214,130.5699,20' for geo   coord
    Returns:    idx : 2D np.array in bool type
                    mask matrix for those pixel falling into the circle
                    defined by circle_par
    Examples:   idx_mat = ut.circle_index(atr, '200,300,20')
                idx_mat = ut.circle_index(atr, '31.0214,130.5699,20')
    r   r   r   r   r   r   r4   z+Input circle index in y/x coord: %d, %d, %dr   r   rS   r   z7Input circle index in lat/lon coord: {:.4f}, {:.4f}, {}z*
ERROR: Unrecognized circle index format: zSupported format:z4--circle 200,300,20            for radar coord inputz5--circle 31.0214,130.5699,20   for geo   coord input
)r   r   r   r   replacesplitrK   r   r   r   rintformatr  )r   
circle_parr$   r#   cir_parr   c_yc_xr  c_latc_lonr   rk   r  s                 r   circle_indexr    s     GEXF*e$	J	%$$S#.446&'!s1v'G''!*o'!*oU71:&';sC>PPQ" 88SDOcT%)^34DAq
Q$A+
"CJ5 (	'!*%E'!*%Ewqz*+F''5s9~!66%H:NNOC''5s9~!66%H:NNOC ''-veUF'CE	?
JK%&HIJKEs2   'C7<AC< <G/?B5F54G/51G)&G/)G/c                     t        t        | dz               j                         j                         }|d   dk(  ry|d   dk(  ryt	        d      S )zHgarrettdreyfus on Github: https://gist.github.com/garrettdreyfus/8153571z (y/n): r   r   TnFzUhhhh... please enter )rK   inputlowerstrip	yes_or_no)questionreplys     r   r  r    sP    hz)*+11399;EQx3	qS122r   c                     | j                         D ]R  }t        | |         }||j                         v r|t        ||         k(  r|dk7  r:||j                         vr|dk(  rR y y)z)Compare new attributes with existing onesNoneTF)r   rK   )atr_newatr_origkeyvalues       r   update_attribute_or_notr    sf    ||~ GCL!'ES#5G,GEU[Ox}}.5F?	
 r   c                 H   d }t         j                  j                  |       d   r ||       r| S yt         j                  d   j                  t         j                        D ]?  }|j                  d      }t         j                  j                  ||       } ||      s=|c S  y)zTest if executable existsc                     t         j                  j                  |       xr$ t        j                  | t         j                        S r,   )rc   rd   re   accessX_OK)fpaths    r   is_exezwhich.<locals>.is_exe  s)    ww~~e$B5"'')BBr   r   PATH"N)rc   rd   r  environpathsepr  r   )programr  rd   exe_files       r   whichr    s    C 
ww}}Wa '?N  JJv&,,RZZ8 	 D::c?Dww||D'2Hh		 
 r   c                    d}| dk  rd}|rt        d       d|ddfS 	 ddlm}m} t	        t        j                         | |      }|dk  r.d}t        d
       t        dt        j                                 n|rt        d|z         	 ||||fS #  t        d       t        d	       d}d|ddfcY S xY w#  ||ddfcY S xY w)aE  Check parallel option based file num and installed module
    Link: https://joblib.readthedocs.io/en/latest/parallel.html
    Examples:
        num_cores, inps.parallel, Parallel, delayed = ut.check_parallel(len(file_list))
        Parallel(n_jobs=num_cores)(delayed(subset_file)(file, vars(inps)) for file in file_list)
    Tr   Fz2parallel processing is disabled for one input fileNr   )ParalleldelayedzCan not import joblibzparallel is disabled.zNparallel processing is disabled because min of the following two numbers <= 1:z&available cpu number of the computer: z&parallel processing using %d cores ...)r   joblibr  r  r   rc   	cpu_count)file_numr    maxParallelNumenable_parallelr  r  	num_coress          r   check_parallelr  +  s     O 1}FG/4--., BLLNHn=IA~^_6r||~6FGH	6)DE6/8W<<!.%&%&/4--6/455s   B 	B4  B14B>c                 z    | }|D ])  }|j                  d      sd|v r
|d| dz  }"|d| z  }+ t        |       y)zprint the command line with "" for arguments containing *.

    Parameters: script_name - str, e.g. prep_isce.py
                args        - list(str), list of input arguments
    -*z "r  r   N)r   r   )script_namer.   cmdr  s       r   print_command_liner  S  sZ     C  ~~c"sczRuA;CQse9C 
#J
r   c                    t        j                  |       } | j                  dkD  r!| j                  d   }| j	                  |d      } |[t        j
                  | d      }| j                  dk(  r5t        j                  |j	                  dd      d| j                  d   f      }t        j
                  t        j                  | |z
        d      |z  }|S )a  Compute the median absolute deviation (MAD) of the data along the LAST axis.

    This function is also available in the following packages:
    + statsmodels.robust.mad()
      https://www.statsmodels.org/dev/generated/statsmodels.robust.scale.mad.html
    + scipy.stats.median_abs_deviation() since v1.5.0
      https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.median_abs_deviation.html

    The implementation here is preferred because we would like to:
    1. omit the NaN value in the data for the median and MAD calculation
    2. scale the returned value to be comparable with standard deviation (STD)
       for easy interpretation with 1/2/3-sigma rule.
    While statsmodels could not handle the NaN value in the data; and scipy does not hebave
    as desired in the default setting (propagate nan and do not scale).

    The following two are equivalent for a 2D np.ndarray X:
    + mintpy.utils.utils0.median_abs_deviation(X)
    + scipy.stats.median_abs_deviation(X, axis=-1, center=np.nanmedian, scale=0.67449, nan_policy='omit')

    Parameters: data   - 1/2D np.ndarray, input array
                center - 0/1D np.ndarray or None
                scale  - float, the normalization constant
    Returns:    mad    - 0/1D np.ndarray
    r4   r   rr   )axisr   )r   r   r   ru  r  	nanmedianr   r   )rY  centerscalentimemads        r   median_abs_deviationr  g  s    4 88D>Dyy1}

1||E2& ~d, 99>WWV^^B2Q

14FGF ,,rvvdVm,2
6
>CJr   c                 ^    |t        j                  |       }t        | |      }|||z  z   }|S )zvcalculate rms_threshold based on the standardized residual

    Outlier detection with median absolute deviation.
    )r  )r   r  r  )rY  r  cutoffr  	thresholds        r   median_abs_deviation_thresholdr     s7    
 ~d#
tF
3C#%Ir   c                    t        j                  |       j                         } |gt        j                  |      j                         }| j                  |j                  k7  r&t	        d| j                   d|j                   d      | |z  } | t        j
                  |           } t        j                  t        j                  | dz        | j                  dz
  z        }|S )z5Calculate the root-mean-square error between x and y.z!Input x & y have different size: z vs. r2  r4   r   )r   r   rz  sizer   isnanr  sum)rk   r   rmses      r   root_mean_sq_errorr    s     	A}HHQK!66QVV@affXUVWXX	Q 	
288A;,A77266!Q$<166A:./DKr   c           	          t        t        j                  t        j                  t	        |                         }t        | |       }|| k\  r|}|S |d|z  z   }|S )z@Return the most significant digit of input number and ceiling it
   r   r   floorlog10r   r&  )rk   r   x_roundx_ceils       r   	ceil_to_1r    sX    #a&)*+EAvG!| M 2u9$Mr   c           	          t        t        j                  t        j                  t	        |                         }t        | |       S )z1Return the most significant digit of input numberr	  )rk   r   s     r   
round_to_1r    s1    #a&)*+EUFr   c                 |    t        j                  |       dz  dz  dz   }|j                  t         j                        S )zfRound a float up to the next odd integer .
    Link: https://stackoverflow.com/questions/31648729
    r4   r   )r   ceilastypeint16)rk   r   s     r   round_up_to_oddr    s2     	
a!aA88BHHr   c                     t        j                  dt        j                  t        j                  |                   }t        j                  |      }|S )z7Given a number x, find the highest power of 2 that <= xr4   )r   powerr
  log2r  )rk   ress     r   highest_power_of_2r    s5    
((1bhhrwwqz*
+C
((3-CJr   c                     ddl m}  ||       }|j                  |      D cg c]  }|d   	 }}|dk(  r|d   }|S c c}w )zReturn the k most common item in the list L.
    Examples:
        5, 8 = most_common([4,5,5,5,5,8,8,8,9], k=2)
        'duck' = most_common(['goose','duck','duck','dog'])
        'goose' = most_common(['goose','duck','duck','goose'])
    r   )Counterr   )collectionsr  most_common)r  r  r  cntr   item_mms         r   r  r    sJ     $
!*C __Q/0qt0G0Av!*N 1s   <c                 :    	 t        |        y# t        $ r Y yw xY w)a	  Check string is a number.
    Not using str.isnumeric() because it can not handle floating point nor negative sign.
    Link: https://elearning.wsldp.com/python3/python-check-string-is-a-number/
    Parameters: string - str, a string
    Returns:    True/False
    TF)r   r   )strings    r   	is_numberr#    s#    f s    	)r4   T)Nr4   T)Fr,   )NNr4   r   r   )r   )r"  )NN)r7  N)rd  )rd  F)linear)r   T   )NgLTol?)Ng      @)r   ):__doc__r  rc   r   numpyr   SPEED_OF_LIGHTr2   Kr   r)   rG   rQ   rU   r`   rm   r~   r   r   r   r   r   r   r   r   r  r   r*  r.  r0  r7  r:  r>  rR  r;   rZ  rb  rk  rf  r  r  r  r  r  r  r  r  r  r  r  r   r  r  r  r  r  r  r#  r-   r   r   <module>r*     s<   ,&  	   	2&.RIX F	*6,*<82
L^4$$'V.J$8 	BN ""%%i/ 	 8@B$3p3"%6P(*Z	 	r   