// $Id: Chain.java,v 1.8 2007/02/19 07:31:05 Sasha Buzko Exp $ // // Copyright (c) 2000-2004 San Diego Supercomputer Center (SDSC), // a facility operated by the University of California, // San Diego (UCSD), San Diego, California, USA. // // Users and possessors of this source code are hereby granted a // nonexclusive, royalty-free copyright and design patent license to // use this code in individual software. License is not granted for // commercial resale, in whole or in part, without prior written // permission from SDSC. This source is provided "AS IS" without express // or implied warranty of any kind. // // For further information, please see: http://mbt.sdsc.edu // // History: // $Log: Chain.java,v $ // Revision 1.8 2007/02/19 07:31:05 Sasha Buzko // *** empty log message *** // // Revision 1.7 2007/02/18 05:08:04 Sasha Buzko // *** empty log message *** // // Revision 1.6 2007/02/13 19:08:41 Sasha Buzko // *** empty log message *** // // Revision 1.5 2007/02/09 18:18:17 Sasha Buzko // *** empty log message *** // // Revision 1.4 2007/02/09 05:08:53 Sasha Buzko // *** empty log message *** // // Revision 1.3 2006/11/21 01:02:05 Sasha Buzko // *** empty log message *** // // Revision 1.2 2006/08/11 16:44:50 Sasha Buzko // *** empty log message *** // // Revision 1.1 2006/05/20 17:02:07 Sasha Buzko // Updated version // // Revision 1.1 2006/04/30 20:14:05 Sasha Buzko // New version of the app // // Revision 1.1 2006/04/15 19:42:27 Sasha Buzko // Initial commit // // Revision 1.2 2005/11/13 23:44:31 Administrator // *** empty log message *** // // Revision 1.1 2005/11/13 04:35:24 Administrator // *** empty log message *** // // Revision 1.25 2004/01/31 19:11:48 moreland // Removed outdated programming note. // // Revision 1.24 2004/01/29 17:08:15 moreland // Updated copyright and class block comments. // // Revision 1.23 2004/01/16 23:05:14 moreland // Added exception handling for (startResidue > endResidue) condition. // // Revision 1.22 2004/01/15 00:47:02 moreland // Added more bounds checking and exception handling in the setFragment method. // // Revision 1.21 2003/12/20 00:59:21 moreland // The generateFragments method now sets the parent Fragment for each Residue. // // Revision 1.20 2003/12/09 21:17:50 moreland // Commented out debug print statements. // // Revision 1.19 2003/11/20 21:31:40 moreland // Added setChain, getChain, getResidueCount and getResidue methods to Fragment. // Added call to fragment.setChain method to Chain class. // Both changes above enable the Fragment class to access parent and child objects. // // Revision 1.18 2003/10/06 23:12:44 moreland // Cleaned up code to generate Fragments in StructureMap so that Fragments are set // as complete ranges (instead of individual residues - which didn't work well). // // Revision 1.17 2003/10/03 23:59:16 moreland // Added support for setCollapseOn flag to maintain fragment integrity. // // Revision 1.16 2003/10/01 21:16:15 agramada // Changes made by John M in the generating of fragments when derived from // data. // // Revision 1.15 2003/09/19 22:27:13 moreland // Added getResidueIndex method by using the residueToIndexHash Hashtable. // // Revision 1.14 2003/09/16 17:18:22 moreland // Added code to enable secondary structure generation from data VS derivation. // // Revision 1.13 2003/09/11 19:40:42 moreland // Set "structure" field when a new Fragment object is created. // // Revision 1.12 2003/07/21 20:48:09 moreland // Added getFragment method which returns a Fragment object. // // Revision 1.11 2003/06/24 23:32:14 moreland // Added null alphaAtom checks to resetFragments method. // // Revision 1.10 2003/04/30 17:48:52 moreland // Changed default chain id from "A" to "-" (bourne). // // Revision 1.9 2003/04/28 21:56:34 moreland // If the fragmentType is a real conformation type (Helix, Turn, Strand) and the // fragment only covers one residue, then replace the fragment type with Coil. // // Revision 1.8 2003/04/25 17:28:29 moreland // Fragment methods check "fragments" field rather than "residues" field for null-ness. // // Revision 1.7 2003/04/25 00:56:09 moreland // Added code to resetFragments method to fill gaps after conformations are applied. // // Revision 1.6 2003/04/24 21:07:02 moreland // Added gap/Coil/fragment filling code to resetFragments method. // // Revision 1.5 2003/04/24 17:56:22 moreland // Corrected private VS public declaration in fragment methods. // // Revision 1.4 2003/04/24 17:52:47 moreland // Corrected spelling error of Fragment routines. // // Revision 1.3 2003/04/24 17:11:54 moreland // Added secondary structure conformation fragment support. // // Revision 1.2 2003/04/23 17:20:10 moreland // Removed StructureComponentID/scid and replaced it with a "structure" field // in the StructureComponent base class. // Changed "getType" method to "getStructureComponentType" to return dynamic // SC type (ie: class name). // Enabled adding/removing of Residue objects. // // Revision 1.1 2003/04/03 23:08:40 moreland // First version. // // Revision 1.0 2002/10/24 17:54:01 moreland // First implementation. // package edu.sdsc.mbt; // MBT import edu.sdsc.mbt.util.*; import edu.sdsc.mbt.viewables.*; // Core import java.util.*; /** * Implements a StructureComponent container for chain information. * This may be an amino acid chain (eg: protein), a nucleic acid * chain (eg: RNA/DNA), or a ligand chain. * This class contains a list of Residue records. *

