Source code for schrodinger.application.desmond.system_builder_inp
#Name: System Builder Input Script
#Command: $SCHRODINGER/run system_builder_inp.py
"""
A script to create a system builder input file.
"""
#  System Builder Input Script
#  Developed by Byungchan Kim
#  April 2007,
#  Copyright Schrodinger, LLC.,
#  All rights reserved.
import os
import re
import sys
from schrodinger import structure
from schrodinger.application.desmond import smarts
from schrodinger.application.desmond.constants import CT_TYPE
from schrodinger.application.desmond.constants import NUM_COMPONENT
from schrodinger.infra import mm
from schrodinger.job import jobcontrol
from schrodinger.structutils.analyze import evaluate_asl
# Define water SMARTS patterns
water_smarts = ["[H]O[H]"]
zob_water_smarts = ["[H]O([H])_[*]", "[H]O[H]_[*]"]
[docs]class SystemBuilderInput:
[docs]    def reset(self):
        self.vdw_scaling_factor = -1.0
        self.oplsaa_version = ''
        self.solute_alignment_type = ''
        self.solute_alignment_value = 0
        self.solute_fname = ''
        self.solute_st = []
        self.membrane = 'DPPC.mae.gz'
        self.positive_ion = 'Na.mae'
        self.negative_ion = 'Cl.mae'
        self.salt_positive_ion = 'Na.mae'
        self.salt_negative_ion = 'Cl.mae'
        self.solvent = 'spc.box.mae'
        self.x_membrane_patch = 10.0
        self.y_membrane_patch = 10.0
        self.ion_type = 'positive'
        self.nion = 0
        self.mmfepio_map_mode_option = -1
        self.mmfepio_retain_angle_option = -1
        self._ion_location = []
        self._exclude_location = []
        self._exclude_distance = 0.0
        self.salt_concentration = 0.0
        self.boundary_condition = 'cubic'
        self.a = 10.0
        self.b = 10.0
        self.c = 10.0
        self.alpha = 90.0
        self.beta = 90.0
        self.gamma = 90.0
        self._should_membranize = 0
        self._should_solvate = 1
        self._should_neutralize = 1
        self._add_alchemical_ions = 0
        self._use_alchemical_water = 0
        self._remove_overlapped_crystal_water = 0
        self.use_buffer = 1
        self.one_mae_file = ''
        self.mae_file = ''
        self.maeff_file = ''
        self.pdb_file = ''
        self.xyz_file = ''
        self.top_file = ''
        self.g96_file = ''
[docs]    def setSoluteAlignment(self, name='', value=1):
        self.solute_alignment_type = name
        self.solute_alignment_value = value
[docs]    def fixSolute(self):
        name = self.solute_fname.lstrip('"').rstrip('"')
        st_reader = structure.StructureReader(name)
        full_system = -1
        comp_st = []
        for i, st in enumerate(st_reader):
            try:
                if st.property[CT_TYPE] == CT_TYPE.VAL.FULL_SYSTEM:
                    full_system = i
            except:
                pass
            comp_st.append(st)
        if full_system >= 0:
            nfull_atom = comp_st[full_system].atom_total
            natom = 0
            for i, st in enumerate(comp_st):
                if i != full_system:
                    natom += st.atom_total
            if nfull_atom != natom:
                for st in comp_st:
                    try:
                        if st.property[CT_TYPE] == CT_TYPE.VAL.FULL_SYSTEM:
                            del st.property[CT_TYPE]
                    except:
                        pass
        # remove alternate coordinates
        alternate_coord_names = [
            "_pdb_alt_",
            "_m_alt_",
            "s_pdb_altloc_chars",
        ]
        for st in comp_st:
            for a in st.atom:
                for p in list(a.property):
                    for alt in alternate_coord_names:
                        if p.find(alt) >= 0:
                            del a.property[p]
        self.solute_st = comp_st
[docs]    def setMembranePatch(self, x_mem=10.0, y_mem=10.0):
        self.x_membrane_patch = x_mem
        self.y_membrane_patch = y_mem
