B
    ß‹dÿr ã               @   s  d Z ddlmZ dZddlmZ ejZej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ZddlZddlZddlmZ yddlmZ W n  ek
rÄ   dd	lmZ Y nX yddlZW n   Y nX dd
lm Z m!Z! dd„ Z"G dd„ de#ƒZ$G dd„ de$ƒZ%G dd„ de$ƒZ&G dd„ de$ƒZ'G dd„ de$ƒZ(G dd„ de$ƒZ)G dd„ de#ƒZ*G dd„ de+ƒZ,G dd„ de,ƒZ-G dd „ d e+ƒZ.G d!d"„ d"e+ƒZ/G d#d$„ d$e/ƒZ0G d%d&„ d&e+ƒZ1G d'd(„ d(e+ƒZ2G d)d*„ d*e+ƒZ3G d+d,„ d,e+ƒZ4G d-d.„ d.e+ƒZ5G d/d0„ d0e+ƒZ6G d1d2„ d2e+ƒZ7G d3d4„ d4e-e2ƒZ8G d5d6„ d6e/e3ƒZ9G d7d8„ d8e-e2ƒZ:G d9d:„ d:e/e3ƒZ;G d;d<„ d<e-e2ƒZ<G d=d>„ d>e/e3ƒZ=G d?d@„ d@e-e2ƒZ>G dAdB„ dBe/e3ƒZ?G dCdD„ dDe-e2ƒZ@G dEdF„ dFe/e3ƒZAG dGdH„ dHe@ƒZBG dIdJ„ dJeAƒZCG dKdL„ dLe jDƒZEdS )Ma*  
This modules contains objects that make it simple for the user to
create python scripts that build Condor DAGs to run code on the LSC
Data Grid.

This file is part of the Grid LSC User Environment (GLUE)

GLUE is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
details.

You should have received a copy of the GNU General Public License along with
this program.  If not, see <http://www.gnu.org/licenses/>.
é    )Úprint_functionz*Duncan Brown <duncan@gravity.phys.uwm.edu>)Úgit_versionN)Úurllib)Úmd5)Údecode)Úloads)ÚconfigparserÚStringIOc             C   s   | d d dk S )zd
  Return True if t is in the S2 playground, False otherwise
  t = GPS time to test if playground
  iÕw+iâ  iX  © )Útr
   r
   úZ/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/glue/pipeline.pyÚs2play6   s    r   c               @   s   e Zd ZdZddd„ZdS )ÚCondorErrorzError thrown by Condor JobsNc             C   s
   || _ d S )N)Úargs)Úselfr   r
   r
   r   Ú__init__@   s    zCondorError.__init__)N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r
   r
   r
   r   r   >   s   r   c               @   s   e Zd ZdS )ÚCondorJobErrorN)r   r   r   r
   r
   r
   r   r   B   s   r   c               @   s   e Zd ZdS )ÚCondorSubmitErrorN)r   r   r   r
   r
   r
   r   r   D   s   r   c               @   s   e Zd ZdS )ÚCondorDAGErrorN)r   r   r   r
   r
   r
   r   r   F   s   r   c               @   s   e Zd ZdS )ÚCondorDAGJobErrorN)r   r   r   r
   r
   r
   r   r   H   s   r   c               @   s   e Zd ZdS )ÚCondorDAGNodeErrorN)r   r   r   r
   r
   r
   r   r   J   s   r   c               @   s   e Zd Zddd„ZdS )ÚSegmentErrorNc             C   s
   || _ d S )N)r   )r   r   r
   r
   r   r   M   s    zSegmentError.__init__)N)r   r   r   r   r
   r
   r
   r   r   L   s   r   c               @   sP  e Zd ZdZdd„ Zdd„ Zdd„ Zdd	„ Zd
d„ Zdd„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zd d!„ Zd"d#„ Zd$d%„ Zd&d'„ Zd(d)„ Zd*d+„ Zd,d-„ Zd.d/„ Zd0d1„ Zd2d3„ Zd4d5„ Zd6d7„ Zd8d9„ Zd:d;„ Z d<d=„ Z!d>d?„ Z"d@dA„ Z#dBdC„ Z$dDdE„ Z%dFdG„ Z&dHdI„ Z'dJdK„ Z(dLdM„ Z)dNdO„ Z*dPdQ„ Z+dRS )SÚ	CondorJobz{
  Generic condor job class. Provides methods to set the options in the
  condor submit file for a particular executable
  c             C   s|   || _ || _|| _i | _i | _g | _i | _d| _d| _d| _	d| _
d| _d| _g | _g | _g | _d| _d| _d| _d| _dS )zš
    @param universe: the condor universe to run the job in.
    @param executable: the executable to run.
    @param queue: number of jobs to queue.
    NT)Ú_CondorJob__universeÚ_CondorJob__executableÚ_CondorJob__queueÚ_CondorJob__optionsÚ_CondorJob__short_optionsÚ_CondorJob__argumentsÚ_CondorJob__condor_cmdsÚ_CondorJob__notificationÚ_CondorJob__log_fileÚ_CondorJob__in_fileÚ_CondorJob__err_fileÚ_CondorJob__out_fileÚ_CondorJob__sub_file_pathÚ_CondorJob__output_filesÚ_CondorJob__input_filesÚ_CondorJob__checkpoint_filesÚ_CondorJob__grid_typeÚ_CondorJob__grid_serverÚ_CondorJob__grid_schedulerZ _CondorJob__executable_installed)r   ÚuniverseÚ
executableÚqueuer
   r
   r   r   V   s(    zCondorJob.__init__c             C   s   | j S )z9
    Return the name of the executable for this job.
    )r   )r   r
   r
   r   Úget_executables   s    zCondorJob.get_executablec             C   s
   || _ dS )z6
    Set the name of the executable for this job.
    N)r   )r   r1   r
   r
   r   Úset_executabley   s    zCondorJob.set_executablec             C   s   | j S )z>
    Return the condor universe that the job will run in.
    )r   )r   r
   r
   r   Úget_universe   s    zCondorJob.get_universec             C   s
   || _ dS )zt
    Set the condor universe for the job to run in.
    @param universe: the condor universe to run the job in.
    N)r   )r   r0   r
   r
   r   Úset_universe…   s    zCondorJob.set_universec             C   s   | j S )z*
    Return the grid type of the job.
    )r-   )r   r
   r
   r   Úget_grid_typeŒ   s    zCondorJob.get_grid_typec             C   s
   || _ dS )za
    Set the type of grid resource for the job.
    @param grid_type: type of grid resource.
    N)r-   )r   Z	grid_typer
   r
   r   Úset_grid_type’   s    zCondorJob.set_grid_typec             C   s   | j S )z;
    Return the grid server on which the job will run.
    )r.   )r   r
   r
   r   Úget_grid_server™   s    zCondorJob.get_grid_serverc             C   s
   || _ dS )zk
    Set the grid server on which to run the job.
    @param grid_server: grid server on which to run.
    N)r.   )r   Zgrid_serverr
   r
   r   Úset_grid_serverŸ   s    zCondorJob.set_grid_serverc             C   s   | j S )z$
    Return the grid scheduler.
    )r/   )r   r
   r
   r   Úget_grid_scheduler¦   s    zCondorJob.get_grid_schedulerc             C   s
   || _ dS )z\
    Set the grid scheduler.
    @param grid_scheduler: grid scheduler on which to run.
    N)r/   )r   Zgrid_schedulerr
   r
   r   Úset_grid_scheduler¬   s    zCondorJob.set_grid_schedulerc             C   s   || j |< dS )z¢
    Add a Condor command to the submit file (e.g. a class add or evironment).
    @param cmd: Condor command directive.
    @param value: value for command.
    N)r#   )r   ÚcmdÚvaluer
   r
   r   Úadd_condor_cmd³   s    zCondorJob.add_condor_cmdc             C   s   | j S )zD
    Return the dictionary of condor keywords to add to the job
    )r#   )r   r
   r
   r   Úget_condor_cmds»   s    zCondorJob.get_condor_cmdsc             C   s   || j kr| j  |¡ dS )zo
    Add filename as a necessary input file for this DAG node.

    @param filename: input filename to add
    N)r+   Úappend)r   Úfilenamer
   r
   r   Úadd_input_fileÁ   s    
zCondorJob.add_input_filec             C   s   || j kr| j  |¡ dS )zg
    Add filename as a output file for this DAG node.

    @param filename: output filename to add
    N)r*   rA   )r   rB   r
   r
   r   Úadd_output_fileÊ   s    
zCondorJob.add_output_filec             C   s   || j kr| j  |¡ dS )z=
    Add filename as a checkpoint file for this DAG job.
    N)r,   rA   )r   rB   r
   r
   r   Úadd_checkpoint_fileÓ   s    
zCondorJob.add_checkpoint_filec             C   s   | j S )z7
    Return list of input files for this DAG node.
    )r+   )r   r
   r
   r   Úget_input_filesÚ   s    zCondorJob.get_input_filesc             C   s   | j S )z8
    Return list of output files for this DAG node.
    )r*   )r   r
   r
   r   Úget_output_filesà   s    zCondorJob.get_output_filesc             C   s   | j S )z=
    Return a list of checkpoint files for this DAG node
    )r,   )r   r
   r
   r   Úget_checkpoint_filesæ   s    zCondorJob.get_checkpoint_filesc             C   s   | j  |¡ dS )z™
    Add an argument to the executable. Arguments are appended after any
    options and their order is guaranteed.
    @param arg: argument to add.
    N)r"   rA   )r   Úargr
   r
   r   Úadd_argì   s    zCondorJob.add_argc             C   s&   | j  |¡ || jkr"| j |¡ dS )z÷
    Add a file argument to the executable. Arguments are appended after any
    options and their order is guaranteed. Also adds the file name to the
    list of required input data for this job.
    @param filename: file to add as argument.
    N)r"   rA   r+   )r   rB   r
   r
   r   Úadd_file_argô   s    
zCondorJob.add_file_argc             C   s   | j S )zO
    Return the list of arguments that are to be passed to the executable.
    )r"   )r   r
   r
   r   Úget_argsÿ   s    zCondorJob.get_argsc             C   s   || j |< dS )aÀ  
    Add a command line option to the executable. The order that the arguments
    will be appended to the command line is not guaranteed, but they will
    always be added before any command line arguments. The name of the option
    is prefixed with double hyphen and the program is expected to parse it
    with getopt_long().
    @param opt: command line option to add.
    @param value: value to pass to the option (None for no argument).
    N)r    )r   Úoptr>   r
   r
   r   Úadd_opt  s    
zCondorJob.add_optc             C   s   || j kr| j | S dS )z±
    Returns the value associated with the given command line option.
    Returns None if the option does not exist in the options list.
    @param opt: command line option
    N)r    )r   rM   r
   r
   r   Úget_opt  s    

zCondorJob.get_optc             C   s$   || j |< || jkr | j |¡ dS )aÀ  
    Add a command line option to the executable. The order that the arguments
    will be appended to the command line is not guaranteed, but they will
    always be added before any command line arguments. The name of the option
    is prefixed with double hyphen and the program is expected to parse it
    with getopt_long().
    @param opt: command line option to add.
    @param value: value to pass to the option (None for no argument).
    N)r    r+   rA   )r   rM   rB   r
   r
   r   Úadd_file_opt  s    


zCondorJob.add_file_optc             C   s   | j S )z4
    Return the dictionary of opts for the job.
    )r    )r   r
   r
   r   Úget_opts)  s    zCondorJob.get_optsc             C   s   || j |< dS )a{  
    Add a command line option to the executable. The order that the arguments
    will be appended to the command line is not guaranteed, but they will
    always be added before any command line arguments. The name of the option
    is prefixed with single hyphen and the program is expected to parse it
    with getopt() or getopt_long() (if a single character option), or
    getopt_long_only() (if multiple characters).  Long and (single-character)
    short options may be mixed if the executable permits this.
    @param opt: command line option to add.
    @param value: value to pass to the option (None for no argument).
    N)r!   )r   rM   r>   r
   r
   r   Úadd_short_opt/  s    zCondorJob.add_short_optc             C   s   | j S )z=
    Return the dictionary of short options for the job.
    )r!   )r   r
   r
   r   Úget_short_opts=  s    zCondorJob.get_short_optsc             C   s6   x0|  |¡D ]"}t| ||¡ƒ ¡ }|| j|< qW dS )zè
    Parse command line options from a given section in an ini file and
    pass to the executable.
    @param cp: ConfigParser object pointing to the ini file.
    @param section: section of the ini file to add to the options.
    N)ÚoptionsÚstrÚgetÚstripr    )r   ÚcpÚsectionrM   rI   r
   r
   r   Úadd_ini_optsC  s    zCondorJob.add_ini_optsc             C   s
   || _ dS )zv
    Set the email address to send notification to.
    @param value: email address or never for no notification.
    N)r$   )r   r>   r
   r
   r   Úset_notificationN  s    zCondorJob.set_notificationc             C   s
   || _ dS )zE
    Set the Condor log file.
    @param path: path to log file.
    N)r%   )r   Úpathr
   r
   r   Úset_log_fileU  s    zCondorJob.set_log_filec             C   s
   || _ dS )zk
    Set the file from which Condor directs the stdin of the job.
    @param path: path to stdin file.
    N)r&   )r   r\   r
   r
   r   Úset_stdin_file\  s    zCondorJob.set_stdin_filec             C   s   | j S )zF
    Get the file from which Condor directs the stdin of the job.
    )r&   )r   r
   r
   r   Úget_stdin_filec  s    zCondorJob.get_stdin_filec             C   s
   || _ dS )zk
    Set the file to which Condor directs the stderr of the job.
    @param path: path to stderr file.
    N)r'   )r   r\   r
   r
   r   Úset_stderr_filei  s    zCondorJob.set_stderr_filec             C   s   | j S )zE
    Get the file to which Condor directs the stderr of the job.
    )r'   )r   r
   r
   r   Úget_stderr_filep  s    zCondorJob.get_stderr_filec             C   s
   || _ dS )zk
    Set the file to which Condor directs the stdout of the job.
    @param path: path to stdout file.
    N)r(   )r   r\   r
   r
   r   Úset_stdout_filev  s    zCondorJob.set_stdout_filec             C   s   | j S )zE
    Get the file to which Condor directs the stdout of the job.
    )r(   )r   r
   r
   r   Úget_stdout_file}  s    zCondorJob.get_stdout_filec             C   s
   || _ dS )z
    Set the name of the file to write the Condor submit file to when
    write_sub_file() is called.
    @param path: path to submit file.
    N)r)   )r   r\   r
   r
   r   Úset_sub_fileƒ  s    zCondorJob.set_sub_filec             C   s   | j S )zw
    Get the name of the file which the Condor submit file will be
    written to when write_sub_file() is called.
    )r)   )r   r
   r
   r   Úget_sub_file‹  s    zCondorJob.get_sub_filec             C   sL  | j stdƒ‚| jstdƒ‚| js*tdƒ‚| js8tdƒ‚yt| jdƒ}W n   td| j ƒ‚Y nX | jdkrØ| jdkr‚td	ƒ‚nV| jd
