Skip to content

Commit

Permalink
Merge pull request #15 from Kortemme-Lab/input_refactoring
Browse files Browse the repository at this point in the history
Make the 01 script more user friendly.
  • Loading branch information
kalekundert committed Mar 15, 2018
2 parents 5572512 + 951e940 commit 0ca2667
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 91 deletions.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Empty file.
File renamed without changes.
File renamed without changes.
170 changes: 85 additions & 85 deletions pull_into_place/commands/01_setup_workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,16 @@
that will be used by the rest of the scripts in this pipeline.
Usage:
pull_into_place 01_setup_workspace <workspace> [--remote]
[--overwrite] [--copy]
pull_into_place 01_setup_workspace <workspace> [<params>] [--remote]
[--overwrite]
Arguments:
<workspace>
The name of the workspace directory to create.
<params>
The path to a directory containing the input files specific to your
project. If provided, these will be installed into the workspace.
Options:
--remote, -r
Expand All @@ -20,10 +28,6 @@
--overwrite, -o
If a design with the given name already exists, remove it and replace
it with the new design created by this script.
--copy, -c
Setup a workspace with the same inputs as a previously set-up
workspace.
"""

import os, re, shutil, subprocess
Expand All @@ -35,7 +39,16 @@ def ensure_path_exists(path):
return path


class RosettaDir:
class Installer:
prompt = None
description = None

@staticmethod
def already_installed(workspace):
return False


class RosettaDir(Installer):
prompt = "Path to rosetta: "
description = """\
Rosetta checkout: Path to the main directory of a Rosetta source code checkout.
Expand Down Expand Up @@ -67,36 +80,41 @@ def install(workspace, rosetta_dir):

os.symlink(rosetta_dir, workspace.rosetta_dir)

class CopyWorkspaceInputs:
prompt="Path to previous workspace: "
description = """\
Copying inputs from previous workspace."""

@staticmethod
def install(workspace, old_workspace):
from distutils.dir_util import copy_tree
class ParamDirs(Installer):

old_workspace = ensure_path_exists(old_workspace)
old_workspace = pipeline.Workspace(old_workspace)
old_workspace.check_paths()
def __init__(self, src):
self.src = src

def install(self, workspace):
from distutils.dir_util import copy_tree

# Always copy in the standard input files.
copy_tree(
old_workspace.standard_params_dir,
pipeline.big_job_path('standard_params'),
workspace.standard_params_dir,
preserve_symlinks=True,
)
copy_tree(
old_workspace.custom_params_dir,
workspace.custom_params_dir,
preserve_symlinks=True,
)

class InputPdb:
# Copy in project-specific input files if we were given any. If we
# weren't, just make an empty directory so we don't get errors if/when
# we try to install other files there.
if self.src is not None:
copy_tree(
ensure_path_exists(self.src),
workspace.project_params_dir,
preserve_symlinks=True,
)
else:
scripting.mkdir(workspace.project_params_dir)


class InputPdb(Installer):
prompt = "Path to the input PDB file: "
description = """\
Input PDB file: A structure containing the functional groups to be positioned.
This file should already be parse-able by rosetta, which often means it must be
stripped of waters and extraneous ligands."""
This file should already be prepared for input (i.e. renumbered and cleaned of
problematic ligands) and relaxed in the rosetta score function."""

@staticmethod
def install(workspace, pdb_path):
Expand All @@ -109,8 +127,12 @@ def install(workspace, pdb_path):
else:
raise ValueError("'{0}' is not a PDB file.".format(pdb_path))

@staticmethod
def already_installed(workspace):
return os.path.exists(workspace.input_pdb_path)


class LoopsFile:
class LoopsFile(Installer):
prompt = "Path to the loops file: "
description = """\
Loops file: A file specifying which backbone regions will be allowed to move.
Expand All @@ -122,8 +144,12 @@ def install(workspace, loops_path):
loops_path = ensure_path_exists(loops_path)
shutil.copyfile(loops_path, workspace.loops_path)

@staticmethod
def already_installed(workspace):
return os.path.exists(workspace.loops_path)