[docs]    def setRemoveOverlappedCrystalWater(self, value=1):
        self._remove_overlapped_crystal_water = value
[docs]    def addIons(self, ion_type='positive', nion=0):
        self.setNeutralize(0)
        self.ion_type = ion_type
        self.nion = nion
[docs]    def addSalt(self, c=0.0):
        """
        Add salt at a target concentration.
        NOTE: In case of FEP inputs for membrane systems, the receptor may
        already contain salt ions. In this case we will adjust the target
        concentration to account for these ions. If the intput system
        concentration is above the target concentration, salt concentration
        will be set to 0.0
        """
        self.salt_concentration = c
        if self.salt_concentration == 0.0:
            return
        # Adjust ion concentration if the system already contains salt ions.
        if not self.solute_st and self.solute_fname:
            self.fixSolute()
        # get number of waters
        nwaters = None
        # Since the inputs contain water box and membrane CTs, the variable
        # name is inaccurate and `self.solute_st` will contain solvent CTs.
        for st in self.solute_st:
            if st.property.get(CT_TYPE) == CT_TYPE.VAL.SOLVENT:
                # NOTE: ghost waters should not be part of this CT
                nwaters = st.mol_total
                break
        if nwaters:
            pos_salt_ions, neg_salt_ions = 0, 0
            pos_ion = self.salt_positive_ion.strip('"')[:-4]
            neg_ion = self.salt_negative_ion.strip('"')[:-4]
            for st in self.solute_st:
                pos_salt_ions += len(evaluate_asl(st, f'a.e {pos_ion}'))
                neg_salt_ions += len(evaluate_asl(st, f'a.e {neg_ion}'))
            # molarity of pure water is 55.5
            pos_salt_concentr = 55.5 * pos_salt_ions / nwaters
            neg_salt_concentr = 55.5 * neg_salt_ions / nwaters
            current_salt_concentr = max(pos_salt_concentr, neg_salt_concentr)
            if current_salt_concentr < self.salt_concentration:
                self.salt_concentration -= current_salt_concentr
            else:
                print('WARNING: Skip adding salt as the current concentration '
                      f'is {current_salt_concentr:0.2f} M, which is greater '
                      f'than the target of {self.salt_concentration} M.')
                self.salt_concentration = 0.0
[docs]    def setExcludeLocation(self, value, distance):
        if type(value) is not list:
            print('Argument must be list of list type.')
            sys.exit(1)
        if len(value) == 0:
            return
        self._exclude_location = value
        self._exclude_distance = distance
[docs]    def setIonLocation(self, value):
        if type(value) is not list:
            print('Argument must be list of list type.')
            sys.exit(1)
        if len(value) == 0:
            return
        for v in value:
            if type(v) is not list:
                print('Argument must be list of list type.')
                sys.exit(1)
        self._ion_location = value
[docs]    def setBoundaryCondition(self, **kwargs):
        if 'use_buffer' in kwargs:
            self.use_buffer = kwargs['use_buffer']
        if 'boundary_condition' in kwargs:
            self.boundary_condition = kwargs['boundary_condition']
        if 'a' in kwargs:
            self.a = kwargs['a']
        if 'b' in kwargs:
            self.b = kwargs['b']
        if 'c' in kwargs:
            self.c = kwargs['c']
        if 'alpha' in kwargs:
            self.alpha = kwargs['alpha']
        if 'beta' in kwargs:
            self.beta = kwargs['beta']
        if 'gamma' in kwargs:
            self.gamma = kwargs['gamma']