kr | jdkrØtdƒ‚n8| jdkrÐ| jdkr¼tdƒ‚| j	dkrØtdƒ‚ntdƒ‚| 
d| j d ¡ | 
d| j d ¡ | jdkrT| jd
kr.| 
d| j| jf ¡ | jdkrT| 
d| j| j| j	f ¡ | jdkr~| 
d¡ | 
d¡ | 
d¡ t| j ¡ ƒs¦t| j ¡ ƒs¦| jrv| 
d¡ xL| j ¡ D ]>}| j| rê| 
d| d | j|  ¡ n| 
d| ¡ q¼W xL| j ¡ D ]>}| j| r8| 
d| d | j|  ¡ n| 
d| ¡ q
W x| jD ]}| 
d| ¡ qTW | 
d¡ x8| j ¡ D ]*}| 
t|ƒd t| j| ƒ d ¡ q‚W | 
d| j  d ¡ | jdk	rä| 
d| j d ¡ | 
d| j d ¡ | 
d | j d ¡ | jr(| 
d!| j d ¡ | 
d"t| jƒ d ¡ | ¡  dS )#z2
    Write a submit file for this Condor job.
    zLog file not specified.zError file not specified.zOutput file not specified.zNo path for submit file.ÚwzCannot open file ÚgridNzNo grid type specified.Zgt2z&No server specified for grid resource.Zgt4z)No scheduler specified for grid resource.zUnsupported grid resource.zuniverse = Ú
zexecutable = zgrid_resource = %s %s
zgrid_resource = %s %s %s
z"when_to_transfer_output = ON_EXIT
z'transfer_output_files = $(macrooutput)
z%transfer_input_files = $(macroinput)
zarguments = "z --ú z -z "
z = zlog = zinput = zerror = z	output = znotification = zqueue )r%   r   r'   r(   r)   Úopenr   r-   r.   r/   Úwriter   Úlistr    Úkeysr!   r"   r#   rU   r&   r$   r   Úclose)r   ZsubfileÚcr=   r
   r
   r   Úwrite_sub_file’  sz    














(

*zCondorJob.write_sub_fileN),r   r   r   r   r   r3   r4   r5   r6   r7   r8   r9   r:   r;   r<   r?   r@   rC   rD   rE   rF   rG   rH   rJ   rK   rL   rN   rO   rP   rQ   rR   rS   rZ   r[   r]   r^   r_   r`   ra   rb   rc   rd   re   rp   r
   r
   r
   r   r   Q   sR   		
r   c                   sD   e Zd ZdZ‡ fdd„Zdd„ Zddd„Zd	d
„ Zddd„Z‡  Z	S )ÚCondorDAGJobz°
  A Condor DAG job never notifies the user on completion and can have variable
  options that are set for a particular node in the DAG. Inherits methods
  from a CondorJob.
  c                sH   t t| ƒ ||d¡ t | d¡ g | _d| _g | _g | _t	 
d¡| _dS )zn
    universe = the condor universe to run the job in.
    executable = the executable to run in the DAG.
    é   Úneverr   z[_-]N)Úsuperrq   r   r   r[   Ú_CondorDAGJob__var_optsÚ_CondorDAGJob__arg_indexÚ_CondorDAGJob__var_argsÚ_CondorDAGJob__var_cmdsÚreÚcompileÚ_CondorDAGJob__bad_macro_chars)r   r0   r1   )Ú	__class__r
   r   r   è  s    zCondorDAGJob.__init__c             C   s   t | ƒS )a>  
    Create a condor node from this job. This provides a basic interface to
    the CondorDAGNode class. Most jobs in a workflow will subclass the
    CondorDAGNode class and overwrite this to give more details when
    initializing the node. However, this will work fine for jobs with very simp
    input/output.
    )ÚCondorDAGNode)r   r
   r
   r   Úcreate_nodeõ  s    zCondorDAGJob.create_nodeFc             C   sV   || j krR| j  |¡ | j d|¡}|r>|  |d| d ¡ n|  |d| d ¡ dS )zß
    Add a variable (or macro) option to the condor job. The option is added
    to the submit file and a different argument to the option can be set for
    each node in the DAG.
    @param opt: name of option to add.
    Ú z$(macroú)N)ru   rA   r{   ÚsubrR   rN   )r   rM   ÚshortÚmacror
   r
   r   Úadd_var_optÿ  s    
zCondorDAGJob.add_var_optc             C   s<   || j kr8| j  |¡ | j d|¡}|  |d| d ¡ dS )z|
    Add a condor command to the submit file that allows variable (macro)
    arguments to be passes to the executable.
    r   z$(macror€   N)rx   rA   r{   r   r?   )r   Úcommandrƒ   r
   r
   r   Úadd_var_condor_cmd  s    
zCondorDAGJob.add_var_condor_cmdc             C   sˆ   y| j |  W nt tk
r‚   || jkr0tdƒ‚|rJ| j  dt|ƒ ¡ n| j  dt|ƒ ¡ |  | j | j ¡ |  jd7  _Y nX dS )zr
    Add a command to the submit file to allow variable (macro) arguments
    to be passed to the executable.
    z+mismatch between job and node var_arg indexz'$(macroargument%s)'z$(macroargument%s)rr   N)rw   Ú
IndexErrorrv   r   rA   rU   rJ   )r   Ú	arg_indexÚquoter
   r
   r   Úadd_var_arg  s    
zCondorDAGJob.add_var_arg)F)F)
r   r   r   r   r   r~   r„   r†   rŠ   Ú__classcell__r
   r
   )r|   r   rq   â  s   


rq   c               @   sR   e Zd ZdZddd„Zdd„ Zdd„ Zd	d
„ Zdd„ Zdd„ Z	dd„ Z
dd„ ZdS )ÚCondorDAGManJobzU
  Condor DAGMan job class. Appropriate for setting up DAGs to run within a
  DAG.
  Nc             C   s   || _ d| _|| _dS )zn
    dag = the name of the condor dag file to run
    dir = the diretory in which the dag file is located
    N)Ú_CondorDAGManJob__dagÚ_CondorDAGManJob__notificationÚ_CondorDAGManJob__dag_directory)r   ZdagÚdirr
   r
   r   r   /  s    zCondorDAGManJob.__init__c             C   s   t | ƒS )aD  
    Create a condor node from this job. This provides a basic interface to
    the CondorDAGManNode class. Most jobs in a workflow will subclass the
    CondorDAGManNode class and overwrite this to give more details when
    initializing the node. However, this will work fine for jobs with very simp
    input/output.
    )ÚCondorDAGManNode)r   r
   r
   r   r~   8  s    zCondorDAGManJob.create_nodec             C   s
   || _ dS )zy
    Set the directory where the dag will be run
    @param dir: the name of the directory where the dag will be run
    N)r   )r   r   r
   r
   r   Úset_dag_directoryB  s    z!CondorDAGManJob.set_dag_directoryc             C   s   | j S )z5
    Get the directory where the dag will be run
    )r   )r   r
   r
   r   Úget_dag_directoryI  s    z!CondorDAGManJob.get_dag_directoryc             C   s
   || _ dS )zv
    Set the email address to send notification to.
    @param value: email address or never for no notification.
    N)rŽ   )r   r>   r
   r
   r   r[   O  s    z CondorDAGManJob.set_notificationc             C   s   | j S )zp
    Return the name of the dag as the submit file name for the
    SUBDAG EXTERNAL command in the uber-dag
    )r   )r   r
   r
   r   re   V  s    zCondorDAGManJob.get_sub_filec             C   s   dS )zm
    Do nothing as there is not need for a sub file with the
    SUBDAG EXTERNAL command in the uber-dag
    Nr
   )r   r
   r
   r   rp   ]  s    zCondorDAGManJob.write_sub_filec             C   s   | j S )z4
    Return the name of any associated dag file
    )r   )r   r
   r
   r   Úget_dagd  s    zCondorDAGManJob.get_dag)N)r   r   r   r   r   r~   r’   r“   r[   re   rp   r”   r
   r
   r
   r   rŒ   *  s   
	
rŒ   c               @   sž  e Zd ZdZdd„ Zdd„ Zdd„ Zdd	„ Zd
d„ Zdd„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zd d!„ Zd"d#„ Zd$d%„ Zd&d'„ Zd(d)„ Zd*d+„ Zd,d-„ Zd.d/„ Zd0d1„ Zd2d3„ Zd4d5„ Zd6d7„ Zd8d9„ Zdfd;d<„Z dgd=d>„Z!dhd?d@„Z"dAdB„ Z#dCdD„ Z$dEdF„ Z%dGdH„ Z&dIdJ„ Z'dKdL„ Z(dMdN„ Z)dOdP„ Z*dQdR„ Z+dSdT„ Z,dUdV„ Z-dWdX„ Z.dYdZ„ Z/d[d\„ Z0d]d^„ Z1d_d`„ Z2dadb„ Z3dcdd„ Z4deS )ir}   zõ
  A CondorDAGNode represents a node in the DAG. It corresponds to a particular
  condor job (and so a particular submit file). If the job has variable
  (macro) options, they can be set here so each nodes executes with the
  correct options.
  c             C   s  t |tƒst |tƒstdƒ‚d| _|| _d| _d| _d| _g | _	d| _
g | _i | _i | _g | _d| _d| _g | _t d¡| _g | _g | _g | _d| _t |tƒr²| ¡ dkr²d| _nd| _ttt ¡ d ƒƒ}ttt ¡ d ƒƒ}t| jƒ}t || |  !¡ ƒ "¡ | _| j| _#dS )	zB
    @param job: the CondorJob that this node corresponds to.
    zCA DAG node must correspond to a Condor DAG job or Condor DAGMan jobNr   z[_-]ÚstandardÚnoneiè  l     ;á)$Ú
isinstancerq   rŒ   r   Ú_CondorDAGNode__nameÚ_CondorDAGNode__jobÚ_CondorDAGNode__categoryÚ_CondorDAGNode__priorityÚ_CondorDAGNode__pre_scriptÚ_CondorDAGNode__pre_script_argsÚ_CondorDAGNode__post_scriptÚ _CondorDAGNode__post_script_argsÚ_CondorDAGNode__macrosÚ_CondorDAGNode__optsÚ_CondorDAGNode__argsÚ_CondorDAGNode__arg_indexÚ_CondorDAGNode__retryÚ_CondorDAGNode__parentsry   rz   Ú_CondorDAGNode__bad_macro_charsÚ_CondorDAGNode__output_filesÚ_CondorDAGNode__input_filesÚ _CondorDAGNode__checkpoint_filesZ_CondorDAGNode__vds_groupr5   Z_CondorDAGNode__grid_startrU   ÚintÚtimeÚrandomr|   r   ÚencodeÚ	hexdigestZ_CondorDAGNode__md5name)r   Újobr   ÚrÚar
   r
   r   r   r  s>    


zCondorDAGNode.__init__c             C   s   | j S )N)r˜   )r   r
   r
   r   Ú__repr__™  s    zCondorDAGNode.__repr__c             C   s   | j S )zA
    Return the CondorJob that this node is associated with.
    )r™   )r   r
   r
   r   r¯   œ  s    zCondorDAGNode.jobc             C   s
   || _ dS )z|
    Sets the name of the pre script that is executed before the DAG node is
    run.
    @param script: path to script
    N)rœ   )r   Úscriptr
   r
   r   Úset_pre_script¢  s    zCondorDAGNode.set_pre_scriptc             C   s   | j  |¡ dS )z]
    Adds an argument to the pre script that is executed before the DAG node is
    run.
    N)r   rA   )r   rI   r
   r
   r   Úadd_pre_script_argª  s    z CondorDAGNode.add_pre_script_argc             C   s
   || _ dS )z}
    Sets the name of the post script that is executed before the DAG node is
    run.
    @param script: path to script
    N)rž   )r   r³   r
   r
   r   Úset_post_script±  s    zCondorDAGNode.set_post_scriptc             C   s   | j S )z€
    returns the name of the post script that is executed before the DAG node is
    run.
    @param script: path to script
    )rž   )r   r
   r
   r   Úget_post_script¹  s    zCondorDAGNode.get_post_scriptc             C   s   | j  |¡ dS )z^
    Adds an argument to the post script that is executed before the DAG node is
    run.
    N)rŸ   rA   )r   rI   r
   r
   r   Úadd_post_script_argÁ  s    z!CondorDAGNode.add_post_script_argc             C   s   | j S )zl
    Returns and array of arguments to the post script that is executed before
    the DAG node is run.
    )rŸ   )r   r
   r
   r   Úget_post_script_argÈ  s    z!CondorDAGNode.get_post_script_argc             C   s   t |ƒ| _dS )z0
    Set the name for this node in the DAG.
    N)rU   r˜   )r   Únamer
   r
   r   Úset_nameÏ  s    zCondorDAGNode.set_namec             C   s   | j S )z0
    Get the name for this node in the DAG.
    )r˜   )r   r
   r
   r   Úget_nameÕ  s    zCondorDAGNode.get_namec             C   s   t |ƒ| _dS )z4
    Set the category for this node in the DAG.
    N)rU   rš   )r   Úcategoryr
   r
   r   Úset_categoryÛ  s    zCondorDAGNode.set_categoryc             C   s   | j S )z4
    Get the category for this node in the DAG.
    )rš   )r   r
   r
   r   Úget_categoryá  s    zCondorDAGNode.get_categoryc             C   s   t |ƒ| _dS )z4
    Set the priority for this node in the DAG.
    N)rU   r›   )r   Úpriorityr
   r
   r   Úset_priorityç  s    zCondorDAGNode.set_priorityc             C   s   | j S )z4
    Get the priority for this node in the DAG.
    )r›   )r   r
   r
   r   Úget_priorityí  s    zCondorDAGNode.get_priorityc             C   sB   || j kr>| j  |¡ t|  ¡ tƒs>|  ¡  ¡ dkr>|  |¡ dS )zo
    Add filename as a necessary input file for this DAG node.

    @param filename: input filename to add
    rg   N)r¨   rA   r—   r¯   rŒ   r5   Úadd_input_macro)r   rB   r
   r
   r   rC   ó  s
    
