/*
* BioJava development code
*
* This code may be freely distributed and modified under the
* terms of the GNU Lesser General Public Licence. This should
* be distributed with the code. If you do not have a copy,
* see:
*
* http://www.gnu.org/copyleft/lesser.html
*
* Copyright for this code is held jointly by the individual
* authors. These should be listed in @author doc comments.
*
* For more information on the BioJava project and its aims,
* or to join the biojava-l mailing list, visit the home page
* at:
*
* http://www.biojava.org/
*
*/
package org.biojava.nbio.structure.align.util;
import org.biojava.nbio.structure.*;
import org.biojava.nbio.structure.io.LocalPDBDirectory;
import org.biojava.nbio.structure.io.LocalPDBDirectory.FetchBehavior;
import org.biojava.nbio.structure.io.LocalPDBDirectory.ObsoleteBehavior;
import org.biojava.nbio.structure.io.MMCIFFileReader;
import org.biojava.nbio.structure.scop.ScopDatabase;
import org.biojava.nbio.structure.scop.ScopFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import static org.junit.Assert.*;
/**
* A test for {@link AtomCache}.
* @author dmyerstu
* @since 3.0.6
*/
public class AtomCacheTest {
private AtomCache cache;
private String previousPDB_DIR;
@Before
public void setUp() {
previousPDB_DIR = System.getProperty(UserConfiguration.PDB_DIR, null);
cache = new AtomCache();
cache.setObsoleteBehavior(ObsoleteBehavior.FETCH_OBSOLETE);
// Use a fixed SCOP version for stability
ScopFactory.setScopDatabase(ScopFactory.VERSION_1_75B);
}
@After
public void tearDown() {
if (previousPDB_DIR != null)
System.setProperty(UserConfiguration.PDB_DIR, previousPDB_DIR);
}
/**
* Tests {@link AtomCache#getStructureForDomain(String)} on a multi-chain domain with no ligands but an explicit range (not whole-chain).
*/
@Test
public void testGetStructureForDomain1() throws IOException, StructureException {
String ranges = "A:328-396,B:518-527";
Structure whole = cache.getStructure("1h6w");
AtomPositionMap map = new AtomPositionMap(StructureTools.getAllAtomArray(whole), AtomPositionMap.ANYTHING_MATCHER);
List<ResidueRangeAndLength> rrs = ResidueRangeAndLength.parseMultiple(ranges, map);
int expectedLengthA = rrs.get(0).getLength();
int expectedLengthB = rrs.get(1).getLength();
Structure structure = cache.getStructureForDomain("d1h6w.2");
assertEquals(2, structure.getPolyChains().size());
Chain a = structure.getPolyChainByPDB("A");
Chain b = structure.getPolyChainByPDB("B");
assertEquals(expectedLengthA, a.getAtomGroups().size());
assertEquals(expectedLengthB, b.getAtomGroups().size());
}
/**
* Tests {@link AtomCache#getStructureForDomain(String)} on a multi-chain domain with two zinc ligands that occurs after the TER. The ligands are in chains E and F, so they should not be included in the domain.
*/
@Test
public void testGetStructureForDomain2() throws IOException, StructureException {
String ranges = "A:,B:";
Structure whole = cache.getStructure("1I3O");
AtomPositionMap map = new AtomPositionMap(StructureTools.getAllAtomArray(whole), AtomPositionMap.ANYTHING_MATCHER);
List<ResidueRangeAndLength> rrs = ResidueRangeAndLength.parseMultiple(ranges, map);
int expectedLengthA = rrs.get(0).getLength();
int expectedLengthB = rrs.get(1).getLength();
Structure structure = cache.getStructureForDomain("d1i3o.1");
assertEquals(2, structure.getPolyChains().size());
Chain a = structure.getPolyChainByPDB("A");
Chain b = structure.getPolyChainByPDB("B");
// since biojava 5.0 we have no ligand or water molecules in the polymer chains, we have to subtract the 3 water molecules
assertEquals(expectedLengthA - 3, a.getAtomGroups().size());
// since biojava 5.0 we have no ligand or water molecules in the polymer chains, we have to subtract the 4 water molecules
assertEquals(expectedLengthB - 4, b.getAtomGroups().size());
List<Group> ligandsA = StructureTools.filterLigands(b.getAtomGroups());
assertEquals(0, ligandsA.size());
List<Group> ligandsB = StructureTools.filterLigands(b.getAtomGroups());
assertEquals(0, ligandsB.size());
}
/**
* Tests {@link AtomCache#getStructureForDomain(String)} on a single-chain domain with two zinc ligands that occurs after the TER.
*/
@Test
public void testGetStructureForDomain3() throws IOException, StructureException {
String ranges = "E:";
Structure whole = cache.getStructure("1I3O");
AtomPositionMap map = new AtomPositionMap(StructureTools.getAllAtomArray(whole), AtomPositionMap.ANYTHING_MATCHER);
List<ResidueRangeAndLength> rrs = ResidueRangeAndLength.parseMultiple(ranges, map);
int expectedLengthE = rrs.get(0).getLength();
Structure structure = cache.getStructureForDomain("d1i3oe_");
assertEquals(1, structure.getPolyChains().size());
Chain e = structure.getPolyChainByPDB("E");
// since biojava 5.0 we have no ligand molecules in the polymer chains, we have to subtract the 2 zinc molecules
assertEquals(expectedLengthE - 2, e.getAtomGroups().size());
Chain eligands = structure.getNonPolyChainsByPDB("E").get(0);
List<Group> ligandsE = StructureTools.filterLigands(eligands.getAtomGroups());
assertEquals(1, ligandsE.size());
}
/**
* Test parsing of chain-less ranges (present in SCOP < 1.73)
* @throws IOException
* @throws StructureException
*/
@Test
public void testGetStructureForChainlessDomains() throws IOException, StructureException {
ScopDatabase scop = ScopFactory.getSCOP(ScopFactory.VERSION_1_71); // Uses the range '1-135' without a chain
Structure structure = cache.getStructureForDomain("d1hcy_1",scop);
//System.out.println(cache.getStructure("1hcy"));
//System.out.println(structure);
assertEquals(1, structure.getPolyChains().size());
Chain a = structure.getPolyChainByPDB("A");
int expectedLengthA = 135;
assertEquals(expectedLengthA, a.getAtomGroups().size());
assertTrue(structure.hasNonPolyChain("M"));
assertTrue(structure.hasNonPolyChain("N"));
Chain copper = structure.getNonPolyChain("M");
assertEquals(1,copper.getAtomGroups().size());
}
@Test
public void testSetPath_withTilde() throws Exception {
cache.setPath("~" + File.separator);
assertEquals(System.getProperty("user.home") + File.separator, cache.getPath());
}
@Test
public void testNewInstanceWithTilder() throws Exception {
AtomCache cache1 = new AtomCache("~" + File.separator);
assertEquals(System.getProperty("user.home") + File.separator, cache1.getPath());
}
@Test
public void testFetchBehavior() throws IOException, ParseException {
// really more of a LocalPDBDirectory test, but throw it in with AtomCache
String pdbId = "1hh0"; // A small structure, since we download it multiple times
LocalPDBDirectory reader = new MMCIFFileReader(cache.getPath());
// delete
reader.deleteStructure(pdbId);
assertNull("Failed to delete previous version",reader.getLocalFile(pdbId));
// LOCAL_ONLY fails
reader.setFetchBehavior(FetchBehavior.LOCAL_ONLY);
Structure s;
try {
s = reader.getStructureById(pdbId);
fail("LOCAL_ONLY shouldn't download files");
} catch(IOException e) {
assertTrue("Wrong IOException reason", e.getMessage().contains("configured not to download"));
}
// delete
reader.deleteStructure(pdbId);
assertNull("Failed to delete previous version",reader.getLocalFile(pdbId));
// fetch from server
reader.setFetchBehavior(FetchBehavior.FETCH_FILES);
s = reader.getStructureById(pdbId);
assertNotNull("Failed to fetch structure",s);
File location = reader.getLocalFile(pdbId);
long prerem = LocalPDBDirectory.LAST_REMEDIATION_DATE-1000*60*60*25; // 25 hours before the remediation
location.setLastModified(prerem);
assertEquals(prerem,location.lastModified()); //sanity check
// force refetching
reader.setFetchBehavior(FetchBehavior.FORCE_DOWNLOAD);
s = reader.getStructureById(pdbId);
assertNotNull("Failed to fetch structure",s);
location = reader.getLocalFile(pdbId);
assertTrue(location.exists());
long currMod = location.lastModified();
assertTrue("Not re-downloaded", currMod > prerem);
// Now LOCAL_ONLY should work
reader.setFetchBehavior(FetchBehavior.LOCAL_ONLY);
s = reader.getStructureById(pdbId);
assertNotNull("Failed to fetch structure",s);
// Check remediation
location.setLastModified(prerem);
// Shouldn't re-fetch
reader.setFetchBehavior(FetchBehavior.FETCH_FILES);
s = reader.getStructureById(pdbId);
location = reader.getLocalFile(pdbId);
assertTrue(location.exists());
assertEquals("Falsely re-downloaded", prerem,location.lastModified());
// Now should re-fetch
reader.setFetchBehavior(FetchBehavior.FETCH_REMEDIATED);
s = reader.getStructureById(pdbId);
assertNotNull("Failed to fetch structure",s);
location = reader.getLocalFile(pdbId);
assertTrue(location.exists());
currMod = location.lastModified();
assertTrue("Not re-downloaded", currMod > prerem);
// test FETCH_IF_OUTDATED: change existing file timestamp to 2000 and try refetching (the file is from March 2009)
SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd", Locale.US);
Date d = formatter.parse("2000/01/01");
location.setLastModified(d.getTime());
reader.setFetchBehavior(FetchBehavior.FETCH_IF_OUTDATED);
s = reader.getStructureById(pdbId);
assertNotNull("Failed to fetch structure",s);
currMod = location.lastModified();
assertTrue("Not re-downloaded", currMod>d.getTime());
// try again: should not download
reader.setFetchBehavior(FetchBehavior.FETCH_IF_OUTDATED);
location = reader.getLocalFile(pdbId);
currMod = location.lastModified();
s = reader.getStructureById(pdbId);
assertEquals("Falsely re-downloaded", currMod, location.lastModified());
}
@Test
public void testSeqRes() throws StructureException, IOException {
String name;
StructureIdentifier id;
Structure full, reduced;
Chain chain;
List<Group> seqres;
// normal structure
name = "1hh0";
id = new SubstructureIdentifier(name);
full = id.loadStructure(cache);
assertEquals("Wrong number of models in full "+name,1,full.nrModels());
assertEquals("Wrong number of chains in full "+name,1,full.getChains().size());
chain = full.getChainByIndex(0);
seqres = chain.getSeqResGroups();
assertEquals("Wrong seqres length in full "+name,46,seqres.size());
reduced = id.reduce(full);
assertEquals("Wrong number of models in reduced "+name,1,reduced.nrModels());
assertEquals("Wrong number of chains in reduced "+name,1,reduced.getChains().size());
chain = reduced.getChainByIndex(0);
seqres = chain.getSeqResGroups();
assertEquals("Wrong seqres length in reduced "+name,46,seqres.size());
// single chain
name = "1hh0.A";
id = new SubstructureIdentifier(name);
full = id.loadStructure(cache);
assertEquals("Wrong number of models in full "+name,1,full.nrModels());
assertEquals("Wrong number of chains in full "+name,1,full.getChains().size());
chain = full.getChainByIndex(0);
seqres = chain.getSeqResGroups();
assertEquals("Wrong seqres length in full "+name,46,seqres.size());
reduced = id.reduce(full);
assertEquals("Wrong number of models in reduced "+name,1,reduced.nrModels());
assertEquals("Wrong number of chains in reduced "+name,1,reduced.getChains().size());
chain = reduced.getChainByIndex(0);
seqres = chain.getSeqResGroups();
assertEquals("Wrong seqres length in reduced "+name,46,seqres.size());
// subrange
name = "1hh0.A:10-20";
id = new SubstructureIdentifier(name);
full = id.loadStructure(cache);
assertEquals("Wrong number of models in full "+name,1,full.nrModels());
assertEquals("Wrong number of chains in full "+name,1,full.getChains().size());
chain = full.getChainByIndex(0);
seqres = chain.getSeqResGroups();
assertEquals("Wrong seqres length in full "+name,46,seqres.size());
assertEquals("Wrong SeqNum at first group in full",1,(int)chain.getAtomGroup(0).getResidueNumber().getSeqNum());
reduced = id.reduce(full);
assertEquals("Wrong number of models in reduced "+name,1,reduced.nrModels());
assertEquals("Wrong number of chains in reduced "+name,1,reduced.getChains().size());
chain = reduced.getChainByIndex(0);
seqres = chain.getSeqResGroups();
assertEquals("Wrong seqres length in reduced "+name,46,seqres.size());
assertEquals("Wrong SeqNum at first group in reduced",10,(int)chain.getAtomGroup(0).getResidueNumber().getSeqNum());
}
}