B
    Qa>x                 @   s  d dl Z d dlZd dlZd dlmZ d dlmZ d dl	m
Z
mZmZ dZdZdZdUd	d
ZdVddZdd ZdWddZdd ZdXddZdd Zdd ZdYddZdd Zdd Zd d! ZdZd"d#Zd$d% Zd&d' Zd(d) Zd*ej  ej gfd+d,Z!d[d.d/Z"d\d0d1Z#d]d2d3Z$d^d5d6Z%d7d8 Z&d9d: Z'd;d< Z(d=d> Z)d_dAdBZ*d`dDdEZ+dadGdHZ,dbdIdJZ-dKdL Z.dMdN Z/dOdP Z0dcdQdRZ1dSdT Z2dS )d    N)ndimage)CRSProjTransformeriJxg    MXAgHz'D@   Tc             C   s   d|   kr$|dkr$d}|r$td t| d t| d  }}t| d t| d  }}|||d   }|| d	 }|rtd
|  td|  td|  |dkrt|tjS tj|||d}	|dkrt|	tjS t|	|df}
t|
tjS d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WIDTH   g       @znear   range : %.2f mzcenter range : %.2f mzfar    range : %.2f m)numN)	keysprintfloatintnparrayfloat32linspacetile)atr	dimension	print_msgrange_ndRlengthwidthrange_fZrange_cZrange_xZrange_xy r   I/home/centos/operations/rsmas_insar/sources/MintPy/mintpy/utils/utils0.pyrange_distance    s&    r!   c          	   C   s  d|   kr$|dkr$d}|r$td t| d }t| d }t| d }t| d }t| d }|||  }	tjt|d	 |d	  || d	  d	| |   d
 tj }
tjt|d	 |	d	  || d	  d	| |	   d
 tj }|
| d }|r$td|
 td| td| |dkr4|}n|dkrVtj|
||dtj	d}n|d	krt| d }|dk	rt
| d	dd}tjt|| d	 |d	  || d	  d	||  |   d
 tj }n"ttj|
||dtj	d|df}ntd||S )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
                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)
    r   r   z9input file is geocoded, return center incident angle onlyr   r	   EARTH_RADIUSHEIGHTr   r   g     f@g       @z&near   incidence angle : {:.4f} degreez&center incidence angle : {:.4f} degreez&far    incidence angle : {:.4f} degreer   FALSE)r   endpointdtyper
   NF)r   r   z un-supported dimension input: {})r   r   r   r   r   piarccosformatr   r   r!   r   	Exception)r   demr   r   r   r   rHr   r   Zinc_angle_nZinc_angle_fZinc_angle_c	inc_angler   
range_distr   r   r    incidence_angleI   s>    >>




Hr0   c             C   s   t |trt|}tj|tjdd tj }t| d }t| d }|| ttj|  }t|| }|| }|t| }|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
    )r&      r"   r#   )	
isinstancestrr   r   r   r   r'   sinarcsin)r   r.   r,   r-   ZR2Z
look_angleZrange_angler/   r   r   r    $incidence_angle2slant_range_distance   s    
r6   Fc             C   sJ   d|   krtd dS t| d|d}t| d t|d tj  }|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   )r   r   r	   g     f@)r   r   r0   r   r   r4   r'   )r   r   r.   Zrg_stepr   r   r    range_ground_resolution   s     r8   c             C   s   d|   krtd dS y| d }W n   d}Y nX |dkrpt| d }t| d }t| d	 | ||  }n|d
krt| d	 }|S )zmGet azimuth resolution on the ground in meters,
        from ROI_PAC attributes, for file in radar coord
    r7   z7Input file is in geo coord, no azimuth resolution info.N	PROCESSORisce)roipacr:   r"   r#   AZIMUTH_PIXEL_SIZEgamma)r   r   r   )r   procReheightZaz_stepr   r   r    azimuth_ground_resolution   s    
rA   c          
   C   s   | sdS t | tr| g} dd | D } xF| D ]>}tj|r,t|d t|| td|  W dQ R X q,W t| dkr| d } | S )a  python equivalent function to Unix utily - 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
    Nc             S   s   g | ]}|d k	r|qS )Nr   ).0xr   r   r    
<listcomp>   s    ztouch.<locals>.<listcomp>aztouch r   r   )	r2   r3   ospathisfileopenutimer   len)Z
fname_listtimesfnamer   r   r    touch   s    

