Browse Source

wip, various nci fixes and tweaks

Alexander Rose 5 years ago
parent
commit
0f33144935

+ 10 - 17
src/mol-model-props/computed/interactions/charged.ts

@@ -11,7 +11,7 @@ import { ParamDefinition as PD } from '../../../mol-util/param-definition';
 import { Structure, Unit, StructureElement } from '../../../mol-model/structure';
 import { FeaturesBuilder, Features } from './features';
 import { ProteinBackboneAtoms, PolymerNames, BaseNames, ElementSymbol } from '../../../mol-model/structure/model/types';
-import { typeSymbol, atomId, altLoc, eachBondedAtom } from '../chemistry/util';
+import { typeSymbol, atomId, eachBondedAtom, compId } from '../chemistry/util';
 import { Elements } from '../../../mol-model/structure/model/properties/atomic/types';
 import { ValenceModelProvider } from '../valence-model';
 import { degToRad } from '../../../mol-math/misc';
@@ -187,6 +187,8 @@ const AromaticRingElements = [
 const AromaticRingPlanarityThreshold = 0.05
 
 function isRingAromatic(unit: Unit.Atomic, ring: SortedArray<StructureElement.UnitIndex>) {
+    // ignore Proline (can be flat because of bad geometry)
+    if (compId(unit, ring[0]) === 'PRO') return
     // TODO also check `chem_comp_bond.pdbx_aromatic_flag`
     let hasAromaticRingElement = false
     for (let i = 0, il = ring.length; i < il; ++i) {
@@ -207,7 +209,6 @@ export function addUnitAromaticRings(structure: Structure, unit: Unit.Atomic, bu
 
     for (const ring of unit.rings.all) {
         if (!isRingAromatic(unit, ring)) continue
-
         builder.startState()
         for (let i = 0, il = ring.length; i < il; ++i) {
             const j = ring[i]
@@ -258,14 +259,17 @@ const tmpVecC = Vec3()
 const tmpVecD = Vec3()
 
 function getNormal(out: Vec3, info: Features.Info) {
-    const { unit, feature, offsets} = info
+    const { unit, feature, offsets, members } = info
     const { elements } = unit
     const { x, y, z } = unit.model.atomicConformation
 
     const i = offsets[feature]
-    Vec3.set(tmpVecA, x[elements[i]], y[elements[i]], z[elements[i]])
-    Vec3.set(tmpVecB, x[elements[i + 1]], y[elements[i + 1]], z[elements[i + 1]])
-    Vec3.set(tmpVecC, x[elements[i + 2]], y[elements[i + 2]], z[elements[i + 2]])
+    const aI = elements[members[i]]
+    const bI = elements[members[i + 1]]
+    const cI = elements[members[i + 2]]
+    Vec3.set(tmpVecA, x[aI], y[aI], z[aI])
+    Vec3.set(tmpVecB, x[bI], y[bI], z[bI])
+    Vec3.set(tmpVecC, x[cI], y[cI], z[cI])
 
     return Vec3.triangleNormal(out, tmpVecA, tmpVecB, tmpVecC)
 }
@@ -303,17 +307,6 @@ function testCharged(structure: Structure, infoA: Features.Info, infoB: Features
     const typeA = infoA.types[infoA.feature]
     const typeB = infoB.types[infoB.feature]
 
-    const indexA = infoA.members[infoA.offsets[infoA.feature]]
-    const indexB = infoB.members[infoB.offsets[infoB.feature]]
-
-    if (indexA === indexB) return // to self
-
-    const altA = altLoc(infoA.unit, indexA)
-    const altB = altLoc(infoB.unit, indexB)
-
-    if (altA && altB && altA !== altB) return // incompatible alternate location id
-    if (infoA.unit.residueIndex[infoA.unit.elements[indexA]] === infoB.unit.residueIndex[infoB.unit.elements[indexB]]) return // same residue
-
     if (isIonicInteraction(typeA, typeB)) {
         if (areFeaturesWithinDistanceSq(infoA, infoB, opts.ionicDistanceMaxSq)) {
             return InteractionType.IonicInteraction

+ 1 - 1
src/mol-model-props/computed/interactions/features.ts

@@ -62,7 +62,7 @@ namespace Features {
         const bucketFill = new Int32Array(elementsCount)
         const bucketSizes = new Int32Array(elementsCount)
         const { members, count, offsets: featureOffsets } = data
-        for (let i = 0; i < count; ++i) ++bucketSizes[members[i]]
+        for (let i = 0, il = featureOffsets[count]; i < il; ++i) ++bucketSizes[members[i]]
 
         let offset = 0
         for (let i = 0; i < elementsCount; i++) {

+ 2 - 26
src/mol-model-props/computed/interactions/halogen-bonds.ts

@@ -12,7 +12,7 @@ import { Structure, Unit, StructureElement } from '../../../mol-model/structure'
 import { calcAngles } from '../chemistry/geometry';
 import { FeaturesBuilder, Features } from './features';
 import { ElementSymbol } from '../../../mol-model/structure/model/types';
-import { typeSymbol, altLoc, eachBondedAtom } from '../chemistry/util';
+import { typeSymbol, eachBondedAtom } from '../chemistry/util';
 import { Elements } from '../../../mol-model/structure/model/properties/atomic/types';
 import { degToRad } from '../../../mol-math/misc';
 import { FeatureType, FeatureGroup, InteractionType } from './common';
@@ -79,22 +79,6 @@ function isHalogenBond (ti: FeatureType, tj: FeatureType) {
 const OptimalHalogenAngle = degToRad(180)  // adjusted from 165 to account for spherical statistics
 const OptimalAcceptorAngle = degToRad(120)
 
-interface Info {
-    unit: Unit.Atomic,
-    types: ArrayLike<FeatureType>,
-    feature: number,
-    members: ArrayLike<StructureElement.UnitIndex>,
-    offsets: ArrayLike<number>,
-}
-function Info(structure: Structure, unit: Unit.Atomic, features: Features) {
-    return {
-        unit,
-        types: features.types,
-        members: features.members,
-        offsets: features.offsets,
-    } as Info
-}
-
 function getOptions(props: HalogenBondsProps) {
     return {
         distanceMax: props.distanceMax,
@@ -103,7 +87,7 @@ function getOptions(props: HalogenBondsProps) {
 }
 type Options = ReturnType<typeof getOptions>
 
-function testHalogenBond(structure: Structure, infoA: Info, infoB: Info, opts: Options): InteractionType | undefined {
+function testHalogenBond(structure: Structure, infoA: Features.Info, infoB: Features.Info, opts: Options): InteractionType | undefined {
     const typeA = infoA.types[infoA.feature]
     const typeB = infoB.types[infoB.feature]
 
@@ -114,14 +98,6 @@ function testHalogenBond(structure: Structure, infoA: Info, infoB: Info, opts: O
     const donIndex = don.members[don.offsets[don.feature]]
     const accIndex = acc.members[acc.offsets[acc.feature]]
 
-    if (accIndex === donIndex) return // DA to self
-
-    const altD = altLoc(don.unit, donIndex)
-    const altA = altLoc(acc.unit, accIndex)
-
-    if (altD && altA && altD !== altA) return // incompatible alternate location id
-    if (don.unit.residueIndex[don.unit.elements[donIndex]] === acc.unit.residueIndex[acc.unit.elements[accIndex]]) return // same residue
-
     const halogenAngles = calcAngles(structure, don.unit, donIndex, acc.unit, accIndex)
     // Singly bonded halogen only (not bromide ion for example)
     if (halogenAngles.length !== 1) return

+ 1 - 12
src/mol-model-props/computed/interactions/hydrogen-bonds.ts

@@ -12,7 +12,7 @@ import { Structure, Unit, StructureElement } from '../../../mol-model/structure'
 import { AtomGeometry, AtomGeometryAngles, calcAngles, calcPlaneAngle } from '../chemistry/geometry';
 import { FeaturesBuilder, Features } from './features';
 import { MoleculeType, ProteinBackboneAtoms } from '../../../mol-model/structure/model/types';
-import { typeSymbol, bondToElementCount, bondCount, formalCharge, atomId, compId, altLoc, connectedTo } from '../chemistry/util';
+import { typeSymbol, bondToElementCount, bondCount, formalCharge, atomId, compId } from '../chemistry/util';
 import { Elements } from '../../../mol-model/structure/model/properties/atomic/types';
 import { ValenceModelProvider } from '../valence-model';
 import { degToRad } from '../../../mol-math/misc';
@@ -236,20 +236,9 @@ function testHydrogenBond(structure: Structure, infoA: Features.Info, infoB: Fea
     const donIndex = don.members[don.offsets[don.feature]]
     const accIndex = acc.members[acc.offsets[acc.feature]]
 
-    if (accIndex === donIndex) return // DA to self
-
-    const altD = altLoc(don.unit, donIndex)
-    const altA = altLoc(acc.unit, accIndex)
-
-    if (altD && altA && altD !== altA) return // incompatible alternate location id
-    if (don.unit.residueIndex[don.unit.elements[donIndex]] === acc.unit.residueIndex[acc.unit.elements[accIndex]]) return // same residue
-
     // check if distance is ok for non-sulfur-containing hbond
     if (typeSymbol(don.unit, donIndex) !== Elements.S && typeSymbol(acc.unit, accIndex) !== Elements.S && distanceSq > opts.maxHbondDistSq) return
 
-    // no hbond if donor and acceptor are bonded
-    if (connectedTo(structure, don.unit, donIndex, acc.unit, accIndex)) return
-
     const donAngles = calcAngles(structure, don.unit, donIndex, acc.unit, accIndex)
     const idealDonAngle = AtomGeometryAngles.get(don.idealGeometry[donIndex]) || deg120InRad
     if (donAngles.some(donAngle => Math.abs(idealDonAngle - donAngle) > opts.maxDonAngleDev)) return

+ 3 - 0
src/mol-model-props/computed/interactions/interactions.ts

@@ -122,6 +122,9 @@ export async function computeInteractions(runtime: RuntimeContext, structure: St
 
     for (let i = 0, il = structure.unitSymmetryGroups.length; i < il; ++i) {
         const group = structure.unitSymmetryGroups[i]
+        if (runtime.shouldUpdate) {
+            await runtime.update({ message: 'computing interactions', current: i, max: il })
+        }
         const d = findIntraUnitLinksAndFeatures(structure, group.units[0], linkTesters)
         for (let j = 0, jl = group.units.length; j < jl; ++j) {
             const u = group.units[j]

+ 19 - 0
src/mol-model-props/computed/interactions/links.ts

@@ -10,6 +10,7 @@ import { Features } from './features';
 import { InteractionType } from './common';
 import { IntraLinksBuilder, InterLinksBuilder } from './builder';
 import { Mat4, Vec3 } from '../../../mol-math/linear-algebra';
+import { altLoc, connectedTo } from '../chemistry/util';
 
 const MAX_DISTANCE = 5
 
@@ -24,6 +25,20 @@ export interface LinkTester {
     getType: (structure: Structure, infoA: Features.Info, infoB: Features.Info, distanceSq: number, ) => InteractionType | undefined
 }
 
+function validPair(structure: Structure, infoA: Features.Info, infoB: Features.Info): boolean {
+    const indexA = infoA.members[infoA.offsets[infoA.feature]]
+    const indexB = infoB.members[infoB.offsets[infoB.feature]]
+    if (indexA === indexB) return false // no self interaction
+    const altA = altLoc(infoA.unit, indexA)
+    const altB = altLoc(infoB.unit, indexB)
+    if (altA && altB && altA !== altB) return false // incompatible alternate location id
+    if (infoA.unit.residueIndex[infoA.unit.elements[indexA]] === infoB.unit.residueIndex[infoB.unit.elements[indexB]]) return false // same residue
+    // no hbond if donor and acceptor are bonded
+    if (connectedTo(structure, infoA.unit, indexA, infoB.unit, indexB)) return false
+
+    return true
+}
+
 /**
  * Add all intra-unit links, i.e. pairs of features
  */
@@ -47,6 +62,8 @@ export function addUnitLinks(structure: Structure, unit: Unit.Atomic, features:
 
             const distanceSq = squaredDistances[r]
             infoB.feature = j
+            if (!validPair(structure, infoA, infoB)) continue
+
             for (const tester of testers) {
                 if (distanceSq < tester.maxDistanceSq) {
                     const type = tester.getType(structure, infoA, infoB, distanceSq)
@@ -95,6 +112,8 @@ export function addStructureLinks(structure: Structure, unitA: Unit.Atomic, feat
             const j = indices[r]
             const distanceSq = squaredDistances[r]
             infoB.feature = j
+            if (!validPair(structure, infoA, infoB)) continue
+
             for (const tester of testers) {
                 if (distanceSq < tester.maxDistanceSq) {
                     const type = tester.getType(structure, infoA, infoB, distanceSq)

+ 8 - 1
src/mol-repr/structure/complex-visual.ts

@@ -30,6 +30,7 @@ import { Mesh } from '../../mol-geo/geometry/mesh/mesh';
 import { Text } from '../../mol-geo/geometry/text/text';
 import { SizeTheme } from '../../mol-theme/size';
 import { DirectVolume } from '../../mol-geo/geometry/direct-volume/direct-volume';
+import { createMarkers } from '../../mol-geo/geometry/marker-data';
 
 export interface  ComplexVisual<P extends StructureParams> extends Visual<Structure, P> { }
 
@@ -103,6 +104,7 @@ export function ComplexVisual<G extends Geometry, P extends ComplexParams & Geom
         setUpdateState(updateState, newProps, currentProps, newTheme, currentTheme, newStructure, currentStructure)
 
         if (Structure.conformationHash(newStructure) !== Structure.conformationHash(currentStructure)) {
+            updateState.updateTransform = true;
             updateState.createGeometry = true
         }
 
@@ -132,7 +134,12 @@ export function ComplexVisual<G extends Geometry, P extends ComplexParams & Geom
                 throw new Error('expected renderObject to be available')
             }
 
-            locationIt.reset()
+            if (updateState.updateTransform) {
+                // console.log('update transform')
+                locationIt = createLocationIterator(newStructure)
+                const { instanceCount, groupCount } = locationIt
+                createMarkers(instanceCount * groupCount, renderObject.values)
+            }
 
             if (updateState.createGeometry) {
                 if (newGeometry) {

+ 2 - 1
src/mol-repr/structure/visual/interactions-inter-unit-cylinder.ts

@@ -75,7 +75,8 @@ export function InteractionsInterUnitVisual(materialId: number): ComplexVisual<I
 
             const interactionsHash = InteractionsProvider.getValue(newStructure).version
             if ((state.info.interactionsHash as number) !== interactionsHash) {
-                state.createGeometry = true;
+                state.createGeometry = true
+                state.updateTransform = true
                 state.info.interactionsHash = interactionsHash
             }
         }

+ 2 - 1
src/mol-repr/structure/visual/interactions-intra-unit-cylinder.ts

@@ -75,7 +75,8 @@ export function InteractionsIntraUnitVisual(materialId: number): UnitsVisual<Int
 
             const interactionsHash = InteractionsProvider.getValue(newStructureGroup.structure).version
             if ((state.info.interactionsHash as number) !== interactionsHash) {
-                state.createGeometry = true;
+                state.createGeometry = true
+                state.updateTransform = true
                 state.info.interactionsHash = interactionsHash
             }
         }