Explorar o código

improved xtal symmetry support for props & sequence

Alexander Rose %!s(int64=5) %!d(string=hai) anos
pai
achega
6201dd1d74

+ 1 - 1
src/mol-math/geometry/spacegroup/construction.ts

@@ -90,7 +90,7 @@ namespace Spacegroup {
 
     export function getSymmetryOperator(spacegroup: Spacegroup, index: number, i: number, j: number, k: number): SymmetryOperator {
         const operator = updateOperatorMatrix(spacegroup, index, i, j, k, Mat4.zero());
-        return SymmetryOperator.create(`${index + 1}_${5 + i}${5 + j}${5 + k}`, operator, { id: '', operList: [] }, '', Vec3.create(i, j, k));
+        return SymmetryOperator.create(`${index + 1}_${5 + i}${5 + j}${5 + k}`, operator, { id: '', operList: [] }, '', Vec3.create(i, j, k), index);
     }
 
     function getOperatorMatrix(ids: number[]) {

+ 9 - 5
src/mol-math/geometry/symmetry-operator.ts

@@ -6,6 +6,7 @@
 
 import { Vec3, Mat4, Mat3, Quat } from '../linear-algebra/3d'
 import { lerp as scalar_lerp } from '../../mol-math/interpolate';
+import { defaults } from '../../mol-util';
 
 interface SymmetryOperator {
     readonly name: string,
@@ -21,6 +22,8 @@ interface SymmetryOperator {
     readonly ncsId: string,
 
     readonly hkl: Vec3,
+    /** spacegroup symmetry operator index, -1 if not applicable */
+    readonly spgrOp: number,
 
     readonly matrix: Mat4,
     // cache the inverse of the transform
@@ -35,12 +38,13 @@ namespace SymmetryOperator {
 
     export const RotationTranslationEpsilon = 0.005;
 
-    export function create(name: string, matrix: Mat4, assembly: SymmetryOperator['assembly'], ncsId?: string, hkl?: Vec3): SymmetryOperator {
+    export function create(name: string, matrix: Mat4, assembly: SymmetryOperator['assembly'], ncsId?: string, hkl?: Vec3, spgrOp?: number): SymmetryOperator {
         const _hkl = hkl ? Vec3.clone(hkl) : Vec3.zero();
+        spgrOp = defaults(spgrOp, -1)
         ncsId = ncsId || ''
-        if (Mat4.isIdentity(matrix)) return { name, assembly, matrix, inverse: Mat4.identity(), isIdentity: true, hkl: _hkl, ncsId };
+        if (Mat4.isIdentity(matrix)) return { name, assembly, matrix, inverse: Mat4.identity(), isIdentity: true, hkl: _hkl, spgrOp, ncsId };
         if (!Mat4.isRotationAndTranslation(matrix, RotationTranslationEpsilon)) throw new Error(`Symmetry operator (${name}) must be a composition of rotation and translation.`);
-        return { name, assembly, matrix, inverse: Mat4.invert(Mat4.zero(), matrix), isIdentity: false, hkl: _hkl, ncsId };
+        return { name, assembly, matrix, inverse: Mat4.invert(Mat4.zero(), matrix), isIdentity: false, hkl: _hkl, spgrOp, ncsId };
     }
 
     export function checkIfRotationAndTranslation(rot: Mat3, offset: Vec3) {
@@ -106,11 +110,11 @@ namespace SymmetryOperator {
 
     /**
      * Apply the 1st and then 2nd operator. ( = second.matrix * first.matrix).
-     * Keep `name`, `assembly`, `ncsId` and `hkl` properties from second.
+     * Keep `name`, `assembly`, `ncsId`, `hkl` and `spgrOpId` properties from second.
      */
     export function compose(first: SymmetryOperator, second: SymmetryOperator) {
         const matrix = Mat4.mul(Mat4.zero(), second.matrix, first.matrix);
-        return create(second.name, matrix, second.assembly, second.ncsId, second.hkl);
+        return create(second.name, matrix, second.assembly, second.ncsId, second.hkl, second.spgrOp);
     }
 
     export interface CoordinateMapper<T extends number> { (index: T, slot: Vec3): Vec3 }

+ 2 - 0
src/mol-model/structure/structure/properties.ts

@@ -113,6 +113,8 @@ const entity = {
 const unit = {
     id: StructureElement.property(l => l.unit.id),
     operator_name: StructureElement.property(l => l.unit.conformation.operator.name),
+    hkl: StructureElement.property(l => l.unit.conformation.operator.hkl),
+    spgrOp: StructureElement.property(l => l.unit.conformation.operator.spgrOp),
 
     model_num: StructureElement.property(l => l.unit.model.modelNum),
     pdbx_struct_assembly_id: StructureElement.property(l => l.unit.conformation.operator.assembly.id),

+ 1 - 1
src/mol-model/structure/structure/symmetry.ts

@@ -117,7 +117,7 @@ function getOperators(symmetry: ModelSymmetry, ijkMin: Vec3, ijkMax: Vec3) {
                         for (let u = 0; u < ncsCount; ++u) {
                             const ncsOp = ncsOperators![u]
                             const matrix = Mat4.mul(Mat4.zero(), symOp.matrix, ncsOp.matrix)
-                            const operator = SymmetryOperator.create(`${symOp.name} ${ncsOp.name}`, matrix, symOp.assembly, ncsOp.ncsId, symOp.hkl);
+                            const operator = SymmetryOperator.create(`${symOp.name} ${ncsOp.name}`, matrix, symOp.assembly, ncsOp.ncsId, symOp.hkl, symOp.spgrOp);
                             operators[operators.length] = operator;
                         }
                     } else {

+ 9 - 5
src/mol-plugin/ui/sequence.tsx

@@ -18,8 +18,12 @@ import { MarkerAction } from '../../mol-util/marker-action';
 import { ParameterControls } from './controls/parameters';
 import { ParamDefinition as PD } from '../../mol-util/param-definition';
 
-function opKey(ids: string[]) {
-    return ids.sort().join(',')
+function opKey(l: StructureElement) {
+    const ids = SP.unit.pdbx_struct_oper_list_ids(l)
+    const ncs = SP.unit.struct_ncs_oper_id(l)
+    const hkl = SP.unit.hkl(l)
+    const spgrOp = SP.unit.spgrOp(l)
+    return `${ids.sort().join(',')}|${ncs}|${hkl}|${spgrOp}`
 }
 
 function getSequenceWrapper(state: SequenceViewState, structureSelection: StructureElementSelectionManager): SequenceWrapper.Any | undefined {
@@ -32,7 +36,7 @@ function getSequenceWrapper(state: SequenceViewState, structureSelection: Struct
         StructureElement.set(l, unit, unit.elements[0])
         if (SP.entity.id(l) !== entity) continue
         if (SP.chain.label_asym_id(l) !== chain) continue
-        if (opKey(SP.unit.pdbx_struct_oper_list_ids(l)) !== operator) continue
+        if (opKey(l) !== operator) continue
 
         // console.log('new PolymerSequenceWrapper', structureSelection.get(structure))
         const sw = new PolymerSequenceWrapper({ structure, unit })
@@ -96,10 +100,10 @@ function getOperatorOptions(structure: Structure, entityId: string, label_asym_i
         if (SP.entity.id(l) !== entityId) return
         if (SP.chain.label_asym_id(l) !== label_asym_id) return
 
-        const id = opKey(SP.unit.pdbx_struct_oper_list_ids(l))
+        const id = opKey(l)
         if (seen.has(id)) return
 
-        const label = `${SP.unit.pdbx_struct_oper_list_ids(l).join(', ')}`
+        const label = unit.conformation.operator.name
         options.push([ id, label ])
         seen.add(id)
     })