class Resfile:
class Resfile(Installer):
prompt = "Path to resfile: "
description = """\
Resfile: A file specifying which positions to design and which positions to
Expand All @@ -134,8 +160,12 @@ def install(workspace, resfile_path):
resfile_path = ensure_path_exists(resfile_path)
shutil.copyfile(resfile_path, workspace.resfile_path)

@staticmethod
def already_installed(workspace):
return os.path.exists(workspace.resfile_path)


class RestraintsFile:
class RestraintsFile(Installer):
prompt = "Path to restraints file: "
description = """\
Restraints file: A file describing the geometry you're trying to design. In
Expand All @@ -147,19 +177,23 @@ def install(workspace, restraints_path):
restraints_path = ensure_path_exists(restraints_path)
shutil.copyfile(restraints_path, workspace.restraints_path)

@staticmethod
def already_installed(workspace):
return os.path.exists(workspace.restraints_path)


class ScoreFunction:
class ScoreFunction(Installer):
prompt = "Path to weights file [optional]: "
description = """\
Score function: A file that specifies weights for all the terms in the score
function, or the name of a standard rosetta score function. The default is
talaris2014. That should be ok unless you have some particular interaction
ref2015. That should be ok unless you have some particular interaction
(e.g. ligand, DNA, etc.) that you want to score in a particular way."""

@staticmethod
def install(workspace, scorefxn_path):

# If the user didn't specify a score function, use talaris2014 by
# If the user didn't specify a score function, use ref2015 by
# default.

if not scorefxn_path:
Expand All @@ -181,7 +215,7 @@ def install(workspace, scorefxn_path):
shutil.copyfile(scorefxn_path, workspace.scorefxn_path)


class BuildScript:
class BuildScript(Installer):
prompt = "Path to build script [optional]: "
description = """\
Build script: An XML rosetta script that generates backbones capable of
Expand All @@ -193,12 +227,9 @@ def install(workspace, script_path):
if script_path:
script_path = ensure_path_exists(script_path)
shutil.copyfile(script_path, workspace.build_script_path)
else:
default_path = pipeline.big_job_path('build_models.xml')
shutil.copyfile(default_path, workspace.build_script_path)


class DesignScript:
class DesignScript(Installer):
prompt = "Path to design script [optional]: "
description = """\
Design script: An XML rosetta script that performs design to stabilize the
Expand All @@ -209,12 +240,9 @@ def install(workspace, script_path):
if script_path:
script_path = ensure_path_exists(script_path)
shutil.copyfile(script_path, workspace.design_script_path)
else:
default_path = pipeline.big_job_path('design_models.xml')
shutil.copyfile(default_path, workspace.design_script_path)


class ValidateScript:
class ValidateScript(Installer):
prompt = "Path to validate script [optional]: "
description = """\
Validate script: An XML rosetta script that samples the designed loop to
Expand All @@ -227,22 +255,9 @@ def install(workspace, script_path):
if script_path:
script_path = ensure_path_exists(script_path)
shutil.copyfile(script_path, workspace.validate_script_path)
else:
default_path = pipeline.big_job_path('validate_designs.xml')
shutil.copyfile(default_path, workspace.validate_script_path)


class SharedDefs:
prompt = None
description = None

@staticmethod
def install(workspace):
print "Installing shared defs."
shared_defs_path = pipeline.big_job_path('shared_defs.xml')
shutil.copyfile(shared_defs_path, workspace.shared_defs_path)

class FilterScript:
class FilterScript(Installer):
prompt = "Path to filters script [optional]: "
description = """\
Filters script: An XML rosetta script that defines filters to be applied to
Expand All @@ -251,21 +266,19 @@ class FilterScript:
Note that the name that you give the filter in RosettaScripts
will appear in the plots that PIP produces, so choose something that will
be descriptive for graphing purposes. Also, it is recommended that you
indicate whether higher filter scores or lower filter scores indicate better structures,
as this allows PIP to color the final xls table accordingly. You can indicate
this with a "[[+]]" or a "[[-]]" anywhere in the filter name in RosettaScripts
(for example, name="PackStat Score [[+]]")."""
indicate whether higher filter scores or lower filter scores indicate better
structures, as this allows PIP to color the final xls table accordingly. You
can indicate this with a "[[+]]" or a "[[-]]" anywhere in the filter name in
RosettaScripts (for example, name="PackStat Score [[+]]")."""