zCondorDAGNode.add_input_filec             C   sB   || j kr>| j  |¡ t|  ¡ tƒs>|  ¡  ¡ dkr>|  |¡ dS )zg
    Add filename as a output file for this DAG node.

    @param filename: output filename to add
    rg   N)r§   rA   r—   r¯   rŒ   r5   Úadd_output_macro)r   rB   r
   r
   r   rD   ÿ  s
    
zCondorDAGNode.add_output_filec             C   sB   || j kr>| j  |¡ t|  ¡ tƒs>|  ¡  ¡ dkr>|  |¡ dS )zm
    Add filename as a checkpoint file for this DAG node
    @param filename: checkpoint filename to add
    rg   N)r©   rA   r—   r¯   rŒ   r5   Úadd_checkpoint_macro)r   rB   r
   r
   r   rE     s
    
z!CondorDAGNode.add_checkpoint_filec             C   s,   t | jƒ}t|  ¡ tƒr(||  ¡  ¡  }|S )zC
    Return list of input files for this DAG node and its job.
    )rl   r¨   r—   r¯   rq   rF   )r   Zinput_filesr
   r
   r   rF     s    
zCondorDAGNode.get_input_filesc             C   s,   t | jƒ}t|  ¡ tƒr(||  ¡  ¡  }|S )zD
    Return list of output files for this DAG node and its job.
    )rl   r§   r—   r¯   rq   rG   )r   Zoutput_filesr
   r
   r   rG     s    
zCondorDAGNode.get_output_filesc             C   s,   t | jƒ}t|  ¡ tƒr(||  ¡  ¡  }|S )zJ
    Return a list of checkpoint files for this DAG node and its job.
    )rl   r©   r—   r¯   rq   rH   )r   Zcheckpoint_filesr
   r
   r   rH   (  s    
z"CondorDAGNode.get_checkpoint_filesc             C   s   | j  d|¡}|| j|< dS )a…  
    Add a variable (macro) for this node.  This can be different for
    each node in the DAG, even if they use the same CondorJob.  Within
    the CondorJob, the value of the macro can be referenced as
    '$(name)' -- for instance, to define a unique output or error file
    for each node.
    @param name: macro name.
    @param value: value of the macro for this node in the DAG
    r   N)r¦   r   r¡   )r   rº   r>   rƒ   r
   r
   r   Ú	add_macro1  s    
zCondorDAGNode.add_macroc             C   sL   | j  d|¡}|| jkr$|| j|< n$|| j| krH| j|  d| 7  < dS )z¾
    Add a variable (macro) for storing the input/output files associated
    with this node.
    @param io: macroinput or macrooutput
    @param filename: filename of input/output file
    r   z,%sN)r¦   r   r¡   )r   ÚiorB   r
   r
   r   Úadd_io_macro>  s
    
zCondorDAGNode.add_io_macroc             C   s   |   d|¡ dS )z‡
    Add a variable (macro) for storing the input files associated with
    this node.
    @param filename: filename of input file
    Z
macroinputN)rÈ   )r   rB   r
   r
   r   rÃ   L  s    zCondorDAGNode.add_input_macroc             C   s   |   d|¡ dS )z‰
    Add a variable (macro) for storing the output files associated with
    this node.
    @param filename: filename of output file
    ZmacrooutputN)rÈ   )r   rB   r
   r
   r   rÄ   T  s    zCondorDAGNode.add_output_macroc             C   s   |   d|¡ d S )NZmacrocheckpoint)rÈ   )r   rB   r
   r
   r   rÅ   \  s    z"CondorDAGNode.add_checkpoint_macroc             C   s   | j S )z±
    Return the opts for this node. Note that this returns only
    the options for this instance of the node and not those
    associated with the underlying job template.
    )r¡   )r   r
   r
   r   rQ   _  s    zCondorDAGNode.get_optsc             C   s,   | j  d|¡}|| jd| < | j |¡ dS )a  
    Add a variable (macro) condor command for this node. If the command
    specified does not exist in the CondorJob, it is added so the submit file
    will be correct.
    PLEASE NOTE: AS with other add_var commands, the variable must be set for
    all nodes that use the CondorJob instance.
    @param command: command name
    @param value: Value of the command for this node in the DAG.
    r   rƒ   N)r¦   r   r    r™   r†   )r   r…   r>   rƒ   r
   r
   r   r†   g  s    
z CondorDAGNode.add_var_condor_cmdFc             C   s.   | j  d|¡}|| jd| < | j ||¡ dS )a  
    Add a variable (macro) option for this node. If the option
    specified does not exist in the CondorJob, it is added so the submit
    file will be correct when written.
    @param opt: option name.
    @param value: value of the option for this node in the DAG.
    r   rƒ   N)r¦   r   r¡   r™   r„   )r   rM   r>   r‚   rƒ   r
   r
   r   r„   u  s    zCondorDAGNode.add_var_optc             C   s*   |   ||¡ |r|  |¡ n
|  |¡ dS )aê  
    Add a variable (macro) option for this node. If the option
    specified does not exist in the CondorJob, it is added so the submit
    file will be correct when written. The value of the option is also
    added to the list of input files.
    @param opt: option name.
    @param value: value of the option for this node in the DAG.
    @param file_is_output_file: A boolean if the file will be an output file
    instead of an input file.  The default is to have it be an input.
    N)r„   rD   rC   )r   rM   rB   Zfile_is_output_filer
   r
   r   rP     s     zCondorDAGNode.add_file_optc             C   s0   | j  |¡ | jj| j|d |  jd7  _dS )zâ
    Add a variable (or macro) argument to the condor job. The argument is
    added to the submit file and a different value of the argument can be set
    for each node in the DAG.
    @param arg: name of option to add.
    )r‰   rr   N)r¢   rA   r™   rŠ   r£   )r   rI   r‰   r
   r
   r   rŠ     s    zCondorDAGNode.add_var_argc             C   s   |   |¡ |  |¡ dS )a-  
    Add a variable (or macro) file name argument to the condor job. The
    argument is added to the submit file and a different value of the
    argument can be set for each node in the DAG. The file name is also
    added to the list of input files.
    @param filename: name of option to add.
    N)rC   rŠ   )r   rB   r
   r
   r   rK   ›  s    
zCondorDAGNode.add_file_argc             C   s   | j S )z¸
    Return the arguments for this node. Note that this returns
    only the arguments for this instance of the node and not those
    associated with the underlying job template.
    )r¢   )r   r
   r
   r   rL   ¦  s    zCondorDAGNode.get_argsc             C   s
   || _ dS )zz
    Set the number of times that this node in the DAG should retry.
    @param retry: number of times to retry node.
    N)r¤   )r   Úretryr
   r
   r   Ú	set_retry®  s    zCondorDAGNode.set_retryc             C   s   | j S )z}
    Return the number of times that this node in the DAG should retry.
    @param retry: number of times to retry node.
    )r¤   )r   r
   r
   r   Ú	get_retryµ  s    zCondorDAGNode.get_retryc             C   sž   t |  ¡ tƒrP| d d| j| j ¡ g¡¡ |  ¡  ¡ rn| d|  ¡  ¡  ¡ n| d| j d | j ¡  ¡ | d¡ | d| j d t	| j
ƒ d ¡ dS )zy
    Write the DAG entry for this node's job to the DAG file descriptor.
    @param fh: descriptor of open DAG file.
    ri   zSUBDAG EXTERNALz DIR zJOB rh   zRETRY N)r—   r¯   rŒ   rk   Újoinr˜   r™   re   r“   rU   r¤   )r   Úfhr
   r
   r   Ú	write_job¼  s    
zCondorDAGNode.write_jobc             C   s"   |  d| j d | j d ¡ dS )z~
    Write the DAG entry for this node's category to the DAG file descriptor.
    @param fh: descriptor of open DAG file.
    z	CATEGORY ri   rh   N)rk   r˜   rš   )r   rÍ   r
   r
   r   Úwrite_categoryÎ  s    zCondorDAGNode.write_categoryc             C   s"   |  d| j d | j d ¡ dS )z~
    Write the DAG entry for this node's priority to the DAG file descriptor.
    @param fh: descriptor of open DAG file.
    z	PRIORITY ri   rh   N)rk   r˜   r›   )r   rÍ   r
   r
   r   Úwrite_priorityÕ  s    zCondorDAGNode.write_priorityc             C   sö   t | j ¡ ƒs"t | j ¡ ƒs"| jr2| d| j ¡ x:| j ¡ D ],}| dt|ƒ d t| j| ƒ d ¡ q>W x:| j ¡ D ],}| dt|ƒ d t| j| ƒ d ¡ qzW | jrèx6t| j	ƒD ](}| dt|ƒ d | j|  d ¡ q¼W | d¡ dS )z†
    Write the variable (macro) options and arguments to the DAG file
    descriptor.
    @param fh: descriptor of open DAG file.
    zVARS ri   z="ú"z macroargumentrh   N)
rl   r    rm   r¡   r¢   rk   r˜   rU   Úranger£   )r   rÍ   ÚkÚir
   r
   r   Ú
write_varsÜ  s    ",,(zCondorDAGNode.write_varsc             C   s6   x0| j D ]&}| dt|ƒ d t| ƒ d ¡ qW dS )z
    Write the parent/child relations for this job to the DAG file descriptor.
    @param fh: descriptor of open DAG file.
    zPARENT z CHILD rh   N)r¥   rk   rU   )r   rÍ   Úparentr
   r
   r   Úwrite_parentsí  s    zCondorDAGNode.write_parentsc             C   s:   | j r6| dt| ƒ d | j  d d | j¡ d ¡ dS )zg
    Write the pre script for the job, if there is one
    @param fh: descriptor of open DAG file.
    zSCRIPT PRE ri   rh   N)rœ   rk   rU   rÌ   r   )r   rÍ   r
   r
   r   Úwrite_pre_scriptõ  s    zCondorDAGNode.write_pre_scriptc             C   s:   | j r6| dt| ƒ d | j  d d | j¡ d ¡ dS )zh
    Write the post script for the job, if there is one
    @param fh: descriptor of open DAG file.
    zSCRIPT POST ri   rh   N)rž   rk   rU   rÌ   rŸ   )r   rÍ   r
   r
   r   Úwrite_post_scriptþ  s    zCondorDAGNode.write_post_scriptc             C   s(   x"| j D ]}| d| j|f ¡ qW dS )zŠ
    Write as a comment into the DAG file the list of input files
    for this DAG node.

    @param fh: descriptor of open DAG file.
    z!## Job %s requires input file %s
N)r¨   rk   r˜   )r   rÍ   Úfr
   r
   r   Úwrite_input_files  s    zCondorDAGNode.write_input_filesc             C   s(   x"| j D ]}| d| j|f ¡ qW dS )z‹
    Write as a comment into the DAG file the list of output files
    for this DAG node.

    @param fh: descriptor of open DAG file.
    z### Job %s generates output file %s
N)r§   rk   r˜   )r   rÍ   rÚ   r
   r
   r   Úwrite_output_files  s    z CondorDAGNode.write_output_filesc             C   s   | j  |¡ dS )zh
    Set the Condor log file to be used by this CondorJob.
    @param log: path of Condor log file.
    N)r™   r]   )r   Úlogr
   r
   r   r]     s    zCondorDAGNode.set_log_filec             C   s&   t |ttfƒstdƒ‚| j |¡ dS )z¥
    Add a parent to this node. This node will not be executed until the
    parent node has run sucessfully.
    @param node: CondorDAGNode to add as a parent.
    z4Parent must be a CondorDAGNode or a CondorDAGManNodeN)r—   r}   r‘   r   r¥   rA   )r   Únoder
   r
   r   Ú
add_parent"  s    zCondorDAGNode.add_parentc          	   C   sš  t  d¡}t  d¡}|  ¡  ¡ }|  ¡ }g }xb|D ]Z}|| }| |¡}|rv| d¡}	||	 }
| d| t|
ƒf¡ q2| d| t|ƒf¡ q2W |  ¡  ¡ }xb|D ]Z}|| }| |¡}|ræ| d¡}	||	 }
| d| t|
ƒf¡ q¢| d| t|ƒf¡ q¢W |  ¡  	¡ }|  	¡ }x€|D ]x}| 
|¡}|r~t| |¡d ƒ}y| d||  df¡ W n  tk
rz   | d¡ Y nX n| d| df¡ qW |S )	zE
    Return a list of tuples containg the command line arguments
    z
