def writePDB(protein, file=None, filename=None, include_hydrogens=False, options=None): """ Write the residue to the new pdbfile """ if file == None: # opening file if not given if filename == None: filename = "%s.pdb" % (protein.name) file = open(filename, 'w') info("writing pdbfile %s" % (filename)) close_file = True else: # don't close the file, it was opened in a different place close_file = False numb = 0 for chain in protein.chains: for residue in chain.residues: if residue.resName not in ["N+ ", "C- "]: for atom in residue.atoms: if include_hydrogens == False and atom.name[0] == "H": """ don't print """ else: numb += 1 line = atom.makePDBLine(numb=numb) line += "\n" file.write(line) if close_file == True: file.close()
def find_non_covalently_coupled_groups(self): """Find non-covalently coupled groups.""" info('-' * 103) verbose = self.options.display_coupled_residues for name in self.conformation_names: self.conformations[name].find_non_covalently_coupled_groups( verbose=verbose)
def protonate_30_style(molecular_container): for name in molecular_container.conformation_names: info('Now protonating', name) # split atom into residues curres = -1000000 residue = [] O = None C = None for atom in molecular_container.conformations[name].atoms: if atom.resNumb != curres: curres = atom.resNumb if len(residue) > 0: #backbone [O, C] = addBackBoneHydrogen(residue, O, C) #arginine if residue[0].resName == 'ARG': addArgHydrogen(residue) #histidine if residue[0].resName == 'HIS': addHisHydrogen(residue) #tryptophan if residue[0].resName == 'TRP': addTrpHydrogen(residue) #amides if residue[0].resName in ['GLN', 'ASN']: addAmdHydrogen(residue) residue = [] if atom.type == 'atom': residue.append(atom) return
def addAmdHydrogen(residue): """ Adds Gln & Asn hydrogen atoms to residues according to the 'old way'. """ C = None O = None N = None for atom in residue: if (atom.resName == "GLN" and atom.name == "CD") or (atom.resName == "ASN" and atom.name == "CG"): C = atom elif (atom.resName == "GLN" and atom.name == "OE1") or (atom.resName == "ASN" and atom.name == "OD1"): O = atom elif (atom.resName == "GLN" and atom.name == "NE2") or (atom.resName == "ASN" and atom.name == "ND2"): N = atom if C == None or O == None or N == None: str = "Did not find N, C and/or O in %s%4d - in %s" % ( atom.resName, atom.resNumb, "addAmdHydrogen()") info(str) sys.exit(0) H1 = protonateDirection([N, O, C]) H1.name = "HN1" H2 = protonateAverageDirection([N, C, O]) H2.name = "HN2" return
def get_backbone_hydrogen_bond_parameters(self, backbone_atom, atom): if atom.type == 'atom': # this is a backbone-protein interaction if backbone_atom.group_type == 'BBC' and\ atom.group_type in self.parameters.backbone_CO_hydrogen_bond.keys(): [v, c1, c2 ] = self.parameters.backbone_CO_hydrogen_bond[atom.group_type] return [v, [c1, c2]] if backbone_atom.group_type == 'BBN' and\ atom.group_type in self.parameters.backbone_NH_hydrogen_bond.keys(): [v, c1, c2 ] = self.parameters.backbone_NH_hydrogen_bond[atom.group_type] return [v, [c1, c2]] else: # this is a backbone-ligand interaction # make sure that we are using the heavy atoms for finding paramters elements = [] for a in [backbone_atom, atom]: if a.element == 'H': elements.append(a.bonded_atoms[0].element) else: elements.append(a.element) res = self.parameters.hydrogen_bonds.get_value( elements[0], elements[1]) if not res: info( 'Could not determine backbone interaction parameters for:', backbone_atom, atom) return return None
def find_non_covalently_coupled_groups(self): info('-' * 103) for name in self.conformation_names: self.conformations[name].find_non_covalently_coupled_groups( verbose=self.options.display_coupled_residues) return
def writePDB(protein, file=None, filename=None, include_hydrogens=False, options=None): """ Write the residue to the new pdbfile """ if file == None: # opening file if not given if filename == None: filename = "%s.pdb" % (protein.name) file = open(filename, "w") info("writing pdbfile %s" % (filename)) close_file = True else: # don't close the file, it was opened in a different place close_file = False numb = 0 for chain in protein.chains: for residue in chain.residues: if residue.resName not in ["N+ ", "C- "]: for atom in residue.atoms: if include_hydrogens == False and atom.name[0] == "H": """ don't print """ else: numb += 1 line = atom.makePDBLine(numb=numb) line += "\n" file.write(line) if close_file == True: file.close()
def addAmdHydrogen(residue): """ Adds Gln & Asn hydrogen atoms to residues according to the 'old way'. """ C = None O = None N = None for atom in residue: if (atom.resName == "GLN" and atom.name == "CD") or (atom.resName == "ASN" and atom.name == "CG"): C = atom elif (atom.resName == "GLN" and atom.name == "OE1") or (atom.resName == "ASN" and atom.name == "OD1"): O = atom elif (atom.resName == "GLN" and atom.name == "NE2") or (atom.resName == "ASN" and atom.name == "ND2"): N = atom if C == None or O == None or N == None: str = "Did not find N, C and/or O in %s%4d - in %s" % (atom.resName, atom.resNumb, "addAmdHydrogen()") info(str) sys.exit(0) H1 = protonateDirection([N, O, C]) H1.name = "HN1" H2 = protonateAverageDirection([N, C, O]) H2.name = "HN2" return
def get_backbone_hydrogen_bond_parameters(self, backbone_atom, atom): if atom.type == 'atom': # this is a backbone-protein interaction if backbone_atom.group_type == 'BBC' and\ atom.group_type in self.parameters.backbone_CO_hydrogen_bond.keys(): [v,c1,c2] = self.parameters.backbone_CO_hydrogen_bond[atom.group_type] return [v,[c1,c2]] if backbone_atom.group_type == 'BBN' and\ atom.group_type in self.parameters.backbone_NH_hydrogen_bond.keys(): [v,c1,c2] = self.parameters.backbone_NH_hydrogen_bond[atom.group_type] return [v,[c1,c2]] else: # this is a backbone-ligand interaction # make sure that we are using the heavy atoms for finding paramters elements = [] for a in [backbone_atom, atom]: if a.element == 'H': elements.append(a.bonded_atoms[0].element) else: elements.append(a.element) res = self.parameters.hydrogen_bonds.get_value(elements[0], elements[1]) if not res: info('Could not determine backbone interaction parameters for:', backbone_atom, atom) return return None
def protonate_30_style(molecular_container): for name in molecular_container.conformation_names: info('Now protonating', name) # split atom into residues curres = -1000000 residue = [] O=None C=None for atom in molecular_container.conformations[name].atoms: if atom.resNumb != curres: curres = atom.resNumb if len(residue)>0: #backbone [O, C]= addBackBoneHydrogen(residue,O,C) #arginine if residue[0].resName == 'ARG': addArgHydrogen(residue) #histidine if residue[0].resName == 'HIS': addHisHydrogen(residue) #tryptophan if residue[0].resName == 'TRP': addTrpHydrogen(residue) #amides if residue[0].resName in ['GLN','ASN']: addAmdHydrogen(residue) residue = [] if atom.type=='atom': residue.append(atom) return
def find_covalently_coupled_groups(self): """ Finds covalently coupled groups and sets common charge centres if needed """ for group in self.get_titratable_groups(): # Find covalently bonded groups bonded_groups = self.find_bonded_titratable_groups(group.atom, 1, group.atom) # couple groups for cg in bonded_groups: if cg in group.covalently_coupled_groups: continue if cg.atom.sybyl_type == group.atom.sybyl_type: group.couple_covalently(cg) # check if we should set a common charge centre as well if self.parameters.common_charge_centre: self.set_common_charge_centres() # print coupling map map = propka.output.make_interaction_map('Covalent coupling map for %s'%self, #self.get_titratable_groups(), self.get_covalently_coupled_groups(), lambda g1,g2: g1 in g2.covalently_coupled_groups) info(map) return
def calculate_pka(self, version, options): """Calculate pKas for conformation container. Args: version: version object options: option object """ info('\nCalculating pKas for', self) # calculate desolvation for group in self.get_titratable_groups() + self.get_ions(): version.calculate_desolvation(group) # calculate backbone interactions set_backbone_determinants( self.get_titratable_groups(), self.get_backbone_groups(), version) # setting ion determinants set_ion_determinants(self, version) # calculating the back-bone reorganization/desolvation term version.calculate_backbone_reorganization(self) # setting remaining non-iterative and iterative side-chain & Coulomb # interaction determinants set_determinants( self.get_sidechain_groups(), version=version, options=options) # calculating the total pKa values for group in self.groups: group.calculate_total_pka() # take coupling effects into account penalised_labels = self.coupling_effects() if (self.parameters.remove_penalised_group and len(penalised_labels) > 0): info('Removing penalised groups!!!') for group in self.get_titratable_groups(): group.remove_determinants(penalised_labels) # re-calculating the total pKa values for group in self.groups: group.calculate_total_pka()
def printTmProfile(protein, reference="neutral", window=[0., 14., 1.], Tm=[0., 0.], Tms=None, ref=None, verbose=False, options=None): """ prints Tm profile """ profile = protein.getTmProfile(reference=reference, grid=[0., 14., 0.1], Tms=Tms, ref=ref, options=options) if profile == None: str = "Could not determine Tm-profile\n" else: str = " suggested Tm-profile for %s\n" % (protein.name) for (pH, Tm) in profile: if pH >= window[0] and pH <= window[1] and ( pH % window[2] < 0.01 or pH % window[2] > 0.99 * window[2]): str += "%6.2lf%10.2lf\n" % (pH, Tm) info(str)
def protonate_30_style(molecular_container): """Protonate the molecule. Args: molecular_container: molecule """ for name in molecular_container.conformation_names: info('Now protonating', name) # split atom into residues curres = -1000000 residue = [] o_atom = None c_atom = None for atom in molecular_container.conformations[name].atoms: if atom.res_num != curres: curres = atom.res_num if len(residue) > 0: #backbone [o_atom, c_atom] = add_backbone_hydrogen(residue, o_atom, c_atom) #arginine if residue[0].res_name == 'ARG': add_arg_hydrogen(residue) #histidine if residue[0].res_name == 'HIS': add_his_hydrogen(residue) #tryptophan if residue[0].res_name == 'TRP': add_trp_hydrogen(residue) #amides if residue[0].res_name in ['GLN', 'ASN']: add_amd_hydrogen(residue) residue = [] if atom.type == 'atom': residue.append(atom)
def print_interactions_latex(self): """Print interactions in LaTeX.""" # TODO - are these the same lists as above? Convert to module constants. agroups = [ 'COO', 'HIS', 'CYS', 'TYR', 'SER', 'N+', 'LYS', 'AMD', 'ARG', 'TRP', 'ROH', 'CG', 'C2N', 'N30', 'N31', 'N32', 'N33', 'NAR', 'OCO', 'NP1', 'OH', 'O3', 'CL', 'F', 'NAM', 'N1', 'O2', 'OP', 'SH' ] lines = [ "", "\\begin{{longtable}}{{{0:s}}}".format('l' * len(agroups)), ("\\caption{{Ligand interaction parameters. For interactions not " "listed, the default value of {0:s} is applied.}}").format( str(self.sidechain_cutoffs.default)), "\\label{{tab:ligand_interaction_parameters}}\\\\", "\\toprule", "Group1 & Group2 & Interaction & c1 &c2 \\\\", "\\midrule", "\\endfirsthead", "", "\\multicolumn{{5}}{{l}}{\\emph{{continued from the previous page}}}\\\\", "\\toprule", "Group1 & Group2 & Interaction & c1 &c2 \\\\", "\\midrule", "\\endhead", "", "\\midrule", "\\multicolumn{{5}}{{r}}{\\emph{{continued on the next page}}}\\\\", "\\endfoot", "", "\\bottomrule", "\\endlastfoot", "" ] str_ = "\n".join(lines) for group1 in agroups: for group2 in agroups: fmt = '{g1:>3s} & {g2:>3s} & {mat:1s} & {val1:>4s} & {val2:>4s}\\\\ \n' str_ += fmt.format( group1, group2, self.interaction_matrix[group1][group2], str(self.sidechain_cutoffs.get_value(group1, group2)[0]), str(self.sidechain_cutoffs.get_value(group1, group2)[1])) if group1 == group2: break str_ += ' \\end{{longtable}}\n' info(str_)
def print_tm_profile(protein, reference="neutral", window=[0., 14., 1.], __=[0., 0.], tms=None, ref=None, _=False, options=None): """Print Tm profile. I think Tm refers to the denaturation temperature. Args: protein: protein object reference: reference state window: pH window [min, max, step] __: temperature range [min, max] tms: TODO - figure this out ref: TODO - figure this out (probably reference state?) _: Boolean for verbosity options: options object """ profile = protein.getTmProfile( reference=reference, grid=[0., 14., 0.1], tms=tms, ref=ref, options=options) if profile is None: str_ = "Could not determine Tm-profile\n" else: str_ = " suggested Tm-profile for {0:s}\n".format(protein.name) for (ph, tm_) in profile: if (ph >= window[0] and ph <= window[1] and (ph % window[2] < 0.01 or ph % window[2] > 0.99*window[2])): str_ += "{0:>6.2f}{1:>10.2f}\n".format(ph, tm_) info(str_)
def printHeader(): """ prints the header section """ str = "%s\n" % (getPropkaHeader()) str += "%s\n" % (getReferencesHeader()) str += "%s\n" % (getWarningHeader()) info(str)
def print_out_swaps(self, conformation, verbose=True): map = propka.output.make_interaction_map('Non-covalent coupling map for %s'%conformation, conformation.get_non_covalently_coupled_groups(), lambda g1,g2: g1 in g2.non_covalently_coupled_groups) info(map) for system in conformation.get_coupled_systems(conformation.get_non_covalently_coupled_groups(),propka.group.Group.get_non_covalently_coupled_groups): self.print_system(conformation, list(system)) return
def printPKASection(protein, conformation, parameters): """ prints out the pka-section of the result """ # geting the determinants section str = getDeterminantSection(protein, conformation, parameters) info(str) str = getSummarySection(protein, conformation, parameters) info(str)
def find_in_path(self, program): path = os.environ.get('PATH').split(os.pathsep) l = [i for i in filter(lambda loc: os.access(loc, os.F_OK), map(lambda dir: os.path.join(dir, program),path))] if len(l) == 0: info('Error: Could not find %s. Please make sure that it is found in the path.' % program) sys.exit(-1) return l[0]
def additional_setup_when_reading_input_file(self): """Generate interaction map and charge centers.""" # if a group is coupled and we are reading a .propka_input file, then # some more configuration might be needed map_ = make_interaction_map( 'Covalent coupling map for {0:s}'.format(str(self)), self.get_covalently_coupled_groups(), lambda g1, g2: g1 in g2.covalently_coupled_groups) info(map_) # check if we should set a common charge centre as well if self.parameters.common_charge_centre: self.set_common_charge_centres()
def print_pka_section(protein, conformation, parameters): """Prints out pKa section of results. Args: protein: protein object conformation: specific conformation parameters: parameters """ # geting the determinants section str_ = get_determinant_section(protein, conformation, parameters) info(str_) str_ = get_summary_section(protein, conformation, parameters) info(str_)
def identify_non_covalently_coupled_groups(self, conformation, verbose=True): """Find coupled residues in protein. Args: conformation: protein conformation to test verbose: verbose output (boolean) """ self.parameters = conformation.parameters if verbose: info_fmt = ( '\n' ' Warning: When using the -d option, pKa values based on \n' '\'swapped\' interactions\n' ' will be writting to the output .pka file\n' '\n' '{sep}\n' '\n' ' Detecting non-covalently coupled residues\n' '{sep}\n' ' Maximum pKa difference: {c.max_intrinsic_pka_diff:>4.2f} pKa units\n' ' Minimum interaction energy: {c.min_interaction_energy:>4.2f} pKa units\n' ' Maximum free energy diff.: {c.max_free_energy_diff:>4.2f} pKa units\n' ' Minimum swap pKa shift: {c.min_swap_pka_shift:>4.2f} pKa units\n' ' pH: {c.pH:>6} \n' ' Reference: {c.reference}\n' ' Min pKa: {c.min_pka:>4.2f}\n' ' Max pKa: {c.max_pka:>4.2f}\n' '\n') sep = "-" * 103 info(info_fmt.format(sep=sep, c=self)) # find coupled residues titratable_groups = conformation.get_titratable_groups() if not conformation.non_covalently_coupled_groups: for group1 in titratable_groups: for group2 in titratable_groups: if group1 == group2: break if (group1 not in group2.non_covalently_coupled_groups and self.do_prot_stat): data = ( self .is_coupled_protonation_state_probability( group1, group2, conformation.calculate_folding_energy)) if data['coupling_factor'] > 0.0: group1.couple_non_covalently(group2) if verbose: self.print_out_swaps(conformation)
def writePKA( protein, parameters, filename=None, conformation="1A", reference="neutral", direction="folding", verbose=False, options=None, ): """ Write the pka-file based on the given protein """ verbose = True if filename == None: filename = "%s.pka" % (protein.name) file = open(filename, "w") if verbose == True: info("Writing %s" % (filename)) # writing propka header str = "%s\n" % (getPropkaHeader()) str += "%s\n" % (getReferencesHeader()) str += "%s\n" % (getWarningHeader()) # writing pKa determinant section str += getDeterminantSection(protein, conformation, parameters) # writing pKa summary section str += getSummarySection(protein, conformation, parameters) str += "%s\n" % (getTheLine()) # printing Folding Profile str += getFoldingProfileSection( protein, conformation=conformation, reference=reference, direction=direction, window=[0.0, 14.0, 1.0], options=options, ) # printing Protein Charge Profile str += getChargeProfileSection(protein, conformation=conformation) # now, writing the pka text to file file.write(str) file.close()
def print_interactions_latex(self): agroups = [ 'COO', 'HIS', 'CYS', 'TYR', 'SER', 'N+', 'LYS', 'AMD', 'ARG', 'TRP', 'ROH', 'CG', 'C2N', 'N30', 'N31', 'N32', 'N33', 'NAR', 'OCO', 'NP1', 'OH', 'O3', 'CL', 'F', 'NAM', 'N1', 'O2', 'OP', 'SH' ] lgroups = [ 'CG', 'C2N', 'N30', 'N31', 'N32', 'N33', 'NAR', 'OCO', 'NP1', 'OH', 'O3', 'CL', 'F', 'NAM', 'N1', 'O2', 'OP', 'SH' ] s = """ \\begin{longtable}{%s} \\caption{Ligand interaction parameters. For interactions not listed, the default value of %s is applied.} \\label{tab:ligand_interaction_parameters}\\\\ \\toprule Group1 & Group2 & Interaction & c1 &c2 \\\\ \\midrule \\endfirsthead \\multicolumn{5}{l}{\\emph{continued from the previous page}}\\\\ \\toprule Group1 & Group2 & Interaction & c1 &c2 \\\\ \\midrule \\endhead \\midrule \\multicolumn{5}{r}{\\emph{continued on the next page}}\\\\ \\endfoot \\bottomrule \\endlastfoot """ % ('l' * len(agroups), self.sidechain_cutoffs.default) for g1 in agroups: for g2 in agroups: s += '%3s & %3s & %1s & %4s & %4s\\\\ \n' % ( g1, g2, self.interaction_matrix[g1][g2], self.sidechain_cutoffs.get_value(g1, g2)[0], self.sidechain_cutoffs.get_value(g1, g2)[1]) if g1 == g2: break s += ' \\end{longtable}\n' info(s) return
def print_out_swaps(self, conformation): """Print out something having to do with coupling interactions. Args: conformation: conformation to print """ map_ = make_interaction_map( 'Non-covalent coupling map for {0:s}'.format(str(conformation)), conformation.get_non_covalently_coupled_groups(), lambda g1, g2: g1 in g2.non_covalently_coupled_groups) info(map_) for system in conformation.get_coupled_systems( conformation.get_non_covalently_coupled_groups(), Group.get_non_covalently_coupled_groups): self.print_system(conformation, list(system))
def find_in_path(self, program): path = os.environ.get('PATH').split(os.pathsep) l = [ i for i in filter(lambda loc: os.access(loc, os.F_OK), map(lambda dir: os.path.join(dir, program), path)) ] if len(l) == 0: info( 'Error: Could not find %s. Please make sure that it is found in the path.' % program) sys.exit(-1) return l[0]
def __mul__(self, other): """Dot product, scalar and matrix multiplication.""" if isinstance(other, Vector): return self.x * other.x + self.y * other.y + self.z * other.z elif isinstance(other, Matrix4x4): return Vector(xi=other.a11 * self.x + other.a12 * self.y + other.a13 * self.z + other.a14 * 1.0, yi=other.a21 * self.x + other.a22 * self.y + other.a23 * self.z + other.a24 * 1.0, zi=other.a31 * self.x + other.a32 * self.y + other.a33 * self.z + other.a34 * 1.0) elif type(other) in [int, float]: return Vector(self.x * other, self.y * other, self.z * other) else: info('{0:s} not supported'.format(type(other))) raise TypeError
def __mul__(self, other): """ Dot product, scalar and matrix multiplication """ if isinstance(other,vector): return self.x * other.x + self.y * other.y + self.z * other.z elif isinstance(other, matrix4x4): return vector( xi = other.a11*self.x + other.a12*self.y + other.a13*self.z + other.a14*1.0, yi = other.a21*self.x + other.a22*self.y + other.a23*self.z + other.a24*1.0, zi = other.a31*self.x + other.a32*self.y + other.a33*self.z + other.a34*1.0 ) elif type(other) in [int, float]: return vector(self.x * other, self.y * other, self.z * other) else: info('%s not supported' % type(other)) raise TypeError
def additional_setup_when_reading_input_file(self): # if a group is coupled and we are reading a .propka_input file, # some more configuration might be needed # print coupling map map = propka.output.make_interaction_map('Covalent coupling map for %s'%self, self.get_covalently_coupled_groups(), lambda g1,g2: g1 in g2.covalently_coupled_groups) info(map) # check if we should set a common charge centre as well if self.parameters.common_charge_centre: self.set_common_charge_centres() return
def write_pka(protein, parameters, filename=None, conformation='1A', reference="neutral", _="folding", verbose=False, __=None): """Write the pKa-file based on the given protein. Args: protein: protein object filename: output file name conformation: TODO - figure this out reference: reference state _: "folding" or other verbose: Boolean flag for verbosity __: options object """ # TODO - the code immediately overrides the verbose argument; why? verbose = True if filename is None: filename = "{0:s}.pka".format(protein.name) # TODO - this would be much better with a context manager file_ = open(filename, 'w') if verbose: info("Writing {0:s}".format(filename)) # writing propka header str_ = "{0:s}\n".format(get_propka_header()) str_ += "{0:s}\n".format(get_references_header()) str_ += "{0:s}\n".format(get_warning_header()) # writing pKa determinant section str_ += get_determinant_section(protein, conformation, parameters) # writing pKa summary section str_ += get_summary_section(protein, conformation, parameters) str_ += "{0:s}\n".format(get_the_line()) # printing Folding Profile str_ += get_folding_profile_section(protein, conformation=conformation, reference=reference, window=[0., 14., 1.0]) # printing Protein Charge Profile str_ += get_charge_profile_section(protein, conformation=conformation) # now, writing the pka text to file file_.write(str_) file_.close()
def writePKA(protein, parameters, filename=None, conformation='1A', reference="neutral", direction="folding", verbose=False, options=None): """ Write the pka-file based on the given protein """ verbose = True if filename == None: filename = "%s.pka" % (protein.name) file = open(filename, 'w') if verbose == True: info("Writing %s" % (filename)) # writing propka header str = "%s\n" % (getPropkaHeader()) str += "%s\n" % (getReferencesHeader()) str += "%s\n" % (getWarningHeader()) # writing pKa determinant section str += getDeterminantSection(protein, conformation, parameters) # writing pKa summary section str += getSummarySection(protein, conformation, parameters) str += "%s\n" % (getTheLine()) # printing Folding Profile str += getFoldingProfileSection(protein, conformation=conformation, reference=reference, direction=direction, window=[0., 14., 1.0], options=options) # printing Protein Charge Profile str += getChargeProfileSection(protein, conformation=conformation) # now, writing the pka text to file file.write(str) file.close()
def print_interaction_parameters_latex(self): """Print interaction parameters in LaTeX format.""" # TODO - if these lists and dictionaries are the same as above, then # should be constants at the level of the module agroups = [ 'COO', 'HIS', 'CYS', 'TYR', 'SER', 'N+', 'LYS', 'AMD', 'ARG', 'TRP', 'ROH', 'CG', 'C2N', 'N30', 'N31', 'N32', 'N33', 'NAR', 'OCO', 'NP1', 'OH', 'O3', 'CL', 'F', 'NAM', 'N1', 'O2', 'OP', 'SH' ] lgroups = [ 'CG', 'C2N', 'N30', 'N31', 'N32', 'N33', 'NAR', 'OCO', 'NP1', 'OH', 'O3', 'CL', 'F', 'NAM', 'N1', 'O2', 'OP', 'SH' ] lines = [ "", "\\begin{{longtable}}{{lllll}}", ("\\caption{{Ligand interaction parameters. For interactions not " "listed, the default value of {0:s} is applied.}}").format( self.sidechain_cutoffs.default), "\\label{{tab:ligand_interaction_parameters}}\\\\", "\\toprule", "Group1 & Group2 & Interaction & c1 &c2 \\\\", "\\midrule", "\\endfirsthead", "", "\\multicolumn{{5}}{{l}}{\\emph{{continued from the previous page}}}\\\\", "\\toprule", "Group1 & Group2 & Interaction & c1 &c2 \\\\", "\\midrule", "\\endhead", "", "\\midrule", "\\multicolumn{{5}}{{r}}{\\emph{{continued on the next page}}}\\\\", "\\endfoot", "", "\\bottomrule", "\\endlastfoot", "" ] str_ = "\n".join(lines) for group1 in agroups: for group2 in lgroups: if self.interaction_matrix[group1][group2] == '-': continue if (self.sidechain_cutoffs.get_value( group1, group2) == self.sidechain_cutoffs.default): continue fmt = ("{grp1:>3s} & {grp2:>3s} & {mat:1s} & {val1:4} & " "{val2:4}\\\\ \n") str_ += fmt.format( group1, group2, self.interaction_matrix[group1][group2], self.sidechain_cutoffs.get_value(group1, group2)[0], self.sidechain_cutoffs.get_value(group1, group2)[1]) if group1 == group2: break str_ += ' \\end{{longtable}}\n' info(str_)
def find_in_path(program): """Find a program in the system path. Args: program: program to find Returns: location of program """ path = os.environ.get('PATH').split(os.pathsep) locs = [ i for i in filter(lambda loc: os.access(loc, os.F_OK), map(lambda dir: os.path.join(dir, program), path))] if len(locs) == 0: str_ = "'Error: Could not find {0:s}.".format(program) str_ += ' Please make sure that it is found in the path.' info(str_) sys.exit(-1) return locs[0]
def __init__(self, atom): Group.__init__(self, atom) # set the charge and determine type (acid or base) self.charge = atom.charge if self.charge < 0: self.type = 'ALG' self.residue_type = 'ALG' elif self.charge > 0: self.type = 'BLG' self.residue_type = 'BLG' else: raise Exception('Unable to determine type of ligand group - ' 'charge not set?') # check if marvin model pka has been calculated # this is not true if we are reading an input file if atom.marvin_pka: self.model_pka = atom.marvin_pka info('Titratable ligand group ', atom, self.model_pka, self.charge) self.model_pka_set = True
def get_backbone_hydrogen_bond_parameters(self, backbone_atom, atom): """Get hydrogen bond parameters between backbone atom and other atom. Args: backbone_atom: backbone atom atom: other atom Returns [v, [c1, c3]] TODO - figure out what this is """ if atom.type == 'atom': # this is a backbone-protein interaction if (backbone_atom.group_type == 'BBC' and atom.group_type in self.parameters.backbone_CO_hydrogen_bond.keys()): [v, c1, c2] = self.parameters.backbone_CO_hydrogen_bond[ atom.group_type] return [v, [c1, c2]] if (backbone_atom.group_type == 'BBN' and atom.group_type in self.parameters.backbone_NH_hydrogen_bond.keys()): [v, c1, c2] = self.parameters.backbone_NH_hydrogen_bond[ atom.group_type] return [v, [c1, c2]] else: # this is a backbone-ligand interaction # make sure that we are using the heavy atoms for finding paramters elements = [] for atom2 in [backbone_atom, atom]: if atom2.element == 'H': elements.append(atom2.bonded_atoms[0].element) else: elements.append(atom2.element) res = self.parameters.hydrogen_bonds.get_value( elements[0], elements[1]) if not res: info( 'Could not determine backbone interaction parameters for:', backbone_atom, atom) return None return None
def find_covalently_coupled_groups(self): """Find covalently coupled groups and set common charge centres.""" for group in self.get_titratable_groups(): # Find covalently bonded groups bonded_groups = self.find_bonded_titratable_groups( group.atom, 1, group.atom) # coupled groups for bond_group in bonded_groups: if bond_group in group.covalently_coupled_groups: continue if bond_group.atom.sybyl_type == group.atom.sybyl_type: group.couple_covalently(bond_group) # check if we should set a common charge centre as well if self.parameters.common_charge_centre: self.set_common_charge_centres() # print coupling map map_ = make_interaction_map( 'Covalent coupling map for {0:s}'.format(str(self)), self.get_covalently_coupled_groups(), lambda g1, g2: g1 in g2.covalently_coupled_groups) info(map_)
def printTmProfile( protein, reference="neutral", window=[0.0, 14.0, 1.0], Tm=[0.0, 0.0], Tms=None, ref=None, verbose=False, options=None, ): """ prints Tm profile """ profile = protein.getTmProfile(reference=reference, grid=[0.0, 14.0, 0.1], Tms=Tms, ref=ref, options=options) if profile == None: str = "Could not determine Tm-profile\n" else: str = " suggested Tm-profile for %s\n" % (protein.name) for (pH, Tm) in profile: if pH >= window[0] and pH <= window[1] and (pH % window[2] < 0.01 or pH % window[2] > 0.99 * window[2]): str += "%6.2lf%10.2lf\n" % (pH, Tm) info(str)
def __init__(self, atom): Group.__init__(self, atom) # set the charge and determine type (acid or base) self.charge = atom.charge if self.charge <0: self.type = 'ALG' self.residue_type = 'ALG' elif self.charge > 0: self.type = 'BLG' self.residue_type = 'BLG' else: raise Exception('Unable to determine type of ligand group - charge not set?') # check if marvin model pka has been calculated # this is not true if we are reading an input file if atom.marvin_pka: self.model_pka = atom.marvin_pka info('Titratable ligand group ', atom, self.model_pka, self.charge) self.model_pka_set = True return
def addTrpHydrogen(residue): """ Adds Trp hydrogen atoms to residues according to the 'old way'. """ CD = None NE = None DE = None for atom in residue: if atom.name == "CD1": CD = atom elif atom.name == "NE1": NE = atom elif atom.name == "CE2": CE = atom if CD == None or NE == None or CE == None: str = "Did not find all atoms in %s%4d - in %s" % (self.resName, self.resNumb, "addTrpHydrogen()") info(str) sys.exit(0) HE = protonateSP2([CD, NE, CE]) HE.name = "HNE" return
def calculate_pka(self, version, options): info('\nCalculating pKas for', self) # calculate desolvation for group in self.get_titratable_groups()+self.get_ions(): version.calculate_desolvation(group) # calculate backbone interactions propka.determinants.setBackBoneDeterminants(self.get_titratable_groups(), self.get_backbone_groups(), version) # setting ion determinants propka.determinants.setIonDeterminants(self, version) # calculating the back-bone reorganization/desolvation term version.calculateBackBoneReorganization(self) # setting remaining non-iterative and iterative side-chain & Coulomb interaction determinants propka.determinants.setDeterminants(self.get_sidechain_groups(), version=version, options=options) # calculating the total pKa values for group in self.groups: group.calculate_total_pka() # take coupling effects into account penalised_labels = self.coupling_effects() if self.parameters.remove_penalised_group and len(penalised_labels)>0: info('Removing penalised groups!!!') for g in self.get_titratable_groups(): g.remove_determinants(penalised_labels) # re-calculating the total pKa values for group in self.groups: group.calculate_total_pka() return
def __init__(self, parameters): self.parameters = parameters # attempt to find Marvin executables in the path self.molconvert = self.find_in_path('molconvert') self.cxcalc = self.find_in_path('cxcalc') info('Found Marvin executables:') info(self.cxcalc) info(self.molconvert) return
def find_bonds_for_protein(self, protein): """ Finds bonds proteins based on the way atoms normally bond in proteins""" info('++++ Side chains ++++') # side chains for chain in protein.chains: for residue in chain.residues: if residue.resName.replace(' ','') not in ['N+','C-']: self.find_bonds_for_side_chain(residue.atoms) info('++++ Backbones ++++') # backbone last_residues = [] for chain in protein.chains: for i in range(1,len(chain.residues)): if chain.residues[i-1].resName.replace(' ','') not in ['N+','C-']: if chain.residues[i].resName.replace(' ','') not in ['N+','C-']: self.connect_backbone(chain.residues[i-1], chain.residues[i]) last_residues.append(chain.residues[i]) info('++++ terminal oxygen ++++') # terminal OXT for last_residue in last_residues: self.find_bonds_for_terminal_oxygen(last_residue) info('++++ cysteines ++++') # Cysteines for chain in protein.chains: for i in range(0,len(chain.residues)): if chain.residues[i].resName == 'CYS': for j in range(0,len(chain.residues)): if chain.residues[j].resName == 'CYS' and j != i: self.check_for_cysteine_bonds(chain.residues[i], chain.residues[j]) return
def print_system(self, conformation, system): info('System containing %d groups:' % len(system)) # make list of interactions withi this system interactions = list(itertools.combinations(system,2)) # print out coupling info for each interaction coup_info = '' for interaction in interactions: data = self.is_coupled_protonation_state_probability(interaction[0], interaction[1],conformation.calculate_folding_energy, return_on_fail=False) coup_info += self.make_data_to_string(data,interaction[0],interaction[1])+'\n\n' info(coup_info) # make list of possible combinations of swap to try out combinations = propka.lib.generate_combinations(interactions) # Make possible swap combinations swap_info = '' swap_info += self.print_determinants_section(system,'Original') for combination in combinations: # Tell the user what is swap in this combination swap_info += 'Swapping the following interactions:\n' for interaction in combination: swap_info += ' %s %s\n'%(interaction[0].label, interaction[1].label) # swap... for interaction in combination: self.swap_interactions([interaction[0]],[interaction[1]]) swap_info += self.print_determinants_section(system,'Swapped') # ...and swap back #for interaction in combination: # self.swap_interactions([interaction[0]], [interaction[1]]) info(swap_info) return
def find_covalently_coupled_groups(self): info('-' * 103) for name in self.conformation_names: self.conformations[name].find_covalently_coupled_groups() return
def find_non_covalently_coupled_groups(self): info('-' * 103) for name in self.conformation_names: self.conformations[name].find_non_covalently_coupled_groups(verbose=self.options.display_coupled_residues) return
def identify_non_covalently_coupled_groups(self, conformation, verbose=True): """ Finds coupled residues in protein """ self.parameters = conformation.parameters if verbose: info('') info(' Warning: When using the -d option, pKa values based on \'swapped\' interactions') info(' will be writting to the output .pka file') info('') info('-' * 103) info(' Detecting non-covalently coupled residues') info('-' * 103) info(' Maximum pKa difference: %4.2f pKa units' % self.parameters.max_intrinsic_pKa_diff) info(' Minimum interaction energy: %4.2f pKa units' % self.parameters.min_interaction_energy) info(' Maximum free energy diff.: %4.2f pKa units' % self.parameters.max_free_energy_diff) info(' Minimum swap pKa shift: %4.2f pKa units' % self.parameters.min_swap_pka_shift) info(' pH: %6s ' % str(self.parameters.pH)) info(' Reference: %s' % self.parameters.reference) info(' Min pKa: %4.2f' % self.parameters.min_pka) info(' Max pKa: %4.2f' % self.parameters.max_pka) info('') # find coupled residues titratable_groups = conformation.get_titratable_groups() if not conformation.non_covalently_coupled_groups: for g1 in titratable_groups: for g2 in titratable_groups: if g1==g2: break if not g1 in g2.non_covalently_coupled_groups and self.do_prot_stat: data = self.is_coupled_protonation_state_probability(g1, g2,conformation.calculate_folding_energy) if data['coupling_factor'] >0.0: g1.couple_non_covalently(g2) if verbose: self.print_out_swaps(conformation) return
def print_interactions_latex(self): agroups = [ "COO", "HIS", "CYS", "TYR", "SER", "N+", "LYS", "AMD", "ARG", "TRP", "ROH", "CG", "C2N", "N30", "N31", "N32", "N33", "NAR", "OCO", "NP1", "OH", "O3", "CL", "F", "NAM", "N1", "O2", "OP", "SH", ] lgroups = [ "CG", "C2N", "N30", "N31", "N32", "N33", "NAR", "OCO", "NP1", "OH", "O3", "CL", "F", "NAM", "N1", "O2", "OP", "SH", ] s = """ \\begin{longtable}{%s} \\caption{Ligand interaction parameters. For interactions not listed, the default value of %s is applied.} \\label{tab:ligand_interaction_parameters}\\\\ \\toprule Group1 & Group2 & Interaction & c1 &c2 \\\\ \\midrule \\endfirsthead \\multicolumn{5}{l}{\\emph{continued from the previous page}}\\\\ \\toprule Group1 & Group2 & Interaction & c1 &c2 \\\\ \\midrule \\endhead \\midrule \\multicolumn{5}{r}{\\emph{continued on the next page}}\\\\ \\endfoot \\bottomrule \\endlastfoot """ % ( "l" * len(agroups), self.sidechain_cutoffs.default, ) for g1 in agroups: for g2 in agroups: s += "%3s & %3s & %1s & %4s & %4s\\\\ \n" % ( g1, g2, self.interaction_matrix[g1][g2], self.sidechain_cutoffs.get_value(g1, g2)[0], self.sidechain_cutoffs.get_value(g1, g2)[1], ) if g1 == g2: break s += " \\end{longtable}\n" info(s) return
def __init__(self, input_file, options=None): # printing out header before parsing input propka.output.printHeader() # set up some values self.options = options self.input_file = input_file self.dir = os.path.split(input_file)[0] self.file = os.path.split(input_file)[1] self.name = self.file[0:self.file.rfind('.')] input_file_extension = input_file[input_file.rfind('.'):] # set the version if options: parameters = propka.parameters.Parameters(self.options.parameters) else: parameters = propka.parameters.Parameters('propka.cfg') try: exec('self.version = propka.version.%s(parameters)'%parameters.version) except: raise Exception('Error: Version %s does not exist'%parameters.version) # read the input file if input_file_extension[0:4] == '.pdb': # input is a pdb file # read in atoms and top up containers to make sure that all atoms are present in all conformations [self.conformations, self.conformation_names] = propka.pdb.read_pdb(input_file, self.version.parameters,self) if len(self.conformations)==0: info('Error: The pdb file does not seems to contain any molecular conformations') sys.exit(-1) self.top_up_conformations() # make a structure precheck propka.pdb.protein_precheck(self.conformations, self.conformation_names) # set up atom bonding and protonation self.version.setup_bonding_and_protonation(self) # Extract groups self.extract_groups() # sort atoms for name in self.conformation_names: self.conformations[name].sort_atoms() # find coupled groups self.find_covalently_coupled_groups() # write out the input file filename = self.file.replace(input_file_extension,'.propka_input') propka.pdb.write_input(self, filename) elif input_file_extension == '.propka_input': #input is a propka_input file [self.conformations, self.conformation_names] = propka.pdb.read_input(input_file, self.version.parameters, self) # Extract groups - this merely sets up the groups found in the input file self.extract_groups() # do some additional set up self.additional_setup_when_reading_input_file() else: info('Unrecognized input file:%s' % input_file) sys.exit(-1) return
def __init__(self, parameters): # set the calculation rutines used in this version version_A.__init__(self, parameters) info('Using simple hb model') return
if not name_j in self.protein_bonds[resi_j]: self.protein_bonds[resi_j][name_j] = [] if not name_i in self.protein_bonds[resi_j][name_j]: self.protein_bonds[resi_j][name_j].append(name_i) return if __name__ == '__main__': # If called directly, set up protein bond dictionary import protein, pdb, sys,os arguments = sys.argv if len(arguments) != 2: info('Usage: bonds.py <pdb_file>') sys.exit(0) filename = arguments[1] if not os.path.isfile(filename): info('Error: Could not find \"%s\"' % filename) sys.exit(1) pdblist = pdb.readPDB(filename) my_protein = protein.Protein(pdblist,'test.pdb') for chain in my_protein.chains: for residue in chain.residues: residue.atoms = [atom for atom in residue.atoms if atom.element != 'H'] b = bondmaker()
def __init__(self, parameters): # set the calculation rutines used in this version version_A.__init__(self, parameters) info('Using detailed SC model!') return
def print_interaction_parameters(self): info("--------------- Model pKa values ----------------------") for k in self.model_pkas.keys(): info("%3s %8.2f" % (k, self.model_pkas[k])) info("") info("--------------- Interactions --------------------------") agroups = [ "COO", "HIS", "CYS", "TYR", "SER", "N+", "LYS", "AMD", "ARG", "TRP", "ROH", "CG", "C2N", "N30", "N31", "N32", "N33", "NAR", "OCO", "NP1", "OH", "O3", "CL", "F", "NAM", "N1", "O2", "OP", "SH", ] lgroups = [ "CG", "C2N", "N30", "N31", "N32", "N33", "NAR", "OCO", "NP1", "OH", "O3", "CL", "F", "NAM", "N1", "O2", "OP", "SH", ] map = { "CG": ["ARG"], "C2N": ["ARG"], "N30": ["N+", "LYS"], "N31": ["N+", "LYS"], "N32": ["N+", "LYS"], "N33": ["N+", "LYS"], "NAR": ["HIS"], "OCO": ["COO"], "OP": [], # ['TYR','SER'], "SH": ["CYS"], "NP1": [], "OH": ["ROH"], "O3": [], "CL": [], "F": [], "NAM": ["AMD"], "N1": [], "O2": [], } for g1 in agroups: for g2 in lgroups: interaction = "%3s %3s %1s %4s %4s" % ( g1, g2, self.interaction_matrix[g1][g2], self.sidechain_cutoffs.get_value(g1, g2)[0], self.sidechain_cutoffs.get_value(g1, g2)[1], ) map_interaction = "" if g2 in map: for m in map[g2]: map_interaction += "|%3s %3s %1s %4s %4s" % ( g1, m, self.interaction_matrix[g1][m], self.sidechain_cutoffs.get_value(g1, m)[0], self.sidechain_cutoffs.get_value(g1, m)[1], ) if self.interaction_matrix[g1][m] != self.interaction_matrix[g1][g2]: map_interaction += "* " if ( self.sidechain_cutoffs.get_value(g1, m)[0] != self.sidechain_cutoffs.get_value(g1, g2)[0] or self.sidechain_cutoffs.get_value(g1, m)[1] != self.sidechain_cutoffs.get_value(g1, g2)[1] ): map_interaction += "! " else: map_interaction += " " if len(map[g2]) == 0 and ( self.sidechain_cutoffs.get_value(g1, g2)[0] != 3 or self.sidechain_cutoffs.get_value(g1, g2)[1] != 4 ): map_interaction += "? " info(interaction, map_interaction) if g1 == g2: break info("-") info("--------------- Exceptions ----------------------------") info("COO-HIS", self.COO_HIS_exception) info("OCO-HIS", self.OCO_HIS_exception) info("CYS-HIS", self.CYS_HIS_exception) info("CYS-CYS", self.CYS_CYS_exception) info("--------------- Mapping -------------------------------") info( """ Titratable: CG ARG C2N ARG N30 N+/LYS N31 N+/LYS N32 N+/LYS N33 N+/LYS NAR HIS OCO COO OP TYR/SER? SH CYS Non-titratable: NP1 AMD? OH ROH O3 ? CL F NAM N1 O2 """ ) return
def print_interaction_parameters_latex(self): # info('--------------- Model pKa values ----------------------') # for k in self.model_pkas.keys(): # info('%3s %8.2f'%(k,self.model_pkas[k])) # info('') # info('--------------- Interactions --------------------------') agroups = [ "COO", "HIS", "CYS", "TYR", "SER", "N+", "LYS", "AMD", "ARG", "TRP", "ROH", "CG", "C2N", "N30", "N31", "N32", "N33", "NAR", "OCO", "NP1", "OH", "O3", "CL", "F", "NAM", "N1", "O2", "OP", "SH", ] lgroups = [ "CG", "C2N", "N30", "N31", "N32", "N33", "NAR", "OCO", "NP1", "OH", "O3", "CL", "F", "NAM", "N1", "O2", "OP", "SH", ] map = { "CG": ["ARG"], "C2N": ["ARG"], "N30": ["N+", "LYS"], "N31": ["N+", "LYS"], "N32": ["N+", "LYS"], "N33": ["N+", "LYS"], "NAR": ["HIS"], "OCO": ["COO"], "OP": [], # ['TYR','SER'], "SH": ["CYS"], "NP1": ["AMD"], "OH": ["ROH"], "O3": [], "CL": [], "F": [], "NAM": [], "N1": [], "O2": [], } s = """ \\begin{longtable}{lllll} \\caption{Ligand interaction parameters. For interactions not listed, the default value of %s is applied.} \\label{tab:ligand_interaction_parameters}\\\\ \\toprule Group1 & Group2 & Interaction & c1 &c2 \\\\ \\midrule \\endfirsthead \\multicolumn{5}{l}{\\emph{continued from the previous page}}\\\\ \\toprule Group1 & Group2 & Interaction & c1 &c2 \\\\ \\midrule \\endhead \\midrule \\multicolumn{5}{r}{\\emph{continued on the next page}}\\\\ \\endfoot \\bottomrule \\endlastfoot """ % ( self.sidechain_cutoffs.default ) for g1 in agroups: for g2 in lgroups: if self.interaction_matrix[g1][g2] == "-": continue if self.sidechain_cutoffs.get_value(g1, g2) == self.sidechain_cutoffs.default: continue s += "%3s & %3s & %1s & %4s & %4s\\\\ \n" % ( g1, g2, self.interaction_matrix[g1][g2], self.sidechain_cutoffs.get_value(g1, g2)[0], self.sidechain_cutoffs.get_value(g1, g2)[1], ) if g1 == g2: break s += " \\end{longtable}\n" info(s) return
def addDeterminants(iterative_interactions, version, options=None): """ The iterative pKa scheme. Later it is all added in 'calculateTotalPKA' """ # --- setup --- iteratives = [] done_group = [] # creating iterative objects with references to their real group counterparts for interaction in iterative_interactions: pair = interaction[0] for group in pair: if group in done_group: #print "done already" """ do nothing - already have an iterative object for this group """ else: newIterative = Iterative(group) iteratives.append(newIterative) done_group.append(group) # Initialize iterative scheme debug("\n --- pKa iterations (%d groups, %d interactions) ---" % (len(iteratives), len(iterative_interactions))) converged = False iteration = 0 # set non-iterative pka values as first step for itres in iteratives: itres.pKa_iter.append(itres.pKa_NonIterative) # --- starting pKa iterations --- while converged == False: # initialize pKa_new iteration += 1 for itres in iteratives: itres.determinants = {'sidechain':[],'backbone':[],'coulomb':[]} itres.pKa_new = itres.pKa_NonIterative # Adding interactions to temporary determinant container for interaction in iterative_interactions: pair = interaction[0] values = interaction[1] annihilation = interaction[2] #print "len(interaction) = %d" % (len(interaction)) object1, object2 = findIterative(pair, iteratives) Q1 = object1.Q Q2 = object2.Q if Q1 < 0.0 and Q2 < 0.0: """ both are acids """ addIterativeAcidPair(object1, object2, interaction) elif Q1 > 0.0 and Q2 > 0.0: """ both are bases """ addIterativeBasePair(object1, object2, interaction) else: """ one of each """ addIterativeIonPair(object1, object2, interaction, version) # Calculating pKa_new values for itres in iteratives: for type in ['sidechain','backbone','coulomb']: for determinant in itres.determinants[type]: itres.pKa_new += determinant[1] # Check convergence converged = True for itres in iteratives: if itres.pKa_new == itres.pKa_old: itres.converged = True else: itres.converged = False converged = False # reset pKa_old & storing pKa_new in pKa_iter for itres in iteratives: itres.pKa_old = itres.pKa_new itres.pKa_iter.append(itres.pKa_new) if iteration == 10: info("did not converge in %d iterations" % (iteration)) break # --- Iterations finished --- # printing pKa iterations # formerly was conditioned on if options.verbosity >= 2 - now unnecessary str = "%12s" % (" ") for index in range(0, iteration+1 ): str += "%8d" % (index) debug(str) for itres in iteratives: str = "%s " % (itres.label) for pKa in itres.pKa_iter: str += "%8.2lf" % (pKa) if itres.converged == False: str += " *" debug(str) # creating real determinants and adding them to group object for itres in iteratives: for type in ['sidechain','backbone','coulomb']: for interaction in itres.determinants[type]: #info('done',itres.group.label,interaction[0],interaction[1]) value = interaction[1] if value > 0.005 or value < -0.005: g = interaction[0] newDeterminant = Determinant(g, value) itres.group.determinants[type].append(newDeterminant)