[docs]    def write(self, name):
        if self.solute_st:
            try:
                solute_fname = os.path.basename(self.solute_fname)
                base = solute_fname.rindex(".mae")
                root = solute_fname[:base]
                ext = solute_fname[base:]
                solute_fname = root + '_sb' + ext
                solute_fname = solute_fname.lstrip('"').rstrip('"')
            except:
                print("Unrecognized file format for file %s" % solute_fname)
                sys.exit(1)
            if os.path.exists(solute_fname):
                os.remove(solute_fname)
            for st in self.solute_st:
                st.append(solute_fname)
            self.solute_fname = solute_fname
        if self.membrane == '':
            self.membrane = 'DPPC.mae.gz'
        if self.positive_ion == '':
            self.positive_ion = 'Na.mae'
        if self.negative_ion == '':
            self.negative_ion = 'Cl.mae'
        if self.salt_positive_ion == '':
            self.salt_positive_ion = 'Na.mae'
        if self.salt_negative_ion == '':
            self.salt_negative_ion = 'Cl.mae'
        input_line = '{\n'
        if self.oplsaa_version:
            input_line += '  set_oplsaa_version_as %s\n' % self.oplsaa_version
        if self.vdw_scaling_factor != -1.0:
            input_line += '  vdw_scaling_factor %f\n' % self.vdw_scaling_factor
        if self.mmfepio_map_mode_option != -1:
            input_line += '  mmfepio_map_mode_option %d\n' % self.mmfepio_map_mode_option
        if self.mmfepio_retain_angle_option != -1:
            input_line += '  mmfepio_retain_angle_option %d\n' % self.mmfepio_retain_angle_option
        if self.solute_alignment_type == 'xyz' and self.solute_alignment_value:
            input_line += '  align_principal_axes_with_xyz Yes\n'
        elif self.solute_alignment_type == 'xyz' and not self.solute_alignment_value:
            input_line += '  align_principal_axes_with_xyz No\n'
        elif self.solute_alignment_type == 'diagonal' and self.solute_alignment_value:
            input_line += '  align_principal_axis_with_diagonal Yes\n'
        elif self.solute_alignment_type == 'diagonal' and not self.solute_alignment_value:
            input_line += '  align_principal_axis_with_xyz No\n'
        elif self.solute_alignment_type == 'rezero' and self.solute_alignment_value:
            input_line += '  rezero_to_center_of_mass Yes\n'
        elif self.solute_alignment_type == 'rezero' and not self.solute_alignment_value:
            input_line += '  rezero_to_center_of_mass No\n'
        if self.solute_fname != '':
            input_line += '  read_solute_structure "%s"\n' % self.solute_fname
        if self.solvent and self._should_solvate:
            input_line += '  solvent_desmond_oplsaa_typer {\n'
            input_line += '    input_file_name "%s"\n' % (
                self.solvent.strip('"'))
            input_line += '    run\n'
            input_line += '  }\n'
        if self._should_membranize:
            input_line += '  vdw_scaling_factor_membrane 0.25\n'
            input_line += '  membranize "%s" %f %f\n' % (self.membrane.strip(
                '"'), self.x_membrane_patch, self.y_membrane_patch)
        if self.use_buffer:
            input_line += '  create_boundary_conditions '
        else:
            input_line += '  boundary_conditions '
        if (self.boundary_condition == 'cubic'):
            input_line += 'cubic '
            input_line += '%f\n' % float(self.a)
        elif (self.boundary_condition == 'orthorhombic'):
            input_line += 'orthorhombic '
            input_line += '%f %f %f\n' % (float(self.a), float(
                self.b), float(self.c))
        elif (self.boundary_condition == 'triclinic'):
            input_line += 'triclinic '
            input_line += '%f %f %f %f %f %f\n' % (float(self.a), float(
                self.b), float(self.c), float(self.alpha), float(
                    self.beta), float(self.gamma))
        elif (self.boundary_condition == 'truncated_octahedron'):
            if self.use_buffer:
                input_line += 'truncated_octahedron '
                input_line += '%f 70.53 109.47 70.53\n' % float(self.a)
            else:
                input_line += 'triclinic '
                input_line += '%f %f %f 70.53 109.47 70.53\n' % (float(
                    self.a), float(self.a), float(self.a))
        elif (self.boundary_condition == 'dodecahedron_square'):
            if self.use_buffer:
                input_line += 'dodecahedron_square '
                input_line += '%f 60.0 60.0 90.0\n' % float(self.a)
            else:
                input_line += 'triclinic '
                input_line += '%f %f %f 60.0 60.0 90.0\n' % (float(
                    self.a), float(self.a), float(self.a))
        elif (self.boundary_condition == 'dodecahedron_hexagon'):
            if self.use_buffer:
                input_line += 'dodecahedron_hexagon '
                input_line += '%f 60.0 60.0 60.0\n' % float(self.a)
            else:
                input_line += 'triclinic '
                input_line += '%f %f %f 60.0 60.0 60.0\n' % (float(
                    self.a), float(self.a), float(self.a))
        else:
            print(self.boundary_condition + ' is not recognizable.')
            sys.exit(1)
        if (self.nion > 0 or self._should_neutralize or
                self._add_alchemical_ions):
            input_line += '  positive_ion_desmond_oplsaa_typer {\n'
            input_line += '    input_file_name "%s"\n' % self.positive_ion.strip(
                '"')
            input_line += '    run\n'
            input_line += '  }\n'
            input_line += '  negative_ion_desmond_oplsaa_typer {\n'
            input_line += '    input_file_name "%s"\n' % self.negative_ion.strip(
                '"')
            input_line += '    run\n'
            input_line += '  }\n'
        if self._should_neutralize:
            input_line += '  neutralize\n'
        elif self.nion:
            input_line += '  add_ion %s %d\n' % (self.ion_type, self.nion)
        if self._add_alchemical_ions:
            if self._use_alchemical_water:
                input_line += '  use_alchemical_water Yes\n'
            input_line += '  add_alchemical_ions\n'
        if len(self._exclude_location) > 0:
            input_line += '  exclude_ion_from { '
            for a in self._exclude_location:
                input_line += str(a) + ' '
            input_line += '} '
            input_line += str(self._exclude_distance) + '\n'
        if len(self._ion_location) > 0:
            input_line += '  ion_location {\n'
            for a in self._ion_location:
                input_line += '    { '
                for b in a:
                    input_line += str(b) + ' '
                input_line += '}\n'
            input_line += '  }\n'
        if self.salt_concentration > 0.0:
            input_line += '  salt_positive_ion_desmond_oplsaa_typer {\n'
            input_line += '    input_file_name "%s"\n' % self.salt_positive_ion.strip(
                '"')
            input_line += '    run\n'
            input_line += '  }\n'
            input_line += '  salt_negative_ion_desmond_oplsaa_typer {\n'
            input_line += '    input_file_name "%s"\n' % self.salt_negative_ion.strip(
                '"')
            input_line += '    run\n'
            input_line += '  }\n'
            input_line += '  add_salt %f\n' % self.salt_concentration
        if self._remove_overlapped_crystal_water:
            input_line += '  check_crystal_water_overlap Yes\n'
        if self._should_solvate:
            input_line += '  solvate\n'
        if (os.path.exists(name)):
            os.remove(name)
        base = name
        index = name.rfind('.csb')
        if index > 0:
            base = name[:index]
        if self.one_mae_file == '-1':
            input_line += '  write_one_mae_file %s\n' % (base + '-out.mae')
        elif len(self.one_mae_file) > 0:
            input_line += '  write_one_mae_file %s\n' % self.one_mae_file
        if self.mae_file == '-1':
            input_line += '  write_mae_file "%s"\n' % (base + '.mae').strip('"')
        elif len(self.mae_file) > 0:
            input_line += '  write_mae_file "%s"\n' % self.mae_file.strip('"')
        if self.maeff_file == '-1':
            input_line += '  write_maeff_file "%s"\n' % (base +
                                                         '-out.cms').strip('"')
        elif len(self.maeff_file) > 0:
            input_line += '  write_maeff_file "%s"\n' % self.maeff_file.strip(
                '"')
        if self.pdb_file == '-1':
            input_line += '  write_pdb_file %s\n' % (base + '.pdb')
        elif len(self.pdb_file) > 0:
            input_line += '  write_pdb_file %s\n' % self.pdb_file
        if self.xyz_file == '-1':
            input_line += '  write_xyz_file %s\n' % (base + '.xyz')
        elif len(self.xyz_file) > 0:
            input_line += '  write_xyz_file %s\n' % self.xyz_file
        if self.top_file == '-1':
            input_line += '  write_gromacs_topology %s\n' % (base + '.top')
        elif len(self.top_file) > 0:
            input_line += '  write_gromacs_topology %s\n' % self.top_file
        if self.g96_file == '-1':
            input_line += '  write_g96_file %s\n' % (base + '.g96')
        elif len(self.g96_file) > 0:
            input_line += '  write_g96_file %s\n' % self.g96_file
        input_line += '}\n'
        with open(name, 'w') as f:
            f.write(input_line)
        return self.solute_fname