\$\((.+)\)z\d+rr   z--%sz-%sr   z%sr   )ry   rz   r¯   rQ   ÚmatchÚgrouprA   rU   rS   rL   Úsearchrª   Úfindallr‡   )r   ÚpatZargpatrT   ÚmacrosÚcmd_listrÓ   ÚvalÚmÚkeyr>   r   r±   rˆ   r
   r
   r   Úget_cmd_tuple_list,  sD    









z CondorDAGNode.get_cmd_tuple_listc             C   s0   d}|   ¡ }x|D ]}|d |¡d 7 }qW |S )z]
    Return the full command line that will be used when this node
    is run by DAGman.
    r   ri   )rê   rÌ   )r   r=   ræ   Úargumentr
   r
   r   Úget_cmd_linee  s
    
zCondorDAGNode.get_cmd_linec             C   s   dS )zÉ
    The finalize method of a node is called before the node is
    finally added to the DAG and can be overridden to do any last
    minute clean up (such as setting extra command line arguments)
    Nr
   )r   r
   r
   r   Úfinalizer  s    zCondorDAGNode.finalizeN)F)F)F)5r   r   r   r   r   r²   r¯   r´   rµ   r¶   r·   r¸   r¹   r»   r¼   r¾   r¿   rÁ   rÂ   rC   rD   rE   rF   rG   rH   rÆ   rÈ   rÃ   rÄ   rÅ   rQ   r†   r„   rP   rŠ   rK   rL   rÊ   rË   rÎ   rÏ   rÐ   rÕ   r×   rØ   rÙ   rÛ   rÜ   r]   rß   rê   rì   rí   r
   r
   r
   r   r}   k  sd   '			


		


9r}   c                   s@   e Zd ZdZ‡ fdd„Zdd„ Zdd„ Zdd	„ Zd
d„ Z‡  Z	S )r‘   zæ
  Condor DAGMan node class. Appropriate for setting up DAGs to run within a
  DAG. Adds the user-tag functionality to condor_dagman processes running in
  the DAG. May also be used to extend dagman-node specific functionality.
  c                s&   t t| ƒ |¡ d| _g | _d| _dS )z"
    @job: a CondorDAGNodeJob
    N)rt   r‘   r   Ú_CondorDAGManNode__user_tagÚ%_CondorDAGManNode__maxjobs_categoriesZ_CondorDAGManNode__cluster_jobs)r   r¯   )r|   r
   r   r     s    zCondorDAGManNode.__init__c             C   s   t |ƒ| _dS )zu
    Set the user tag that is passed to the analysis code.
    @param user_tag: the user tag to identify the job
    N)rU   rî   )r   Úusertagr
   r
   r   Úset_user_tagŠ  s    zCondorDAGManNode.set_user_tagc             C   s   | j S )z$
    Returns the usertag string
    )rî   )r   r
   r
   r   Úget_user_tag‘  s    zCondorDAGManNode.get_user_tagc             C   s   | j  t|ƒt|ƒf¡ dS )z®
    Add a category to this DAG called categoryName with a maxjobs of maxJobsNum.
    @param node: Add (categoryName,maxJobsNum) tuple to CondorDAG.__maxjobs_categories.
    N)rï   rA   rU   )r   ÚcategoryNameÚ
maxJobsNumr
   r
   r   Úadd_maxjobs_category—  s    z%CondorDAGManNode.add_maxjobs_categoryc             C   s   | j S )zH
    Return an array of tuples containing (categoryName,maxJobsNum)
    )rï   )r   r
   r
   r   Úget_maxjobs_categoriesž  s    z'CondorDAGManNode.get_maxjobs_categories)
r   r   r   r   r   rñ   rò   rõ   rö   r‹   r
   r
   )r|   r   r‘   {  s   	r‘   c               @   s€   e Zd ZdZdd„ Zdd„ Zdd„ Zdd	„ Zd
d„ Zdd„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ ZdS )Ú	CondorDAGa[  
  A CondorDAG is a Condor Directed Acyclic Graph that describes a collection
  of Condor jobs and the order in which to run them. All Condor jobs in the
  DAG must write their Codor logs to the same file.
  NOTE: The log file must not be on an NFS mounted system as the Condor jobs
  must be able to get an exclusive file lock on the log file.
  c             C   s4   || _ d| _g | _g | _g | _d| _d| _d| _dS )zW
    @param log: path to log file which must not be on an NFS mounted file system.
    Nr   )Ú_CondorDAG__log_file_pathÚ_CondorDAG__dag_file_pathÚ_CondorDAG__jobsÚ_CondorDAG__nodesÚ_CondorDAG__maxjobs_categoriesÚ_CondorDAG__integer_node_namesÚ_CondorDAG__node_countÚ_CondorDAG__nodes_finalized)r   rÝ   r
   r
   r   r   ­  s    zCondorDAG.__init__c             C   s   | j S )z;
    Return a list containing all the nodes in the DAG
    )rû   )r   r
   r
   r   Ú	get_nodesº  s    zCondorDAG.get_nodesc             C   s   | j S )z:
    Return a list containing all the jobs in the DAG
    )rú   )r   r
   r
   r   Úget_jobsÀ  s    zCondorDAG.get_jobsc             C   s
   d| _ dS )z,
    Use integer node names for the DAG
    rr   N)rý   )r   r
   r
   r   Úset_integer_node_namesÆ  s    z CondorDAG.set_integer_node_namesc             C   s   |d | _ dS )zd
    Set the name of the file into which the DAG is written.
    @param path: path to DAG file.
    z.dagN)rù   )r   r\   r
   r
   r   Úset_dag_fileÌ  s    zCondorDAG.set_dag_filec             C   s   | j stdƒ‚n| jS dS )z*
    Return the path to the DAG file.
    zNo path for DAG fileN)rø   r   rù   )r   r
   r
   r   Úget_dag_fileÓ  s    
zCondorDAG.get_dag_filec             C   s~   t |tƒstdƒ‚t | ¡ tƒs,| | j¡ | j |¡ | j	rN| 
t| jƒ¡ |  jd7  _| ¡ | jkrz| j | ¡ ¡ dS )ae  
    Add a CondorDAGNode to this DAG. The CondorJob that the node uses is
    also added to the list of Condor jobs in the DAG so that a list of the
    submit files needed by the DAG can be maintained. Each unique CondorJob
    will be added once to prevent duplicate submit files being written.
    @param node: CondorDAGNode to add to the CondorDAG.
    z-Nodes must be class CondorDAGNode or subclassrr   N)r—   r}   r   r¯   rŒ   r]   rø   rû   rA   rý   r»   rU   rþ   rú   )r   rÞ   r
   r
   r   Úadd_nodeÜ  s    
zCondorDAG.add_nodec             C   s   | j  t|ƒt|ƒf¡ dS )z®
    Add a category to this DAG called categoryName with a maxjobs of maxJobsNum.
    @param node: Add (categoryName,maxJobsNum) tuple to CondorDAG.__maxjobs_categories.
    N)rü   rA   rU   )r   ró   rô   r
   r
   r   rõ   ï  s    zCondorDAG.add_maxjobs_categoryc             C   s   | j S )zH
    Return an array of tuples containing (categoryName,maxJobsNum)
    )rü   )r   r
   r
   r   rö   ö  s    z CondorDAG.get_maxjobs_categoriesc             C   s.   |  dt|d ƒ d t|d ƒ d ¡ dS )a  
    Write the DAG entry for this category's maxjobs to the DAG file descriptor.
    @param fh: descriptor of open DAG file.
    @param category: tuple containing type of jobs to set a maxjobs limit for
        and the maximum number of jobs of that type to run at once.
    zMAXJOBS r   ri   rr   rh   N)rk   rU   )r   rÍ   r½   r
   r
   r   Úwrite_maxjobsü  s    zCondorDAG.write_maxjobsc             C   s:   | j sx| jD ]}| ¡  qW x| jD ]}| ¡  q&W dS )z„
    Write all the submit files used by the dag to disk. Each submit file is
    written to the file name set in the CondorJob.
    N)rÿ   rû   rí   rú   rp   )r   rÞ   r¯   r
   r
   r   Úwrite_sub_files  s
    zCondorDAG.write_sub_filesc             C   sì   | j stdƒ‚yt| j dƒ}W n   td| j  ƒ‚Y nX xn| jD ]d}| |¡ | |¡ | ¡ rl| |¡ | ¡ r~| 	|¡ | 
|¡ | |¡ | |¡ | |¡ qBW x| jD ]}| |¡ q²W x| jD ]}|  ||¡ qÌW | ¡  dS )z9
    Write all the nodes in the DAG to the DAG file.
    zNo path for DAG filerf   zCannot open file N)rù   r   rj   rû   rÎ   rÕ   r¿   rÏ   rÂ   rÐ   rØ   rÙ   rÛ   rÜ   r×   rü   r  rn   )r   ZdagfilerÞ   r½   r
   r
   r   Úwrite_concrete_dag  s,    






zCondorDAG.write_concrete_dagc             C   s*   | j sx| jD ]}| ¡  qW |  ¡  dS )z
    Write a dag.
    N)rÿ   rû   rí   r  )r   rÞ   r
   r
   r   Ú	write_dag+  s    zCondorDAG.write_dagc             C   sä   | j stdƒ‚y0| j }d | d¡dd… ¡d }t|dƒ}W n   td| j  ƒ‚Y nX x`| jD ]V}| d| ¡  ¡ t|t	ƒrš| d	| 
¡  ¡  ¡ qb| d
| 
¡  ¡ | ¡ f ¡ qbW | ¡  t |t |¡d tjB ¡ dS )zµ
    Write the workflow to a script (.sh instead of .dag).

    Assuming that parents were added to the DAG before their children,
    dependencies should be handled correctly.
    zNo path for DAG fileÚ.Néÿÿÿÿz.shrf   zCannot open file z	# Job %s
zcondor_submit_dag %s

z%s %s

r   )rù   r   rÌ   Úsplitrj   rû   rk   r¼   r—   r‘   r¯   r”   r3   rì   rn   ÚosÚchmodÚstatÚS_IEXEC)r   ZdfpZoutfilenameÚoutfilerÞ   r
   r
   r   Úwrite_script4  s     
zCondorDAG.write_scriptN)r   r   r   r   r   r   r  r  r  r  r  rõ   rö   r  r  r  r	  r  r
   r
   r
   r   r÷   ¥  s   			r÷   c               @   s0   e Zd ZdZdd„ Zdd„ Zdd„ Zdd	„ Zd
S )ÚAnalysisJobz]
  Describes a generic analysis job that filters LIGO data as configured by
  an ini file.
  c             C   s:   || _ yt| j  dd¡ƒ ¡ | _W n   d| _Y nX dS )zV
    @param cp: ConfigParser object that contains the configuration for this job.
    ÚinputÚchannelN)Ú_AnalysisJob__cprU   rV   rW   Ú_AnalysisJob__channel)r   rX   r
   r
   r   r   V  s
    zAnalysisJob.__init__c             C   s   t | j ||¡ƒ ¡ S )z¥
    Get the configration variable in a particular section of this jobs ini
    file.
    @param sec: ini file section.
    @param opt: option from section sec.
    )rU   r  rV   rW   )r   ÚsecrM   r
   r
   r   Ú
get_config`  s    zAnalysisJob.get_configc             C   s
   || _ dS )z€
    Set the name of the channel that this job is filtering.  This will
    overwrite the value obtained at initialization.
    N)r  )r   r  r
   r
   r   Úset_channeli  s    zAnalysisJob.set_channelc             C   s   | j S )zß
    Returns the name of the channel that this job is filtering. Note that
    channel is defined to be IFO independent, so this may be LSC-AS_Q or
    IOO-MC_F. The IFO is set on a per node basis, not a per job basis.
    )r  )r   r
   r
   r   r  p  s    zAnalysisJob.channelN)r   r   r   r   r   r  r  r  r
   r
   r
   r   r  Q  s
   
	r  c               @   s  e Zd ZdZdd„ Zd>dd„Zdd„ Zd?d	d
„Zdd„ Zdd„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zdd„ Zd@dd„Zdd„ ZdAdd„Zdd „ ZdBd!d"„Zd#d$„ ZdCd%d&„Zd'd(„ Zd)d*„ Zd+d,„ ZdDd-d.„Zd/d0„ ZdEd1d2„Zd3d4„ Zd5d6„ Zd7d8„ Zd9d:„ Zd;d<„ Z d=S )FÚAnalysisNodezc
  Contains the methods that allow an object to be built to analyse LIGO
  data in a Condor DAG.
  c             C   st   d| _ d| _d| _d| _d| _d| _d| _d | _d | _d | _	d | _
