U $gg@sddlZddlZddlZddlZddlZddlZddlZddlZddl Zddl Z ddl Z ddl Z ddlZ ddl mZmZmZddlmZmZmZddlmZmZmZddl mZmZmZddlmZGdddeZGd d d eZGd d d eZ Gd dde j!j"Z#GdddeZ$dS)N) setrlimitrusage getrlimit) isnonempty make_symlink deliver_file)mpirunmpiopenmp) to_fractionto_datetime_rel TimeMapping)jloggerc@s0eZdZdZddZeddZeddZdS) ComponentafThis is a simple utility class that stores information about coupler components (wrf, pom, hycom, wavewatch3, coupler, etc.) for the CoupledWRF class. You should never instantiate a Component -- only CoupledWRF should do that. It will return one of these when you run CoupledWRF's "component" function. You can safely modify the exe, rankname, rankdefault and initer elements of this class, and it will modify the corresponding information in the CoupledWRF. Do not modify the name and order. Modifying the name or order will break the internal data structures in CoupledWRFcCs,|||||f\|_|_|_|_|_d|_dS)zCreates a Component with the given characteristics. Initializes the order to None. The order must be overwritten externally, and is done in CoupledWRF.couple.N)_nameexerankname rankdefaultiniter_order)selfnamerrrrr;/lfs/h1/ops/prod/packages/hwrf.v13.2.9/ush/hwrf/coupling.py__init__s zComponent.__init__cCs|jSN)rrrrrr!szComponent.namecCs|jSr)rrrrrorder#szComponent.orderN)__name__ __module__ __qualname____doc__rpropertyrrrrrrrs   rc@s(eZdZdZddZddZddZdS) ComponentIniteraThis class should be subclassed to make coupling component initializers for CoupledWRF. That is, you should implement a subclass and send it to the CoupledWRF.couple(...,initer=). Its job is to provide input data and initialization checks for the various coupling components such as ocean and wave. Note that the CoupledWRF itself initializes the WRF and coupler, so you do not need a ComponentIniter for those components.cCs tddS)zThis function implements a very fast (<1 second) check to see if the components initialization was complete. Returns True on success or False on failure.z2Subclass forgot to implement check_coupled_inputs.N)NotImplementedErrorrloggerrrrcheck_coupled_inputs/sz$ComponentIniter.check_coupled_inputscCs|r||SdS)aIf just_check is True, then this function implements a more expensive check of whether the initialization for this component succeeded. If just_check is False, then this component should link or copy all files needed to run a coupled forecast. The default implementation calls check_coupled_inputs if just_check is True, and simply returns True if just_check is False. Subclasses should re-implement this function.T)r')r just_checkr&rrrlink_coupled_inputs5s  z#ComponentIniter.link_coupled_inputscCst|||S)a)Called when it is time to actually run the coupled forecast executables. Returns a produtil.mpiprog.MPIRanksBase for the MPI ranks for this component of the coupling. By default, this returns mpi(task.getexe(exe))*ranks. However, the caller can re-implement this function to replace the executable depending on the results of the initialization. If that is desired, the task.getexe (and other task.get*) should be used so the executable locations can be overridden in the config files.)r getexe)rtaskrranksrrrmake_exeAs zComponentIniter.make_exeN)rrr r!r'r)r-rrrrr#'s r#cs$eZdZddZfddZZS) TurboInitercCsdSNTrr%rrrr'Nsz TurboIniter.check_coupled_inputscsBtt||||}d|_tddt|f|js>t|S)zk!Turns on Intel turbo mode for the specified executable, if the local MPI implementation knows how.Tz coupling.pyzexe for wrf compute is %s) superr.r- turbomodelogging getLoggerinforeprAssertionError)rr+rr,m __class__rrr-Ps   zTurboIniter.make_exe)rrr r'r- __classcell__rrr8rr.Msr.cseZdZdZd+fdd Zd,fdd Zd-fd d Zd.fd d ZfddZd/ddZ ddZ d0ddZ ddZ ddZ ddZd1ddZdd Zd!d"Zd#d$Zd%d&Zd2d'd(Zd3fd)d* ZZS)4 CoupledWRFzRuns the NCEP coupler and WRF, coupled to at least one ocean or wave model. This class is not thread-safe due to how self.couple is implemented.Tauxhist1c sFtt|j||||||f|t|_t|_t|_d|_d|_ dSr/) r0r;rdict_CoupledWRF__componentslist_CoupledWRF__order_coupled_products_CoupledWRF__coupled_default_coupling)rdstoreconfsectionwrfkeeprunwrfdiag_streamkwargsr8rrr_szCoupledWRF.__init__Ncs\|dk r|j|_|}tt|}|rX|rX|D] }|jdk r6|jj|d}q6|S)zReturns True if all inputs needed to run the forecast are present, and false otherwise. If coupled=True (the default), then coupled components inputs are also checked, otherwise only WRF inputs are checked.Nr&) rCrBlogr0r;check_all_inputs coupleiterrr')rcoupledr&okaycr8rrrMls  zCoupledWRF.check_all_inputsFcs|}tt|j|d}|r8|r.|dn |d|dkrF|j}|dkrT|j}|sf|d|S|st|d| D]d}|j dk r||o|j j ||d}|sd|j f}|||st j|d S|d |j fq||S) aIf just_check=True, links or copies inputs required by all components of the coupled simulation. If just_check=False, runs through all steps required to link or copy inputs without actually linking or copying. That mode is intended to be an expensive but more thurough check than check_all_inputs. Returns True if all inputs were linked, and False otherwise.)r(zWRF inputs are present.zFAIL: WRF inputs are missing.NzYNot copying ocean, wave and coupler inputs because an uncoupled simulation was requested.cpl_nmlrKz%s inputs are missing.Fz%s inputs are all present.)rLr0r;link_all_inputsr4errorrBrCmake_coupler_namelistrNrr)rhwrf exceptionsOceanInitFailed)rr(rOr&rPrQmsgr8rrrSzs@          zCoupledWRF.link_all_inputscs&|dkr|j}||_tt|dS)zRuns the coupled simulation. Sets the internal coupled vs. uncoupled flag to the specified value. Default: True (coupled).N)rCrBr0r;run)rrOr8rrrZszCoupledWRF.runc s|}t|dddtjdd}t|}|jdkr>|j|_|jr|dd}t }t }| D]V}|d|j |j |j|jt|jf|j}||j|j}t|tstd t|jt|f|d kstd ||jdk r2|j d ks|j d kr t|j||||d} n|j|||} nF|j d ksJ|j d krftt||||d} nt|||} |dt| t| jf|||j <||j |dkr| n|| }qh|dkrtj !d|"d} t#d| f|j$ddD]B\} } |dt| t| t| jf| dkr| jst%qt&|j'|d| k}|(|||}t)dsztj *dt+t,|-dd|n|dt+t,|-ddddS)zrRuns the MPI command for the coupled coupled simulation. Do not call this directly: call self.run instead.g ZAT)r&stackignore ATM_THREADS1Nz#Starting the coupled wrf simulationz6Component #%d is %s: exe=%s ranks from %s (default %s)zbSomehow ended up with a non-int for ranks in CoupledWRF.run_exe. Check inputs. Ranks is a %s %s.rzLRanks (%d) is not >0 in CoupledWRF.run_exe. Check config files and scripts. wrf_computewrf_io)threadsz Appending ranks %s with turbo=%szTNo coupled components specified in CoupledWRF. You must call CoupledWRF.couple(...)z {coupled_log}z)%s: will log coupled forecast stdout hereF)expandz#Will run rank %s * %s with turbo=%si)OMP_NUM_THREADSrRz5Logic error: somehow the cpl_nml is empty or missing.rGz%Starting the uncoupled wrf simulation).rLrosenvirongetintrBrCr4r=r?rNrrrrr5rconfint isinstance TypeErrortyper ValueErrorrr r-r r*r1appendrVrWNoCoupledComponents confstrinterpr expand_iterr6renvcall_run_exe_callbacksrEmptyCouplerNamelistr0r;run_exe) rr&racmdZ callback_argsZcallback_componentsrQrr,ZmpiifiedZlogfilerankcountr8rrrts           zCoupledWRF.run_exerRc Cs|}|d|jf|d}|d}t|}t|j|j}t t t ||}t ||d}|dt|t|t|t|ftjj|j||d} t|d} | j|d} | | W5QRXd S) z'Makes the namelist for the NCEP Couplerz section is %srRdt_c)cstepmaxrxz'dt_c=%s f_dt_c=%s simlen=%s cstepmax=%s)rErFmorevarswt)rzN)rLr4rFconfstrrhr simsimendsimstartrgmathceilfloatr=r5rVnamelist Conf2NamelistrEopen make_namelistwrite) rfilenamer&ZcplsecrxZf_dt_csimlenryrzZcplnmlZcnZnmlstrrrrrUs,     z CoupledWRF.make_coupler_namelistccs,d}|jD]}|d7}|j|}|Vq dS)zNIterates over all Component objects that describe coupling components.N)r@r>)rirrQrrrrNs   zCoupledWRF.coupleitercCst|ts$tdt|jt|f|dksH|ddksH|ddkrPtd|dk r|t|ts|tdt|jt|ft|tstd t|jt|ft|tstd t|jt|f|dkrdnt|}||j kr|j |t |||||}| ||_||j |<|S) aWAdds the specified coupling component. Returns self. name -- a user-defined name of this component, must be a string. exe -- option in the [exe] section with the executable path rankname -- name of the option in this task's section that has the number of ranks rankdefault -- number of ranks if the rankname option is missing or empty. Can be None, in which case the rankname option must be set. initer -- the object that will link inputs ot the working directory before the forecast begins. Can be None. Note that the superclass, WRFAtmos, initializes the WRF component and this class initializes the coupler, so you can pass None for those components' "initer" objects. This subroutine is not thread-safe.zOThe "name" argument to CoupledWRF.couple must be a string. You passed a %s %s.outputhistoryrestartZ restartininputinputoutauxhistrauxinputzComponent name cannot be the same as any WRF stream name: output, history, restart, restartin, input, inputout, auxhist* or auxinput*.Nz\The "rankdefault" argument to CoupledWRF.couple must be None or an int. You passed a %s %s.zOThe "exe" argument to CoupledWRF.couple must be a string. You plassed a %s %s.zTThe "rankname" argument to CoupledWRF.couple must be a string. You plassed a %s %s.)ristrrjrkrr5findrlrgr>r@rmrrr)rrrrrrZrdrQrrrcouplesN         zCoupledWRF.couplecCs|}|j}|j}|dd}t|ts4t|trB|t|}n|}|||}|dkr|dkrp||}nd}| ddd|t | ddd|n|dkr| ddd|t dS) a}!Wrapper around one or two calls to couple() to add the WRF. Attempts to add the WRF to the coupling in two different sets of MPI ranks: one for WRF compute, and one for WRF I/O. This is done to allow the local MPI implementation to set up the compute nodes differently for the two blocks of processors, thereby speeding up the forecast. wrf_ranksrNr_rGwrf_compute_ranksr`Z wrf_io_ranks) rGnio_tasks_per_group nio_groupsrhrir?tuplesummaxdomrr.)rrGZ nio_pergrouprrniorrrrr couplewrf@s    zCoupledWRF.couplewrfcCsdSrrrrrr remove_waveizCoupledWRF.remove_wavecCsdSrrrrrr remove_oceanjrzCoupledWRF.remove_oceancCsx|dkrd|_|S|j|=t}|jD]}||kr&||q&||_|D]}||j|_qLt |dkrt| |S)z!Removes a component, or all components, from the coupling. @param which the name of the component to remove. If None or unspecified, run totally uncoupled. @returns selfNF) rCr>r?r@rmrNrrrlenuncouple)rwhichrwrQrrrrls    zCoupledWRF.uncouplecCsPt|tr|j|St|tr2|j|}|j|Stdt|jt|fdS)zReturns information about the component with the specified name (a string) or at the specified zero-based index (an int). Returns a mutable object of class Component.zMCoupledWRF.component requires an int or string argument. You passed a %s %s.N) rirr>rgr@rjrkrr5)rrrrrr components     zCoupledWRF.componentcCs4d}|jD]}|d7}||kr |Sq t|dS)aComponents of coupling are ordered by where they show up in the MPI execution. The NCEP coupler must be first. This function returns the zero-based order. Hence, if one does: self.couple("coupler",...).couple("hycom",...).couple("wrf",...) then: self.order("coupler") = 0 self.order("hycom") = 1 self.order("wrf") = 2 Other values will raise KeyError.rrN)r@KeyError)rrrorrrrs   zCoupledWRF.ordercsl|dks$|ddks$|ddkr2td|f||jkrh|jfdd|D}t|t|j|<|S)z!Adds a new non-WRF output stream.rrrrzComponent stream name (%s) cannot be the same as any WRF stream name: output, history, restart, restartin, input, inputout, auxhist* or auxinput*.csg|]}t|qSr)r ).0tarr sz1CoupledWRF.add_coupled_stream..)rrlrAr}rr r?)rstreamtimesZtimerelrrradd_coupled_streams    zCoupledWRF.add_coupled_streamcCs|j||||S)z;Adds a product for a non-WRF output stream at a given time.)rArm)rrtimeproductrrradd_coupled_productszCoupledWRF.add_coupled_productccs|dkr|dkrH|jD]*\}}|D]\}}|D] }|Vq6q*qq|jD].\}}||d}|dkrpqR|D] }|VqtqRnd||jkr|j|}|dkr|D]\}}|D] }|Vqqn$||d}|dk r|D] }|VqdS)zIterates over non-WRF products.N)rAitemsrf)rrrstprodrprodsprrrcoupled_productss,      zCoupledWRF.coupled_productsc+sp|dkrd}d}n||jk}| }|rPtt|jf|||d|D] }|VqD|rl|||D] }|Vq`dS)z1Iterates over all products, both WRF and non-WRF.NT)domainsrr)rAr0r;productsr)rrrrrJrOrGrr8rrrs"   zCoupledWRF.products)Tr<)N)FN)N)rR)NN)N)NN)NNN)rrr r!rrMrSrZrtrUrNrrrrrrrrrrrr:rrr8rr;[s* ' G  1)   r;c@sneZdZdZdddZeddZeddZed d Zdd d Z d dZ dddZ dddZ dddZ dS)CouplingStatusz?Maintains the ocean and wave status files in the COM directory.NcCsL||_||_t|ts0tdt|jt|f|dkrB||}||_ dS)NzNThe section argument to CouplingStatus.__init__ must be a string, not a %s %s.) _CouplingStatus__conf_CouplingStatus__sectionrirrjrkrr5rL_CouplingStatus__logger)rrErFr&rrrrs  zCouplingStatus.__init__cCs|jS)z/The logging.Logger to use for logging messages.)rrrrrr&szCouplingStatus.loggercCs|jS)z>The configuration object, a subclass of hwrf.config.HWRFConfig)rrrrrrEszCouplingStatus.confcCs|jS)z>The section in self.conf to use for configuration information.)rrrrrrFszCouplingStatus.sectioncCs`|dkr|j}|j|jdfD]<}|j|j|}tj|jd|}tj j |d|dqdS)zzDelete the coupling status files. If the logger is not specified, the section name is used for the logging domainN2comT)r4r&) r&rFrEgetstrrdpathjoingetdirprodutilfileop remove_file)rr&Zocstat ocstatfilerrrunsets zCouplingStatus.unsetccs<|j|jd|jdV|j|jd|jdVdS)N{}z2})rE strinterprFrrrrfileiterszCouplingStatus.fileiterc Cs|dkr|}t|}|D]|}|r,dnd}|d||ft|dJ}|d|d|dk r|D]$}|d||f||dqlW5QRXq dS) zSet RUN_COUPLED=YES (true) or =NO (false) depending on the value of coupled_flag. If the logger is not specified, the section name is used as the logging domain.NYESNOz(Setting RUN_COUPLED=%s in status file %sr{z RUN_COUPLED= z %s: write %s)rLboolrr4rr)rZ coupling_flagr&Z morelinesrZstrflagflinerrrsets   zCouplingStatus.setc Cs^|dkr|j}|j|jd|jd}tj|s:tSt|d}| d}W5QRX|S)zvReads the first coupling status file (identified by {section}=) and returns the contents as an array of lines.Nrrrti) r&rErrFrdrexistsr?r readlines)rr&rrlinesrrrreads  zCouplingStatus.readc CsR|dkr|j}|j|jd|jd}d}|d|zft|dR}|D]F}|ddkrrd}|d qL|d dkrLd }|d qLW5QRXWnvt k r}z|j d t |fddW5d}~XYn>t k r}z|j dt |fddW5d}~XYnX|dkr2|dd }n|rD|dn |d|S)aChecks the coupling status file. If the file does not exist or cannot be opened or read, then False is returned. Otherwise, the file is scanned for RUN_COUPLED=YES or RUN_COUPLED=NO (case insensitive). The last of those RUN_COUPLED lines is used: NO=return False, YES=return True. If the logger is not specified, the section name is used as the logging domainNrrz.%s: scan status file for RUN_COUPLED=YES or NOrzRUN_COUPLED=YESrTz!Status file says: RUN_COUPLED=YESzRUN_COUPLED=NOFz Status file says: RUN_COUPLED=NOzError checking status file: %s)exc_infoz2Unhandled exception while checking status file: %szOCould not scan status file for RUN_COUPLED=YES or NO. Assuming RUN_COUPLED=NO.zCRUN_COUPLED=YES: status file says coupled component init succeeded.z?RUN_COUPLED=NO: status file says coupled component init failed.) r&rErrFr4rupperrwarningEnvironmentErrorrTr Exception)rr&rZsuccessrreeerrrrfs\   zCouplingStatus.get)N)N)NN)N)N)rrr r!rr"r&rErFrrrrrfrrrrrs       r)%rdshutilrr2produtil.datastorerprodutil.fileop produtil.cd produtil.runprodutil.rusage hwrf.hwrftaskrV hwrf.numericshwrf.exceptions hwrf.fcsttaskrrrrrrrr r r r r produtil.logrobjectrr#r.fcsttaskWRFAtmosr;rrrrrs    &