@staticmethod
def install(workspace, script_path):
if script_path:
script_path = ensure_path_exists(script_path)
shutil.copyfile(script_path, workspace.filters_path)
else:
default_path = pipeline.big_job_path('filters.xml')
shutil.copyfile(default_path, workspace.filters_path)

class FlagsFile:

class FlagsFile(Installer):
prompt = "Path to flags file [optional]: "
description = """\
Flags file: A file containing command line flags that should be passed to every
Expand All @@ -277,23 +290,9 @@ def install(workspace, flags_path):
if flags_path:
flags_path = ensure_path_exists(flags_path)
shutil.copyfile(flags_path, workspace.flags_path)
else:
scripting.touch(workspace.flags_path)

class FragmentWeights:
prompt = None
description = """\
Fragment weights files, describing how any fragment-based filter should
behave. A simple and standard set of weights are provided."""

@staticmethod
def install(workspace):
standard_weights = pipeline.big_job_path('fragment.wts')
shutil.copyfile(standard_weights,
workspace.fragment_weights_path)


class RsyncUrl:
class RsyncUrl(Installer):
prompt = "Path to project on remote host: "
description = """\
Rsync URL: An ssh-style path to the directory that contains (i.e. is one level
Expand Down Expand Up @@ -334,7 +333,7 @@ def main():
shutil.rmtree(workspace.root_dir)
else:
scripting.print_error_and_die("""\
Design '{0}' already exists. Use '-o' to overwrite.""", workspace.root_dir)
Workspace '{0}' already exists. Use '-o' to overwrite.""", workspace.root_dir)

workspace.make_dirs()

Expand All @@ -345,12 +344,9 @@ def main():
RosettaDir,
RsyncUrl,
)
elif arguments['--copy']:
installers = (
CopyWorkspaceInputs,
)
else:
installers = (
ParamDirs(arguments['<params>']),
RosettaDir,
InputPdb,
LoopsFile,
Expand All @@ -361,9 +357,7 @@ def main():
DesignScript,
ValidateScript,
FilterScript,
SharedDefs,
FlagsFile,
FragmentWeights,
)

# Get the necessary settings from the user and use them to fill in the
Expand All @@ -376,6 +370,12 @@ def main():

for installer in installers:

# Skip installing any files that are already installed (e.g. the
# resfile if a resfile was copied in with the params dirs).

if installer.already_installed(workspace):
continue

# If the installer doesn't have a prompt, just install it without
# asking any questions.

Expand Down
15 changes: 9 additions & 6 deletions pull_into_place/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ def standard_params_dir(self):
return os.path.join(self.root_dir, 'standard_params')

@property
def custom_params_dir(self):
return os.path.join(self.root_dir, 'custom_params')
def project_params_dir(self):
return os.path.join(self.root_dir, 'project_params')

@property
def seqprof_dir(self):
Expand Down Expand Up @@ -246,10 +246,12 @@ def find_path(self, basename):
in a directory associated with that stage.
"""

preferred_install_path = \
os.path.join(self.project_params_dir, self.focus_name, basename)
paths = [
os.path.join(self.focus_dir, basename),
os.path.join(self.custom_params_dir, self.focus_name, basename),
os.path.join(self.custom_params_dir, basename),
preferred_install_path,
os.path.join(self.project_params_dir, basename),
os.path.join(self.standard_params_dir, self.focus_name, basename),
os.path.join(self.standard_params_dir, basename),
os.path.join(self.root_dir, basename),
Expand All @@ -268,8 +270,9 @@ def find_path(self, basename):
if os.path.exists(path):
return path

# If we didn't find the file, just return the last path we checked.
return paths[-1]
# If we didn't find the file, return the path to where we'd like it to
# be installed.
return preferred_install_path

def check_paths(self):
required_paths = [
Expand Down

0 comments on commit 0ca2667

Please sign in to comment.