d | _d | _t d¡| _|  ¡  ¡  dd ¡| _d S )Nr   ZH2zuser-tag)Ú_AnalysisNode__startÚ_AnalysisNode__endÚ_AnalysisNode__data_startÚ_AnalysisNode__pad_dataÚ_AnalysisNode__data_endÚ_AnalysisNode__trig_startÚ_AnalysisNode__trig_endÚ_AnalysisNode__ifoÚ_AnalysisNode__ifo_tagÚ_AnalysisNode__inputÚ_AnalysisNode__outputÚ_AnalysisNode__calibrationÚ _AnalysisNode__calibration_cachery   rz   Ú_AnalysisNode__LHO2kr¯   rQ   rV   Ú_AnalysisNode__user_tag)r   r
   r
   r   r   ~  s    zAnalysisNode.__init__Tc             C   s    |r|   d|¡ || _|| _dS )zî
    Set the GPS start time of the analysis node by setting a --gps-start-time
    option to the node when it is executed.
    @param time: GPS start time of job.
    @bool pass_to_command_line: add gps-start-time as variable option.
    zgps-start-timeN)r„   r  r  )r   r«   Úpass_to_command_liner
   r
   r   Ú	set_start  s    zAnalysisNode.set_startc             C   s   | j S )z-
    Get the GPS start time of the node.
    )r  )r   r
   r
   r   Ú	get_start  s    zAnalysisNode.get_startc             C   s    |r|   d|¡ || _|| _dS )zæ
    Set the GPS end time of the analysis node by setting a --gps-end-time
    option to the node when it is executed.
    @param time: GPS end time of job.
    @bool pass_to_command_line: add gps-end-time as variable option.
    zgps-end-timeN)r„   r  r   )r   r«   r+  r
   r
   r   Úset_end£  s    zAnalysisNode.set_endc             C   s   | j S )z+
    Get the GPS end time of the node.
    )r  )r   r
   r
   r   Úget_end¯  s    zAnalysisNode.get_endc             C   s
   || _ dS )zr
    Set the GPS start time of the data needed by this analysis node.
    @param time: GPS start time of job.
    N)r  )r   r«   r
   r
   r   Úset_data_startµ  s    zAnalysisNode.set_data_startc             C   s   | j S )zA
    Get the GPS start time of the data needed by this node.
    )r  )r   r
   r
   r   Úget_data_start¼  s    zAnalysisNode.get_data_startc             C   s
   || _ dS )zr
    Set the GPS start time of the data needed by this analysis node.
    @param time: GPS start time of job.
    N)r  )r   Úpadr
   r
   r   Úset_pad_dataÂ  s    zAnalysisNode.set_pad_datac             C   s   | j S )zA
    Get the GPS start time of the data needed by this node.
    )r  )r   r
   r
   r   Úget_pad_dataÉ  s    zAnalysisNode.get_pad_datac             C   s
   || _ dS )zn
    Set the GPS end time of the data needed by this analysis node.
    @param time: GPS end time of job.
    N)r   )r   r«   r
   r
   r   Úset_data_endÏ  s    zAnalysisNode.set_data_endc             C   s   | j S )z?
    Get the GPS end time of the data needed by this node.
    )r   )r   r
   r
   r   Úget_data_endÖ  s    zAnalysisNode.get_data_endc             C   s   |r|   d|¡ || _dS )zô
    Set the trig start time of the analysis node by setting a
    --trig-start-time option to the node when it is executed.
    @param time: trig start time of job.
    @bool pass_to_command_line: add trig-start-time as a variable option.
    ztrig-start-timeN)r„   r!  )r   r«   r+  r
   r
   r   Úset_trig_startÜ  s    zAnalysisNode.set_trig_startc             C   s   | j S )z.
    Get the trig start time of the node.
    )r!  )r   r
   r
   r   Úget_trig_startç  s    zAnalysisNode.get_trig_startc             C   s   |r|   d|¡ || _dS )zì
    Set the trig end time of the analysis node by setting a --trig-end-time
    option to the node when it is executed.
    @param time: trig end time of job.
    @bool pass_to_command_line: add trig-end-time as a variable option.
    ztrig-end-timeN)r„   r"  )r   r«   r+  r
   r
   r   Úset_trig_endí  s    zAnalysisNode.set_trig_endc             C   s   | j S )z,
    Get the trig end time of the node.
    )r"  )r   r
   r
   r   Úget_trig_endø  s    zAnalysisNode.get_trig_endc             C   s$   || _ |r|  d|¡ |  |¡ dS )zµ
    Add an input to the node by adding a --input option.
    @param filename: option argument to pass as input.
    @bool pass_to_command_line: add input as a variable option.
    r  N)r%  r„   rC   )r   rB   r+  r
   r
   r   Ú	set_inputþ  s    zAnalysisNode.set_inputc             C   s   | j S )z4
    Get the file that will be passed as input.
    )r%  )r   r
   r
   r   Ú	get_input	  s    zAnalysisNode.get_inputc             C   s$   || _ |r|  d|¡ |  |¡ dS )z¹
    Add an output to the node by adding a --output option.
    @param filename: option argument to pass as output.
    @bool pass_to_command_line: add output as a variable option.
    ÚoutputN)r&  r„   rD   )r   rB   r+  r
   r
   r   Ú
set_output  s    zAnalysisNode.set_outputc             C   s   | j S )z5
    Get the file that will be passed as output.
    )r&  )r   r
   r
   r   Ú
get_output  s    zAnalysisNode.get_outputc             C   s2   || _ |  ¡  ¡ r.|  d|d |  ¡  ¡  ¡ dS )a  
    Set the ifo name to analyze. If the channel name for the job is defined,
    then the name of the ifo is prepended to the channel name obtained
    from the job configuration file and passed with a --channel-name option.
    @param ifo: two letter ifo code (e.g. L1, H1 or H2).
    zchannel-nameú:N)r#  r¯   r  r„   )r   Zifor
   r
   r   Úset_ifo   s    zAnalysisNode.set_ifoc             C   s   | j S )z8
    Returns the two letter IFO code for this node.
    )r#  )r   r
   r
   r   Úget_ifo+  s    zAnalysisNode.get_ifoc             C   s   || _ |r|  d|¡ dS )zº
    Set the ifo tag that is passed to the analysis code.
    @param ifo_tag: a string to identify one or more IFOs
    @bool pass_to_command_line: add ifo-tag as a variable option.
    zifo-tagN)r$  r„   )r   Zifo_tagr+  r
   r
   r   Úset_ifo_tag1  s    zAnalysisNode.set_ifo_tagc             C   s   | j S )z$
    Returns the IFO tag string
    )r$  )r   r
   r
   r   Úget_ifo_tag;  s    zAnalysisNode.get_ifo_tagc             C   s   || _ |r|  d|¡ dS )z¸
    Set the user tag that is passed to the analysis code.
    @param user_tag: the user tag to identify the job
    @bool pass_to_command_line: add user-tag as a variable option.
    zuser-tagN)r*  r„   )r   rð   r+  r
   r
   r   rñ   A  s    zAnalysisNode.set_user_tagc             C   s   | j S )z$
    Returns the usertag string
    )r*  )r   r
   r
   r   rò   K  s    zAnalysisNode.get_user_tagc       	      C   sò   t |tƒr"|  d|¡ |  |¡ nÌt |tƒræ|  dd¡ t|ƒdkrLtdƒ‚xŠ|D ]‚}| d¡d  d¡\}}}}t|ƒ}t|ƒt|ƒ }||  	¡ |  
¡  t|ƒ d krR||  ¡ |  
¡  t|ƒ d krR|  |¡ qRW |  d	|¡ ntd
ƒ‚dS )z¤
    Set the LAL frame cache to to use. The frame cache is passed to the job
    with the --frame-cache argument.
    @param filename: calibration file to use.
    zframe-cachezglob-frame-datari   r   z?LDR did not return any LFNs for query: check ifo and frame typer
  ú-rr   z
frame-typezUnknown LFN cache formatN)r—   rU   r„   rC   rl   Úlenr   r  rª   r6  r4  r1  )	r   rB   Úlfnr±   Úbro   ÚdZt_startZt_endr
   r
   r   Ú	set_cacheQ  s"    


  zAnalysisNode.set_cachec             C   s¸   | j r¨| jdkr¨|  ¡  dd¡}| j | j ¡r€| jdkr€| jdkr€| jt|  ¡  dd¡ƒk rn|  ¡  dd¡}q’|  ¡  dd¡}n|  ¡  d| j ¡}tj 	||¡}|| _
nd	}t|ƒ‚d
S )zJ
    Determine the path to the correct calibration cache file to use.
    r   Úcalibrationr\   iÕw+i}Å+zH2-cal-epoch-boundaryzH2-1zH2-2z$IFO and start-time must be set firstN)r#  r  r¯   r  r)  rà   rª   r  r\   rÌ   r(  r   )r   Zcal_pathZcal_fileÚcalÚmsgr
   r
   r   Úcalibration_cache_patho  s    z#AnalysisNode.calibration_cache_pathc             C   s.   |   ¡  |  d| j¡ | j| _|  | j¡ dS )zË
    Set the path to the calibration cache file for the given IFO.
    During S2 the Hanford 2km IFO had two calibration epochs, so
    if the start time is during S2, we use the correct cache file.
    zcalibration-cacheN)rN  r„   r(  r'  rC   )r   r
   r
   r   rK  ˆ  s    zAnalysisNode.calibrationc             C   s   | j S )zF
    Return the calibration cache file to be used by the
    DAG.
    )r(  )r   r
   r
   r   Úget_calibration–  s    zAnalysisNode.get_calibrationN)T)T)T)T)T)T)T)T)!r   r   r   r   r   r,  r-  r.  r/  r0  r1  r3  r4  r5  r6  r7  r8  r9  r:  r;  r<  r>  r?  rA  rB  rC  rD  rñ   rò   rJ  rN  rK  rO  r
   r
   r
   r   r  y  s<   









r  c               @   sb   e Zd ZdZddd„Zdd„ Zdd„ Zd	d
„ Zdd„ Zdd„ Z	dd„ Z
dd„ Zdd„ Zdd„ ZdS )ÚAnalysisChunkzm
  An AnalysisChunk is the unit of data that a node works with, usually some
  subset of a ScienceSegment.
  r   c             C   s&   || _ || _|| | _|| _|| _dS )zè
    @param start: GPS start time of the chunk.
    @param end: GPS end time of the chunk.
    @param trig_start: GPS time at which to start generating triggers
    @param trig_end: GPS time at which to stop generating triggers
    N)Ú_AnalysisChunk__startÚ_AnalysisChunk__endÚ_AnalysisChunk__lengthÚ_AnalysisChunk__trig_startÚ_AnalysisChunk__trig_end)r   ÚstartÚendÚ
trig_startÚtrig_endr
   r
   r   r   ¤  s
    
zAnalysisChunk.__init__c             C   sx   | j r$| jr$d| j| j| j | jf S | j rD| jsDd| j| j| j f S | j sd| jrdd| j| j| jf S d| j| jf S d S )Nz=<AnalysisChunk: start %d, end %d, trig_start %d, trig_end %d>z0<AnalysisChunk: start %d, end %d, trig_start %d>z.<AnalysisChunk: start %d, end %d, trig_end %d>z!<AnalysisChunk: start %d, end %d>)rT  rU  rQ  rR  )r   r
   r
   r   r²   ±  s    zAnalysisChunk.__repr__c             C   sx   | j r| jr| j| j  }n@| j r4| js4| j| j  }n&| j sN| jrN| j| j }n| j| j }|dk rpt| d ƒ‚n|S dS )zi
    Returns the length of data for which this AnalysisChunk will produce
    triggers (in seconds).
    r   zhas negative lengthN)rT  rU  rR  rQ  r   )r   Úxr
   r
   r   Ú__len__¾  s    zAnalysisChunk.__len__c             C   s   | j S )z2
    Returns the GPS start time of the chunk.
    )rQ  )r   r
   r
   r   rV  Ñ  s    zAnalysisChunk.startc             C   s   | j S )z0
    Returns the GPS end time of the chunk.
    )rR  )r   r
   r
   r   rW  ×  s    zAnalysisChunk.endc             C   s   | j S )z@
    Returns the length (duration) of the chunk in seconds.
    )rS  )r   r
   r
   r   ÚdurÝ  s    zAnalysisChunk.durc             C   s   | j S )z]
    Return the first GPS time at which triggers for this chunk should be
    generated.
    )rT  )r   r
   r
   r   rX  ã  s    zAnalysisChunk.trig_startc             C   s   | j S )z\
    Return the last GPS time at which triggers for this chunk should be
    generated.
    )rU  )r   r
   r
   r   rY  ê  s    zAnalysisChunk.trig_endc             C   s
   || _ dS )zZ
    Set the first GPS time at which triggers for this chunk should be
    generated.
    N)rT  )r   rV  r
   r
   r   r7  ñ  s    zAnalysisChunk.set_trig_startc             C   s
   || _ dS )zY
    Set the last GPS time at which triggers for this chunk should be
    generated.
    N)rU  )r   rW  r
   r
   r   r9  ø  s    zAnalysisChunk.set_trig_endN)r   r   )r   r   r   r   r   r²   r[  rV  rW  r\  rX  rY  r7  r9  r
   r
   r
   r   rP  Ÿ  s   
rP  c               @   sœ   e Zd ZdZdd„ Zdd„ Zdd„ Zdd	„ Zd
d„ Zd&dd„Z	d'dd„Z
dd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd „ Zd!d"„ Zd#d$„ Zd%S )(ÚScienceSegmentaP  
  A ScienceSegment is a period of time where the experimenters determine
  that the inteferometer is in a state where the data is suitable for
  scientific analysis. A science segment can have a list of AnalysisChunks
  asscociated with it that break the segment up into (possibly overlapping)
  smaller time intervals for analysis.
  c             C   sH   |d | _ |d | _|d | _|d | _g | _|  ¡ | _d| _d| _dS )zy
    @param segment: a tuple containing the (segment id, gps start time, gps end
    time, duration) of the segment.
    r   rr   é   é   N)	Ú_ScienceSegment__idÚ_ScienceSegment__startÚ_ScienceSegment__endÚ_ScienceSegment__durÚ_ScienceSegment__chunksr\  Ú_ScienceSegment__unusedZ_ScienceSegment__ifoÚ_ScienceSegment__df_node)r   Úsegmentr
   r
   r   r   	  s    




