
    7f7U                        d dl Z d dlZd dlZd dlZd dlZd dlmZmZ d dlmZ d dl	Z	d dl
Z
d dlZd dlZd dlZd dlZd dlmZ d dlZd dlmZ d Zd Zdgd	gfd
Zd ZddZddZd Zd Zd Zd Z d Z!ddZ"d Z#d Z$ddZ%ddZ&y)    N)datetimedate)relativedelta)cm)PATH_JETSTREAMc                 |   | t        j                  |       ryt        |       t        k(  r	 t	        j
                  | d      }n| }|j                  }|j                         j                  }|dz  dk(  r|dz  dk7  s|dz  dk(  rd}nd	}||d
z
  |z  z   }t        |d      }|S #  t	        j
                  | d      }Y vxY w)aN  
    Converts a date string or date object to a decimal year.

    Parameters:
    date_str (str or datetime.date): The date string in the format 'YYYY-MM-DD' or a datetime.date object.

    Returns:
    float: The decimal year representation of the input date.

    Example:
    >>> date_to_decimal_year('2022-01-01')
    2022.0
    N%Y-%m-%d%Y%m%d   r   d   i  g     v@g     v@   )
pdisnatypestrr   strptimeyear	timetupletm_ydayround)date_strdate_objr   day_of_yeardays_in_yeardecimal_years         P/home/exouser/operations/rsmas_insar/tools/Precip/src/precip/helper_functions.pydate_to_decimal_yearr      s     2778,H~	=((:>H ==D$$&..K 	qA$*/tczQ ;?l::Lq)L'	=((8<Hs   B! !B;c                     	 t        t         | j                  d            \  }}}t        j                  ||      d   }|S #  | j                  | j                  }}Y 7xY w)a)  
    Get the number of days in a given month.

    Args:
        date (str or datetime.date): The date in the format "YYYY-MM-DD" or a datetime.date object.

    Returns:
        int: The number of days in the month.

    Raises:
        ValueError: If the date is not in the correct format.

    -r   )mapintsplitr   monthcalendar
monthrange)r   r   r#   daynum_dayss        r   days_in_monthr(   >   sZ    ,sJDJJsO4eS ""4/2HO,iies   $A Afffff~f|Vc                    	 t        j                  t        j                  | d   | d   d      d      }t        j                  t        j                  |d   |d   d      d      }||fS #  t        j                  t        j                  | d   dd      d      }t        j                  t        j                  |d   dd      d      }Y ||fS xY w)a   
    Generate an array of coordinates based on the given longitude and latitude ranges.

    Args:
        longitude (list, optional): A list containing the minimum and maximum longitude values. Defaults to [-179.95].
        latitude (list, optional): A list containing the minimum and maximum latitude values. Defaults to [-89.95].

    Returns:
        tuple: A tuple containing the generated longitude and latitude arrays.

    The default list generated is used to reference the indexes of the precipitation array in the netCDF4 file.
    r   r   g?   gf@g33333V@)npr   arange)	longitudelatitudelonlats       r   generate_coordinate_arrayr3   V   s    >hhryy1y|SA1Ehhryy!hqk3?C 8O	>hhryy1vs;Q?hhryy!eS91=8Os   A"A( (ACc                 j   t        |t              st        |t              r||g}t        | t              st        | t              r| | g} t        t	        |             D ]]  }t        t        | |         dz        dz  }d|cxk  rdk  r)n t        d	      |dkD  rdnd}t        ||z   d      | |<   Tt        d	       t        t	        |            D ]]  }t        t        ||         dz        dz  }d
|cxk  rdk  r)n t        d      |dkD  rdnd}t        ||z   d      ||<   Tt        d       | |fS )a  
    Adjusts the latitude and longitude coordinates to ensure they fall within the valid range (GPM dataset resolution).

    Parameters:
    latitude (float or str or list): The latitude coordinate(s) to be adjusted.
    longitude (float or str or list): The longitude coordinate(s) to be adjusted.

    Returns:
    tuple: A tuple containing the adjusted latitude and longitude coordinates.

    Raises:
    ValueError: If any of the latitude or longitude values are not within the valid range.

    
   g      $@r*   g|V@r   g?gr,   z*Values not in the Interval (-89.95, 89.95)r)   gfffff~f@z*Values not in the Interval (-179.5, 179.5))
