o f@sdZddlZddlZddlmZddlmZddlmZddl m Z ddl m Z m Z ddlmZddlZddlZddlZd Zd Zd Ze Gd d d Ze GdddZe GdddZejejfdededefddZddZdedededejfddZ dedededejdejf ddZ!d edejdejdejfd!d"Z"d#ed$ed efd%d&Z#d'ed$ed(efd)d*Z$d#ed+e%d,e%d-e&fd.d/Z'd#ed0e%d,e%d-e&d1ed2e%f d3d4Z(d#ed+e%d,e%d-e&fd5d6Z)d'ed7e%d,e%d-e&fd8d9Z*d'ed0e%d,e%d-e&d1ed2e%f d:d;Z+dd?d@dAdBdCdCdDf dEedFdGedHedIedJe%dKej-dLej-dMej-dNe&dOe&dPe&d2e%fdQdRZ.dSdTZ/dUdVZ0e1dWkrDe/Z2e0e2dSdS)XaW Contains the C code that does the actual tide calculations... This code was based on astrti.f... We needed to re-write the code so that we didn't need a fortran compiler. In the process several inefficiencies were discovered. For algorithm information see tide.txt Copyright (c) 2002 Arthur Taylor. Notes: We could have difficulties switching from one year to the next, since there is a small discontinuity there. Main equation is: H(T) += Xode * Am * cos (PI/180 * (T * Ang + VP - EP)) NOS TIDE DATA IS STORRED FOR THE FORMULA: Z=SUM(NODE(J)*AMP(J)*COS(ANG(J)*T+VPU(J)-EPOC(J))). N)datetime)partial)pi)Path) dataclassfield)Literal%g?c@seZdZUdZeed<dZeed<dZeed<ee e j e fdZ e jed<ee e j e fdZe jed<ee e j e fdZe jed <ee e j e fdZe jed <ee e j e fdZe jed <d S) TideConstitTypermllwnstayeardefault_factoryxodevpuangampepocN)__name__ __module__ __qualname__r int__annotations__rrrrnpemptyNUMTrndarrayrrrrr r @/lfs/h1/ops/prod/packages/stofs.v2.1.9/ush/stofs_2d_glo/tide3.pyr ,s   "r c@seZdZUdZeed<dZeed<dZeed<dZe ed<dZ e ed<dZ e ed<dZ e ed <e ed Zeed <d Zeed <d Zeed<dZe ed<dZe ed<d Zeed<dZeed<dZeed<dS) SecondaryTyper secStarmaxTimeminTimemaxAdjminAdjmaxIncminIncrtcname1name2latlonbsnijN)rrrr#rrr$r%r&floatr'r(r)rr r*r,strr-r.r/r0r1r2r r r r!r"8s             r"c@s\eZdZUeedZeed<eedZeed<dZ e j ed<dZ e j ed<dZ e j ed <d S) TideTyperr*stft03.dtaft03ft07.dtaft07ft08.dtaft08N)rrrrr r*rr"r6r8osPathLiker:r<r r r r!r5Ls r5linebegendcCsxt|dd}|dd}t||dD]$}t|ddd||d<t|ddd||d<|dd}q|S)a0 Helper function to read_ft03. Variables: ptr Current line that has been read in from file. beg Where in arrays to start storing data read end Where in arrays to stop storing data read xode place to store the xodes (yearly constants) vpu place to store the vpu (yearly constants) Returns: iyr place to store the year Notes: ft03.dta updated in 2024 by Huiqing, we will run out in 2045. VPU = V + U, ANOTHER PHASE LEAD (DEG) XODE = NODE FACTOR Nr )rrange)r?r@rArrZiyrr1r r r!read_format_ft03Vs rGc Cst|dk}|}t|d}||krtd|dt||ddD]}|q(||kr7|}t|dd||}||krGtdd d d d tffD]\}} |}|d kr_tdt||| ||}qOWddS1sswYdS)aE Reads in the data from file ft03.dta... used to be called "rnos2" The file contains xode and vpu VPU = V + U, ANOTHER PHASE LEAD (DEG) XODE = NODE FACTOR Variables: ft03 Name of the file that contains the yearly constants. iyear Year we are interested in xode place to store the xodes (yearly constants) vpu place to store the vpu (yearly constants) Returns: True on success, raises on error Notes: ft03.dta updated in 2024 by Huiqing, we will run out in 2045. rtrzInvalid year from ft03: <>rDrCz"Encountered unexpected year entry!) )) !r+Encountered unexpected EOF!NT)openreadlinersplit ValueErrorrFrGr) ft03_pathZiyearrrfpr?Ziyr1_r@rAr r r! read_ft03|s,   rZrcCs@t||dD]}t|ddd||d<|dd}qdS)a  Helper function to read_ft07. Handles the formatted reads dealing with angle. (see beginning of ft07 file) Variables: ptr Current line that has been read in from file. beg Where in arrays to start storing data read end Where in arrays to stop storing data read ang place to store the angle (or speed) Notes: To verify these angles see: http://www.co-ops.nos.noaa.gov/data_retrieve.shtml?input_code=100201001har This is the "speed" column. rDNrEirFr)r?r@rArr1r r r! read_ang_ft07sr\rrcCsh|dd}t||dD]$}t|ddd||d<t|ddd||d<|dd}q dS)a, Helper function to read_ft07. Handles the formatted reads dealing with amplitude and epoch. Variables: ptr Current line that has been read in from file. beg Where in arrays to start storing data read end Where in arrays to stop storing data read amp place to store the amplitude epoch place to store the epoch Notes: To verify these numbers see: http://www.co-ops.nos.noaa.gov/data_retrieve.shtml?input_code=100201001har This is the "ampl" and "epoch" columns. rCNrDrJr rKrEr[)r?r@rArrr1r r r!read_amp_epoc_ft07s r]rcCs`t|d}tddD])}d|dd}t|dkrtn|d}|} | dkr-tdt| |||q d|d} td| dD]}|} | dkrPtdqB|} | dkr]td|t| dd krktd |} | dkrwtdt| dd} gd } | D]\} }|} | dkrtdt| | |||qWd| S1swY| S) as Reads in the data from file ft07.dta The file contains MLLW, speeds (angles), and station specific epochs, and amplitudes. Variables: ft07 Name of the file that contains the station specific constants nsta Which station to look for. ang place to store the speed adjustments. amp place to store the amplitude epoch place to store the epoch Returns: mllw on success, raises on error mllw place to store the mean lower low water adjustment. Notes: To verify these numbers see: http://www.co-ops.nos.noaa.gov/data_retrieve.shtml?input_code=100201001har This is the "ampl" and "epoch" columns. Originally f_seasonal was sent in here, and we did: if (! f_seasonal) { amp[15-1] = 0; amp[17-1] = 0; } rHrDr+rRrCNz"Encountered unexpected station ID!))rDr^)rC)))#)$r )rSrFrrTrVr\rr]) ft07_pathrrrrrXr1Zj1Zj2r?Znrecr Z read_tuplesr@rAr r r! read_ft07sD '   ))rjr*rcCsN|j|kr||_t|||j|j|j|kr%||_t|||j|j|j|_ dS)a@ Reads in the constituent data needed to predict tides at a primary tidal station. Variables: tc A pointer to the structure to read the constituents into ft03 Name of the file that contains the ft03 data (yearly stuff) ft07 Name of the file that contains the ft07 data (station stuff) year The year we are interested in. nsta The station we are interested in. Returns: True on success, raises on error Notes: We could have difficulties switching from one year to the next. T) rrZrrrrjrrrr )r*rWrirrr r r! LoadConstit<s  rkr6r#cCs |j|krt|j||||jjSd}t|d;}|D],}|ddkr#q|d} | dkr-qt|d| } | |kr:q||_|| dd}ntd Wdn1sUwY|d} | dkrgtd |d| |_ || dd}|d} | dkrtd |d| |_ || dd}|d} | dkrtd |d| |_ || dd}|d} | dkrtd t|d| |_ || dd}|d} | dkrtd t|d| |_ || dd}|d} | dkrtd t|d| |_|| dd}|d} | dkrtd t|d| |_|| dd}|d} | dkr;td t|d| } || dd}|d} | dkrYtd |d| d } | dkrktd t|d| d| } t|d| | dd}| d ||_|| dd}|d} | dkrtd |d| d } | dkrtd t|d| d| } t|d| | dd}| d ||_|| dd}|d} | dkrtd t|d| |_|| dd}t||_d|_d|_t|j|||| S) a Reads in the constituent data needed to predict tides at a secondary tidal station. Variables: st A pointer to the structure to read the constituents into ft03 Name of the file that contains the ft03 data (yearly stuff) ft07 Name of the file that contains the ft07 data (station stuff) ft08 Name of the file that contains the adjustments to the secondary station from the primary. year The year we are interested in. secSta The station we are interested in. Returns: True on success, raises on error Notes: We could have difficulties switching from one year to the next. r+rHr#|r NrDz'Couldn't find the station in FT08 file!z$Invalid line formatting for station!:<)r#rkr*rrSfindrrVstripr,r-r0r1r2r3r.r/r$r%r&r'r(r))r6rWri ft08_pathrr#Z work_linerXr?idxnumZrefStaZidx2hrZminmr r r! LoadSecond`s                       rvtz0 f_seasonalcCs|jdks |jdkrtd|}|j|jttd|j||j |j }|r3|t |}|S|t |dd|dt |dd}|S) a Compute the tide at time t where: t is a double in hours since beginning of year 1hr 3 min since begining of year is t = 1.05 18 seconds would be .005, 3 min would be .05, Variables: tc A pointer that contains all the tidal constits. t The time in hours from beginning of year loaded into tc that we want to compute the tide for. z0 What to init the water level to. Returns: z on success, raises on error z Where to store the answer Notes: We could have difficulties switching from one year to the next. NOS TIDE DATA IS STORRED FOR THE FORMULA: Z=SUM(NODE(J)*AMP(J)*COS(ANG(J)*T+VPU(J)-EPOC(J))). rDr $Invalid tide constituent info input!NrarbrM) rrrVrrrcosPIrrrsum)r*rwrxryzeqnr r r!tide_ts00rinitHournumHoursdeltc Cs|jdks |jdkrtd|t|f}|t||}|j|jtt dt ||j |j |j }|rF|tj|dd}|S|tj|ddddfdd|dddftj|ddd dfdd}|S) a Compute a number of hours of tide, from inital hour (hours since beginning of the year that is loaded into tc) to numHours later, storing the result in zhr, (which is allocated by caller to contain numHours + 1 values). Variables: tc A pointer that contains all the tidal constits. initHour The hour since the begining of the year at which to start. z0 What to init the water level to. f_seasonal If we want Seasonal adjusments or not. numHours How many hours to compute. delt Usually 1, but we allow < 1 if delt * numHours < 24. Returns: zhr on success, raises on error zhr where to store the answers. Notes: We could have difficulties switching from one year to the next. NOS TIDE DATA IS STORRED FOR THE FORMULA: Z=SUM(NODE(J)*AMP(J)*COS(ANG(J)*T+VPU(J)-EPOC(J))). rDr rzr{)axisNrarbrM)rrrVronesarangerrr|r}outerrrrr~) r*rrxryrrzhrtsrr r r! tide_hourss&!  rc Cstj}tj}tj }tj }|jdks|jdkrtdt||||}|t} t|| ||} | |krA| t8} t|| ||} | |ks2| |kr|} | | kr\| } | t8} t|| ||} | | ksK| }| t}|} |} | | kr{| } | t7} t|| ||} | | ksj| }| t}n<|} | | kr| } | t8} t|| ||} | | ks| }| t}|} |} | | kr| } | t7} t|| ||} | | ks| }| t}||||fS)a Compute the values of the Max and Min that surround a given time t. Variables: tc A pointer that contains all the tidal constits. t The hour since the begining of the year which defines where to start looking for the min/max. z0 What to init the water level to. f_seasonal If we want Seasonal adjusments or not. Returns: (hMax, tMax, hMin, tMin) on success, raises on error hMax Where to store the Max value. tMax Where to store the time of the Max (hours since beg of year) hMin Where to store the Min value. tMin Where to store the time of the Min (hours since beg of year) Notes: Current algorithm: steps away from t in intervals of .05 hours (3 min) Could switch to using MAX_RES to denote direction instead of having a big if section, but this adds complexity and computations. Would prefer a newton-raphon method of finding the min/max, but we would need to blend the tides to handle the end of year discontinuity and that adds too much complexity for too little improvement. One idea might be to do newton-raphon method when not near the end of the year (say 2 or 3 days from end of year?). rDr rz)rinfrrrVrMAX_RES) r*rwrxryhMaxtMaxhMintMinrt1z1z2r r r! tide_MaxMinRsb#  rlocTc Cs |jdkr td|jjdks|jjdkrtd||j|jdd}t|j|||}t|j|||\}}}} t dD] } ||j|||j||||d}t|j|||}q=||jj d} | |j |||j ||||} | |j |||j||||} | S) aH Compute the values of a secondary tidal station at time t where: t is a double in hours since beginning of year. 1hr 3 min since begining of year is t = 1.05 18 seconds would be .005, 3 min would be .05, Variables: st A pointer to the secondary tidal constants. locT The time in hours from beginning of (year loaded into st) that we want to compute the tide for. z0 What to init the water level to. f_seasonal If we want Seasonal adjusments or not. Returns: locZ on success, raises on error locZ Where to store the answer (overwrites what is in here) Notes: Algorithm is as follows (see tide.txt) : 1) Initial Guess for refT from locT 2) Compute ref_hMin, ref_hMax surrounding refT 3) Repeat 5 times (arbitrary, original version was 1): Make new guess of refT using ref_hMin/Max, and h(refT) 4) Calc LocZ from h(refT): Adjust to mllw from mean tide level. 5) multiply by multiplicative Adjustment 6) add Additive Adjustment rD!secSta not initialized correctly!r rz@N@rJ@@)r#rVr*rrr$r%rrrFr r'r&r(r)) r6rrxryrefTrefZrrrrr1ZlocZr r r! secTide_ts0 #  rcCsf|jdkr td|jjdks|jjdkrtdt|f}d}|}||j|jdd} t |j| ||} t |j| ||\} } } }t dD] }||j| | |j| | | | d} t |j| ||} qG| |jj d ||<|||j | | |j| | | | ||<|||j| | |j| | | | 7<||7}t d|D]}| |7} t |j| ||} | | kr| |krt |j| ||\} } } }t dD] }||j| | |j| | | | d} t |j| ||} q| |jj d ||<|||j | | |j| | | | ||<|||j| | |j| | | | 7<||7}q|S) a Compute a number of hours of a secondary tidal station, from inital hour (hours since beginning of the year that is loaded into tc) to numHours later, storing the result in zhr, (which is allocated by caller to contain numHours + 1 values). Variables: st A pointer to the secondary tidal constants. initHour The hour since the begining of the year at which to start. z0 What to init the water level to. numHours How many hours to compute. delt Usually 1, but we allow < 1 if delt * numHours < 24. Returns: zhr on success, raises on error zhr where to store the answers. Notes: General Idea: Do it the same as secTide_t once, and then use that info for the rest... rDrr rzrrrrJr)r#rVr*rrrrr$r%rrrFr r'r&r(r))r6rrxryrrrr1rrrrrrrr2r r r! secTide_hourssd       rr `gr7r9r;TFrDcmd)hourlysingler configstationdatenumHour initHeightrWrirr is_seasonal is_secondaryadd_mllwc Csj|jdusJ|}|dkrtdt|||d} | dkr,| dks(| |dkr,td|dkrB|tjur9td|d krAtd n |d ksK|tjurMd Sd |jkr[d ks`tdtdt|t |jdd|jd d} | st | j | j | j|j|std| r|| j jd7}nt| j| j | j| j|j|std| s|| jj jd8}|dkrt|f}|| dkr| st| j | |||| }|St| j| |||| }|S|j}dt| d}||kr|}| st| j | |||| }n t| j| |||| }|}| |7} ||8}|ddkr#|ddks |ddkr#d}nd}|dkr| |krw| |8} |d7}|ddkrO|ddksL|ddkrOd}nd}| set | j | j | j||sdtdnt| j| j | j| j||swtd| st| j | |||dkrdn|| }nt| j| |||dkrdn|| }t||f}|d8}| d7} |dks*|SdS)Nrz#Only hourly is implemented for now!)r8r:r<rDrNz\If not 1, `delt` should be less than 1, and multipled by `numHour` it should be less than 24rz6To run hourly tide calculation `date` must be providedr zStation input must be provided!Tiiz(Date must be between year 1800 and 2045!)rmonthdaytzinfo#Unable to load primary contituents!r Unable to load secondary tides!i8"rBrdiiP")rlowerNotImplementedErrorr5rVpdNaTrrr total_secondsrkr*r8r:IOErrorr rvr6r<rrrrcopyhstack)rrrrrrWrirrrrrrttrdatarZendHourrZtotHourr r r! TideC_stnVs    qh  *  *   /rcCst}|jddddgdd|jdtddd |jd tjdd d |jd tdd d |jdddd|jdddd|}|S)Nz--typeTprimary secondaryz!Secondary or Primary tidal staion)requiredchoiceshelpz --stationzWhich station?)typerrz --datetimez!Inital Year to compute tides for.z --numHourszHow many hours to compute.z--mllw store_truezAdd mean lower low water?)actionrz --seasonalzAdd seasonal adjustments?)argparseArgumentParser add_argumentrr to_datetime parse_args)parserargsr r r! parse_clis<rcCst}t}d}|jdkrd}n|jdkrd}n td|jd|j}|jj}|jj}|jj}|jj } t |jt|ddd d } |j } |j } |j} t| f}|dkrt|d d ||sctd | rl||j d 7}t|| || | d}tdD] }t|d||qytdD]}t|| |d|| }t|dd|qdSt|d d d||std| s||j d 8}t|| || | d}tdD] }t|d||qtdD]}t|| |d|| }t|dd|qdS)a Main routine, used for testing, and as an example of how one might use Tcl/Tk to call this. Variables: args (argv array) Secondary or Primary tidal staion. Which station? Inital datetime (yr, mo, dy, hr) How many hours to compute. Add mean lower low water? Add seasonal adjustments? Returns: 0 on success, -1 on error rrrDrzType z is not supported!)rrrrr7r9rr  g?r;rrNN)r r"rrVrrrrrhourrrrr ZseasonalrrrkrrrFprintrrvrr)rr*r6rxrrrrrrZihrZf_mllwryrr1rr r r!main8s\       r__main__)3__doc__r=rr functoolsrmathrr}pathlibr dataclassesrrtypingrpytznumpyrpandasrZLINE_LENrrr r"r5rr4rrGrZr\r]rjrkrvr3boolrrrrrrr>rrrrrr r r r!sV        &2   T $   , : ^ K ]    A" U