zScienceSegment.__init__c             C   s   |dk rt dƒ‚| j| S )zm
    Allows iteration over and direct access to the AnalysisChunks contained
    in this ScienceSegment.
    r   zlist index out of range)r‡   rd  )r   rÔ   r
   r
   r   Ú__getitem__  s     zScienceSegment.__getitem__c             C   s
   t | jƒS )zP
    Returns the number of AnalysisChunks contained in this ScienceSegment.
    )rF  rd  )r   r
   r
   r   r[    s    zScienceSegment.__len__c             C   s$   d|   ¡ |  ¡ |  ¡ |  ¡ | jf S )Nz<<ScienceSegment: id %d, start %d, end %d, dur %d, unused %d>)ÚidrV  rW  r\  re  )r   r
   r
   r   r²   %  s    zScienceSegment.__repr__c             C   s   t |  ¡ | ¡ ƒS )zL
    ScienceSegments are compared by the GPS start time of the segment.
    )ÚcmprV  )r   Úotherr
   r
   r   Ú__cmp__)  s    zScienceSegment.__cmp__r   c             C   s>  |   ¡ d|  }|  ¡ | }|| }	x||kr.|| }
|rj|r|
| | d d d| d|  k r|dkr
ddt |
| | d d ¡  }|d }d}d}|d |krÒtddd td	ƒ t d
¡ n ||krât|ƒ}||
k ròt|ƒ}| j 	t
||
||ƒ¡ n| j 	t
||
ƒ¡ ||	7 }||	8 }q(W || | _dS )a|  
    Divides the science segment into chunks of length seconds overlapped by
    overlap seconds. If the play option is set, only chunks that contain S2
    playground data are generated. If the user has a more complicated way
    of generating chunks, this method should be overriden in a sub-class.
    Any data at the end of the ScienceSegment that is too short to contain a
    chunk is ignored. The length of this unused data is stored and can be
    retrieved with the unused() method.
    @param length: length of chunk in seconds.
    @param overlap: overlap between chunks in seconds.
    @param play: 1 : only generate chunks that overlap with S2 playground data.
                 2 : as play = 1 plus compute trig start and end times to
                     coincide with the start/end of the playground
    @param sl: slide by sl seconds before determining playground data.
    @param excl_play: exclude the first excl_play second from the start and end
    of the chunk when computing if the chunk overlaps with playground.
    @param pad_data: exclude the first and last pad_data seconds of the segment
    when generating chunks
    r^  iÕw+iâ  iX  r   z&Two playground segments in this chunk:ri   )rW  z3  Code to handle this case has not been implementedrr   N)r\  rV  ÚmathÚfloorÚprintÚsysÚexitrª   rd  rA   rP  re  )r   ÚlengthÚoverlapÚplayÚslÚ	excl_playÚpad_dataZ	time_leftrV  Ú	incrementrW  Ú
play_startÚplay_endrX  rY  r
   r
   r   Úmake_chunks/  s4    
zScienceSegment.make_chunksc             C   s   | j  t||||ƒ¡ dS )zß
    Add an AnalysisChunk to the list associated with this ScienceSegment.
    @param start: GPS start time of chunk.
    @param end: GPS end time of chunk.
    @param trig_start: GPS start time for triggers from chunk
    N)rd  rA   rP  )r   rV  rW  rX  rY  r
   r
   r   Ú	add_chunka  s    zScienceSegment.add_chunkc             C   s   | j S )zT
    Returns the length of data in the science segment not used to make chunks.
    )re  )r   r
   r
   r   Úunusedj  s    zScienceSegment.unusedc             C   s
   || _ dS )zP
    Set the length of data in the science segment not used to make chunks.
    N)re  )r   r}  r
   r
   r   Ú
set_unusedp  s    zScienceSegment.set_unusedc             C   s   | j S )z0
    Returns the ID of this ScienceSegment.
    )r`  )r   r
   r
   r   ri  v  s    zScienceSegment.idc             C   s   | j S )z<
    Returns the GPS start time of this ScienceSegment.
    )ra  )r   r
   r
   r   rV  |  s    zScienceSegment.startc             C   s   | j S )z:
    Returns the GPS end time of this ScienceSegment.
    )rb  )r   r
   r
   r   rW  ‚  s    zScienceSegment.endc             C   s   |  j | j| 7  _ || _dS )zv
    Override the GPS start time (and set the duration) of this ScienceSegment.
    @param t: new GPS start time.
    N)rc  ra  )r   r   r
   r
   r   r,  ˆ  s    zScienceSegment.set_startc             C   s   |  j | j| 8  _ || _dS )zr
    Override the GPS end time (and set the duration) of this ScienceSegment.
    @param t: new GPS end time.
    N)rc  rb  )r   r   r
   r
   r   r.    s    zScienceSegment.set_endc             C   s   | j S )zJ
    Returns the length (duration) in seconds of this ScienceSegment.
    )rc  )r   r
   r
   r   r\  ˜  s    zScienceSegment.durc             C   s
   || _ dS )zŽ
    Set the DataFind node associated with this ScienceSegment to df_node.
    @param df_node: the DataFind node for this ScienceSegment.
    N)rf  )r   Zdf_noder
   r
   r   Úset_df_nodež  s    zScienceSegment.set_df_nodec             C   s   | j S )z<
    Returns the DataFind node for this ScienceSegment.
    )rf  )r   r
   r
   r   Úget_df_node¥  s    zScienceSegment.get_df_nodeN)r   r   r   r   r   r   )r   r   )r   r   r   r   r   rh  r[  r²   rl  r{  r|  r}  r~  ri  rV  rW  r,  r.  r\  r  r€  r
   r
   r
   r   r]    s$   
2
	r]  c               @   s²   e Zd ZdZdd„ Zdd„ Zdd„ Zdd	„ Zd*dd„Zdd„ Z	dd„ Z
d+dd„Zd,dd„Zd-dd„Zd.dd„Zdd„ Zdd„ Zdd„ Zdd „ Zd!d"„ Zd#d$„ Zd%d&„ Zd'd(„ Zd)S )/ÚScienceDatazÔ
  An object that can contain all the science data used in an analysis. Can
  contain multiple ScienceSegments and has a method to generate these from
  a text file produces by the LIGOtools segwizard program.
  c             C   s   g | _ d | _d S )N)Ú_ScienceData__sci_segsÚ_ScienceData__filename)r   r
   r
   r   r   ²  s    zScienceData.__init__c             C   s
   | j | S )zl
    Allows direct access to or iteration over the ScienceSegments associated
    with the ScienceData.
    )r‚  )r   rÔ   r
   r
   r   rh  ¶  s    zScienceData.__getitem__c             C   s
   d| j  S )Nz<ScienceData: file %s>)rƒ  )r   r
   r
   r   r²   ½  s    zScienceData.__repr__c             C   s
   t | jƒS )zP
    Returns the number of ScienceSegments associated with the ScienceData.
    )rF  r‚  )r   r
   r
   r   r[  À  s    zScienceData.__len__r   c             C   sÔ   || _ t d¡}x¾t|ƒD ]²}| |¡st| ¡ d ƒ|krttt| ¡ ƒƒ\}}}	}
|dkrh||7 }n|dk rx|	|7 }	|
t	|ƒ8 }
|dkr¬||7 }|	|8 }	|
dt	|ƒ 8 }
t
t|||	|
gƒƒ}| j |¡ qW dS )aõ  
    Parse the science segments from the segwizard output contained in file.
    @param filename: input text file containing a list of science segments generated by
    segwizard.
    @param min_length: only append science segments that are longer than min_length.
    @param slide_sec: Slide each ScienceSegment by::

      delta > 0:
        [s,e] -> [s+delta,e].
      delta < 0:
        [s,e] -> [s,e-delta].

    @param buffer: shrink the ScienceSegment::

      [s,e] -> [s+buffer,e-buffer]
    z\A#r_  r   r^  N)rƒ  ry   rz   rj   rà   rª   r  rl   ÚmapÚabsr]  Útupler‚  rA   )r   rB   Ú
min_lengthZ	slide_secÚbufferZ
octothorpeÚlineri  ÚstÚenZdurZ  r
   r
   r   ÚreadÆ  s     

zScienceData.readc             C   s   t |ƒ}| j |¡ d S )N)r]  r‚  rA   )r   Z	seg_tuplerZ  r
   r
   r   Úappend_from_tupleí  s    zScienceData.append_from_tuplec       	      C   s„   || _ xxt|ƒD ]l}| ¡ }t|d ƒ}tt t|d ƒ¡ƒ}tt t|d ƒ¡ƒ}|| }tt	||||gƒƒ}| j
 |¡ qW dS )z´
    Parse the science segments from a tama list of locked segments contained in
                file.
    @param filename: input text file containing a list of tama segments.
    r   r_  é   N)rƒ  rj   r  rª   rm  ÚceilÚfloatrn  r]  r†  r‚  rA   )	r   rB   r‰  Úcolumnsri  rV  rW  r\  rZ  r
   r
   r   Ú	tama_readñ  s    zScienceData.tama_readc          	   C   s(   x"| j D ]}| ||||||¡ qW dS )aæ  
    Divide each ScienceSegment contained in this object into AnalysisChunks.
    @param length: length of chunk in seconds.
    @param overlap: overlap between segments.
    @param play: if true, only generate chunks that overlap with S2 playground
    data.
    @param sl: slide by sl seconds before determining playground data.
    @param excl_play: exclude the first excl_play second from the start and end
    of the chunk when computing if the chunk overlaps with playground.
    N)r‚  r{  )r   rr  rs  rt  ru  rv  rw  Úsegr
   r
   r   r{    s    zScienceData.make_chunksc             C   s6  x.| j D ]"}| ¡ |kr
| ¡ | }	|	| }
|r`|r$|	| | d d d| d|  k r$|	| ¡  | }|dkrddt |	| | d d ¡  }|d }d}|d |
krÐtdƒ tdƒ t d¡ nD||kràt|ƒ}||	k rðt|ƒ}|dks||kr$| 	|
|	||¡ n| 	|
|	|¡ | 
d¡ q
W d	S )
a€  
    Create an extra chunk that uses up the unused data in the science segment.
    @param length: length of chunk in seconds.
    @param trig_overlap: length of time start generating triggers before the
    start of the unused data.
    @param play:
                - 1 : only generate chunks that overlap with S2 playground data.
                - 2 : as 1 plus compute trig start and end times to coincide
                        with the start/end of the playground
    @param min_length: the unused data must be greater than min_length to make a
    chunk.
    @param sl: slide by sl seconds before determining playground data.
    @param excl_play: exclude the first excl_play second from the start and end
    of the chunk when computing if the chunk overlaps with playground.
    @param pad_data: exclude the first and last pad_data seconds of the segment
    when generating chunks

    iÕw+iâ  iX  r^  r   z%Two playground segments in this chunkz3  Code to handle this case has not been implementedrr   N)r‚  r}  rW  rm  rn  ro  rp  rq  rª   r|  r~  )r   rr  Ztrig_overlaprt  r‡  ru  rv  rw  r“  rW  rV  rX  ry  rz  rY  r
   r
   r   Úmake_chunks_from_unused  s0    
z#ScienceData.make_chunks_from_unusedc       
      C   sˆ   x‚| j D ]x}| ¡ |kr| ¡ | ¡  | }| ¡ }|| }	|rh|rv|| | d d d|	 d|  k rv| |||¡ | d¡ qW dS )a  
    Create a chunk that uses up the unused data in the science segment
    @param min_length: the unused data must be greater than min_length to make a
    chunk.
    @param overlap: overlap between chunks in seconds.
    @param play: if true, only generate chunks that overlap with S2 playground data.
    @param sl: slide by sl seconds before determining playground data.
    @param excl_play: exclude the first excl_play second from the start and end
    of the chunk when computing if the chunk overlaps with playground.
    iÕw+iâ  iX  r^  r   N)r‚  r}  rW  r|  r~  )
r   r‡  rs  rt  ru  rv  r“  rV  rW  rr  r
   r
   r   Úmake_short_chunks_from_unusedB  s    z)ScienceData.make_short_chunks_from_unusedc             C   sÞ   xØ| j D ]Î}| ¡ | }| ¡ | }| ¡ |kr²|| | }x4t|d ƒD ]$}|||  }	|	| }
| |	|
¡ qJW ||d |  }	|	| d }| |	|¡ | ||¡ | d¡ q| ¡ |krÌ| ||¡ q| d¡ qW dS )ap  
    Splits ScienceSegments up into chunks, of a given maximum length.
    The length of the last two chunks are chosen so that the data
    utilisation is optimised.
    @param min_length: minimum chunk length.
    @param max_length: maximum chunk length.
    @param pad_data: exclude the first and last pad_data seconds of the
    segment when generating chunks
    rr   r^  r   N)r‚  rV  rW  r}  rÒ   r|  r~  )r   r‡  Ú
max_lengthrw  r“  Z	seg_startZseg_endÚNrÔ   rV  ÚstopÚmiddler
   r
   r   Úmake_optimised_chunksX  s"    
z!ScienceData.make_optimised_chunksc             C   sô   t | ƒ}t |ƒ}d}g }d}d}d}xÀ| D ]¸}	|	 ¡ }
|	 ¡ }|	 ¡ }xš||k rà||
kr¨|
|k rf|}n|
}||krx|}n|}tt||||| gƒƒ}| |¡ ||kr¨P |d7 }|t |ƒk rÖ|| }| ¡ }| ¡ }qHd}d}qHW q*W || _t | ƒS )a  
    Replaces the ScienceSegments contained in this instance of ScienceData
    with the intersection of those in the instance other. Returns the number
    of segments in the intersection.
    @param other: ScienceData to use to generate the intersection
    r  rr   i ”5w)rF  rV  rW  ri  r]  r†  rA   r‚  )r   rk  Úlength1Úlength2ÚostartÚoutlistZiseg2Ústart2Ústop2Zseg1Ústart1Ústop1ri  ÚostoprZ  Zseg2r
   r
   r   Úintersection~  s@    	



