3 `Mc @sdZddddddddd d d d d ddddddddgZddlZddlZddlZddlZddlZddlZddlZ ddl Z ddl Z ddl m Z ddl Z ddlmZddZeejjjdZGddde ZGdddeZGdddeZGd ddeZGd!ddeZGd"ddeZGd#ddeZd$d Zd%d Zd&d Zd'd Zd(d Z d6d)dZ!d7d+dZ"d8d.dZ#d9d0dZ$d:d1dZ%d;d3dZ&Gd4dde'Z(dt|j|j}|S)a!A cmp comparison for StormInfo objects intended to be used with sorted(). This is intended to be used on cleaned vitals returned by clean_up_vitals. For other purposes, use vitcmp. Uses the following method: 1. Sort numerically by when.year 2. Break ties by sorting lexically by stormid3 3. Break ties by sorting by date/time 4. Break ties by retaining original order ("stable sort"). @param a,b StormInfo objects to orderr)rwhenyear longstormid)rrcrrrr s cCsVt|j|j}|dkr&t|j|j }|dkrstormid3r;have34kt)rrrArrrr scCs|j|j|jfS)a !Generates a hashable key for hashing StormInfo objects Lines are considered to be for the same database entry if they're from the same forecasting center, have the same basin, date/time and storm number. Note that the public two-letter basin (AL, EP, CP, WP, IO, SH, SL) is used here (stormid4) so that a/b and s/p conflicts are handled by keeping the last entry in the file. @param vit the StormInfo of interest. @returns a tuple (center,stormid4,when) from the corresponding members of vit)r;stormid4r>)vitrrrr s c Cs|dkr t}|dkrt}|dkr$t}t|t|d}|}dd||D}|}dd||D}|}t}t}x6t|D]*} t| } | |krqz|j | |j | qzWddt|D} | S)a!Given a list of StormInfo, sorts using the vitcmp comparison, discards suspect storm names and numbers as per name_number_okay, and discards invalid basin/center combinations as per basin_center_okay. Lastly, loops over all lines keeping only the last line for each storm and analysis time. The optional name_number_checker is a function or callable object that takes a StormInfo as an argument, and returns True if the name and number match some internal requirements. By default, the name_number_okay function is used. @param vitals A list of StormInfo @param name_number_checker A function that looks like name_number_okay() for determining which storm names and numbers are acceptable @param basin_center_checker A function that looks like basin_center_okay() for determining which basins and RSMCs are okay. @param vitals_cmp a cmp-like function for ordering two StormInfo objectsN)keycSsg|]}|qSrr).0vrrr sz#clean_up_vitals..cSsg|]}|qSrr)rGrHrrrrIscSsg|]}|qSrr)rGxrrrrIs) r r r sortedrlistsetreversedr addappend) vitalsname_number_checkerbasin_center_checkerZ vitals_cmpZ sortvitalsZ nn_ok_vitalsZ keepvitalsZ revuniqvitalsseenr8rFZ uniqvitalsrrrrs, $@cCsJtjd|}|rF|j}t|d|}d|krB|ddk rB| }|SdS)a!Converts a string like "551N" to 55.1, correctly handling the sign of each hemisphere. @code floatlatlon(string="311N",fact=10.0) = float(31.1) # degrees North @endcode @returns degrees North or degrees East @param string Latitude or longitude in sum multiple of a degree, followed by N, S, E or W to specify the hemisphere. Must be a positive number @param fact The strung value is divided by this number. The default is to convert from tenths of a degree in string to a degree return value. @note This function does not accept negative numbers. That means the tcvitals "badval" -999 or -99 or -9999 will result in a None return value. z@\A(?P0*\d+)(?:(?P[NnEe ])|(?P[SsWw]))\ZZnumnegativeN)research groupdictfloat)stringZfactmmdictZlatlonrrrrs ?c CsDt|dkstdddddddd g}t|}d gd}d } xltdD]`} || d k rD|| d krDt|| || <|| d krd|| <qD|| |9<t| || } qDW|dkrtd krd||f} | || <|j| nh|d krd S|j|} xPtdD]D} d||| d| t|d d|f} || || <|j| qWd S)a!Internal function that parses wind or sea quadrant information. This is part of the internal implementation of StormInfo: it deals with parsing wind or sea quadrant information. @param[out] data Output quadrant information, a dict mapping from the quadrant name in qset. @param[out] qset output set of quadrants that were seen @param irad Integer radius. For example, 34 may indicate the 34 kt wind radius. @param qcode Special code used for circular (all quadrants) data @param qdata String quadrant data information for each quadrant @param what What type of data is this? Wind radii? Sea height radii? This should be an alphanumeric string. @param conversion Unit conversion. ZNNQZNEQZEEQZSEQZSSQZSWQZWWQZNWQNgr^riZAAAz %sCIRCLE%dz%s%s%di) lenAssertionErrorintrangerZmaxcountrOindex) dataqsetiradZqcodeZqdataZwhat conversionZquadrantZfqdataZmaxdataivarZiquadrrrr s0      * FcCs`t}xT|D]L}y|jtd|jdWq ttfk rV}z |rFWYdd}~Xq Xq W|S)a!Reads data from a tcvitals file. This reads line by line from the given file object fd, parsing tcvitals. @returns A list of StormInfo objects, one per line. @param fd An opened file to read. @param raise_all If raise_all=True, exceptions will be raised immediately. Otherwise, any StormInfoError or ValueError will be logged or ignored, and parsing will continue. @param logger The logger is a logging.Logger object in which to log messages, or None (the default) to disable logging.tcvitals N)rLrPrrstripr ValueError)fdlogger raise_alloutlineerrrr7s  c csXt|trt|}t|t s"t|dk rdtjj|jd}d}|dk sLt|dk rd|jd|f|dk rd|f}|dk r|jd|f|dk rt|dj } |dk r|jd|fd} xv|D]n} |dk r| d d |krq|dk o| d d |krq|dk r| d | krq| d 7} t d| j dVqW|dk rT|jd| fdS)a<!Faster way of finding tcvitals data for a specific case. A fast method of finding tcvitals in a file: instead of parsing each line into a StormInfo, it simply scans the characters of the line trying to find the right storm and time. Returns a list of matching vitals as StormInfo objects. * fd - the stream-like object to read from * logger - the logging.Logger to log to, or None * raise_all - if True, exceptions are raised immediately instead of just being logged. * when - the date to look for, or None * stnum - the storm number (ie.: 09 in 09L) * basin1 - the basin letter (ie.: L in 09L) @warning This function cannot handle errors in the formatting of the tcvitals lines. It will only work if the data in fd strictly follows the tcvitals format.Nz %Y%m%d %H%MabcdzVITALS: search for when=%sz%02dzVITALS: search for stnum=%srzVITALS: search for basin1=%s rorpzVITALS: yielded %d matches) isinstancestrrdrchwrfnumerics to_datetimestrftimedebugupperrrq) rsrtrur>r5r<ZstrwhenryZstrstnumZ strbasin1rgrwrrrrMs:     Tc Cst}d}t}x|D]}t|dkrB|dk r|jd|fqnNd|kr|ddjddj}|dkst||kr|}|j|qn |dkrqy$|jtd|||d t}d}Wqttfk r}z |rЂWYdd}~XqXqW|S) aM!Scans an A deck file connected to stream-like object fd, reading it into a list of StormInfo objects. Returns the list. @param logger A logging.Logger to log to. @param raise_all If False, log and ignore errors instead of raising them. @param fd the file object to read @returns a list of StormInfo objects N(z#Ignoring short line (<40 chars): %sCARQr,racarq)linetypeinputsrtru) rLrbwarningsplitstriprPrrrr) rsrtrurvr>ZstorerwZwhen2rxrrrrs2     cseZdZdZd6fdd ZddZd d Zd d Zd dZd7ddZ d8ddZ d9ddZ d:ddZ d;ddZ dd d!Zd?d"d#Zd@d$d%Zd&d'Zd(d)Zd*d+Zd,d-ZdAd.d/ZdBd0d1ZdCd2d3Zd4d5ZZS)Dra!Storm vitals information from ATCF, B-deck, tcvitals or message files. Represents all information about a one storm at one time as a Python object. It can read a single line of a tcvitals file, one time from a Best Track file, or CARQ entries from an Aid Deck file at a single time. It will scan multiple lines from a Best Track or CARQ group to get the last forecast hour (up to a maximum of 72hrs) and all possible radii for one time. This class is meant for complex manipulations of a small amount of data, not for manipulations of whole databases. It can be used for manipulating the entire TCVitals database, or multiple ATCF deck files, but will generally be slower than other libraries -- operations will take on the order of ten times as long. @todo Write a separate class for simple manipulations of a whole ATCF database. This could be done efficiently using an in-memory sqlite3 database.rNTc s|dk r(t|tj r(tdt|jtt|jd|_ d|_ ||_ d|_ |dkrpt ||_|j|jnZ|dkrt ||_|j|jn8|dkrtj||_|j|t ||t|dn|dks|d kr|dk}d d }t|tstd t|jx^|jjD]P\}} |d dkr*q|d ddkrF|rFq|| sTq| |j|<qW|rx^|jjD]<\}} || sqv|d ddkrv| |j|dd<qvWntdt|fdS)a!StormInfo constructor Constructor for the StormInfo class. You should not call this directly. Instead, use the other parsing functions in this module to generate tcvitals from file objects. @param linetype type of vitals: tcvitals, message, carq (ATCF CARQ entries), old, or copy. See below @param inputs inputs, converted to a string before processing @param carq additional CARQ data to fill in more information @param logger a logging.Logger for log messages @param raise_all if True, exceptions will be raised if parser errors happen The constructor can create StormInfo objects in several ways, specified by the @c type argument: * @c tcvitals --- Parse a line of a tcvitals file. * @c message --- Parse a tropical cyclone message file. * @c carq --- Parse A deck CARQ entries. * @c old --- Take another StormInfo whose storm id/name has been replaced with another id/name through invest renumbering. Swap the old invest id/name with the current non-invest id/name. * @c copy --- Do a deep copy of the supplied StormInfoNzQIn StormInfo constructor, logger must be a logging.Logger, but instead it is a %sFror-r)linestechrtruoldcopycSs.x(ttttjtjfD]}t||rdSqWdS)NTF)rrdrZdatetime timedeltar)rntrrr checktypes    z%StormInfo.__init__..checktypez\In StormInfo constructor, when linetype=="old", inputs must be a StormInfo object, not a %s.r_r`Zold_zAUnknown storm info format %s: only know "tcvitals" and "message".)rloggingLogger TypeErrorr)rr,rr&_cenlo_cenlaformat has_old_stnumrrw_parse_tcvitals_line_parse_message_linerr _parse_carqbool__dict__itemsZInvalidStormInfoFormatr') r%rrrrtrurrkrH)r.rrr&sV      zStormInfo.__init__cCs td|S)zj!Returns a copy of this StormInfo, but with the last renumbering or renaming of the vitals undone.r)r)r%rrrrsz StormInfo.oldcCs td|S)z!Returns a copy if this object.r)r)r%rrrr szStormInfo.copycCs || S)z\!Same as self + (-amount) @param amount The amount of time to extrapolate backwards.r)r%amountrrr__sub__szStormInfo.__sub__c Cs@|j}tjj|d}td|jd}tjd}tjj }tjj |dd}|tj |j |}|tj |j |} t| ||dtj} t||tj |j||dtj} tt|j| dd|_tt|j| dd|_tjj|d|j|_|jjd |_x"dD]} | |jkr|j| =qWd |_|S)z!Returns a copy of this object, with the vitals extrapolated forward "amount" hours. Only the location is changed. @param amount the amount of time to extrapolate forwardirg$@gf@T)Znegokra z%Y%m%d%HflatflonfhrF)rrr)rrrZ to_timedeltarf stormspeedmathpiZ constantsRearthZ to_fractionsinstormdircosrZr=roundlonto_datetime_relr>rYMDHr havefcstloc) r%rrZdtamountZvmagZpi180rZdtZdxZdyZdlatZdlonrHrrr__add__s& *  zStormInfo.__add__c Cs4|jdk r |jdk r |j|jfS|j}|dk s2t|j}|dk sDt|jrt|jdk sXt|j}|jdk slt|j}n(|d}|dkr|d}|dkr|d}|dk st|dk st|dk r|jd||ft d|d|dd}t |t |dkr|d}t |t |dkr&|d}|}|dkr:| }t j |}|d krRd }|d krd|d}|d krrd }|d krd}|dkrd}|dkrd}|dkrd}|dkr| }|dk r|jd||f||} | dkr|d8}| d kr|d8}t d|d|dd}|dkr0|d8}|d!krB|d7}|} |dk rt|jd| |f|jd||fd} t | t |dkr|d} |dk r|jd| fd} t | t |dkr|d} |dk r|jd| fd} |dk r | r |jd|jd| |f| ||_|_| |fS)"a!Uses the 2013 operational HWRF method of deciding the domain center based on the storm location, basin, and, if available, the 72hr forecast location. Returns a tuple containing a pair of floats (cenlo, cenla) which are the domain center longitude and latitude, respectively. Results are cached internally so future calls will not have to recompute the center location. @param logger a logging.Logger for log messagesNg4@rg$@z$Averaging storm_lat=%f and avglat=%fg@rzg@g.@g>@#gA@rgD@r4gF@7gI@z$Averaging storm_lon=%f and avglon=%fgv@gf@zDecided cenlo=%f cenla=%fzStorm is at lon=%f lat=%fFz1Center is too far east of storm. Moving it to %fTz1Center is too far west of storm. Moving it to %fz2Center is within +/- 5 degrees longitude of storm.z*Final outer domain center is lon=%f lat=%fgvgf) rrrrcr=rrrinfordrfloor) r%rtZ storm_lonZ storm_latZavglonZavglatresultZcenlaZilatdiffZcenloZmovedrrrhwrf_domain_center*s                            zStormInfo.hwrf_domain_centercCs|j}||d<|j||||\}}}} |s8td|dd} xH|D]@} | rh|j|| || ||dd} |j|| || ||dqBW|dk r,y.NcSsg|] }|jqSr)r)rGrJrrrrIszqCARQ entries in deck files must have at least eight fields (everything through lat & lon). Cannot parse this: %scs$g|]}|d|kqS)rr)rGj)rmrrrrIsrr~rar`zgBasin, storm number, YMDH and technique must match for ALL LINES when parsing CARQ data in _parse_carq.rz)rtruH)rr~rar`) rLrerbranyrd_parse_atcf_timerPrc) r%rrrtrurrrZmyfhrr)rmrrrs2     zStormInfo._split_carqc Csd}|ddkr8|dkr&t|d}nt|d|jd<t|d}tj|d|dd |d d |d |ddd d }||jd <|jd |jd<d S)aY!Internal function for getting the time out of ATCF data. Do not call this. It is an internal implementation routine. Adds to this StormInfo object the "when" parameter that contains the analysis time. If available, will also add the "technum" technique sort number. The instr is a line of original input text for error messages, the "data" is an output from _split_carq, and the other parameters are inputs to the original constructor. @param data Four element array where the last two are the forecast hour and minute. @param tech technique name to grep for, usually CARQ, though BEST also works when using B deck files @param logger a logging.Logger for log messages @param raise_all raise all exceptions instead of ignoring some of themrr^ZBESTtechnumrai@Bi'rN)r?monthdayhourminutesecond microsecondtzinfor>z%Y%m%d%Hr)rdrrr)r%rirrtruZiminZiwhenr>rrrrs   zStormInfo._parse_atcf_timecCszddlm}m}m}|j}d|kr*|j} nt} | |d<t|} | dkryBt|d} |d} t || | | |ddd|| |d | f<WnRt t t t fk r} z.|d k r|jd t| |fd d |r̂WYd d } ~ XnX| dkrvyBt|d}|d}t || |||ddd|||d|f<WnJt t t t fk rt|d k rh|jdt| |fd d |rpYnXd S)a!Internal function for parsing radii and sea information in ATCF data Do not call this. It is an internal implementation routine. Adds to this StormInfo object radii and sea height data from the given input. The instr is a line of original input text for error messages, the "data" is an output from _split_carq, and the other parameters are inputs to the original constructor. @param instr string to parse @param tech technique name to grep for, usually CARQ, though BEST also works when using B deck files @param logger a logging.Logger for log messages @param raise_all raise all exceptions instead of ignoring some of themr)ft2mnmi2kmkts2mpsrj r^z windcode%02dNz'could not parse wind radii: %s line: %sT)r"Zseasz seascode%02dz-could not parse wave height info: %s line: %s)hwrf.constantsrrrrrjrMrbrdrrrrrrrr)r%instrrirtrurrrrrjnrkZwindcoderxZiseasZseascoderrrr s@    z StormInfo._parse_atcf_radii_seascs2dk r(ttj r(tdtjddlm}m}m }t }|j d} d} dd<t dd<t d d <t d d <fd d} fdd} |dkrڈddkr| dd||dkrddkr| dd|dkrddkrdd<|dkr>ddkr>| dd|dkrbddkrb| dd||dkrddkr| dd||d krddkr| d!d||d"krΈd dkr| d#d ||d$krd"dkrd"} |d%kr d$dkr d$d&kr | d'd$||d(krDd%dkrDd%d)<|d*kr~d(dkr~d(d+krtd7d-<n | d-d(|d.krd*dkr| d/d*||d0krΈd.dkrtd.jd1<|d2krd0dkrtd0jdd3<|j| | |jt d4d5d1jd6<dS)8a !Internal function that parses most of a line of ATCF data. Do not call this. It is an internal implementation routine. Parses just about everything except the time, radii and sea height from the input ATCF data. The instr is a line of original input text for error messages, the "data" is an output from _split_carq, and the other parameters are inputs to the original constructor. @param instr string to parse @param data split-up elements of a A deck line @param tech technique name to grep for, usually CARQ, though BEST also works when using B deck files @param logger a logging.Logger for log messages @param raise_all raise all exceptions instead of ignoring some of themNzLin _parse_atcf_meat, logger must be a logging.Logger, but instead it is a %sr)rrrr` techniquerztaurr=r{rcsy(t|}|dkr&t|||<Wnrttttfk r}zNdk rnjdt|t|fddrt d|t|fWYdd}~XnXdS)Nrzcould not parse %s: %s line: %sT)rz%s: %s: line %s) rdrZrrrrrrr'rr)srmrAZixrx)rrirrtrurrfic[s z'StormInfo._parse_atcf_meat..ficcsy t|}|dkr||<Wnrttttfk r}zNdk rfjdt|t|fddrtd|t|fWYdd}~XnXdS)Nrzcould not parse %s: %s line: %sT)rz%s: %s: line %s) rZrrrrrrr'rr)rrmZfxrx)rrirrtrurrfaks  z&StormInfo._parse_atcf_meat..fa rr^wmaxrpminr stormtyperpocir|rocirmwgustseyediamLmaxseasrZinitialsXcrrrr6rdepthr~Tri)rrrrr)rrrrrrbrrdrrr _set_basinrenumber_stormr)r%rrirtrurrrrr#r$rrZ subregionr)rrirrtrurr<sd          &      zStormInfo._parse_atcf_meatcCs|j|ttjjjddS)a|!Do not call this routine directly. Call StormInfo("message",instr) instead. This subroutine parses one line of a hurricane message text that is assumed to be for the current century. The format of a hurricane message is the same as for a tcvitals file, except that the century is omitted and the file is always exactly one line.r)century)rrdrutcnowr?)r%rrrrrs zStormInfo._parse_message_linecCs(tjd|}|s$tdt|f|tdA}tdB}tdC}tdD}tdE}tdF} tdG} tdH} |j} d$| kr|| d$} nt} | | d$<t|j}x|jD]\}}|d%kr||krĐqtd&t |t|f|y"||kr|| |<n||krt |j | |<n|| kr0t |j | |<n|| krPt |j d'| |<n||krlt |j | |<n|| krt |j }t |j | |<|d(kr| j |nX||krt|d'}|d%kr||krtd)t |t |t|f||| |jd*d+<WnJtk rL}z,td,t |t|t |t|f|WYd%d%}~XnXqWd| kod | kod!| kod"| ko| dd(kp| d d(kp| d!d(kp| d"d(k| d-<d.| kod/| ko| d.d%k o| d/d%k | d0<d| kr| dj j| d1<ntd2|f|d| krd| krd| krDt | d}n*t t}|d3ks`|d4krntd5|fd6|t | dt | dd7f}|| d8<tjj|| d9<ntd:t|f||jd;kr|jd(krd<|_d| kr|j|jntd=|f||j|jd>d?| d1j| d@<|S)Ia!Parses one line of tcvitals data Do not call this routine directly. Call StormInfo("tcvitals",instr) instead. This subroutine parses one line of a tcvitals file of a format described here: http://www.emc.ncep.noaa.gov/mmb/data_processing/tcvitals_description.htm Here is an example line with only some of the possible data: @code{.tcvitals} JTWC 31W HAIYAN 20131104 1200 061N 1483E 270 077 0989 1008 0352 23 064 0084 0074 0074 0084 M ... more stuff ... @endcode The resulting data is put in self._data. Note that, at this time, there is one new field not present in the above mentioned webpage. The "storm type parameter" is a two letter description of the type of the storm: LO=low, WV=wave, etc. (there are many possibilities). That field is at the end of the line described in the above link, after one space. The "century" argument is the first two digits of the year, so 19 for the 1900s, 20 for the 2000s and so on. If century is missing or None, and the tcvitals does not specify the century either, then InvalidVitals will be raised. If both are available, the tcvitals century is used.ac(?xi) (?P
\S+) \s+ (?P\d\d)(?P[A-Za-z]) \s+ (?P[A-Za-z_ -]+) \s+ (?P\d\d)? (?P\d\d\d\d\d\d) \s+ (?P\d\d\d\d) \s+ (?P-?0*\d+[NS ]) \s+ (?P-?0*\d+[EW ]) \s+ (?P-?0*\d+) \s+ (?P-?0*\d+) \s+ (?P-?0*\d+) \s+ (?P-?0*\d+) \s+ (?P-?0*\d+) \s+ (?P-?0*\d+) \s+ (?P-?0*\d+) \s+ (?P-?0*\d+) \s+ (?P-?0*\d+) \s+ (?P-?0*\d+) \s+ (?P-?0*\d+) (?: \s+ (?P\S) (?: \s+ (?P-?0*\d+) \s+ (?P-?0*\d+) \s+ (?P-?0*\d+) \s+ (?P-?0*\d+) (?: \s+ (?P-?0*\d+) \s+ (?P-?0*\d+[NS ]) \s+ (?P-?0*\d+[EW ]) (?: \s+ (?P-?0*\d+) \s+ (?P-?0*\d+) \s+ (?P-?0*\d+) \s+ (?P-?0*\d+) (?: \s+ (?P\S\S?) )? )? )? )? )?zCannot parse vitals: %sNE50SE50SW50NW50rfstrlatfstrlonNE64SE64SW64NW64r rawcenturyr rawbasin rawstormname rawYYMMDDrawHHMMstrlatstrlonr;r5rrrrrrNE34SE34SW34NW34rrjNz0Mandatory variable %s had None value in line: %sg$@rz6Mandatory variable %s had invalid value %s in line: %srr^z4Cannot parse vitals key %s value %s: %s from line %srCrrrr6z'No storm name detected in this line: %srz8Implausable tcvitals century %d. Require 16 through 20.z %02d%06d%02drrr>z.Cannot determine date and time from vitals: %srQz$Cannot find a basin in this line: %sT) discardoldr)rrrrrrrrrrrrrr )rrrrrr )rrrr)r;r)r5)rrrrrrr) rr r!r"rrrrrrrr)r)rWrXrr'rMrdictrYrrrrZrdrOrreplacerrrrrrrrrr=r r r5r)r%rr r\ZnoneokZrawsZlatlonsZstripmeZint1Zfloat1Z float1radiiZfloat10rrjr]rrHvalreplrxZicenturyZsdaterrrrs              :(:     zStormInfo._parse_tcvitals_lineFcCsd|jkr| r|j|jd<t|tr:t|dd|_n:t|dd|_|jdks\|jdkrdd|_n|jdd|_|jdk stdS)z!Sets the two letter storm type self.stormtype. @param discardold If discardold=False (the default), then the old value, if any, is moved to self.old_stormtype. @param stormtype the storm type informationr old_stormtyperraZXXNr^)rrrrgetattrrc)r%rr%rrr set_stormtypeJs  zStormInfo.set_stormtypecCsd|jkr| r|j|jd<t|dd|_|jdksB|jdkrpd|jdd|jdd|jdd f|_|jj|jd <d S) z!Sets the name of the storm. @param newname the new storm name @param discardold If discardold=False (the default) then the old storm name is moved to self.old_stormname.r6 old_stormnamerrror-z%s%-9s%srNr)rr6rrrwr)r%Znewnamer%rrr rename_storm[s  zStormInfo.rename_stormcCsd|jkrR| rR|j|jd<|j|jd<|j|jd<|j|jd<|j|jd<d|_t||_d|j|jf|_d |j |jf|_d|j|j f|_|j d kr|j j d krd |j |j|j jd f|_nd |j |j|j jf|_|jdks|jdkrd|jd d|j|jd df|_dS)aU!Changes the storm number. Changes the storm number: the 09 in 09L. That changes self.stnum, stormid3, stormid3lc, stormid4 and longstormid. @param newnumber the new storm number @param discardold If discardold=False (the default), then the old values are moved to the old_stnum, old_stormid3, etc.r5 old_stnum old_stormid3old_stormid3lc old_stormid4old_longstormidTz%02d%sz%s%02drr{z %s%02d%04dr~ror-z%s%02d%srzN)rr5rB stormid3lcrDr@rrdr< pubbasin2basin1lcr=r>rr?rrw)r%Z newnumberr%rrrr is&         zStormInfo.renumber_stormcs|fdd}|dd|dd|dd|d d |d d jd ksRjdkrxdjddjjddf_dS)z!Swaps the new and old stormid variables. The stnum and old_stnum are swapped, the stormid3 and old_stormid3 are swapped, and so on.cs<|jkr8|jkr8j|}j|j|<|j|<dS)N)r)orkeep)r%rrswapnames z(StormInfo.swap_numbers..swapnamer/r5r0rBr1r4r2rDr3r@ror-z%s%02d%srrzr{N)rrwr5)r%r9r)r%r swap_numberss      zStormInfo.swap_numberscCs |j|jfS)av!Returns the geographical location (e.g., longitude and latitude) collected from the tcvitals. This is useful for routines which require only TC position as opposed to the entire TC-vitals record. However, this may become obsolete in the future if/when the respective routines are able to handle the entire TC-vitals record. )rr=)r%rrr as_geolocs zStormInfo.as_geoloccCs |jddS)zx!Returns a tcvitals version of this data. This is not cached, and will be recalculated every time it is called.F) no_century)as_tcvitals_or_message)r%rrr as_tcvitalsszStormInfo.as_tcvitalscCs |jddS)z|!Returns a message line version of this data. This is not cached, and will be recalculated every time it is called.T)r<)r=)r%rrr as_messageszStormInfo.as_messagec sX|jfdd}fdd}dd}|r0d}nd}d t|jd d tt|jd t|jd t|jd d |jj |t d||j d|j d krdndt d||j d|j d krdnd|drd:nt d||j |drd;nt d||jd|drdd>nt d||j|drZd?nt d||j|d rvd@nt d||j|d!rdAnt d||j|d"rdBnt d||j|d#rdCnt d||j|d$rdDnt d||jf}d%koDd&koDd'koD|jd(k oD|jd(k oD|jd(k oD|jd k}d)k}d*krl| rl| rl|Sd+|tt|d*d,d f}d-kr| r| r|Sd.||d/rdEnt d||j|d0rdFnt d||j|d1rdGnt d||j|d-r dHnt d||jf}|rd2||jd kr:dInt dt|jt d||jd|jd krjdndt d||jd|jd krdndf}d3kr| r|S|s|d47}d.||d5rdJnt d||j |d6rdKnt d||j!|d7rdLnt d||j"|d3r dMnt d||j#f}|s>|Sd8|t|j$d d9fS)NaP!Internal function that underlies as_tcvitals() and as_message() Returns a tcvitals or message version of this data. This is not cached, and will be recalculated every time it is called. @param no_century If no_century=True, then only two digits of the year are written, and the line will be a message.cs(|kr dS|}|dkr dS|dkS)NTrr)rr()rrrbads z-StormInfo.as_tcvitals_or_message..badcs(|kr dS|}|dkr dS|dkS)NTgh㈵>r)rr()rrrbad0s z.StormInfo.as_tcvitals_or_message..bad0cSsttt|S)N)rdabsr)rmrrrcintsz.StormInfo.as_tcvitals_or_message..cintz %y%m%d %H%Mz %Y%m%d %H%MzX%-4s %02d%s %-9s %s %03d%s %04d%s %03d %03d %04d %04d %04d %02d %03d %04d %04d %04d %04drr`rrig$@NSiEWrrihririLrri'rrrr r!r"rrrNrr z%s %srrz%s %04d %04d %04d %04drrrz%s %02d %03d%s %04d%srz -9 -99N -999Wrrrz%s % 2sraiiiiiiiiiiiiiiiiiiii)%rrr;rdrBr5r<r6r>rminr=rrrrrrrrrr r!r"rrrr+rrrrrrrrr) r%r<r@rArCZ datestringrZgotfcstZgotstr)rrr=s|    "" " ""z StormInfo.as_tcvitals_or_messagecCs|s@|j|jd<|j|jd<|j|jd<|j|jd<|j|jd<|j|||jdkrd|jdd |jd|jd d f|_d S) a=!Changes the basin of this StormInfo @param basin the primary basin (IO, L, etc.) @param subbasin the subbasin. For example, IO has the subbasins AA and BB. @param discardold If discardold=False (the default), then the old values are moved to the old_stnum, old_stormid3, etc. Zold_hwrfbasin2Z old_pubbasin2Z old_basin1Z old_basin1lcZ old_basinnameroz%s%s%srr{rN) hwrfbasin2rr5r<r6 basinnamer rrw)r%r#r$r%rrr change_basins       zStormInfo.change_basincCs\t||}|d|jd<|d|jd<|dj|jd<|dj|jd<|d|jd <d S) a!This is a utility function that creates the one and two letter basins from a raw one and/or two letter basin. If the input basin is invalid, InvalidBasinError is raised. @param basin the primary basin (IO, L, etc.) @param subbasin the subbasin. For example, IO has the subbasins AA and BB. @param discardold If discardold=False (the default), then the old values are moved to the old_stnum, old_stormid3, etc. rrIr~r5rar<r6rrJN)rrrr)r%r#r$r%bbrrrr s zStormInfo._set_basincCsd|_d|_d|_d|_d|_d|_d|_d|_d|_d|_ d|_ d|_ d|_ d|_ d|_d|_d|_d|_d|_d|_d|_d|_d|_d|_d|_d|_d|_d|_d|_d|_d|_d|_d|_ d|_!d|_"d|_#d|_$d|_%d|_&d|_'d|_(d|_)d|_*d|_+d|_,d|_-d|_!d|_.d|_"d|_d|_/d|_0d|_1d|_2d|_3d|_4d|_5d|_/d|_6d|_7d|_8d|_9d|_:d|_;d|_d|_?dS)z`!Ensure that self.varname exists for all member variables, so that Doxygen detects themr^r~N)@r;rrrrr6rrr>rrjZ windcode34Z windcode50Z windcode64rrr=rrrrrrrrrrrr rrrrrrrrrrrrrrrrrrr5rr r!r"r*r-r/rBr0r4r1rDr2r@r3rw)r%rrrZ __doxygen'szStormInfo.__doxygen)rNT)N)rNT)NT)rNT)NT)NT)N)F)F)F)F)NF)NF)rr r!r"r&rrrrrrrrrrrrr,r.r r:r;r>r?r=rKr Z_StormInfo__doxygenr/rr)r.rrs4 F _ 6 /  1 T 0     V  cCst|j}|dkrdn t|j}|dks4|dkr}n|dkr|dkrtd?}n$|dkrd@}n|d*krdA}ndB}nj|dkr|dkrdC}n|dkrdD}ndE}n:|d*krdF}n*|d!krdG}n|d$krdH}n t|||S)Ia.!Converts basin identifiers Given a one-letter or two-letter tropical basin identifier, and possibly another one-letter tropical basin identifier (subbasin), attempts to determine more information about the basin. Some information may be ambiguous if a two letter basin is specified. Returns a four-element tuple: 1. The internal (HWRF/GFDL) two-letter basin identifier. These have an unambiguous mapping to the one-letter basin. 2. The public, standard two-letter basin identifier used by JTWC and others. These are ambiguous: IO can be A or B, and SH can be S or P. 3. The one-letter basin identifier. 4. A description of the meaning of the basin. @param basin the primary basin @param subbasin Optional: the subbasin, if knownNr^ALrNorth Atlantic (L/AL)SLr$South Atlantic (Q/SL/LS)LSEPrFNorth East Pacific (E/EP)CPCNorth Central Pacific (C/CP)SSrESHSouth Pacific (S/SH)PPPSouth Indian Ocean (P/SH/PP)AAAIO#Indian Ocean: Arabian Sea (A/IO/AA)NA#Indian Ocean: Arabian Sea (A/IO/NA)BBB%Indian Ocean: Bay of Bengal (B/IO/BB)WPOOO2North West Pacific: South China Sea Basin (O/W/WP)TTT+North West Pacific: East China Sea (T/W/WP)rGNorth West Pacific (W/WP)South Indian Ocean (P/SH)UUU*South Pacific: Australian Basin (U/P/S/SH)(South Pacific or South Indian Ocean (SH) Indian Ocean: Arabian Sea (A/IO)"Indian Ocean: Bay of Bengal (B/IO)#Unspecified North Indian Ocean (IO))rMrMrrN)rOrOr$rP)rQrQr$rP)rRrRrFrS)rTrTrUrV)rWrXrErY)rZrXr[r\)r]r_r^r`)rar_r^rb)rcr_rdre)rhrfrgri)rkrfrjrl)rfrfrGrm)rfrfrGrm)rWrXrErY)rZrXr[rn)rprXrorq)rXrXrErr)r]r_r^rs)rcr_rdrt)r_r_rdru)rprXrorq)rhrfrgri)rkrfrjrl)rrr)r#r$rrrLrrrr s                )NNN)rU)r^r_)NF)NFNNN)NT)N)*r"__all__rWrrZ fractionsrr hwrf.numericsrrZhwrf.exceptionsrZpdb functoolsrrrdnowr?rrrrrrrrr r r r r rrrrrrobjectrrrrrrsV0   /  +  4 !p