Author: bugman Date: Wed Feb 20 15:34:32 2013 New Revision: 18526 URL: http://svn.gna.org/viewcvs/relax?rev=18526&view=rev Log: Merged revisions 18524-18525 via svnmerge from svn+ssh://bugman@xxxxxxxxxxx/svn/relax/trunk ........ r18524 | bugman | 2013-02-20 14:17:40 +0100 (Wed, 20 Feb 2013) | 3 lines Implemented the PDB HELIX record writing function generic_fns.structure.pdb_write.helix(). ........ r18525 | bugman | 2013-02-20 14:37:40 +0100 (Wed, 20 Feb 2013) | 7 lines Improved PDB writing capabilities. The functions of the generic_fns.structure.pdb_write module now all use the _handle_none() function to avoid the text "None" from appearing in the PDB file and _record_validate() to be sure the record has not been corrupted with bad input causing it to be either less or greater than 80 characters. ........ Modified: branches/frame_order_testing/ (props changed) branches/frame_order_testing/generic_fns/structure/pdb_write.py Propchange: branches/frame_order_testing/ ------------------------------------------------------------------------------ --- svnmerge-integrated (original) +++ svnmerge-integrated Wed Feb 20 15:34:32 2013 @@ -1,1 +1,1 @@ -/trunk:1-18522 +/trunk:1-18525 Modified: branches/frame_order_testing/generic_fns/structure/pdb_write.py URL: http://svn.gna.org/viewcvs/relax/branches/frame_order_testing/generic_fns/structure/pdb_write.py?rev=18526&r1=18525&r2=18526&view=diff ============================================================================== --- branches/frame_order_testing/generic_fns/structure/pdb_write.py (original) +++ branches/frame_order_testing/generic_fns/structure/pdb_write.py Wed Feb 20 15:34:32 2013 @@ -27,6 +27,42 @@ # Python module imports. from textwrap import wrap + +# relax module imports. +from relax_errors import RelaxError + + +def _handle_none(value): + """Auxiliary function for handling values of None. + + @param value: The value to convert. + @type value: anything + @return: If the value is None, then an empty string. Otherwise the original value is returned. + @rtype: anything + """ + + # Handle None. + if value == None: + return '' + + # Normal value. + return value + + +def _record_validate(record): + """Check that the record is ok. + + @param record: The PDB record as text. + @type record: str + @raises RelaxError: If the record is not exactly 80 characters long. + """ + + # Check the length. + if len(record) != 80: + if len(record) < 80: + raise RelaxError("The PDB record '%s' is too short." % record) + else: + raise RelaxError("The PDB record '%s' is too long." % record) def atom(file, serial='', name='', alt_loc='', res_name='', chain_id='', res_seq='', icode='', x='', y='', z='', occupancy='', temp_factor='', element='', charge=''): @@ -188,8 +224,31 @@ @type charge: int """ + # The formatted record. + text = "%-6s%5s %-4s%1s%3s %1s%4s%1s %8.3f%8.3f%8.3f%6.2f%6.2f %2s%2s" % ( + 'ATOM', + _handle_none(serial), + _handle_none(name), + _handle_none(alt_loc), + _handle_none(res_name), + _handle_none(chain_id), + _handle_none(res_seq), + _handle_none(icode), + _handle_none(x), + _handle_none(y), + _handle_none(z), + _handle_none(occupancy), + _handle_none(temp_factor), + _handle_none(element), + _handle_none(charge) + ) + + # Validate. + _record_validate(text) + # Write out the formatted record. - file.write("%-6s%5s %-4s%1s%3s %1s%4s%1s %8.3f%8.3f%8.3f%6.2f%6.2f %2s%2s\n" % ('ATOM', serial, name, alt_loc, res_name, chain_id, res_seq, icode, x, y, z, occupancy, temp_factor, element, charge)) + file.write(text) + file.write('\n') def conect(file, serial='', bonded1='', bonded2='', bonded3='', bonded4=''): @@ -282,8 +341,22 @@ @type bonded4: int """ + # The formatted record. + text = "%-6s%5s%5s%5s%5s%5s \n" % ( + 'CONECT', + _handle_none(serial), + _handle_none(bonded1), + _handle_none(bonded2), + _handle_none(bonded3), + _handle_none(bonded4) + ) + + # Validate. + _record_validate(text) + # Write out the formatted record. - file.write("%-6s%5s%5s%5s%5s%5s \n" % ('CONECT', serial, bonded1, bonded2, bonded3, bonded4)) + file.write(text) + file.write('\n') def end(file): @@ -339,8 +412,15 @@ @type file: file object """ + # The formatted record. + text = "END" + ' '*77 + + # Validate. + _record_validate(text) + # Write out the formatted record. - file.write("END\n") + file.write(text) + file.write('\n') def endmdl(file): @@ -415,8 +495,15 @@ @type file: file object """ + # The formatted record. + text = 'ENDMDL' + ' '*74 + + # Validate. + _record_validate(text) + # Write out the formatted record. - file.write("%-6s\n" % 'ENDMDL') + file.write(text) + file.write('\n') def formul(file, comp_num='', het_id='', continuation='', asterisk='', text=''): @@ -503,8 +590,161 @@ @type text: str """ + # The formatted record. + text = "%-6s %2s %3s %2s%1s%-51s\n" % ( + 'FORMUL', + _handle_none(comp_num), + _handle_none(het_id), + _handle_none(continuation), + _handle_none(asterisk), + _handle_none(text) + ) + + # Validate. + _record_validate(text) + # Write out the formatted record. - file.write("%-6s %2s %3s %2s%1s%-51s\n" % ('FORMUL', comp_num, het_id, continuation, asterisk, text)) + file.write(text) + file.write('\n') + + +def helix(file, ser_num='', helix_id='', init_res_name='', init_chain_id='', init_seq_id='', init_icode='', end_res_name='', end_chain_id='', end_seq_num='', end_icode='', helix_class='', comment='', length=''): + """Generate the HELIX record. + + The following is the PDB v3.3 documentation U{http://www.wwpdb.org/documentation/format33/sect5.html#HELIX}. + + Overview + ======== + + HELIX records are used to identify the position of helices in the molecule. Helices are named, numbered, and classified by type. The residues where the helix begins and ends are noted, as well as the total length. + + + Record Format + ============= + + ______________________________________________________________________________________________ + | | | | | + | Columns | Data type | Field | Definition | + |_________|______________|______________|____________________________________________________| + | | | | | + | 1 - 6 | Record name | "HELIX " | | + | 8 - 10 | Integer | serNum | Serial number of the helix. This starts at 1 and | + | | | | increases incrementally. | + | 12 - 14 | LString(3) | helixID | Helix identifier. In addition to a serial number, | + | | | | each helix is given an alphanumeric character | + | | | | helix identifier. | + | 16 - 18 | Residue name | initResName | Name of the initial residue. | + | 20 | Character | initChainID | Chain identifier for the chain containing this | + | | | | helix. | + | 22 - 25 | Integer | initSeqNum | Sequence number of the initial residue. | + | 26 | AChar | initICode | Insertion code of the initial residue. | + | 28 - 30 | Residue name | endResName | Name of the terminal residue of the helix. | + | 32 | Character | endChainID | Chain identifier for the chain containing this | + | | | | helix. | + | 34 - 37 | Integer | endSeqNum | Sequence number of the terminal residue. | + | 38 | AChar | endICode | Insertion code of the terminal residue. | + | 39 - 40 | Integer | helixClass | Helix class (see below). | + | 41 - 70 | String | comment | Comment about this helix. | + | 72 - 76 | Integer | length | Length of this helix. | + |_________|______________|______________|____________________________________________________| + + Details + ======= + + - Additional HELIX records with different serial numbers and identifiers occur if more than one helix is present. + - The initial residue of the helix is the N-terminal residue. + - Helices are classified as follows: + + _____________________________________________________ + | | CLASS NUMBER | + | TYPE OF HELIX | (COLUMNS 39 - 40) | + |_______________________________|___________________| + | | | + | Right-handed alpha (default) | 1 | + | Right-handed omega | 2 | + | Right-handed pi | 3 | + | Right-handed gamma | 4 | + | Right-handed 3 - 10 | 5 | + | Left-handed alpha | 6 | + | Left-handed omega | 7 | + | Left-handed gamma | 8 | + | 2 - 7 ribbon/helix | 9 | + | Polyproline | 10 | + |_______________________________|___________________| + + + Relationships to Other Record Types + =================================== + + There may be related information in the REMARKs. + + + Example + ======= + + 1 2 3 4 5 6 7 8 + 12345678901234567890123456789012345678901234567890123456789012345678901234567890 + HELIX 1 HA GLY A 86 GLY A 94 1 9 + HELIX 2 HB GLY B 86 GLY B 94 1 9 + + HELIX 21 21 PRO J 385 LEU J 388 5 4 + HELIX 22 22 PHE J 397 PHE J 402 5 6 + + + @param file: The file to write the record to. + @type file: file object + @keyword ser_num: The helix serial number + @type ser_num: int + @keyword helix_id: The helix identifier + @type helix_id: str + @keyword init_res_name: The name of the initial residue + @type init_res_name: str + @keyword init_chain_id: The chain identifier + @type init_chain_id: str + @keyword init_seq_id: The sequence number of the initial residue + @type init_seq_id: int + @keyword init_icode: The insertion code of the initial residue + @type init_icode: str + @keyword end_res_name: The name of the terminal residue + @type end_res_name: str + @keyword end_chain_id: The chain identifier + @type end_chain_id: str + @keyword end_seq_num: The sequence number of the terminal residue + @type end_seq_num: int + @keyword end_icode: The insertion code of the terminal residue + @type end_icode: str + @keyword helix_class: The helix class + @type helix_class: int + @keyword comment: The comment + @type comment: str + @keyword length: The helix length. + @type length: int + """ + + # The formatted record. + text = "%-6s %3s %3s %3s %1s %4s%1s %3s %s %4s%1s%2s%30s %5s " % ( + 'HELIX', + _handle_none(ser_num), + _handle_none(helix_id), + _handle_none(init_res_name), + _handle_none(init_chain_id), + _handle_none(init_seq_id), + _handle_none(init_icode), + _handle_none(end_res_name), + _handle_none(end_chain_id), + _handle_none(end_seq_num), + _handle_none(end_icode), + _handle_none(helix_class), + _handle_none(comment), + _handle_none(length) + ) + + # Validate. + _record_validate(text) + + # Write out the formatted record. + file.write(text) + file.write('\n') def het(file, het_id='', chain_id='', seq_num='', icode='', num_het_atoms='', text=''): @@ -601,8 +841,23 @@ @type text: str """ + # The formatted record. + text = "%-6s %3s %1s%4s%1s %5s %-40s" % ( + 'HET', + _handle_none(het_id), + _handle_none(chain_id), + _handle_none(seq_num), + _handle_none(icode), + _handle_none(num_het_atoms), + _handle_none(text) + ) + + # Validate. + _record_validate(text) + # Write out the formatted record. - file.write("%-6s %3s %1s%4s%1s %5s %-40s\n" % ('HET', het_id, chain_id, seq_num, icode, num_het_atoms, text)) + file.write(text) + file.write('\n') def hetatm(file, serial='', name='', alt_loc='', res_name='', chain_id='', res_seq='', icode='', x='', y='', z='', occupancy='', temp_factor='', element='', charge=''): @@ -714,8 +969,31 @@ @type charge: int """ + # The formatted record. + text = "%-6s%5s %4s%1s%3s %1s%4s%1s %8.3f%8.3f%8.3f%6.2f%6.2f %2s%2s" % ( + 'HETATM', + _handle_none(serial), + _handle_none(name), + _handle_none(alt_loc), + _handle_none(res_name), + _handle_none(chain_id), + _handle_none(res_seq), + _handle_none(icode), + _handle_none(x), + _handle_none(y), + _handle_none(z), + _handle_none(occupancy), + _handle_none(temp_factor), + _handle_none(element), + _handle_none(charge) + ) + + # Validate. + _record_validate(text) + # Write out the formatted record. - file.write("%-6s%5s %4s%1s%3s %1s%4s%1s %8.3f%8.3f%8.3f%6.2f%6.2f %2s%2s\n" % ('HETATM', serial, name, alt_loc, res_name, chain_id, res_seq, icode, x, y, z, occupancy, temp_factor, element, charge)) + file.write(text) + file.write('\n') def hetnam(file, continuation='', het_id='', text=''): @@ -798,8 +1076,20 @@ @type text: str """ + # The formatted record. + text = "%-6s %2s %3s %-55s\n" % ( + 'HETNAM', + _handle_none(continuation), + _handle_none(het_id), + _handle_none(text) + ) + + # Validate. + _record_validate(text) + # Write out the formatted record. - file.write("%-6s %2s %3s %-55s\n" % ('HETNAM', continuation, het_id, text)) + file.write(text) + file.write('\n') def master(file, num_remark=0, num_het=0, num_helix=0, num_sheet=0, num_turn=0, num_site=0, num_xform=0, num_coord=0, num_ter=0, num_conect=0, num_seq=0): @@ -891,8 +1181,29 @@ @type num_seq int """ + # The formatted record. + text = "%-6s %5s%5s%5s%5s%5s%5s%5s%5s%5s%5s%5s%5s" % ( + 'MASTER', + _handle_none(num_remark), + 0, + _handle_none(num_het), + _handle_none(num_helix), + _handle_none(num_sheet), + _handle_none(num_turn), + _handle_none(num_site), + _handle_none(num_xform), + _handle_none(num_coord), + _handle_none(num_ter), + _handle_none(num_conect), + _handle_none(num_seq) + ) + + # Validate. + _record_validate(text) + # Write out the formatted record. - file.write("%-6s %5s%5s%5s%5s%5s%5s%5s%5s%5s%5s%5s%5s\n" % ('MASTER', num_remark, 0, num_het, num_helix, num_sheet, num_turn, num_site, num_xform, num_coord, num_ter, num_conect, num_seq)) + file.write(text) + file.write('\n') def model(file, serial=''): @@ -1000,8 +1311,19 @@ @type serial: int """ + # The formatted record. + text = "%-6s %4i%65s" % ( + 'MODEL', + _handle_none(serial), + '' + ) + + # Validate. + _record_validate(text) + # Write out the formatted record. - file.write("%-6s %4i\n" % ('MODEL', serial)) + file.write(text) + file.write('\n') def remark(file, num='', remark=''): @@ -1037,9 +1359,17 @@ @type remark: str """ - # Write out the formatted record, splitting across lines if needed. + # The formatted record, splitting across lines if needed. for line in wrap(remark, 68): - file.write("%-6s %3s %-68s \n" % ("REMARK", num, line.upper())) + # The text. + text = "%-6s %3s %-68s " % ("REMARK", num, line.upper()) + + # Validate. + _record_validate(text) + + # Write out the formatted record. + file.write(text) + file.write('\n') def ter(file, serial='', res_name='', chain_id='', res_seq='', icode=''): @@ -1134,4 +1464,18 @@ """ # Write out the formatted record. - file.write("%-6s%5s %3s %1s%4s%1s\n" % ('TER', serial, res_name, chain_id, res_seq, icode)) + text = "%-6s%5s %3s %1s%4s%1s" % ( + 'TER', + _handle_none(serial), + _handle_none(res_name), + _handle_none(chain_id), + _handle_none(res_seq), + _handle_none(icode) + ) + + # Validate. + _record_validate(text) + + # Write out the formatted record. + file.write(text) + file.write('\n')