zScienceData.intersectionc             C   sŠ  t | ƒ}t |ƒ}d}g }d}d}d}d}	d}
x |dkrx|d7 }||k rn| |  ¡ }| |  ¡ }| |  ¡ }
n
||krxP |	dkr´|d7 }||k rª||  ¡ }	||  ¡ }n
||kr´P |dkrÚ|	dksÌ||	krÚ|}|}d}n|	dkrð|	}|}d}	nP |dkr|}|}q0||kr"||krL|}n q0tt|
|||| gƒƒ}| |¡ |}|}q0W |dkr|tt|
|||| gƒƒ}| |¡ || _t | ƒS )zý
    Replaces the ScienceSegments contained in this instance of ScienceData
    with the union of those in the instance other. Returns the number of
    ScienceSegments in the union.
    @param other: ScienceData to use to generate the intersection
    r  rr   )rF  rV  rW  ri  r]  r†  rA   r‚  )r   rk  r›  rœ  r  ÚseglistÚi1Úi2r¡  rŸ  ri  r¢  r   ZustartZustopr£  rZ  r
   r
   r   Úunion¼  sd    	





zScienceData.unionc       	      C   sÈ   t | ƒdkrdS | j ¡  g }d}xl| D ]d}| ¡ }| ¡ }| ¡ }||kr€|dkrvtt||||| gƒƒ}| |¡ |}|}q(||kr(|}q(W |dkrºtt||||| gƒƒ}| |¡ || _t | ƒS )zr
    Coalesces any adjacent ScienceSegments. Returns the number of
    ScienceSegments in the coalesced list.
    r   r  )	rF  r‚  ÚsortrV  rW  ri  r]  r†  rA   )	r   rž  r£  r“  rV  r˜  ri  r  rZ  r
   r
   r   Úcoalesce	  s,    



zScienceData.coalescec             C   sÎ   t | ƒdkr"ttddddgƒƒ| _g }d}xj| D ]b}| ¡ }| ¡ }|dk s\||k s\||k rdtdƒ‚|dkrŽttd|||| gƒƒ}| |¡ |}q0W |dk rÀttd|dd| gƒƒ}| |¡ || _t | ƒS )z~
    Inverts the ScienceSegments in the class (i.e. set NOT).  Returns the
    number of ScienceSegments after inversion.
    r   iÿ“5wzInvalid list)rF  r]  r†  r‚  rV  rW  r   rA   )r   rž  r  r“  rV  r˜  rZ  r
   r
   r   Úinvert:	  s$    


zScienceData.invertc             C   sÔ   t | ƒ}d}g }d}d}d}x¨| D ] }| ¡ }| ¡ }	| ¡ }
||dt|| | | ƒ   }xb||	k rÀ||krv|}n|}|| }||	k r|}n|	}tt|
|||| gƒƒ}| |¡ || }q`W q"W || _t | ƒS )zH
    Keep only times in ScienceSegments which are in the playground
    r  iÕw+iâ  iX  rr   )	rF  rV  rW  ri  rª   r]  r†  rA   r‚  )r   rr  r  rž  Zbegin_s2Z
play_spaceZplay_lenr“  rV  r˜  ri  ry  Z	play_stopr£  rZ  r
   r
   r   rt  Z	  s2    


zScienceData.playc             C   s$   |   |¡ |   |¡ |  ¡  t| ƒS )zl
    Intersection routine for three inputs.  Built out of the intersect,
    coalesce and play routines
    )r¤  rª  rF  )r   ÚsecondÚthirdr
   r
   r   Úintersect_3Š	  s    

zScienceData.intersect_3c             C   s.   |   |¡ |   |¡ |   |¡ |  ¡  t| ƒS )z0
     Intersection routine for four inputs.
    )r¤  rª  rF  )r   r¬  r­  Zfourthr
   r
   r   Úintersect_4”	  s
    


zScienceData.intersect_4c       	      C   sž   g }xŠ| D ]‚}|  ¡ }| ¡ }| ¡ }xd||k rŠ|| }||krF|}n|| |krbt|| d ƒ}tt||||| gƒƒ}| |¡ |}q(W q
W || _t| ƒS )zP
      Split the segments in the list is subsegments at least as long as dt
    r^  )	rV  rW  ri  rª   r]  r†  rA   r‚  rF  )	r   Údtrž  r“  rV  r˜  ri  ZtmpstoprZ  r
   r
   r   r  ž	  s     


zScienceData.splitN)r   r   )r   r   r   r   r   )r   r   r   r   r   )r   r   r   r   )r   )r   r   r   r   r   rh  r²   r[  rŒ  r  r’  r{  r”  r•  rš  r¤  r¨  rª  r«  rt  r®  r¯  r  r
   r
   r
   r   r  ¬  s*   
'
 
1

&>U) 0

r  c               @   s.   e Zd Zdd„ Zdd„ Zd
dd„Zdd	„ ZdS )Ú
LsyncCachec             C   s6   || _ d d d dœ| _x| j ¡ D ]}i | j|< q W d S )N)ÚgwfZsftÚxml)Ú_LsyncCache__pathÚcacherm   )r   r\   Útyper
   r
   r   r   ¹	  s    zLsyncCache.__init__c                s   t j‡ ‡fdd„tˆƒD ƒŽ S )zZ
    Group an iterable into an n-tuples iterable. Incomplete
    tuples are discarded
    c                s   g | ]}t  ˆ |d ˆ¡‘qS )N)Ú	itertoolsÚislice)Ú.0rÔ   )ÚlstÚnr
   r   ú
<listcomp>Ë	  s    z$LsyncCache.group.<locals>.<listcomp>)r·  ÚiziprÒ   )r   rº  r»  r
   )rº  r»  r   rá   Æ	  s    zLsyncCache.groupNc             C   s8  | j }| j}|rt |¡}nd}t|dƒ}i }xô|D ]ì}|rL| |¡dkrLq4| ¡  dd¡\}}	}
}| d¡\}}}}}t|ƒ}dd„ |dd	…  d¡D ƒ}d
d„ |  	|d¡D ƒ}||krÂi ||< ||| krÚi || |< ||f}||| | krdt
|ƒ }t|ƒ‚tj |¡|| | |< q4W | ¡  ||d< dS )ay  
    Each line of the frame cache file is like the following:

    /frames/E13/LHO/frames/hoftMon_H1/H-H1_DMT_C00_L2-9246,H,H1_DMT_C00_L2,1,16 1240664820 6231 {924600000 924646720 924646784 924647472 924647712 924700000}

    The description is as follows:

    1.1) Directory path of files
    1.2) Site
    1.3) Type
    1.4) Number of frames in the files (assumed to be 1)
    1.5) Duration of the frame files.

    2) UNIX timestamp for directory modification time.

    3) Number of files that that match the above pattern in the directory.

    4) List of time range or segments [start, stop)

    We store the cache for each site and frameType combination
    as a dictionary where the keys are (directory, duration)
    tuples and the values are segment lists.

    Since the cache file is already coalesced we do not
    have to call the coalesce method on the segment lists.
    Nr°   ri   r_  ú,c             S   s   g | ]}t |ƒ‘qS r
   )rª   )r¹  Úsr
   r
   r   r¼  
  s    z$LsyncCache.parse.<locals>.<listcomp>rr   r  c             S   s   g | ]}t j |¡‘qS r
   )ÚligoÚsegmentsrg  )r¹  r±   r
   r
   r   r¼  
  s    r^  z8The combination %s is not unique in the frame cache filer²  )r´  rµ  ry   rz   rj   râ   rW   r  rª   rá   rU   ÚRuntimeErrorrÀ  rÁ  Úsegmentlistrn   )r   Z
type_regexr\   rµ  Ztype_filterrÚ   ZgwfDictr‰  ÚheaderZmodTimeZ	fileCountÚtimesr   ÚsiteÚ	frameTypeZ
frameCountÚdurationrÁ  ré   rM  r
   r
   r   ÚparseÍ	  s6    


zLsyncCache.parsec          
   C   s  | j }||d krg S ||d | kr*g S tj ||¡}tj |g¡}i }x¢|d | |  ¡ D ]Š\}	}
|	\}}|
 |¡}|s€q`xh|
D ]`}| |¡r†|\}}t|||ƒ}x<|D ]4}| tj ||| ¡¡r®d||||f }d||< q®W q†W q`W t| 	¡ ƒ}| 
¡  |S )z
    r²  z%s-%s-%d-%d.gwfN)rµ  rÀ  rÁ  rg  rÃ  ÚitemsZ
intersectsrÒ   rl   rm   r©  )r   rÆ  rÇ  ZgpsStartZgpsEndrµ  râ   Z
searchlistZlfnDictré   r¥  r   r\  rs  r¿  Út1Út2rÅ  r   rG  Zlfnsr
   r
   r   Úget_lfns
  s0    
 


zLsyncCache.get_lfns)N)r   r   r   r   rá   rÉ  rÍ  r
   r
   r
   r   r±  ¸	  s   
Or±  c               @   s2   e Zd ZdZddd„Zdd„ Zdd„ Zd	d
„ ZdS )ÚLSCDataFindJoba·  
  An LSCdataFind job used to locate data. The static options are
  read from the section [datafind] in the ini file. The stdout from
  LSCdataFind contains the paths to the frame files and is directed to a file
  in the cache directory named by site and GPS start and end times. The stderr
  is directed to the logs directory. The job always runs in the scheduler
  universe. The path to the executable is determined from the ini file.
  Nc       	      C   s,  |  dd¡| _d| _t | | j| j¡ t | |¡ || _|| _d| _| 	dd¡rd|  
d|  dd¡¡ |r~t|ƒ| _| j |¡ xR| j d¡D ]B}t|ƒ ¡ }|dd… dkrŒt| j  d|¡ƒ ¡ }|  ||¡ qŒW |  dd	¡ |  d
d¡ |  
dd¡ |  tj |d¡¡ |  tj |d¡¡ |  d¡ dS )aT  
    @param cache_dir: the directory to write the output lal cache files to.
    @param log_dir: the directory to write the stderr file to.
    @param config_file: ConfigParser object containing the path to the LSCdataFind
    executable in the [condor] section and a [datafind] section from which
    the LSCdataFind options are read.
    ÚcondorÚdatafindÚlocalNÚaccounting_grouprŽ  r¶  z	lal-cacher   zurl-typeÚfileÚgetenvÚTruezkdatafind-$(macroobservatory)-$(macrotype)-$(macrogpsstarttime)-$(macrogpsendtime)-$(cluster)-$(process).errzkdatafind-$(macroobservatory)-$(macrotype)-$(macrogpsstarttime)-$(macrogpsendtime)-$(cluster)-$(process).outzdatafind.sub)rV   Z_LSCDataFindJob__executableZ_LSCDataFindJob__universerq   r   r  Ú_LSCDataFindJob__cache_dirÚ_LSCDataFindJob__config_fileÚ_LSCDataFindJob__lsync_cacheÚ
