pl.poznan.put.pdb.analysis.AbstractPdbModel Maven / Gradle / Ivy
package pl.poznan.put.pdb.analysis;
import pl.poznan.put.pdb.PdbAtomLine;
import pl.poznan.put.pdb.PdbRemark465Line;
import pl.poznan.put.pdb.PdbResidueIdentifier;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/** A structure which detects residues from atoms alone and then chains from residues. */
public abstract class AbstractPdbModel implements PdbModel {
/**
* Groups together residues in the same chain and repeat that for every chain.
*
* @return A list of chains in the structure.
*/
@Override
public List chains() {
final Map> chainResidues = new LinkedHashMap<>();
residues()
.forEach(
residue -> {
chainResidues.putIfAbsent(residue.chainIdentifier(), new ArrayList<>());
chainResidues.get(residue.chainIdentifier()).add(residue);
});
return chainResidues.values().stream()
.flatMap(residueGroup -> residueGroupToChains(residueGroup).stream())
.collect(Collectors.toList());
}
/**
* Groups together atoms from the same residue and repeat that for every residue.
*
* @return A list of residues in the structure.
*/
@Override
public List residues() {
// group atoms by common (chain, number, icode)
final Map> atomGroups = new LinkedHashMap<>();
atoms()
.forEach(
atom -> {
atomGroups.putIfAbsent(PdbResidueIdentifier.from(atom), new ArrayList<>());
atomGroups.get(PdbResidueIdentifier.from(atom)).add(atom);
});
// create residues out of atom groups and leave only those detected as nucleotides or amino
// acids
final Stream existingResidueStream =
atomGroups.values().stream()
.map(this::atomGroupToResidue)
.filter(
residue ->
residue.residueInformationProvider().moleculeType() != MoleculeType.UNKNOWN);
// create residues out of information about missing residues in the headers
final Stream missingResidueStream =
missingResidues().stream().map(PdbRemark465Line::toResidue);
// maintain chain order from the input file
final List order =
atoms().stream().map(PdbAtomLine::chainIdentifier).distinct().collect(Collectors.toList());
// create a list of residues
// the comparator applies chain order, but within a chain it goes back to
// ChainNumberICode::compareTo in order to put missing residues in correct places
return Stream.concat(existingResidueStream, missingResidueStream)
.sorted(
(t, t1) -> {
if (t.chainIdentifier().equals(t1.chainIdentifier())) return t.compareTo(t1);
return Integer.compare(
order.indexOf(t.chainIdentifier()), order.indexOf(t1.chainIdentifier()));
})
.collect(Collectors.toList());
}
private PdbResidue atomGroupToResidue(final List residueAtoms) {
final PdbResidueIdentifier residueIdentifier = PdbResidueIdentifier.from(residueAtoms.get(0));
final boolean isModified = isModified(residueIdentifier);
final String residueName = residueAtoms.get(0).residueName();
final String modifiedResidueName =
isModified ? modificationDetails(residueIdentifier).standardResidueName() : residueName;
return ImmutableDefaultPdbResidue.of(
residueIdentifier, residueName, modifiedResidueName, residueAtoms);
}
private List residueGroupToChains(final List residueGroup) {
final List chains = new ArrayList<>();
final List branchingPoints =
IntStream.range(0, residueGroup.size())
.filter(
i ->
chainTerminatedAfter().contains(PdbResidueIdentifier.from(residueGroup.get(i))))
.boxed()
.collect(Collectors.toList());
int begin = 0;
for (final int branchingPoint : branchingPoints) {
// move `end` past all missing residues after TER line
int end = branchingPoint + 1;
for (; end < residueGroup.size() && residueGroup.get(end).isMissing(); end++)
;
chains.add(
ImmutablePdbChain.of(
residueGroup.get(0).chainIdentifier(), residueGroup.subList(begin, end)));
begin = end;
}
if (begin < residueGroup.size()) {
chains.add(
ImmutablePdbChain.of(
residueGroup.get(0).chainIdentifier(),
residueGroup.subList(begin, residueGroup.size())));
}
return chains;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy