def insertBaseFromMmp(filename, subgroup, tfm, position=position): """ Insert the atoms for a nucleic acid base from an MMP file into a single chunk. - If atomistic, the atoms for each base are in a separate chunk. - If PAM5, the pseudo atoms for each base-pair are together in a chunk. @param filename: The mmp filename containing the base (or base-pair). @type filename: str @param subgroup: The part group to add the atoms to. @type subgroup: L{Group} @param tfm: Transform applied to all new base atoms. @type tfm: V @param position: The origin in space of the DNA duplex, where the 3' end of strand A is 0, 0, 0. @type position: L{V} """ try: ok, grouplist = readmmp(assy, filename, isInsert=True) except IOError: raise PluginBug("Cannot read file: " + filename) if not grouplist: raise PluginBug("No atoms in DNA base? " + filename) viewdata, mainpart, shelf = grouplist for member in mainpart.members: # 'member' is a chunk containing a set of base-pair atoms. for atm in member.atoms.values(): atm._posn = tfm(atm._posn) + position if atm.element.symbol in ('Se3', 'Ss3', 'Ss5'): if atm.getDnaBaseName() == "a": baseLetter = currentBaseLetter else: try: baseLetter = \ basesDict[currentBaseLetter]['Complement'] except: # If complement not found, just assign same # letter. baseLetter = currentBaseLetter if 0: print "Ss(%r) being set to %r." \ % (atm.getDnaBaseName(), baseLetter) atm.setDnaBaseName(baseLetter) member.name = currentBaseLetter subgroup.addchild(member) baseList.append(member) # Clean up. del viewdata shelf.kill()
def build_struct(self, name, params, position): """ Build the DNA helix based on parameters in the UI. @param name: The name to assign the node in the model tree. @type name: str @param params: The list of parameters gathered from the PM. @type params: tuple @param position: The position in 3d model space at which to create the DNA strand. This is always 0, 0, 0. @type position: position """ # No error checking in build_struct, do all your error # checking in gather_parameters numberOfBases, \ dnaForm, \ basesPerTurn, \ endPoint1, \ endPoint2 = params if Veq(endPoint1, endPoint2): raise CadBug("DNA endpoints cannot be the same point.") if numberOfBases < 1: msg = redmsg("Cannot to preview/insert a DNA duplex with 0 bases.") self.MessageGroupBox.insertHtmlMessage(msg, setAsDefault=False) self.dna = None # Fixes bug 2530. Mark 2007-09-02 return None if dnaForm == 'B-DNA': dna = B_Dna_PAM3() else: raise PluginBug("Unsupported DNA Form: " + dnaForm) self.dna = dna # needed for done msg # Create the model tree group node. dnaGroup = Group(self.name, self.win.assy, self.win.assy.part.topnode) try: # Make the DNA duplex. <dnaGroup> will contain three chunks: # - Strand1 # - Strand2 # - Axis dna.make(dnaGroup, numberOfBases, basesPerTurn, endPoint1, endPoint2) return dnaGroup except (PluginBug, UserError): # Why do we need UserError here? Mark 2007-08-28 rawDnaGroup.kill() raise PluginBug( "Internal error while trying to create DNA duplex.") pass
def _create_atomLists_for_regrouping(self, dnaGroup): """ Creates and returns the atom lists that will be used to regroup the chunks within the DnaGroup. @param dnaGroup: The DnaGroup whose atoms will be filtered and put into individual strand A or strandB or axis atom lists. @return: Returns a tuple containing three atom lists -- two atom lists for strand chunks and one for axis chunk. @see: self._regroup() """ _strandA_list = [] _strandB_list = [] _axis_list = [] # Build strand and chunk atom lists. for m in dnaGroup.members: for atom in m.atoms.values(): if atom.element.symbol in ('Pl5', 'Pe5'): if atom.getDnaStrandId_for_generators() == 'Strand1': _strandA_list.append(atom) # Following makes sure that the info record #'dnaStrandId_for_generators' won't be written for #this atom that the dna generator outputs. i.e. #the info record 'dnaStrandId_for_generators' is only #required while generating the dna from scratch #(by reading in the strand base files in 'cad/plugins' #see more comments in Atom.getDnaStrandId_for_generators atom.setDnaStrandId_for_generators('') elif atom.getDnaStrandId_for_generators() == 'Strand2': atom.setDnaStrandId_for_generators('') _strandB_list.append(atom) if atom.element.symbol in ('Ss5', 'Sh5'): if atom.getDnaBaseName() == 'a': _strandA_list.append(atom) #Now reset the DnaBaseName for the added atom # to 'unassigned' base i.e. 'X' atom.setDnaBaseName('X') elif atom.getDnaBaseName() == 'b': _strandB_list.append(atom) #Now reset the DnaBaseName for the added atom # to 'unassigned' base i.e. 'X' atom.setDnaBaseName('X') else: msg = "Ss5 or Sh5 atom not assigned to strand 'a' or 'b'." raise PluginBug(msg) elif atom.element.symbol in ('Ax5', 'Ae5', 'Gv5', 'Gr5'): _axis_list.append(atom) return (_strandA_list, _strandB_list, _axis_list)
def gather_parameters(self): """ Return the parameters from the property manager UI. @return: All the parameters: - dnaSequence - dnaType - basesPerTurn - chunkOption @rtype: tuple """ if not basepath_ok: raise PluginBug("The cad/plugins/DNA directory is missing.") dnaModel = str(self.modelComboBox.currentText()) dnaType = str(self.conformationComboBox.currentText()) assert dnaType in ('B-DNA') # Get bases per turn. basesPerTurnString = str(self.basesPerTurnComboBox.currentText()) basesPerTurn = float(basesPerTurnString) chunkOption = str(self.createComboBox.currentText()) resolve_random = False # Later this flag may depend on a new checkbox in that case; # for now it doesn't matter, since sequence info is # discarded for reduced bases anyway. (dnaSequence, allKnown) = \ self._getSequence( resolve_random = resolve_random) x1 = self.x1SpinBox.value() y1 = self.y1SpinBox.value() z1 = self.z1SpinBox.value() x2 = self.x2SpinBox.value() y2 = self.y2SpinBox.value() z2 = self.z2SpinBox.value() endpoint1 = V(x1, y1, z1) endpoint2 = V(x2, y2, z2) return (dnaSequence, dnaModel, dnaType, basesPerTurn, chunkOption, endpoint1, endpoint2)
def _createStructure(self): """ creates and returns the structure (in this case a L{Group} object that contains the DNA strand and axis chunks. @return : group containing that contains the DNA strand and axis chunks. @rtype: L{Group} @note: This needs to return a DNA object once that model is implemented """ # self.name needed for done message if self.create_name_from_prefix: # create a new name name = self.name = gensym(self.prefix, self.win.assy) # (in _build_struct) self._gensym_data_for_reusing_name = (self.prefix, name) else: # use externally created name self._gensym_data_for_reusing_name = None # (can't reuse name in this case -- not sure what prefix it was # made with) name = self.name # Create the model tree group node. # Make sure that the 'topnode' of this part is a Group (under which the # DNa group will be placed), if the topnode is not a group, make it a # a 'Group' (applicable to Clipboard parts).See part.py # --Part.ensure_toplevel_group method. This is an important line # and it fixes bug 2585 self.win.assy.part.ensure_toplevel_group() dnaGroup = DnaGroup(self.name, self.win.assy, self.win.assy.part.topnode, editCommand=self) try: self.win.assy.place_new_geometry(dnaGroup) return dnaGroup except (PluginBug, UserError): # Why do we need UserError here? Mark 2007-08-28 dnaGroup.kill() raise PluginBug( "Internal error while trying to create DNA duplex.")
def build_struct(self, name, params, position): """ Same API as in GeneratorBaseClass (though we are not its subclass). On error, raise an exception. """ # get executable, append exe, ensure it exists program = self.executable_path # make command line args from params args, outfiles = self.command_line_args_and_outfiles(params, name) # makes param args and outputfile args; # args is a list of strings (including outfile names); # outfiles is a list of full pathnames of files this command might create # run executable using the way we run the sim exitcode = self.run_command(program, args) #e look at exitcode? if exitcode and debug_run(): print "generator exitcode: %r" % (exitcode, ) if exitcode: # treat this as a fatal error for this run [to test, use an invalid chirality with m > n] msg = "Plugin %r exitcode: %r" % (self.plugin_name, exitcode) ## not needed, GBC UserError will do it, more or less: env.history.message(redmsg(msg)) ###e should: self.remove_outfiles(outfiles, complain_if_missing = False) raise UserError( msg ) # this prints a redmsg; maybe we'd rather do that ourselves, and raise SilentUserError (nim)?? # look for outfiles # (if there are more than one specified, for now just assume all of them need to be there) for outfile in outfiles: if not os.path.exists(outfile): ###e should: self.remove_outfiles(outfiles, complain_if_missing = False) raise PluginBug( "generator output file should exist but doesn't: [%s]" % (outfile, )) # insert file contents, rename the object in it, return that (see dna generator) thing = self.insert_output(outfiles, params, name) # we pass params, since some params might affect insertion (or postprocessing) # other than by affecting the command output ###@@@ WARNING: the following repositioning code is not correct for all kinds of "things", # only for single-chunk things like for CoNTub # (and also it probably belongs inside insert_output, not here): for atom in thing.atoms.values(): atom.setposn(atom.posn() + position) self.remove_outfiles(outfiles) return thing
def _createStructure(self): """ Returns the current NanotubeSegment being edited with a new nanotube chunk. @return : Nanotube segment that include the new nanotube chunk. @rtype: L{NanotubeSegment} """ try: # Create a new nanotube chunk using new params. n, m, type, endings, endPoint1, endPoint2 = self._gatherParameters() from cnt.model.NanotubeParameters import NanotubeParameters self.nanotube = NanotubeParameters() nanotube = self.nanotube nanotube.setChirality(n, m) nanotube.setType(type) nanotube.setEndings(endings) nanotube.setEndPoints(endPoint1, endPoint2) position = V(0.0, 0.0, 0.0) ntChunk = nanotube.build(self.struct.name, self.win.assy, position) nanotube.computeEndPointsFromChunk(ntChunk) # Needed. self.struct.addchild(ntChunk) #WARNING 2008-03-05: #When we actually permit modifying a nanotube without recreating it, #then the following properties must be set in self._modifyStructure #as well. Needs more thought. props =(nanotube.getChirality(), nanotube.getType(), nanotube.getEndings(), nanotube.getEndPoints()) self.struct.setProps(props) return self.struct except (PluginBug, UserError): self.struct.kill() raise PluginBug("Internal error while trying to recreate a NanotubeSegment.") return None
def _create_atomLists_for_regrouping(self, dnaGroup): """ Creates and returns the atom lists that will be used to regroup the chunks within the DnaGroup. @param dnaGroup: The DnaGroup whose atoms will be filtered and put into individual strand A or strandB or axis atom lists. @return: Returns a tuple containing three atom lists -- two atom lists for strand chunks and one for axis chunk. @see: self._regroup() """ _strandA_list = [] _strandB_list = [] _axis_list = [] # Build strand and chunk atom lists. for m in dnaGroup.members: for atom in m.atoms.values(): if atom.element.symbol in ('Ss3'): if atom.getDnaBaseName() == 'a': _strandA_list.append(atom) #Now reset the DnaBaseName for the added atom # to 'unassigned' base i.e. 'X' atom.setDnaBaseName('X') elif atom.getDnaBaseName() == 'b': _strandB_list.append(atom) #Now reset the DnaBaseName for the added atom # to 'unassigned' base i.e. 'X' atom.setDnaBaseName('X') else: msg = "Ss3 atom not assigned to strand 'a' or 'b'." raise PluginBug(msg) elif atom.element.symbol in ('Ax3', 'Ae3'): _axis_list.append(atom) return (_strandA_list, _strandB_list, _axis_list)
def build_struct(self, name, params, position): """ Build the DNA helix based on parameters in the UI. @param name: The name to assign the node in the model tree. @type name: str @param params: The list of parameters gathered from the PM. @type params: tuple @param position: The position in 3d model space at which to create the DNA strand. This is always 0, 0, 0. @type position: position """ # No error checking in build_struct, do all your error # checking in gather_parameters theSequence, \ dnaModel, \ dnaType, \ basesPerTurn, \ chunkOption, \ endpoint1, \ endpoint2 = params if Veq(endpoint1, endpoint2): raise CadBug("Dna endpoints cannot be the same point.") return if len(theSequence) < 1: msg = redmsg("Enter a strand sequence to preview/insert DNA") self.MessageGroupBox.insertHtmlMessage(msg, setAsDefault=False) self.dna = None # Fixes bug 2530. Mark 2007-09-02 return None if dnaModel == 'PAM3': dna = B_Dna_PAM3() else: dna = B_Dna_PAM5() self.dna = dna # needed for done msg # Create the model tree group node. rawDnaGroup = Group(self.name, self.win.assy, self.win.assy.part.topnode) try: # Make the DNA duplex. <rawDnaGroup> returns a different # grouping arrangement for atomistic vs. PAM5. This 'issue' # is resolved when we regroup the atoms into strand chunks # below. dna.make(rawDnaGroup, theSequence, basesPerTurn) self._orientRawDnaGroup(rawDnaGroup, endpoint1, endpoint2) # Now group the DNA atoms based on the grouping option selected # (i.e. "Strand chunks" or "Single Chunk"). dnaGroup = self._makePAMStrandAndAxisChunks(rawDnaGroup) if chunkOption == 'Single chunk': return self._makeDuplexChunk(dnaGroup) return dnaGroup except (PluginBug, UserError): # Why do we need UserError here? Mark 2007-08-28 rawDnaGroup.kill() raise PluginBug( "Internal error while trying to create DNA duplex.") return None
def _createStructure(self): """ Creates and returns the structure (in this case a L{Group} object that contains the DNA strand and axis chunks. @return : group containing that contains the DNA strand and axis chunks. @rtype: L{Group} @note: This needs to return a DNA object once that model is implemented """ params = self._gatherParameters() # No error checking in build_struct, do all your error # checking in gather_parameters number_of_basePairs_from_struct,\ numberOfBases, \ dnaForm, \ dnaModel, \ basesPerTurn, \ duplexRise, \ endPoint1, \ endPoint2, \ color_junk = params #Note: color_junk is not used. Ideally it should do struct.setColor(color) #but the color combobox in the PM directly sets the color of the #structure to the specified one when the current index in the combobx #changes #If user enters the number of basepairs and hits preview i.e. endPoint1 #and endPoint2 are not entered by the user and thus have default value #of V(0, 0, 0), then enter the endPoint1 as V(0, 0, 0) and compute #endPoint2 using the duplex length. #Do not use '==' equality check on vectors! its a bug. Use same_vals # or Veq instead. if Veq(endPoint1, endPoint2) and Veq(endPoint1, V(0, 0, 0)): endPoint2 = endPoint1 + \ self.win.glpane.right*getDuplexLength('B-DNA', numberOfBases) if numberOfBases < 1: msg = redmsg("Cannot preview/insert a DNA duplex with 0 bases.") self.propMgr.updateMessage(msg) self.dna = None # Fixes bug 2530. Mark 2007-09-02 return None if dnaForm == 'B-DNA': if dnaModel == 'PAM3': dna = B_Dna_PAM3_Generator() elif dnaModel == 'PAM5': dna = B_Dna_PAM5_Generator() else: print "bug: unknown dnaModel type: ", dnaModel else: raise PluginBug("Unsupported DNA Form: " + dnaForm) self.dna = dna # needed for done msg # self.name needed for done message if self.create_name_from_prefix: # create a new name name = self.name = gensym(self.prefix, self.win.assy) # (in _build_struct) self._gensym_data_for_reusing_name = (self.prefix, name) else: # use externally created name self._gensym_data_for_reusing_name = None # (can't reuse name in this case -- not sure what prefix it was # made with) name = self.name # Create the model tree group node. # Make sure that the 'topnode' of this part is a Group (under which the # DNa group will be placed), if the topnode is not a group, make it a # a 'Group' (applicable to Clipboard parts).See part.py # --Part.ensure_toplevel_group method. This is an important line # and it fixes bug 2585 self.win.assy.part.ensure_toplevel_group() dnaSegment = DnaSegment(self.name, self.win.assy, self.win.assy.part.topnode, editCommand=self) try: # Make the DNA duplex. <dnaGroup> will contain three chunks: # - Strand1 # - Strand2 # - Axis dna.make(dnaSegment, numberOfBases, basesPerTurn, duplexRise, endPoint1, endPoint2) #set some properties such as duplexRise and number of bases per turn #This information will be stored on the DnaSegment object so that #it can be retrieved while editing this object. #This works with or without dna_updater. Now the question is #should these props be assigned to the DnaSegment in #dnaDuplex.make() itself ? This needs to be answered while modifying #make() method to fit in the dna data model. --Ninad 2008-03-05 #WARNING 2008-03-05: Since self._modifyStructure calls #self._createStructure() #If in the near future, we actually permit modifying a #structure (such as dna) without actually recreating the whole #structre, then the following properties must be set in #self._modifyStructure as well. Needs more thought. props = (duplexRise, basesPerTurn) dnaSegment.setProps(props) return dnaSegment except (PluginBug, UserError): # Why do we need UserError here? Mark 2007-08-28 dnaSegment.kill() raise PluginBug( "Internal error while trying to create DNA duplex.")
def _createStructure(self): """ Creates and returns the structure (in this case a L{Group} object that contains the nanotube chunk. @return : group containing the nanotube chunk. @rtype: L{Group} @note: This needs to return a CNT object once that model is implemented """ # self.name needed for done message if self.create_name_from_prefix: # create a new name name = self.name = gensym(self.prefix, self.win.assy) # (in _build_struct) self._gensym_data_for_reusing_name = (self.prefix, name) else: # use externally created name self._gensym_data_for_reusing_name = None # (can't reuse name in this case -- not sure what prefix it was # made with) name = self.name # Create the model tree group node. # Make sure that the 'topnode' of this part is a Group (under which the # Nanotube group will be placed), if the topnode is not a group, make it # a 'Group' (applicable to Clipboard parts). See part.py # --Part.ensure_toplevel_group method. This is an important line # and it fixes bug 2585 self.win.assy.part.ensure_toplevel_group() ntSegment = NanotubeSegment(self.name, self.win.assy, self.win.assy.part.topnode, editCommand=self) try: # Make the nanotube. <ntGroup> will contain one chunk: # - Axis (Segment) # No error checking here; do all error checking in _gatherParameters(). nanotube = self._gatherParameters() position = V(0.0, 0.0, 0.0) self.nanotube = nanotube # needed for done msg #@ ntChunk = nanotube.build(self.name, self.win.assy, position) ntSegment.addchild(ntChunk) #set some properties such as ntRise and its two endpoints. #This information will be stored on the NanotubeSegment object so that #it can be retrieved while editing this object. #WARNING 2008-03-05: Since self._modifyStructure calls #self._createStructure() If in the near future, we actually permit #modifying a #structure (such as a nanotube) without actually recreating the #entire structure, then the following properties must be set in #self._modifyStructure as well. Needs more thought. #props =(nanotube.getChirality(), # nanotube.getType(), # nanotube.getEndings(), # nanotube.getEndPoints()) ntSegment.setProps(nanotube.getParameters()) return ntSegment except (PluginBug, UserError): # Why do we need UserError here? Mark 2007-08-28 self._segmentList.remove(ntSegment) ntSegment.kill_with_contents() raise PluginBug("Internal error while trying to create Nanotube.")
def _strandBinfo(self, sequence, index): """ Raise exception since A-DNA is not support. """ raise PluginBug("A-DNA is not yet implemented.")
def _strandAinfo(self, baseLetter, index): """ Raise exception since A-DNA is not support. """ raise PluginBug("A-DNA is not yet implemented.")