* @author John L. Moreland * @see edu.sdsc.mbt.Residue * @see edu.sdsc.mbt.StructureComponent * @see edu.sdsc.mbt.Structure * @see edu.sdsc.mbt.StructureMap */ public class Chain extends StructureComponent implements java.lang.Cloneable { // The Residue records for the chain. private Vector residues = null; // The residue-to-index hash for the chain. private Hashtable residueToIndexHash = null; // The default chain id. private static final String defaultChainId = "_"; public String id = null;//internal chain id number given when the chain is instantiated and used to reference it instead of the "public" id //the reason is that public ids may be the same (or absent) for a number of chains within the same structure). This way, we do not restrict //the structure to having chains with only unique ids (which frequently becomes a problem). //String id is a String representation of an integer /** * Secondary structure conformation fragments. * This fragment map can be assigned in one of two ways: *

* 1) From the Structure's conformation record assignments * (asigned to each Residue) by calling the resetFragments method.
* OR
* 2) By explictly assigning fragment ranges by calling * the setFragment method to configure ranges. *

*/ private RangeMap fragments = null; private Vector fragmentObjects = null; // // Constructors // /** * Construct a Chain. */ public Chain( ) { } // // StructureComponent methods. // /** * Copy all of the field values from the parameter object into "this". */ public void copy( StructureComponent structureComponent ) { structure = structureComponent.structure; Chain chain = (Chain) structureComponent; // xxx = chain.xxx; } /** * Clone this object. */ public Object clone( ) throws CloneNotSupportedException { return super.clone( ); } private static String className = null; /** * This method returns the fully qualified name of this class. *