rN   c             C   s6   t dt| dd | d dkd}| d }|S )zConvert UTM Zone string to EPSG code.
    Parameters: utm_zone - str, atr['UTM_ZONE']
    Returns:    epsg     - str, EPSG code
    Examples:   epsg = utm_zone2epsg_code('11N')
    ZutmNS)Zprojzonesouthr   )r   Z	from_dictr   Zto_authority)Zutm_zoneZcrsZepsgr   r   r    utm_zone2epsg_code   s
    rS   c       	      C   st   ddl m} || }| }| s<|ddkr<||fS t| }td}t	||}|
||\}}||fS )a  Convert x, y in the projection coordinates of the file to lon/lat 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, coordiantes in x and y direction
    Returns:    y/x    - scalar or 1/2D np.ndarray, coordinates in latitutde and longitude
    r   )gdalunitdegreez	epsg:4326)osgeorT   OpenZGetSpatialRefZIsProjectedGetAttrValuer   GetProjectionr   Z	from_proj	transform)	infilerC   yrT   dssrsZp_inZp_outZtransformerr   r   r    	to_latlon   s    

r`   c          	   C   s  t | d t | d  }}|dkr.dd||f}g }|dk	r^t|d}t| }W dQ R X d|krt|dV}|d |d |d |d |d	 f }|d
 |d |d |d |d	 f }	W dQ R X n$d|  krt| d }
t| d }t| d |
|d d   }t| d ||d d   }|d |d  }|d	 |d  }||
|d   }|||d   }|d	krtj|||d |||d f \}}	n>|dkrtj|||dd}tj|||dd}	nt	d
|nd}|d7 }t	|tj|tjd}tj|	tjd}	||	fS )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)
    Returns:    lats : 2D np.array for latitude  in size of (length, width)
                lons : 2D np.array for longitude in size of (length, width)
    r
   r   Nr   r,   latituder      r   	longituder   Y_STEPX_STEPg      ?r7   y              ?T)r   r%   zun-supported dimension = {}zCan not get pixel-wise lat/lon!z]
meta dict is not geocoded and/or geometry file does not contains latitude/longitude dataset.)r&   )r   h5pyFilelistr   r   r   mgridr   
ValueErrorr)   r   r   )meta	geom_fileboxr   r   r   ds_listflatslonslat_steplon_steplat0Zlon0Zlat_numZlon_numlat1Zlon1msgr   r   r    get_lat_lon  sB    (6

rw   c       	         s&  d   krtdt d t d  }} fdddD } fdddD }tj||ftjd	}tj||ftjd	}xt|D ]}xt|D ]}|d
 ||d |d
   |  ||d |d
   |  |||f< |d
 ||d |d
   |  ||d |d
   |  |||f< qW qW ||fS )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   c                s   g | ]}t  d | qS )z	LAT_REF{})r   r)   )rB   i)rk   r   r    rD   a  s    z#get_lat_lon_rdc.<locals>.<listcomp>)r   r   rb      c                s   g | ]}t  d | qS )z	LON_REF{})r   r)   )rB   rx   )rk   r   r    rD   b  s    )r&   r   r   r   )r   r*   r   r   zerosr   range)	rk   r   r   rp   rq   latlonrx   jr   )rk   r    get_lat_lon_rdcT  s    	@Hr   c             C   s"   d|  }|t |d d 8 }|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
    Z   g     v@)r   round)az_angle
head_angler   r   r    azimuth2heading_anglen  s    
r   c             C   s"   d|  }|t |d d 8 }|S )zNConvert satellite orbit heading angle into azimuth angle as defined in ISCE-2.r   g     v@)r   r   )r   r   r   r   r    heading2azimuth_angle}  s    r   c             C   s   |dkr|dk	rt |}|dkr(td|tjd 9 }|tjd 9 }| t| t| d |t| t|  |t|  }|S )a/  
    Parameters: e          - np.ndarray or float, displacement in east-west direction, east as positive
                n          - np.ndarray or float, displacement in north-south direction, north as positive
                u          - np.ndarray or float, displacement in vertical direction, up as positive
                inc_angle  - np.ndarray or float, local incidence angle from vertical
                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 line-of-sight direction, moving toward satellite as positive

    Typical values in deg for satellites with near-polar orbit:
        For AlosA: inc_angle = 34, head_angle = -12.9,  az_angle = 102.9
        For AlosD: inc_angle = 34, head_angle = -167.2, az_angle = -102.8
        For  SenD: inc_angle = 34, head_angle = -168.0, az_angle = -102.0
    Nzaz_angle can not be None!g     f@rO   )r   rj   r   r'   r4   cos)enur.   r   r   Zv_losr   r   r    enu2los  s    Br   c       	      C   sl   t | d }t | d }t| d }t| d }t| d }t| d }|||  }|||  }||||fS )zReturn 4 corners lat/lonr   r
   re   rd   r7   r   )r   r   )	r   r   r   rs   rr   ZwestnorthrR   eastr   r   r    four_corners  s    r   c       	      C   sJ   |\}}t j| || |  ||  f \}}|d |d  |d k}|S )z5Get mask of pixels within circle defined by (x, y, r)r   )r   ogrid)	rC   r]   radiusshaper   r   yyxxcmaskr   r   r    get_circular_mask  s
    r   c          	   C   s  t | d }t | d }t|tr(|}n t|tr8|}n|dd }dd |D }y>t |d }t |d }t t|d	 }td
|||f  W n   yt|d }t|d }	t t|d	 }t	|t| d  t| d  }t	|	t| d  t| d  }td
||	| W n.   td|  td td td dS Y nX tj| || | || f \}
}|d	 |
d	  |d	 k}|S )a  Return Index of Elements within a Circle centered at input pixel
    Parameters: atr : dictionary
                    containging 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
   , c             S   s   g | ]}t |qS r   )r3   )rB   rx   r   r   r    rD     s    z circle_index.<locals>.<listcomp>r   r   r   z+Input circle index in y/x coord: %d, %d, %dr   rd   r7   re   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   r2   tuplerh   replacesplitr   r   r   rintr)   r   )r   Z
circle_parr   r   Zcir_parZc_yZc_xr   Zc_latZc_lonr]   rC   idxr   r   r    circle_index  s>    

""
&r   g      c             C   s.   |\}}t | }|t || ||  }|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)Zdata_inZ
wrap_rangeZw0Zw1datar   r   r    wrap  s    
r        @c             C   sN   t | } g }t| dd}x.t | sH|| | |N } t| dd}qW |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
    g     @)min_num_pixel)r   r   get_largest_conn_componentallappend)mask_inr   mask_outZmask_ccr   r   r    get_all_conn_components  s    

r   c       	      C   s   t | jt j}t| d }t t | dd }||k rF|S t 	t | dd d }||k}|rt
jddddgd\}}|d |  |d | |d | |A  t
  |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   r   Nrb         )nrowsncolsZfigsizer   )r   rz   r   bool_r   labelmaxbincountflattenargmaxpltZsubplotsimshowshow)	r   r   displayr   labels	num_pixel	max_labelZfigaxr   r   r    r     s     r   c             C   s  ddl m} t| dk\}}t|dd|ddf}||}t|dk\}}t|dd|ddf}||\}	}
t|	}|| }||
|  }|	| }|rt	  t
| d |d   t|d |d g|d |d gd t  |||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   )cKDTreerO   r   r   z-o)Zscipy.spatialr   r   wherehstackreshapequeryargminr   Zfigurer   plotr   )mask1mask2r   r   r]   rC   Zpts1treeZpts2distr   Zidx_minZxy2Zxy1Zmin_distr   r   r    min_region_distance,  s"    
&r   linearc       
   	   C   s   ddl m} | j}t|d t|d f}ttjd|d d |d ddtjd|d d |d dd\}}t|dd|ddf}||| |dd||}	|	S )aa  Interpolate input 2D matrix into different shape.
    Used to get full resolution perp baseline from ISCE coarse grid baseline file.
    Parameters: inData : 2D array
                outShape : tuple of 2 int in (length, width)
                interpMethod : string, choose in [nearest, linear, cubic]
    Returns:    outData : 2D array in outShape
    r   )RegularGridInterpolatorr   F)r%   rO   )methodZbounds_error)	Zscipy.interpolater   r   r   arangemeshgridr   r   r   )
ZinDataZoutShapeZinterpMethodZRGIZinShapeZinPtsr   r   ZoutPtsZoutDatar   r   r    interpolate_dataJ  s     $r   c             C   sT   ddl m}m} |\}}|d||fd}||j| ddd tj|tjd}|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   )Zoutlinefill)r&   )	ZPILr   r   newZDrawpolygonr   r   r   )r   r   r   r   r   r   imgmaskr   r   r    polygon2mask]  s    r   c             C   sD   t t| d   }|d dkr(dS |d dkr8dS tdS dS )	zHgarrettdreyfus on Github: https://gist.github.com/garrettdreyfus/8153571z (y/n): r   r]   Tr   FzUhhhh... please enter N)r3   inputlowerstrip	yes_or_no)ZquestionZreplyr   r   r    r   q  s    r   c             C   sh   d}x^|   D ]R}t| | }||  krB|t|| krB|dksV||  kr\|dkr\t qd}qW |S )z)Compare new attributes with exsiting onesFNoneT)r   r3   next)Zatr_newZatr_origupdatekeyvaluer   r   r    update_attribute_or_not|  s    $r   c             C   sj   dd }t j| d r&|| rf| S n@x>t jd t jD ](}|d}t j|| }||r:|S q:W dS )zTest if executable existsc             S   s   t j| ot | t jS )N)rF   rG   rH   accessX_OK)fpathr   r   r    is_exe  s    zwhich.<locals>.is_exer   PATH"N)rF   rG   r   environpathsepr   join)programr   rG   Zexe_filer   r   r    which  s    
r   r      c             C   s   d}| dkr(d}|rt d d|ddfS yddlm}m} W n&   t d t d	 d}d|ddfS tt | |}|dkrd}t d
 t dt  n|rt d|  y||||fS    ||ddfS dS )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   Fz1parallel processing is diabled 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   Zjoblibr   r   minrF   	cpu_countr)   )Zfile_numr   maxParallelNumZenable_parallelr   r   	num_coresr   r   r    check_parallel  s0    r   LTol?c             C   s   t | } | jdkr*| jd }| |d} |dkr@t j| dd}| jdkrht |ddd| jd f}t jt | | dd| }|S )a  Compute the median absolute deviation of the data along the LAST axis.

    This function is also included as:
        scipy.stats.median_abs_deviation() in scipy v1.5.0
            https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.median_abs_deviation.html
        statsmodels.robust.mad() in statsmodels
            https://www.statsmodels.org/dev/generated/statsmodels.robust.scale.mad.html

    The differences are:
        1. scipy: out = out / scale while mintpy: out = out * scale
        2. scipy propagates nan by default, while mintpy omit nan by default.

    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=1./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
    r   r   rO   N)axisr   )r   r   ndimr   r   	nanmedianr   abs)r   centerscaleZntimemadr   r   r    median_abs_deviation  s    



r         @c             C   s.   |dkrt | }t| |d}|||  }|S )zvcalculate rms_threshold based on the standardised residual

    Outlier detection with median absolute deviation.
    N)r   )r   r   r   )r   r   cutoffr   	thresholdr   r   r    median_abs_deviation_threshold  s
    
r   c             C   s~   t |  } |dk	rLt | }| j|jkrDtd| j|j| |8 } | t |   } t t | d | jd  }|S )z5Calculate the root-mean-square error between x and y.Nz+Input x & y have different size: {} vs. {}!r   r   )	r   r   r   sizerj   r)   isnansqrtsum)rC   r]   Zrmser   r   r    root_mean_sq_error  s    r  c             C   sB   t ttt| }t| | }|| kr2|}n|d|  }|S )z@Return the most significant digit of input number and ceiling it
   )r   r   floorlog10r   r   )rC   digitZx_roundZx_ceilr   r   r    	ceil_to_1  s    r  c             C   s$   t ttt| }t| | S )z1Return the most significant digit of input number)r   r   r  r  r   r   )rC   r  r   r   r    
round_to_1  s    r	  c             C   s&   t dt t | }t |}|S )z7Given a number x, find the highest power of 2 that <= xr   )r   powerr  log2int16)rC   resr   r   r    highest_power_of_2  s    
r  c             C   s<   ddl m} || }dd ||D }|dkr8|d }|S )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   )Counterc             S   s   g | ]}|d  qS )r   r   )rB   rx   r   r   r    rD   )  s    zmost_common.<locals>.<listcomp>r   )collectionsr  most_common)r   kr  cntZitem_mmr   r   r    r     s    r  c             C   s&   yt |  dS  tk
r    dS X dS )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
    TFN)r   rj   )stringr   r   r    	is_number/  s
    r  )r   T)Nr   T)F)N)NNr   )NN)r   )r   F)F)r   )r   Tr   )Nr   )Nr   )N)r   )3rF   rf   numpyr   Zmatplotlib.pyplotZpyplotr   scipyr   Zpyprojr   r   r   SPEED_OF_LIGHTr"   Kr!   r0   r6   r8   rA   rN   rS   r`   rw   r   r   r   r   r   r   r   r'   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r	  r  r  r  r   r   r   r    <module>   sT   
)
B#


>
%	8




*
'


