diff --git a/src/mol-model/structure/model/properties/seconday-structure.ts b/src/mol-model/structure/model/properties/seconday-structure.ts index 45f9a41cf78b1efe985889b10e3127e2170df469..bbadc038b15dd391c09fdae5debc08d021dcbd2d 100644 --- a/src/mol-model/structure/model/properties/seconday-structure.ts +++ b/src/mol-model/structure/model/properties/seconday-structure.ts @@ -13,7 +13,9 @@ interface SecondaryStructure { /** index into the elements array */ readonly key: ArrayLike<number>, /** indexed by key */ - readonly elements: ReadonlyArray<SecondaryStructure.Element> + readonly elements: ReadonlyArray<SecondaryStructure.Element>, + /** string representation of DSSP annotation */ + readonly dsspString: String } namespace SecondaryStructure { diff --git a/src/mol-model/structure/model/properties/utils/secondary-structure.ts b/src/mol-model/structure/model/properties/utils/secondary-structure.ts index cbc23b4db5f283a2dbbc3a4ba38529e754ddf78f..afb3f4aedb619d48313ae02d8c623f6bf0e03d54 100644 --- a/src/mol-model/structure/model/properties/utils/secondary-structure.ts +++ b/src/mol-model/structure/model/properties/utils/secondary-structure.ts @@ -85,10 +85,8 @@ export function computeModelDSSP(hierarchy: AtomicHierarchy, const assign = assignment[i] type[proteinResidues[i]] = assign const flag = getResidueFlag(flags[i]) - // const kind = mapToKind(assign) // TODO is this expected behavior? elements will be strictly split depending on 'winning' flag if (elements.length === 0 || // check ought to fail at very start - // elements[elements.length - 1].kind !== kind || // new element if overall kind changed flag !== (elements[elements.length - 1] as SecondaryStructure.Helix | SecondaryStructure.Sheet).flags) { // exact flag changed elements[elements.length] = createElement(mapToKind(assign), flags[i], getResidueFlag) } @@ -98,24 +96,21 @@ export function computeModelDSSP(hierarchy: AtomicHierarchy, const secondaryStructure: SecondaryStructure = { type, key: keys, - elements: elements + elements: elements, + dsspString: composeDSSPString(flags, getFlagName) } - // console.log(keys) - // console.log(elements) - // printDSSPString(flags, getFlagName) - return secondaryStructure } -// function printDSSPString(flags: Uint32Array, getFlagName: (f: DSSPType) => String) { -// let out = '' -// for (let i = 0, il = flags.length; i < il; ++i) { -// const f = DSSPType.create(flags[i]) -// out += getFlagName(f) -// } -// console.log(out) -// } +function composeDSSPString(flags: Uint32Array, getFlagName: (f: DSSPType) => String) { + let out = '' + for (let i = 0, il = flags.length; i < il; ++i) { + const f = DSSPType.create(flags[i]) + out += getFlagName(f) + } + return out +} function createElement(kind: string, flag: DSSPType.Flag, getResidueFlag: (f: DSSPType) => SecondaryStructureType): SecondaryStructure.Element { // TODO would be nice to add more detailed information @@ -390,22 +385,14 @@ function calculateDihedralAngles(hierarchy: AtomicHierarchy, conformation: Atomi position(caAtomNext, caPosNext) position(nAtomNext, nPosNext) - // const tPhi = calculatePhi(cPosPrev, nPos, caPos, cPos) - // const tPsi = calculatePsi(nPos, caPos, cPos, nPosNext) - // const tOmega = calculateOmega(caPos, cPos, nPosNext, caPosNext) - - // console.log(`phi: ${ tPhi }, psi: ${ tPsi }, omega: ${ tOmega }`) - phi[phi.length] = calculatePhi(cPosPrev, nPos, caPos, cPos) psi[psi.length] = calculatePsi(nPos, caPos, cPos, nPosNext) - // omega[omega.length] = calculateOmega(caPos, cPos, nPosNext, caPosNext) } - return { phi, psi/*, omega*/ }; + return { phi, psi }; } // angle calculations return NaN upon missing atoms -// TODO would be nice to be provided elsewhere, omega is related but not needed here function calculatePhi(c: Vec3, nNext: Vec3, caNext: Vec3, cNext: Vec3) { return Vec3.dihedralAngle(c, nNext, caNext, cNext); } @@ -414,10 +401,6 @@ function calculatePsi(n: Vec3, ca: Vec3, c: Vec3, nNext: Vec3) { return Vec3.dihedralAngle(n, ca, c, nNext); } -// function calculateOmega(ca: Vec3, c: Vec3, nNext: Vec3, caNext: Vec3) { -// return angle(ca, c, nNext, caNext); -// } - function calcBackboneHbonds(hierarchy: AtomicHierarchy, conformation: AtomicConformation, proteinResidues: SortedArray<ResidueIndex>, backboneIndices: BackboneAtomIndices, lookup3d: GridLookup3D): DsspHbonds { const { cIndices, hIndices, nIndices, oIndices } = backboneIndices const { index } = hierarchy @@ -463,7 +446,7 @@ function calcBackboneHbonds(hierarchy: AtomicHierarchy, conformation: AtomicConf const { indices, count } = lookup3d.find(caPos[0], caPos[1], caPos[2], caMaxDist) for (let j = 0; j < count; ++j) { - // if (squaredDistances[j] < caMinDistSq) continue + // if (squaredDistances[j] < caMinDist * caMinDist) continue const nPI = indices[j] @@ -498,7 +481,6 @@ function calcBackboneHbonds(hierarchy: AtomicHierarchy, conformation: AtomicConf const e = calcHbondEnergy(oPos, cPos, nPos, hPos) if (e > hbondEnergyCutoff) continue - // console.log(`detected hbond between ${ oPI } and ${ nPI } with energy ${ e }`) oAtomResidues[oAtomResidues.length] = oPI nAtomResidues[nAtomResidues.length] = nPI energies[energies.length] = e @@ -628,7 +610,6 @@ function assignTurns(ctx: DSSPContext) { const { proteinResidues, hbonds, flags, hierarchy } = ctx const { chains, residueAtomSegments, chainAtomSegments } = hierarchy const { label_asym_id } = chains - // let turns = 0, turnOpenings = 0 const turnFlag = [DSSPType.Flag.T3S, DSSPType.Flag.T4S, DSSPType.Flag.T5S, DSSPType.Flag.T3, DSSPType.Flag.T4, DSSPType.Flag.T5] @@ -644,27 +625,20 @@ function assignTurns(ctx: DSSPContext) { if (!label_asym_id.areValuesEqual(cI, cN)) continue // check if hbond exists - // console.log(`${ i } has ${ idx + 3}-turn opening: ${ hbonds.getDirectedEdgeIndex(i, i + idx + 3) !== -1 }`) if (hbonds.getDirectedEdgeIndex(i, i + idx + 3) !== -1) { - // console.log(`${ idx + 3 }-turn opening at ${ i } to ${ i + idx + 3 }`) flags[i] |= turnFlag[idx + 3] | turnFlag[idx] - // turnOpenings++ if (ctx.oldDefinition) { for (let k = 1; k < idx + 3; ++k) { flags[i + k] |= turnFlag[idx + 3] | DSSPType.Flag.T - // turns++ } } else { for (let k = 0; k <= idx + 3; ++k) { flags[i + k] |= turnFlag[idx + 3] | DSSPType.Flag.T - // turns++ } } } } } - - // console.log(`${ turns } turns, ${ turnOpenings } turn openings`) } /** @@ -734,8 +708,6 @@ function assignBridges(ctx: DSSPContext) { } bridges.sort((a, b) => a.partner1 > b.partner1 ? 1 : a.partner1 < b.partner1 ? -1 : 0) - // console.log(`${ bridges.length } bridges`) - // bridges.forEach(b => console.log(b)) } /** @@ -756,7 +728,6 @@ function assignHelices(ctx: DSSPContext) { const helixFlag = [0, 0, 0, DSSPType.Flag.G, DSSPType.Flag.H, DSSPType.Flag.I] const helixCheckOrder = ctx.oldOrdering ? [4, 3, 5] : [3, 4, 5] - // const count = [0, 0, 0, 0, 0, 0] for (let ni = 0; ni < helixCheckOrder.length; ni++) { const n = helixCheckOrder[ni] @@ -769,35 +740,29 @@ function assignHelices(ctx: DSSPContext) { if (ctx.oldOrdering) { if ((n === 3 && (DSSPType.is(fI, DSSPType.Flag.H) || DSSPType.is(fI2, DSSPType.Flag.H)) || // for 3-10 yield to alpha helix (n === 5 && ((DSSPType.is(fI, DSSPType.Flag.H) || DSSPType.is(fI, DSSPType.Flag.G)) || (DSSPType.is(fI2, DSSPType.Flag.H) || DSSPType.is(fI2, DSSPType.Flag.G)))))) { // for pi yield to all other helices - // console.log('skipping in favor of more preferable helix already present') continue } } else { if ((n === 4 && (DSSPType.is(fI, DSSPType.Flag.G) || DSSPType.is(fI2, DSSPType.Flag.G)) || // for alpha helix yield to 3-10 (n === 5 && ((DSSPType.is(fI, DSSPType.Flag.H) || DSSPType.is(fI, DSSPType.Flag.G)) || (DSSPType.is(fI2, DSSPType.Flag.H) || DSSPType.is(fI2, DSSPType.Flag.G)))))) { // for pi yield to all other helices - // console.log('skipping in favor of more preferable helix already present') continue } } if (DSSPType.is(fI, turnFlag[n]) && DSSPType.is(fI, turnFlag[n - 3]) && // check fI for turn start of proper type DSSPType.is(fI1, turnFlag[n]) && DSSPType.is(fI1, turnFlag[n - 3])) { // check fI1 accordingly - // console.log(`valid hit for ${n} from ${i} to ${i+n}`) if (ctx.oldDefinition) { for (let k = 0; k < n; k++) { flags[i + k] |= helixFlag[n] - // count[n]++ } } else { for (let k = -1; k <= n; k++) { flags[i + k] |= helixFlag[n] - // count[n]++ } } } } } - // console.log(`${ count[3] + count[4] + count[5] } helix elements - ${ count[3] } 3-10, ${ count[4] } alpha, ${ count[5] } pi`) } /** @@ -808,7 +773,6 @@ function assignHelices(ctx: DSSPContext) { function assignLadders(ctx: DSSPContext) { const { bridges, ladders } = ctx - // let ext = 0 // create ladders for (let bridgeIndex = 0; bridgeIndex < bridges.length; bridgeIndex++) { const bridge = bridges[bridgeIndex] @@ -816,7 +780,6 @@ function assignLadders(ctx: DSSPContext) { for (let ladderIndex = 0; ladderIndex < ladders.length; ladderIndex++) { const ladder = ladders[ladderIndex] if (shouldExtendLadder(ladder, bridge)) { - // ext++ found = true ladder.firstEnd++ if (bridge.type === BridgeType.PARALLEL) { @@ -840,7 +803,6 @@ function assignLadders(ctx: DSSPContext) { } } } - // console.log(`${ ext } extension operations`) // connect ladders for (let ladderIndex1 = 0; ladderIndex1 < ladders.length; ladderIndex1++) { @@ -848,14 +810,11 @@ function assignLadders(ctx: DSSPContext) { for (let ladderIndex2 = ladderIndex1; ladderIndex2 < ladders.length; ladderIndex2++) { const ladder2 = ladders[ladderIndex2] if (resemblesBulge(ladder1, ladder2)) { - // console.log(`connecting ladders ${ ladderIndex1 } and ${ ladderIndex2 } with inbetween bulge`) ladder1.nextLadder = ladderIndex2 ladder2.previousLadder = ladderIndex1 } } } - - // console.log(`${ ladders.length } ladders`) } /** @@ -883,18 +842,15 @@ function shouldExtendLadder(ladder: Ladder, bridge: Bridge): boolean { // in order to extend ladders, same type must be present if (bridge.type !== ladder.type) return false - // console.log(`${ bridge.partner1 }-${ bridge.partner2 } ${ ladder.firstEnd }`) // only extend if residue 1 is sequence neighbor with regard to ladder if (bridge.partner1 !== ladder.firstEnd + 1) return false if (bridge.type === BridgeType.PARALLEL) { if (bridge.partner2 === ladder.secondEnd + 1) { - // console.log(ladder) return true } } else { if (bridge.partner2 === ladder.secondStart - 1) { - // console.log(ladder) return true } } diff --git a/src/mol-model/structure/model/properties/utils/secondary-structure.validation b/src/mol-model/structure/model/properties/utils/secondary-structure.validation index 9b76268f33343c71b216674b79e99e6e76d1cf24..4f1a1f1bba2be14065663ee39ef36e21fb2d575a 100644 --- a/src/mol-model/structure/model/properties/utils/secondary-structure.validation +++ b/src/mol-model/structure/model/properties/utils/secondary-structure.validation @@ -70,4 +70,6 @@ DSSP: -------TT----------TT----------------GGGTT------------------------------TT # all # Mol*: --SEEEETTEEEE-EEEEETTEEEEEEEEEE-EE---GGGTTS--EE----SSEEE--S---B-------TTTT-HHHHTTS--S-B-S---EEEEEE-SS--SSEEEEEEE--STTT---S-SGGG-THHHHHHHT-EEEE-----SHHHH---TT-SSS-S-HHHHHHHHHHHHHHHHGGGGTEEEEEEEEEEETHHHHHHHHHHH-HHHHTT-SEEEEES--TTSTTSEEEHHHHHHHHHHHHHHTT---S-HHHHHHHHHHS-HHHHHHHHGGG-SS--SS--S--EEE-SSSSSS-HHHHHHHT-S--S-EEEEEESB-SHHHHHHHSTT--TTS-----HHHHHHHHHHHTTT--HHHHHHHHHHH--GGGTT-HHHHHHHHHHHHHHHHTHHHHHHHHHHHHTTSS-EEEEEE----TT--S-GGG-SBTTTTHHHHTTGGG-GGG---HHHHHHHHHHHHHHHHHHHTSSSS---------SSS-EEEEESSSS--EEESTTHHHHHHHHTHHHHHHHH- DSSP: --SEEEETTEEEE-EEEEETTEEEEEEEEEE-EE---GGGTTS--EE----SSEEE--S---B-------SSTT-HHHHTTS--S-B-S---EEEEEE-SS--SSEEEEEEE--STTT---S-SGGG-THHHHHHHT-EEEE-----SHHHH---TT-SSS-S-HHHHHHHHHHHHHHHHGGGGTEEEEEEEEEEETHHHHHHHHHHH-HHHHTT-SEEEEES--TTSTTS-EEHHHHHHHHHHHHHHTT---S-HHHHHHHHHHS-HHHHHHHHGGG-SS--SS--S---EE-SSSSSS-HHHHHHHT-S--S-EEEEEESB-SHHHHHHHSTT--TTS-----HHHHHHHHHHH-TT--HHHHHHHHHHH--GGGTT-HHHHHHHHHHHHHHHHTHHHHHHHHHHHHTTSS-EEEEEE----TT--S-GGG-SBTTTTHHHHTTGGG-GGG---HHHHHHHHHHHHHHHHHHHTSSSS---------SSS-EEEEESSSS--EEESTTHHHHHHHHTHHHHHHHH- -TODO fix mismatches e.g. here \ No newline at end of file + +TODO fix mismatches e.g. here +TODO move to spec.ts once tests are running \ No newline at end of file diff --git a/src/tests/browser/render-structure.ts b/src/tests/browser/render-structure.ts index e3732508f43a79e42d4aab8db5b558e067a7768a..927e24c14132b9746c37f2d90b2764b6c47652ad 100644 --- a/src/tests/browser/render-structure.ts +++ b/src/tests/browser/render-structure.ts @@ -62,7 +62,7 @@ function getCartoonRepr() { } async function init() { - const cif = await downloadFromPdb('3j3q') + const cif = await downloadFromPdb('1acj') const models = await getModels(cif) console.time('computeModelDSSP') const secondaryStructure = computeModelDSSP(models[0].atomicHierarchy, @@ -72,6 +72,8 @@ async function init() { const structure = await getStructure(models[0]) const cartoonRepr = getCartoonRepr() + console.log(secondaryStructure.dsspString) + cartoonRepr.setTheme({ color: reprCtx.colorThemeRegistry.create('secondary-structure', { structure }), size: reprCtx.sizeThemeRegistry.create('uniform', { structure })