* This name is used by the StructureComponentRegistry class to enable * dynamic registration and discovery of new StructureComponent * sub-classes/types. The name is also used to create a unique integer * indentifier for each type in order to make run-time type comparisons * fast. */ public static String getClassName() { if ( className == null ) className = ((new Throwable()).getStackTrace())[0].getClassName(); return className; } /** * This method returns the fully qualified name of this class. */ public String getStructureComponentType( ) { return className; } // // Chain methods. // /** * Return the chain classification by asking the first residue. * (eg: amino acid, nucleic acid, ligand). If there are no residues * in this chain, this method will return null. */ public String getClassification( ) { if ( residues == null ) return null; int residueCount = residues.size( ); if ( residueCount <= 0 ) return null; // Classify the chain based upon how many residues of each type exist. int classTypes = Residue.COMPOUND_CLASSIFICATIONS.length; int classTalies[] = new int[classTypes]; for ( int r=0; r highestCount ) { highestCount = classTalies[c]; highestIndex = c; } } if ( highestIndex < 0 ) return null; return Residue.COMPOUND_CLASSIFICATIONS[highestIndex]; } /** * Return the chain ID by asking the first Atom of the first Residue. * If there are no residues or atoms, "A" is returned. */ public String getChainId( ) { if ( residues == null ) return defaultChainId; Residue residue = getResidue( 0 ); if ( residue == null ) return defaultChainId; int atomCount = residue.getAtomCount( ); if ( atomCount <= 0 ) return defaultChainId; Atom atom = residue.getAtom( 0 ); if ( atom == null ) return defaultChainId; return atom.chain_id; } /** * Get the number of Atoms contained in the Residues of this Chain. */ public int getAtomCount( ) { int atomCount = 0; int residueCount = getResidueCount( ); for ( int r=0; r= residues.size()) return null; return (Residue) residues.elementAt( index ); } /** * Return the specified Residue index in this Chain. */ public int getResidueIndex( Residue residue ) { if ( residues == null ) throw new IndexOutOfBoundsException( "chain has no residues" ); Integer integer = (Integer) residueToIndexHash.get( residue ); if ( integer == null ) return -1; return integer.intValue( ); } /** * Add a Residue record to this Chain. */ public void addResidue( Residue residue ) { if ( residue == null ) throw new IllegalArgumentException( "null residue" ); if ( false /* TODO: CAN'T ENFORCE MISMATCH residues != null */ ) { if ( residue.getClassification() != getClassification() ){ throw new IllegalArgumentException("classification mismatch: " + residue.getClassification() + " != " + getClassification()); } } if ( residues == null ){ residues = new Vector( ); residueToIndexHash = new Hashtable( ); } residues.add(residue); residueToIndexHash.put( residue, new Integer( residues.size() ) ); if ( fragments == null ){ fragments = new RangeMap( 0, 0, Conformation.TYPE_UNDEFINED ); fragments.setCollapseOn( false ); // Don't append the first value othewise we'll have an invalid rangeMax. fragments.setValue( 0, residue.getConformationType() ); } else { fragments.append( residue.getConformationType() ); } fragmentObjects = null; // Invalidate the old fragmentObjects. } /** * Add a Residue record to this Chain at the specified position. */ public void addResidue( Residue residue, int position ){ if ( residue == null ) return; if ( residues == null ){ residues = new Vector( ); residueToIndexHash = new Hashtable( ); position = 1;//since there is no other residue, let's assume it's 1 } boolean inserted = false; int counter = 0; for (int i = 0; i < residues.size(); i++){ Residue r = (Residue)residues.get(i); counter++; if (counter == position){ if (!inserted){ //insert the new residue before the current one residues.insertElementAt(residue, i);//insert instead of the current residue and shift everything up inserted = true; } break; } } residueToIndexHash.put( residue, new Integer( residue.getResidueId() ) ); if ( fragments == null ){ fragments = new RangeMap( 0, 0, Conformation.TYPE_UNDEFINED ); fragments.setCollapseOn( false ); // Don't append the first value othewise we'll have an invalid rangeMax. fragments.setValue( 0, residue.getConformationType() ); } else { fragments.clearAll(); for (int i = 0; i < residues.size(); i++){ Residue r = (Residue)residues.get(i); fragments.append( r.getConformationType() ); } } fragmentObjects = null; // Invalidate the old fragmentObjects. } /** * Remove all Residue records from this Chain. */ public void removeAllResidues( ) { if ( residues == null ) return; residues.removeAllElements( ); residues = null; residueToIndexHash = null; // Toss the fragments map. fragments = null; fragmentObjects = null; // Invalidate the old fragmentObjects. // TODO: Should we fire a StructureComponentEvent here? } /** * Remove the specified Residue record from this Chain. */ public void removeResidue( int index ) { if ( residues == null ) throw new IndexOutOfBoundsException( "chain has no residues" ); Residue residue = (Residue) residues.elementAt( index ); residueToIndexHash.remove( residue ); residues.remove( residue ); // Remove the corresponding fragment entry. fragments.remove( index ); if ( getResidueCount() == 0 ) fragments = null; fragmentObjects = null; // Invalidate the old fragmentObjects. // TODO: Should we fire a StructureComponentEvent here? } public void removeResidue( Residue residue){ if (residue == null) return; int index = this.getResidueIndex(residue); residueToIndexHash.remove( residue ); residues.remove( residue ); // System.out.println("fragments size = " + fragments.getRangeCount()); // Remove the corresponding fragment entry. try{ fragments.remove( index ); } catch (Exception e){ // e.printStackTrace(); } if ( getResidueCount() == 0 ) fragments = null; fragmentObjects = null; // Invalidate the old fragmentObjects. } // // Secondary structure conformation fragments. // /** * Set a range of residues in this chain's fragment map to the specified * Conformation type. *

*/ public void setFragment( int startResidue, int endResidue, String type ) { if ( residues == null ) throw new IndexOutOfBoundsException( "chain has no residues" ); if ( startResidue < 0 ){ startResidue = 0; // return; } // throw new IndexOutOfBoundsException( "start index < 0" ); if ( endResidue >= getResidueCount( ) ){ endResidue = getResidueCount() - 1; // return; } // throw new IndexOutOfBoundsException( "end index >= residue count" ); if ( startResidue > endResidue ){ return; } // throw new IllegalArgumentException( "start > end (" + startResidue // + ">" + endResidue + ")" ); fragmentObjects = null; // Invalidate the old fragmentObjects. fragments.setRange( startResidue, endResidue, type ); // Make sure that we set each underlying residue's conformation // assignment to match the new fragment assignment! for ( int r=startResidue; r<=endResidue; r++ ) { Residue residue = getResidue( r ); residue.setConformationType( type ); } // TODO: Should we fire a StructureComponentEvent here? } /** * Get the number of fragments (residue ranges) currently assigned to this chain. *

*/ public int getFragmentCount( ) { if ( residues == null ) return 0; if ( fragments == null ) return 0; return fragments.getRangeCount( ); } /** * Get the conformation type currently assigned to the given fragment. *

*/ public String getFragmentType( int fragmentIndex ) { if ( fragments == null ) throw new IndexOutOfBoundsException( "chain has no fragments" ); return (String) fragments.getRangeValue( fragmentIndex ); } /** * Get the start residue index for the given fragment. *

*/ public int getFragmentStartResidue( int fragmentIndex ) { if ( fragments == null ) throw new IndexOutOfBoundsException( "chain has no fragments" ); return fragments.getRangeStart( fragmentIndex ); } /** * Get the end residue index for the given fragment. *

*/ public int getFragmentEndResidue( int fragmentIndex ) { if ( fragments == null ) throw new IndexOutOfBoundsException( "chain has no fragments" ); return fragments.getRangeEnd( fragmentIndex ); } /** * Regenerate the vector of Fragment objects from the fragments RangeMap. *

*/ public void generateFragments( ) { if ( fragments == null ) return; // // Clear the current fragmentObjects list. // Any existing Fragment object for this Chain are now invalid! // // TODO: Should we fire a "remove" StructureComponentEvent here? if ( fragmentObjects != null ) fragmentObjects.clear( ); int fragmentCount = getFragmentCount( ); fragmentObjects = new Vector( fragmentCount ); for ( int i=0; i */ public Fragment getFragment( int fragmentIndex ){ if ( fragmentObjects == null ) generateFragments( ); return (Fragment) fragmentObjects.elementAt( fragmentIndex ); } /** * Get the fragments for this chain. *

*/ public Vector getFragments( ){ Vector frags = new Vector( ); int count = getFragmentCount( ); for ( int i=0; i