[docs]    def read(self, name):
        if (not os.path.exists(name)):
            print(name + ' does not exist.')
            sys.exit(1)
        with open(name, 'r') as f:
            lines = f.readlines()
        l = ''.join(lines)
        l = re.sub(r'#.*\n', '\n', l)
        self.read_text(l)
[docs]    def read_text(self, l):
        # why using "l" here? It's very hard to search and replace
        all_words = set(l.split())
        l = l.replace('\r', '')
        a = re.findall(
            r'solvent_desmond_oplsaa_typer\s+\{\s+input_file_name\s+(.*)\n', l)
        if len(a) > 0:
            self.solvent = a[-1]
        else:
            self.solvent = None
        a = re.findall(
            r'(^|\s+)positive_ion_desmond_oplsaa_typer\s+\{\s+input_file_name\s+(.*)\n',
            l)
        if len(a) > 0:
            self.positive_ion = a[0][-1]
        a = re.findall(
            r'(^|\s+)negative_ion_desmond_oplsaa_typer\s+\{\s+input_file_name\s+(.*)\n',
            l)
        if len(a) > 0:
            self.negative_ion = a[0][-1]
        a = re.findall(
            r'salt_positive_ion_desmond_oplsaa_typer\s+\{\s+input_file_name\s+(.*)\n',
            l)
        if len(a) > 0:
            self.salt_positive_ion = a[-1]
        a = re.findall(
            r'salt_negative_ion_desmond_oplsaa_typer\s+\{\s+input_file_name\s+(.*)',
            l)
        if len(a) > 0:
            self.salt_negative_ion = a[-1]
        a = re.findall(r'membranize\s+(".*?"|\S+)\s+(\S+)\s+(\S+)', l)
        if len(a) > 0:
            self._should_membranize = 1
            self.membrane = a[-1][0]
            self.x_membrane_patch = float(a[-1][1])
            self.y_membrane_patch = float(a[-1][2])
        # ensure to find whole word, not something like "haha_neutralize_"
        self._should_neutralize = int('neutralize' in all_words)
        self._add_alchemical_ions = int('add_alchemical_ions' in all_words)
        self._use_alchemical_water = int('use_alchemical_water' in all_words)
        self._remove_overlapped_crystal_water = int(
            'check_crystal_water_overlap' in
            all_words) and 'check_crystal_water_overlap Yes' in l
        # ensure to find whole word, not something like "haha_solvate_"
        self._should_solvate = int('solvate' in all_words)
        a = re.findall(r'add_ion\s+(\S+)\s+(\S+)', l)
        if len(a) > 0:
            self.addIons(a[-1][0], int(a[-1][1]))
        a = re.findall(r'read_solute_structure\s+(.*)\n', l)
        if len(a) > 0:
            self.solute_fname = a[-1]
        a = re.findall(r'add_salt\s+(\S+)', l)
        if len(a) > 0:
            self.addSalt(float(a[0]))
        a = re.findall(r'exclude_ion_from\s+\{(.*)\}\s+(\S+)', l)
        if len(a) > 0:
            self._exclude_location = a[-1][0].split()
            self._exclude_distance = float(a[-1][1])
        a = re.findall(r'ion_location\s+\{\s*(\{.*\})\s*\}', l, re.DOTALL)
        if len(a) > 0:
            m = a[0]
            a = re.findall(r'\{\s*(.*?)\s*\}', m, re.DOTALL)
            self._ion_location = []
            for b in a:
                self._ion_location.append(b.split())
        a = re.findall(r'align_principal_axes_with_xyz\s+(\S+)', l)
        if len(a) > 0:
            self.solute_alignment_type = 'xyz'
            self.solute_alignment_value = 1
            if str(a[-1]).capitalize() == "NO":
                self.solute_alignment_value = 0
        a = re.findall(r'rezero_to_center_of_mass\s+(\S+)', l)
        if len(a) > 0:
            self.solute_alignment_type = 'rezero'
            self.solute_alignment_value = 1
            if str(a[-1]).upper() == "NO":
                self.solute_alignment_value = 0
        a = re.findall(r'set_oplsaa_version_as\s+(\S+)', l)
        if len(a) > 0:
            self.oplsaa_version = a[-1]
        a = re.findall(r'vdw_scaling_factor\s+(\S+)', l)
        if len(a) > 0:
            self.vdw_scaling_factor = float(a[-1])
        a = re.findall(r'mmfepio_map_mode_option\s+(\S+)', l)
        if len(a) > 0:
            self.mmfepio_map_mode_option = int(a[-1])
        a = re.findall(r'mmfepio_retain_angle_option\s+(\S+)', l)
        if len(a) > 0:
            self.mmfepio_retain_angle_option = int(a[-1])
        a = re.findall(r'write_mae_file\s+(\S+)', l)
        if len(a) > 0:
            self.mae_file = a[-1]
        a = re.findall(r'write_maeff_file\s+(.*)\n', l)
        if len(a) > 0:
            self.maeff_file = a[-1]
        a = re.findall(r'write_pdb_file\s+(\S+)', l)
        if len(a) > 0:
            self.pdb_file = a[-1]
        a = re.findall(r'write_xyz_file\s+(\S+)', l)
        if len(a) > 0:
            self.xyz_file = a[-1]
        a = re.findall(r'write_gromacs_topology\s+(\S+)', l)
        if len(a) > 0:
            self.top_file = a[-1]
        a = re.findall(r'write_g96_file\s+(\S+)', l)
        if len(a) > 0:
            self.g96_file = a[-1]
        a = re.findall(r'(^|\s+)boundary_conditions(\s+)', l)
        if len(a) > 0:
            self.use_buffer = 0
        a = re.findall(r'create_boundary_conditions(\s+)', l)
        if len(a) > 0:
            self.use_buffer = 1
        a = re.findall(r'boundary_conditions\s+cubic\s+(\S+)', l)
        if len(a) > 0:
            self.boundary_condition = 'cubic'
            self.a = a[0]
        a = re.findall(r'boundary_conditions\s+orthorhombic\s+(.*)', l)
        if len(a) > 0:
            a = a[0].split()
            self.boundary_condition = 'orthorhombic'
            self.a = float(a[0])
            self.b = float(a[1])
            self.c = float(a[2])
        a = re.findall(r'boundary_conditions\s+triclinic\s+(.*)', l)
        if len(a) > 0:
            a = a[0].split()
            self.boundary_condition = 'triclinic'
            self.a = float(a[0])
            self.b = float(a[1])
            self.c = float(a[2])
            self.alpha = float(a[3])
            self.beta = float(a[4])
            self.gamma = float(a[5])
        a = re.findall(r'boundary_conditions\s+truncated_octahedron\s+(.*)', l)
        if len(a) > 0:
            a = a[0].split()
            self.boundary_condition = 'truncated_octahedron'
            self.a = float(a[0])
            self.alpha = float(a[1])
            self.beta = float(a[2])
            self.gamma = float(a[3])
        a = re.findall(r'boundary_conditions\s+dodecahedron_square\s+(.*)', l)
        if len(a) > 0:
            a = a[0].split()
            self.boundary_condition = 'dodecahedron_square'
            self.a = float(a[0])
            self.alpha = float(a[1])
            self.beta = float(a[2])
            self.gamma = float(a[3])
        a = re.findall(r'boundary_conditions\s+dodecahedron_hexagon\s+(.*)', l)
        if len(a) > 0:
            a = a[0].split()
            self.boundary_condition = 'dodecahedron_hexagon'
            self.a = float(a[0])
            self.alpha = float(a[1])
            self.beta = float(a[2])
            self.gamma = float(a[3])