isinstancefloatr   rangelenr!   r   
ValueError)r0   r/   ilavallos         r   adapt_coordinatesr?   n   sQ    )U#z)S'A	*	(E"j3&?h'3x=! 
Lx{#r)*d2R 5  IKK	 q&$eCS!,HQK IKK
L 3y>" Ly|$*+t3b"F"
 IKK q&$uC c1-IaLIKKL Y    c                    g d}t        | t              r t        j                  j	                  |       }n| }|d   j
                  t        k(  rt        j                  |d         |d<   |j                  dd       d|v r|rLt        d       |j                  |d         j                         }|j                  d       t        d       |S |r9t        d	       |d   j                         j                         }t        d       |S |sEt        d
       |d   j                         j                         t        |      z  }t        d       |S yt!        d      )a  
    Resamples the precipitation data in the given dictionary by the specified time period.

    Args:
        dictionary (dict): A dictionary containing precipitation data.
        time_period (str): The time period to resample the data by (e.g., 'W' for weekly, 'M' for monthly, 'Y' for yearly).

    Returns:
        pandas.DataFrame: The resampled precipitation data.

    Raises:
        KeyError: If the 'Precipitation' field is not found in the dictionary.
    )            m  DateT)inplacePrecipitationz#Averaging the precipitation data...r   7-------------------------------------------------------z+Calculating the cumulative precipitation...z(Calculating the average precipitation...z6Error: Precipitation field not found in the dictionaryN)r6   dictr   	DataFrame	from_dictdtyper   to_datetime	set_indexprintresamplemeanreset_indexcumsumsumr9   KeyError)
dictionarytime_periodcumulatem_ydfprecipitationcumulative_precipitationaverages           r   #weekly_monthly_yearly_precipitationr`      s?    C*d#\\##J/ 	&z3^^BvJ/6
LLL&"78KKA7<<>M%%d%3KL  ?@')/':'A'A'C'G'G'I$KL++<=)002668R@GKLN  OPPr@   c           
         |r&t        |t              st        |t              r|d   }nd}t        | t              r&	 t	        j
                  | d      j                         }n!t        | t              r	 | j                         }t        |t              r&	 t	        j
                  |d      j                         }nt        |t              r	 |j                         }n||dk(  rXj                  dk(  r9t	        |j                  |j                  t        |            j                         }nH|t        d      z   }n8|dk(  r3t	        j
                  | d      j                         }|t        d	      z   }t	        j                         j                         k\  r/t	        j                         j                         t        d      z
  }t        j                  |
      j                  }t        d|d|dt!        |      d       t        d       |S #  t	        j
                  | d      j                         }Y xY w#  | }Y xY w#  t	        j
                  |d      j                         }Y xY w#  |}Y xY w)a  
    Generate a list of dates based on the given start and end dates.

    Args:
        start (str or date): The start date of the date range. Can be a string in the format 'YYYYMMDD' or 'YYYY-MM-DD',
                             or a date object.
        end (str or date, optional): The end date of the date range. Can be a string in the format 'YYYYMMDD' or 'YYYY-MM-DD',
                                     or a date object. If not provided, the current date will be used.
        average (str or tuple or list, optional): The average period for the date range. Can be 'M' for monthly or 'Y' for yearly.
                                                  If a tuple or list is provided, the first element will be used as the average period.
                                                  Defaults to 'M'.

    Returns:
        list: A list of dates ranging from the start date to the end date.

    Raises:
        ValueError: If the start or end date is not in a valid format.

    r   Mr
   r	   r   rD   )daysYrF   startendz Generated date list ranging fromto
containingrc   rJ   )r6   tuplelistr   r   r   r   r&   r   r#   r(   r   todayr   
date_rangerQ   r9   )rf   rg   r_   sdateedate	date_lists         r   generate_date_listrq      s   * gu%GT)BajG %	?%%eH5::<E
 
E4	 	JJLE
 #s	=%%c(388:E
 
C		HHJE
 
