Author: bugman Date: Thu Oct 23 15:06:11 2014 New Revision: 26387 URL: http://svn.gna.org/viewcvs/relax?rev=26387&view=rev Log: Merged revisions 26380-26383 via svnmerge from svn+ssh://bugman@xxxxxxxxxxx/svn/relax/trunk ........ r26380 | bugman | 2014-10-23 14:27:05 +0200 (Thu, 23 Oct 2014) | 6 lines Created the Structure.test_bug_22861_PDB_writing_chainID_fail system test. This is to catch bug #22861 (https://gna.org/bugs/?22861), the chain IDs in the structure.write_pdb user function PDB files are incorrect after calling structure.delete. ........ r26381 | bugman | 2014-10-23 14:45:25 +0200 (Thu, 23 Oct 2014) | 13 lines The structure.write_pdb user function can now handle empty molecules. This fixes bug #22861 (https://gna.org/bugs/?22861), the chain IDs in the structure.write_pdb user function PDB files are incorrect after calling structure.delete. To handle this consistently, the internal structural object ModelContainer.mol_loop() generator method has been created. This loops over the molecules, yielding those that are not empty. The MolContainer.is_empty() method has been fixed by not checking for the molecule name, as that remains after the structure.delete user function call while all other information has been removed. And finally the write_pdb() structural object method has been modified to use the mol_loop() method rather than performing the loop itself. ........ r26382 | bugman | 2014-10-23 14:55:09 +0200 (Thu, 23 Oct 2014) | 6 lines Small modification of the Structure.test_bug_22861_PDB_writing_chainID_fail system test. File metadata is now being set to demonstrate that the structure.delete user function does not remove this once there is no more data left for the molecule. ........ r26383 | bugman | 2014-10-23 14:56:54 +0200 (Thu, 23 Oct 2014) | 8 lines Fix for the structure.delete user function for molecule metadata once no more data exists. This relates to bug #22861 (https://gna.org/bugs/?22861), the chain IDs in the structure.write_pdb user function PDB files are incorrect after calling structure.delete. The metadata, when it exists, is now deleted for the molecule once no more data is present. ........ Modified: branches/frame_order_cleanup/ (props changed) branches/frame_order_cleanup/lib/structure/internal/models.py branches/frame_order_cleanup/lib/structure/internal/molecules.py branches/frame_order_cleanup/lib/structure/internal/object.py branches/frame_order_cleanup/test_suite/system_tests/structure.py Propchange: branches/frame_order_cleanup/ ------------------------------------------------------------------------------ --- svnmerge-integrated (original) +++ svnmerge-integrated Thu Oct 23 15:06:11 2014 @@ -1 +1 @@ -/trunk:1-26370,26373-26374,26379 +/trunk:1-26385 Modified: branches/frame_order_cleanup/lib/structure/internal/models.py URL: http://svn.gna.org/viewcvs/relax/branches/frame_order_cleanup/lib/structure/internal/models.py?rev=26387&r1=26386&r2=26387&view=diff ============================================================================== --- branches/frame_order_cleanup/lib/structure/internal/models.py (original) +++ branches/frame_order_cleanup/lib/structure/internal/models.py Thu Oct 23 15:06:11 2014 @@ -263,3 +263,20 @@ # The ModelContainer is unmodified. return True + + + def mol_loop(self): + """Generator method to loop over the molecules of this model. + + @return: The molecules of this model. + @rtype: MolContainer instance + """ + + # Loop over all molecules. + for mol in self.mol: + # No data, so do not yield the molecule. + if mol.is_empty(): + continue + + # Yield the molecule. + yield mol Modified: branches/frame_order_cleanup/lib/structure/internal/molecules.py URL: http://svn.gna.org/viewcvs/relax/branches/frame_order_cleanup/lib/structure/internal/molecules.py?rev=26387&r1=26386&r2=26387&view=diff ============================================================================== --- branches/frame_order_cleanup/lib/structure/internal/molecules.py (original) +++ branches/frame_order_cleanup/lib/structure/internal/molecules.py Thu Oct 23 15:06:11 2014 @@ -453,7 +453,6 @@ """Check if the container is empty.""" # Set attributes. - if hasattr(self, 'mol_name'): return False if hasattr(self, 'file_name'): return False if hasattr(self, 'file_path'): return False if hasattr(self, 'file_mol_num'): return False Modified: branches/frame_order_cleanup/lib/structure/internal/object.py URL: http://svn.gna.org/viewcvs/relax/branches/frame_order_cleanup/lib/structure/internal/object.py?rev=26387&r1=26386&r2=26387&view=diff ============================================================================== --- branches/frame_order_cleanup/lib/structure/internal/object.py (original) +++ branches/frame_order_cleanup/lib/structure/internal/object.py Thu Oct 23 15:06:11 2014 @@ -1622,6 +1622,17 @@ for k in range(len(mol.bonded[j])): mol.bonded[j][k] -= 1 + # Reset the metadata if nothing remains. + if mol.atom_num == []: + if hasattr(mol, 'file_name'): + del mol.file_name + if hasattr(mol, 'file_path'): + del mol.file_path + if hasattr(mol, 'file_mol_num'): + del mol.file_mol_num + if hasattr(mol, 'file_model'): + del mol.file_model + # Nothing more to do. if not len(del_res_nums): return @@ -2628,7 +2639,7 @@ # Loop over the molecules of the first model. index = 0 - for mol in self.structural_data[0].mol: + for mol in self.structural_data[0].mol_loop(): # Check the validity of the data. self._validate_data_arrays(mol) @@ -2816,7 +2827,7 @@ # Loop over the molecules. index = 0 atom_serial = 0 - for mol in model.mol: + for mol in model.mol_loop(): # Print out. print("ATOM, HETATM, TER") @@ -2897,7 +2908,7 @@ # The per molecule incremented atom counts. atom_counts = [0] index = 0 - for mol in self.structural_data[0].mol: + for mol in self.structural_data[0].mol_loop(): if index == 0: atom_counts.append(len(mol.atom_name)) else: @@ -2906,7 +2917,7 @@ # Loop over the molecules of the first model. index = 0 - for mol in self.structural_data[0].mol: + for mol in self.structural_data[0].mol_loop(): # Loop over the atoms. for i in range(len(mol.atom_name)): # No bonded atoms, hence no CONECT record is required. Modified: branches/frame_order_cleanup/test_suite/system_tests/structure.py URL: http://svn.gna.org/viewcvs/relax/branches/frame_order_cleanup/test_suite/system_tests/structure.py?rev=26387&r1=26386&r2=26387&view=diff ============================================================================== --- branches/frame_order_cleanup/test_suite/system_tests/structure.py (original) +++ branches/frame_order_cleanup/test_suite/system_tests/structure.py Thu Oct 23 15:06:11 2014 @@ -377,6 +377,40 @@ # CoM. self.assertRaises(RelaxNoPdbError, self.interpreter.structure.com) + + + def test_bug_22861_PDB_writing_chainID_fail(self): + """Catch U{bug #22861<https://gna.org/bugs/?22861>}, the chain IDs in the structure.write_pdb user function PDB files are incorrect after calling structure.delete.""" + + # Add one atom to two different molecules. + self.interpreter.structure.add_atom(mol_name='A', atom_name='N', res_name='Phe', res_num=1, pos=[1.0, 1.0, 1.0], element='N') + self.interpreter.structure.add_atom(mol_name='B', atom_name='N', res_name='Phe', res_num=1, pos=[1.0, 1.0, 1.0], element='N') + + # Add some metadata to demonstrate a problem with the structure.delete user function. + cdp.structure.structural_data[0].mol[0].file_name = 'test.pdb' + cdp.structure.structural_data[0].mol[1].file_name = 'test2.pdb' + + # Delete the first molecule. + self.interpreter.structure.delete('#A') + + # Create a PDB file. + file = DummyFileObject() + self.interpreter.structure.write_pdb(file=file, force=True) + + # The file contents, without remarks, as they should be. + contents = [ + "ATOM 1 N Phe A 1 1.000 1.000 1.000 1.00 0.00 N \n", + "TER 2 Phe A 1 \n", + "MASTER 0 0 0 0 0 0 0 0 1 1 0 0 \n", + "END \n" + ] + + # Check the created PDB file. + lines = file.readlines() + self.strip_remarks(lines) + self.assertEqual(len(contents), len(lines)) + for i in range(len(lines)): + self.assertEqual(contents[i], lines[i]) def test_collapse_ensemble(self):