[docs]    @staticmethod
    def identifySolventAtoms(st, asl=None):
        return evaluate_asl(st, asl) if asl \
            else smarts.evaluate_net_smarts(st, water_smarts, zob_water_smarts)
[docs]    def extractSolventFromSt(self, st, asl=''):
        water_st = None
        water_atoms = self.identifySolventAtoms(st, asl)
        if len(water_atoms) == 0 or len(water_atoms) == st.atom_total:
            return None
        water_st = st.extract(water_atoms)
        renumber_map = st.deleteAtoms(water_atoms, renumber_map=True)
        if self._exclude_location:
            # The atom index may change after exracting waters. Update the
            # `exclude_location` after the atoms are deleted. DESMOND-10210
            self._exclude_location = [
                renumber_map[i] for i in self._exclude_location
            ]
        water_st.property[CT_TYPE] = CT_TYPE.VAL.CRYSTAL_WATER
        water_st.property[NUM_COMPONENT] = 1
        new_st = water_st.copy()
        reorder = [0]
        for m in water_st.molecule:
            for i in m.getAtomIndices():
                reorder.append(i)
        mm.mmct_ct_reorder(new_st, water_st, reorder)
        return new_st
[docs]    def deleteSolventFromSt(self, st, asl=''):
        water_atoms = self.identifySolventAtoms(st, asl)
        nwater = len(water_atoms)
        if nwater > 0 and (nwater != st.atom_total):
            st.deleteAtoms(water_atoms)