c>yyA~ U[[-:NOTTV 2 66^%%eH5::<EMs33E %%'' %%'-Q*?? Eu5::I	
,eT5,PST]P^`fg	
CD[	?%%eJ7<<>E	E	=%%c*5::<E	Es/   $H 2H9 $I 	I. &H69I &I+.I5c           	      b   t        j                  d|       }t        j                  |j	                  d      d      j                         }||vry|et        j                  dd      5 }	t        | z   }
|j                  |
|	j                         t        j                  |	j                        }ddd       nt        j                  |       }dj                  v r|d   n|d	   }|ddt        j                  ||d   k(        d   d   t        j                  ||d
   k(        d   d   d
z   t        j                  ||d   k(        d   d   t        j                  ||d
   k(        d   d   d
z   f   }|j!                  t"              }|j%                          t'        |      |fS # 1 sw Y   xY w)a   
    Process a file and extract a subset of precipitation data based on given coordinates.

    Args:
        file (str): The file path of the NetCDF file to be processed.
        date_list (list): A list of dates to filter the data.
        lon (numpy.ndarray): 1D array of longitudes.
        lat (numpy.ndarray): 1D array of latitudes.
        longitude (tuple): A tuple containing the minimum and maximum longitude values for the subset.
        latitude (tuple): A tuple containing the minimum and maximum latitude values for the subset.

    Returns:
        tuple: A tuple containing the date as a string and the subset of precipitation data as a numpy array.
               Returns None if the date is not in the date_list or if the file cannot be opened.
    z\d{8}r   r
   N.nc4T)suffixdeleteprecipitationCalr]   r   )researchr   r   groupr   tempfileNamedTemporaryFiler   getnamencDataset	variablesr-   whereastyper7   closer   )filerp   r1   r2   r/   r0   clientdr   tmpremote_file_pathdsdatasubsets                 r   process_filer   &  s   $ 			'4 AQWWQZ2779D9((tD 	&-4 JJ'2 CHH%B	& 	& ZZ%72<<%G2 !RP_M`D!RXXcYq\1215a8#STBU9VWX9YZ[9\]^9^^`b`h`hilpxyzp{i{`|}~`  AB  aC  DF  DL  DL  MP  T\  ]^  T_  M_  D`  ab  Dc  de  Df  gh  Dh  ah  h  iF]]5!FHHJIv'	& 	&s   (AF%%F.c                     | dk(  rd}t        d       dfd}t        j                  |      }|j                          |j	                  d       j                         d	k(  S )
z
    Asks the user for input to perform a specific operation.

    Args:
        operation (str): The operation to be performed.

    Returns:
        bool: True if the user's answer is 'yes', False otherwise.
    checkz.Do you want to run a check on files integrity?z
(yes/no): noc                      t                y N)input)answers   r   r   zask_user.<locals>.checkf  s
    r@   )targetr5   )timeoutyes)rQ   	threadingThreadrf   joinlower)	operationmsgr   tr   s       @r   ask_userr   U  s`     G>	#|F 	&AGGIFF2F<<>U""r@   c                      |rt        |        y y r   )rQ   )r   verboses     r   vprintr   o  s    c
 r@   c                 @    | dk(  rd}|S | dk(  rd}|S | dk(  rd}|S d}|S )z
    Simple function used for labelling when plotting.

    Args: 
        color_count: Number of quantiles

    Return:
        quantile: string used in plot labelling

    r,   zhalf    ztertile r   z	quartile z	quantile  )color_countquantiles     r   quantile_namer   t  sP     a O 
	 O 
	 O Or@   c                    t        j                  dd      }| dkD  rd| dz
  z  }t        j                  | dz        }t        j                  | dz        }t        |      D cg c]  } |d||z  z
        dd  }}t        |      D cg c]  } |d	||z  z         dd  }}|j                          ||z   }|S  |d
      g}|S c c}w c c}w )z
    Creates a list of colors to use when plotting.

    Args: 
        color_count: Number of quantiles

    Return:
        colors: List of colors

    viridis   r   Z   r,      Nr         )r   get_cmapmathceilfloorr8   reverse)	r   plasma_colormapcolor_spacing
half_countupp_halfr;   yellowsgreenscolorss	            r   color_schemer     s     kk)S1OQ{1}-YY{Q/
::kAo.GLZGXY!?3=#89"1=YYFKHoV/#-"78!<VV6! M "#&'M ZVs   !CC	c                 ,   |dk(  r| j                         }n`|dk(  r9| | d   j                         | d   j                         z     j                         }n"| | d   |k(  | d   |k(  z     j                         }d| j                  vr5|j                  j	                  t
              |d<   |j                  dg      }d|j                  vr`|dk(  r/|j                  j                  |d	      j                         |d<   n,|j                  j                  |      j                         |d<   |j                  dg
      }d|j                  v r"|dk(  r|j                  j                         |d<   d|j                  v rt        j                  |d         |d<   |S )ao   Uses lat/lon, date, and rainfall amount to create a new dataframe that includes site specific decimal dates, rolling average rain, and cumulative rain.

    Args:
        rainfall: Satellite rain dataframe for volcanos in chosen region. 
        volcanos: A dictionary of sites (eg. sites_dict = {'Wolf': (-91.35, .05, 'Wolf'), 'Fernandina': (-91.45, -.45, 'Fernandina')}).
        pick: volcano or site at which to collect data.  
        roll_count: Number of days to average rain over.

    Return:
        volc_rain: A new dataframe with additional columns for decimal date, rolling average, and cumulative rain.

    NNaN	LongitudeLatitudeDecimal)byrollT)center)r   rI   rU   rG   )copyr   columnsrG   applyr   sort_valuesrI   rollingrV   dropnarU   r   rO   )rainfall
roll_countr1   r2   centeredrU   	volc_rains          r   volcano_rain_framer     s   , d{MMO		h{388:x
?S?X?X?Z[\aac	 h{3s:x
?SWZ?Z[\aac	((((~~334HI	)))i[)9	Y&&&t ) 7 7 ? ?
SW ? X \ \ ^If !* 7 7 ? ?
 K O O QIf   1I)+++T>"+"9"9"@"@"BIh"""NN9V+<=	&r@   c                     | j                   D ]  }	 | |   j                  d       | |<    | S # t        t        f$ r Y 1w xY w)z Converts a nested list of floats to a flat list of floats.

    Args:
        nested: A nested list of floats.

    Return:
        flat: A flat list of floats.

    c                 *    t        | d   d   d         S )Nr   )r7   xs    r   <lambda>z&from_nested_to_float.<locals>.<lambda>  s    ERSTURVWXRYZ[R\L] r@   )r   r   
IndexError	TypeError)	dataframecolumn_names     r   from_nested_to_floatr     sZ     !(( 	%.{%;%A%AB]%^Ik"  9% 		s   -??c           
      D   t        | t              st        |       } g }t        t        |             D ]  }t	        j
                  | |         j                         }t        t        |            D ]N  }	 |j                  |   |cxk  r|j                  |dz      k  r#n n |j                  |j                  |           P  |S #  ||j                  |   k  r|j                  |j                  |          n&t        dt        |j                                d       Y xY w)Nr   z	Removing z) from the list of eruptions. Out of range)r6   rk   r8   r9   r   	Timestamp	normalizeilocappendrQ   r   r   )eruption_datesrp   valid_eruption_datesr;   eruption_datejs         r   adapt_eventsr     s   nd+n-3~&' l^A%67AACs9~& 	lAl>>!$K	qs8KK(//	q0AB		l	l$  l INN1$55(//	q0AB Ic-*<*<*>&?%@@ijks   3A	CADc           
         t        j                         }i }t               \  }}|r|j                  dt               \  }	}
}|
j
                  j                          |
j                         j                         }|j                  d      D cg c]  }|j                  d      s| }}|j                         }n<t        j                  |      D cg c]  }|j                  d      s|dz   |z    }}d}t        d| d       t        |      t        t!        |            k7  rt        d       nt        d	       i }|D ]!  }t#        |||||| |      }||d
   ||d   <   # t        j                  |j%                         ddg      }t        j&                  ||gdd      }|j)                  dd      }|j+                  d      }|S c c}w c c}w )a  
    Creates a map of precipitation data for a given latitude, longitude, and date range.

    Parameters:
    latitude (list): A list containing the minimum and maximum latitude values.
    longitude (list): A list containing the minimum and maximum longitude values.
    date_list (list): A list of dates to include in the map.
    folder (str): The path to the folder containing the data files.

    Returns:
    pandas.DataFrame: A DataFrame containing the precipitation data for the specified location and dates to be plotted.
    zls 
rs   /Nz Checking for duplicate files in z ...z&There are duplicate files in the list.z)There are no duplicate files in the list.r   r   rG   rI   )r   TF)ignore_indexsort)r   	ascending)drop)r   rL   r3   exec_commandr   channelrecv_exit_statusreaddecoder"   endswith	open_sftposlistdirrQ   r9   setr   itemsconcatr   rT   )r0   r/   rp   foldersshfinaldfrX   r1   r2   stdinstdoutstderr	all_filesffilesr   r   resultdf1s                      r   extract_precipitationr    s    llnGJ(*HC  # 0 03~6F1G Hvv 	'')KKM((*	 &OOD1HqQZZ5GHH ,.::f+=TaFAS#!TT 
,VHD
9:
5zSU_$67 	9:J .dIsCHfU$*1IJvay!	. ,,z'')FO3L
MCii#TFG!!Vt!<G!!t!,GNG I Us   G$GG)
Gc           	         |r|j                         }t        j                  d      }t        j                  j                  t        d      }	 |j                  |d      5 }|j                  |j                                d d d        |j                  }	t        j                  |	      }
n6t        j                  j                  |d      }	 t        j                  |      }
|
j#                         }|j%                  d       |j'                         s!|j%                  d       |
j)                          | d	    d
| d    }|d	    d
|d    }d| d| d|d	    d|d    d	}t+        j,                  ||
      }t+        j.                  |d         j0                  j2                  |d<   |D cg c]  }||d   j5                         vs| }}|r|j7                          t9        |d	   |d         }t;        | ||||      }|d   j=                  d       |d<   |j?                         D ]!  \  }}|j%                  d|d   |d   ||f       # |
j)                          t+        j,                  ||
      }|rvj                  t        dz   d      5 }t        	d      5 }|j                  |j                                d d d        d d d        j!                          |j!                          |
j!                          |d   j=                  d       |d<   tA        d       |S # 1 sw Y   xY w# t        $ r9 |j                  |d      5 }	 d d d        n# 1 sw Y   nxY w|j                  }	Y w xY w# t        j                  $ r3 t        |d      j!                          t        j                  |      }
Y w xY wc c}w # 1 sw Y   xY w# 1 sw Y   xY w)NF)ru   zvolcanoes.dbrbwbwzFSELECT name FROM sqlite_master WHERE type='table' AND name='volcanoes'z
            CREATE TABLE volcanoes (
                Date TEXT,
                Precipitation TEXT,
                Latitude REAL,
                Longitude REAL
            )
        r   :r   z<SELECT Date, Precipitation FROM volcanoes WHERE Latitude = 'z' AND Longitude = 'z' and DATE between 'z' and ''rG   re   rI   c                 H    t        j                  | j                               S r   )jsondumpstolistr   s    r   r   z+sql_extract_precipitation.<locals>.<lambda>  s    X\XbXbcdckckcmXn r@   zTINSERT INTO volcanoes (Date, Precipitation, Latitude, Longitude) VALUES (?, ?, ?, ?)c                 f    t         j                  j                  t        j                  |             S r   )r-   maarrayr
  loadsr   s    r   r   z+sql_extract_precipitation.<locals>.<lambda>  s    beekk$**UV->X r@    )!r   rz   r{   r   pathr   r   r   writer   r}   IOErrorsqlite3connectOperationalErroropenr   cursorexecutefetchonecommitr   read_sql_queryrO   dtr   r  r   rq   r  r   iterrowsrQ   )r0   r/   rp   r   r   sftp	temp_filedatabase_pathr   db_pathconnr  r2   r1   queryr\   r   missing_datesr]   indexrow
local_files                         r   sql_extract_precipitationr*  Q  s   
}} //u=	^^D	%=$/ *1)*  nnG w' V^<	2??=1D [[]F
NN[\ ??  	 	a[M8A;-
(Cq\N!IaL>
*CJ3%Obcfbgg{  }F  GH  }I  |J  JQ  R[  \^  R_  Q`  `a  bE 
		5$	'B6
+..33BvJ '0Sd4r&z?P?P?R3RTSMS&]1-==QSCTU	-h	9fVYZ)6)G)M)MNn)oo& (002 	GJE3NNqVc/&:CEG	G 	ud+ YY~6= 	+gt$ +

)*+	+ 			JJL _-334XYB	"IIu* *
  	%=$/ 1    nnG	%" '' 	2$**,??=1D	2B T.+ +	+ 	+s   L+   L L+ M0 *N9N9O N>9OL(#L+ +M-M	M-M	M-,M-0AN65N6>O	OO)NF)Nrb   )NNFTr   )'r   rw   ior   r
  r   r   dateutil.relativedeltar   r$   r  r   rz   numpyr-   pandasr   
matplotlibr   netCDF4r~   precip.configr   r   r(   r3   r?   r`   rq   r   r   r   r   r   r   r   r   r  r*  r   r@   r   <module>r2     s    	 	 	   # 0         ((V0 *1	VH 0+\7QtM`,^#4
063l* 8@Fer@   