has_optionr?   r±  rÉ  rT   rU   rW   rN   r`   r  r\   rÌ   rb   rd   )	r   Ú	cache_dirÚlog_dirÚconfig_fileZlsync_cache_fileZlsync_type_regexÚorM   rI   r
   r
   r   r   Y
  s.    
zLSCDataFindJob.__init__c             C   s   | j S )zD
    returns the directroy that the cache files are written to.
    )rÖ  )r   r
   r
   r   Úget_cache_dir
  s    zLSCDataFindJob.get_cache_dirc             C   s   | j S )z.
    return the configuration file object
    )r×  )r   r
   r
   r   Úget_config_file…
  s    zLSCDataFindJob.get_config_filec             C   s   | j S )N)rØ  )r   r
   r
   r   Úlsync_cache‹
  s    zLSCDataFindJob.lsync_cache)NN)r   r   r   r   r   rÞ  rß  rà  r
   r
   r
   r   rÎ  P
  s
   
&rÎ  c               @   sr   e Zd ZdZdd„ Zdd„ Zddd„Zd	d
„ Zdd„ Zdd„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zdd„ Zdd„ ZdS )ÚLSCDataFindNodezE
  A DataFindNode runs an instance of LSCdataFind in a Condor DAG.
  c             C   sp   t  | |¡ t | ¡ d| _d| _d| _d| _|| _d| _y|  	|  
¡  ¡  dd¡¡ W n   d| _Y nX dS )zM
    @param job: A CondorDAGJob that can run an instance of LALdataFind.
    r   NrÐ  r¶  )r}   r   r  Ú_LSCDataFindNode__startÚ_LSCDataFindNode__endÚ_LSCDataFindNode__observatoryÚ_LSCDataFindNode__outputÚ_LSCDataFindNode__jobZ_LSCDataFindNode__lfn_listÚset_typer¯   rß  rV   Ú_LSCDataFindNode__type)r   r¯   r
   r
   r   r   “
  s    
zLSCDataFindNode.__init__c             C   st   | j rp| jrp| jrp| jrptj | j ¡ | jd | j d d t	| j ƒ d t	| j| j  ƒ d ¡| _
|  | j
¡ dS )z…
    Private method to set the file to write the cache to. Automaticaly set
    once the ifo, start and end times have been set.
    rE  Z_CACHEz.lcfN)râ  rã  rä  rè  r  r\   rÌ   ræ  rÞ  rU   rå  r>  )r   r
   r
   r   Z__set_output¦
  s    LzLSCDataFindNode.__set_outputNc             C   s@   |r|   dt|ƒt|ƒ ¡ n|   dt|ƒ¡ || _|  ¡  dS )z]
    Set the start time of the datafind query.
    @param time: GPS start time of query.
    zgps-start-timeN)r„   rª   râ  Ú_LSCDataFindNode__set_output)r   r«   r2  r
   r
   r   r,  ¯
  s
    zLSCDataFindNode.set_startc             C   s   | j S )z5
    Return the start time of the datafind query
    )râ  )r   r
   r
   r   r-  »
  s    zLSCDataFindNode.get_startc             C   s   |   d|¡ || _|  ¡  dS )zY
    Set the end time of the datafind query.
    @param time: GPS end time of query.
    zgps-end-timeN)r„   rã  ré  )r   r«   r
   r
   r   r.  Á
  s    zLSCDataFindNode.set_endc             C   s   | j S )z5
    Return the start time of the datafind query
    )rã  )r   r
   r
   r   r/  Ê
  s    zLSCDataFindNode.get_endc             C   s"   |   d|¡ t|ƒ| _|  ¡  dS )a!  
    Set the IFO to retrieve data for. Since the data from both Hanford
    interferometers is stored in the same frame file, this takes the first
    letter of the IFO (e.g. L or H) and passes it to the --observatory option
    of LSCdataFind.
    @param obs: IFO to obtain data for.
    ZobservatoryN)r„   rU   rä  ré  )r   Zobsr
   r
   r   Úset_observatoryÐ
  s    
zLSCDataFindNode.set_observatoryc             C   s   | j S )z5
    Return the start time of the datafind query
    )rä  )r   r
   r
   r   Úget_observatoryÜ
  s    zLSCDataFindNode.get_observatoryc             C   s&   |   dt|ƒ¡ t|ƒ| _|  ¡  dS )z2
    sets the frame type that we are querying
    r¶  N)r„   rU   rè  ré  )r   r¶  r
   r
   r   rç  â
  s    
zLSCDataFindNode.set_typec             C   s   | j S )z2
    gets the frame type that we are querying
    )rè  )r   r
   r
   r   Úget_typeê
  s    zLSCDataFindNode.get_typec             C   s   | j S )N)rå  )r   r
   r
   r   Úget_output_cacheð
  s    z LSCDataFindNode.get_output_cachec             C   s   | j S )zP
    Return the output file, i.e. the file containing the frame cache data.
    )rå  )r   r
   r
   r   r?  ó
  s    zLSCDataFindNode.get_output)N)r   r   r   r   r   ré  r,  r-  r.  r/  rê  rë  rç  rì  rí  r?  r
   r
   r
   r   rá  
  s   	
	rá  c               @   s   e Zd ZdZdd„ ZdS )ÚLigolwAddJobzG
  A ligolw_add job can be used to concatenate several ligo lw files
  c             C   s    |  dd¡| _d| _t | | j| j¡ t | |¡ |  |d¡ |  dd¡ | dd¡rj|  d|  dd¡¡ |  	t
j |d¡¡ |  t
j |d¡¡ |  d	¡ d
S )z?
    cp = ConfigParser object from which options are read.
    rÏ  Z
ligolw_addÚvanillarÔ  rÕ  rÒ  z$ligolw_add-$(cluster)-$(process).outz$ligolw_add-$(cluster)-$(process).errzligolw_add.subN)rV   Z_LigolwAddJob__executableZ_LigolwAddJob__universerq   r   r  rZ   r?   rÙ  rb   r  r\   rÌ   r`   rd   )r   rÛ  rX   r
   r
   r   r   þ
  s    zLigolwAddJob.__init__N)r   r   r   r   r   r
   r
   r
   r   rî  ú
  s   rî  c               @   s   e Zd ZdZdd„ ZdS )ÚLigolwAddNodez5
  Runs an instance of ligolw_add in a Condor DAG.
  c             C   s   t  | |¡ t | ¡ dS )zK
    @param job: A CondorDAGJob that can run an instance of ligolw_add
    N)r}   r   r  )r   r¯   r
   r
   r   r     s    zLigolwAddNode.__init__N)r   r   r   r   r   r
   r
   r
   r   rð    s   rð  c               @   s   e Zd ZdZdd„ ZdS )ÚLigolwCutJobzD
  A ligolw_cut job can be used to remove parts of a ligo lw file
  c             C   st   |  dd¡| _d| _t | | j| j¡ t | |¡ |  dd¡ |  tj	 
|d¡¡ |  tj	 
|d¡¡ |  d¡ d	S )
z?
    cp = ConfigParser object from which options are read.
    rÏ  Z
ligolw_cutrï  rÔ  rÕ  z$ligolw_cut-$(cluster)-$(process).outz$ligolw_cut-$(cluster)-$(process).errzligolw_cut.subN)rV   Z_LigolwCutJob__executableZ_LigolwCutJob__universerq   r   r  r?   rb   r  r\   rÌ   r`   rd   )r   rÛ  rX   r
   r
   r   r   !  s    zLigolwCutJob.__init__N)r   r   r   r   r   r
   r
   r
   r   rñ    s   rñ  c               @   s   e Zd ZdZdd„ ZdS )ÚLigolwCutNodez5
  Runs an instance of ligolw_cut in a Condor DAG.
  c             C   s   t  | |¡ t | ¡ dS )zK
    @param job: A CondorDAGJob that can run an instance of ligolw_cut
    N)r}   r   r  )r   r¯   r
   r
   r   r   5  s    zLigolwCutNode.__init__N)r   r   r   r   r   r
   r
   r
   r   rò  1  s   rò  c               @   s   e Zd ZdZdd„ ZdS )ÚNoopJobz
  A Noop Job does nothing.
  c             C   s˜   d| _ d| _t | | j| j ¡ t | |¡ |  dd¡ |  dd¡ | dd¡rb|  d| dd¡¡ |  t	j
 |d¡¡ |  t	j
 |d	¡¡ |  d
¡ dS )z?
    cp = ConfigParser object from which options are read.
    ÚtruerÑ  rÔ  rÕ  Znoop_jobrÏ  rÒ  znoop-$(cluster)-$(process).outznoop-$(cluster)-$(process).errznoop.subN)Z_NoopJob__executableZ_NoopJob__universerq   r   r  r?   rÙ  rV   rb   r  r\   rÌ   r`   rd   )r   rÛ  rX   r
   r
   r   r   A  s    zNoopJob.__init__N)r   r   r   r   r   r
   r
   r
   r   ró  =  s   ró  c               @   s   e Zd ZdZdd„ ZdS )ÚNoopNodez&
  Run an noop job in a Condor DAG.
  c             C   s8   t  | |¡ t | ¡ d| _d| _d| _d| _d| _dS )z7
    @param job: A CondorDAGJob that does nothing.
    N)r}   r   r  Z_NoopNode__serverZ_NoopNode__identityZ_NoopNode__insertZ_NoopNode__pfnZ_NoopNode__query)r   r¯   r
   r
   r   r   X  s    
zNoopNode.__init__N)r   r   r   r   r   r
   r
   r
   r   rõ  T  s   rõ  c               @   s(   e Zd ZdZdd„ Zdd„ Zdd„ ZdS )	Ú	SqliteJoba~  
  A cbc sqlite job adds to CondorDAGJob and AnalysisJob features common to jobs
  which read or write to a sqlite database. Of note, the universe is always set to
  local regardless of what's in the cp file, the extension is set
  to None so that it may be set by individual SqliteNodes, log files do not
  have macrogpsstarttime and endtime in them, and get_env is set to True.
  c             C   s¾   || _ | d|¡}d}t | ||¡ t | |¡ x8|D ]0}| |¡rR|  ||¡ q6tj 	d| d ¡ q6W |  
dd¡ | dd¡r–|  
d| dd¡¡ |  d| d	 ¡ |  d| d
 ¡ dS )zª
    @cp: a ConfigParser object from which options are read
    @sections: list of sections in cp to get added options
    @exec_name: the name of the sql executable
    rÏ  rï  z)warning: config file is missing section [z]
rÔ  rÕ  rÒ  zlogs/z-$(cluster)-$(process).outz-$(cluster)-$(process).errN)Ú_SqliteJob__exec_namerV   rq   r   r  Úhas_sectionrZ   rp  Ústderrrk   r?   rÙ  rb   r`   )r   rX   ÚsectionsÚ	exec_namer1   r0   r  r
   r
   r   r   m  s    

zSqliteJob.__init__c             C   s
   || _ dS )z 
    Set the exec_name name
    N)r÷  )r   rû  r
   r
   r   Úset_exec_name…  s    zSqliteJob.set_exec_namec             C   s   | j S )z 
    Get the exec_name name
    )r÷  )r   r
   r
   r   Úget_exec_name‹  s    zSqliteJob.get_exec_nameN)r   r   r   r   r   rü  rý  r
   r
   r
   r   rö  e  s   rö  c               @   s8   e Zd ZdZdd„ Zdd„ Zdd„ Zdd	„ Zd
d„ ZdS )Ú
SqliteNodezÇ
  A cbc sqlite node adds to the standard AnalysisNode features common to nodes
  which read or write to a sqlite database. Specifically, it adds the set_tmp_space_path
  and set_database methods.
  c             C   s&   t  | |¡ t | ¡ d| _d| _dS )z
    @job: an Sqlite job
    N)r}   r   r  Ú_SqliteNode__tmp_spaceÚ_SqliteNode__database)r   r¯   r
   r
   r   r   ˜  s    
zSqliteNode.__init__c             C   s   |   d|¡ || _dS )z?
    Sets temp-space path. This should be on a local disk.
    z	tmp-spaceN)r„   rÿ  )r   Z	tmp_spacer
   r
   r   Úset_tmp_space¡  s    zSqliteNode.set_tmp_spacec             C   s   | j S )z
    Gets tmp-space path.
    )rÿ  )r   r
   r
   r   Úget_tmp_space¨  s    zSqliteNode.get_tmp_spacec             C   s   |   d|¡ || _dS )z
    Sets database option.
    ÚdatabaseN)rP   r   )r   r  r
   r
   r   Úset_database®  s    zSqliteNode.set_databasec             C   s   | j S )z
    Gets database option.
    )r   )r   r
   r
   r   Úget_databaseµ  s    zSqliteNode.get_databaseN)	r   r   r   r   r   r  r  r  r  r
   r
   r
   r   rþ  ’  s   	rþ  c                   s(   e Zd ZdZ‡ fdd„Zdd„ Z‡  ZS )ÚLigolwSqliteJobzi
  A LigolwSqlite job. The static options are read from the
  section [ligolw_sqlite] in the ini file.
  c                s"   d}dg}t t| ƒ |||¡ dS )z?
    @cp: ConfigParser object from which options are read.
    Zligolw_sqliteN)rt   r  r   )r   rX   rû  rú  )r|   r
   r   r   Á  s    zLigolwSqliteJob.__init__c             C   s   |   dd¡ dS )zy
    Sets the --replace option. This will cause the job
    to overwrite existing databases rather than add to them.
    Úreplacer   N)rN   )r   r
   r
   r   Úset_replaceÉ  s    zLigolwSqliteJob.set_replace)r   r   r   r   r   r  r‹   r
   r
   )r|   r   r  ¼  s   r  c                   sH   e Zd ZdZ‡ fdd„Zdd„ Zdd„ Zdd	„ Zd
d„ Zdd„ Z	‡  Z
S )ÚLigolwSqliteNodez
  A LigolwSqlite node.
  c                s&   t t| ƒ |¡ d| _d| _d| _dS )z!
    @job: a LigolwSqliteJob
    N)rt   r	  r   Ú_LigolwSqliteNode__input_cacheÚ_LigolwSqliteNode__xml_outputZ_LigolwSqliteNode__xml_input)r   r¯   )r|   r
   r   r   Õ  s    zLigolwSqliteNode.__init__c             C   s   |   d|¡ || _dS )z
    Sets input cache.
    zinput-cacheN)rP   r
  )r   Zinput_cacher
   r
   r   Úset_input_cacheÞ  s    z LigolwSqliteNode.set_input_cachec             C   s   | j S )z
    Gets input cache.
    )r
  )r   r
   r
   r   Úget_input_cacheå  s    z LigolwSqliteNode.get_input_cachec             C   s   |   |¡ dS )z.
    Sets xml input file instead of cache
    N)rŠ   )r   Úxml_filer
   r
   r   Úset_xml_inputë  s    zLigolwSqliteNode.set_xml_inputc             C   s*   |   ¡ dkrtdƒ‚|  d|¡ || _dS )zL
    Tell ligolw_sqlite to dump the contents of the database to a file.
    Nzno database specifiedÚextract)r  Ú
ValueErrorrP   r  )r   r  r
   r
   r   Úset_xml_outputñ  s    zLigolwSqliteNode.set_xml_outputc             C   s(   | j r| j S |  ¡ r|  ¡ S tdƒ‚dS )zx
    Override standard get_output to return xml-file if xml-file is specified.
    Otherwise, will return database.
    z(no output xml file or database specifiedN)r  r  r  )r   r
   r
   r   r?  ú  s
    zLigolwSqliteNode.get_output)r   r   r   r   r   r  r  r  r  r?  r‹   r
   r
   )r|   r   r	  Ñ  s   		r	  c               @   s   e Zd ZdZdd„ ZdS )ÚDeepCopyableConfigParserz²
    The standard SafeConfigParser no longer supports deepcopy() as of python
    2.7 (see http://bugs.python.org/issue16058). This subclass restores that
    functionality.
    c             C   s0   t ƒ }|  |¡ | d¡ |  ¡ }| |¡ |S )Nr   )r	   rk   Úseekr|   Úreadfp)r   ÚmemoZconfig_stringZ
new_configr
   r
   r   Ú__deepcopy__  s    


z%DeepCopyableConfigParser.__deepcopy__N)r   r   r   r   r  r
   r
   r
   r   r    s   r  )Fr   Ú
__future__r   Ú
__author__Zgluer   ÚdateÚ__date__ri  Ú__version__r  rp  ry   r«   r¬   rm  Z	six.movesr   r  Úsocketr·  Zligo.segmentsrÀ  Úhashlibr   Zcjsonr   ÚImportErrorÚjsonr   Zsix.moves.http_clientÚsixr   r	   r   Ú	Exceptionr   r   r   r   r   r   r   Úobjectr   rq   rŒ   r}   r‘   r÷   r  r  rP  r]  r  r±  rÎ  rá  rî  rð  rñ  rò  ró  rõ  rö  rþ  r  r	  ÚSafeConfigParserr  r
   r
   r
   r   Ú<module>   s–      HA    * -(  (b ,     ?k-*5