[docs]    def treatSolventFromSolute(self, op='separate', asl=''):
        if op not in set(['separate', 'delete']):
            print('Operation, %s, is not defined.' % op)
            sys.exit(1)
        crystal_water_st = None
        for st in self.solute_st:
            temp_st = self.extractSolventFromSt(st, asl)
            if temp_st:
                if crystal_water_st:
                    crystal_water_st.merge(temp_st)
                else:
                    crystal_water_st = temp_st
        if crystal_water_st and op == 'separate':
            self.solute_st.append(crystal_water_st)
[docs]    def run(self, name='desmond_setup', options=[]):  # noqa: M511
        input_file_name = name + '.csb'
        self.write(input_file_name)
        sb_cmd = os.path.join(os.environ["SCHRODINGER"], "utilities",
                              "system_builder")
        if (not os.path.exists(sb_cmd)):
            print('%s does not exist.' % sb_cmd)
            sys.exit(1)
        if (os.path.expandvars("$PYTHONHOME") != "$PYTHONHOME"):
            del (os.environ['PYTHONHOME'])
        cmd = [
            sb_cmd,
            input_file_name,
        ]
        cmd.extend(options)
        job_log = "Starting system builder"
        job_log += "\n"
        job_log += "Job name: " + name
        job_log += "\n"
        print(job_log)
        job_obj = jobcontrol.launch_job(cmd)
        job_id = job_obj.job_id.strip()
        job_log = "Job ID: " + job_id
        job_log += "\n"
        print(job_log)
if __name__ == "__main__":
    a = SystemBuilderInput()
    a.setSolute('/zone1/kim/chorus/membrane/1cyo.mae')
    a.treatSolventFromSolute()
    a.run('babo')
    a.read('babo.csb')
    a.setSoluteAlignment('xyz')
    a.setNeutralize(1)
    a.setBoundaryCondition(use_buffer=1,
                           boundary_condition='triclinic',
                           a=10.0,
                           b=10.0,
                           c=10.0,
                           alpha=90.0,
                           beta=90.0,
                           gamma=90.0)
    a.setSolvent('tip4p.box.mae')
    a.run('babo2')