Ver código fonte

added assembly property to SymmetryOperator; improved AssemblySymmetry

Alexander Rose 6 anos atrás
pai
commit
84d9a1b8bc

+ 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, Vec3.create(i, j, k));
+        return SymmetryOperator.create(`${index + 1}_${5 + i}${5 + j}${5 + k}`, operator, { id: '', operList: [] }, Vec3.create(i, j, k));
     }
 
     function getOperatorMatrix(ids: number[]) {

+ 18 - 7
src/mol-math/geometry/symmetry-operator.ts

@@ -8,6 +8,14 @@ import { Vec3, Mat4, Mat3 } from '../linear-algebra/3d'
 
 interface SymmetryOperator {
     readonly name: string,
+
+    readonly assembly: {
+        /** pointer to `pdbx_struct_assembly.id` */
+        readonly id: string
+        /** pointers to `pdbx_struct_oper_list_id` */
+        readonly operList: string[]
+    }
+
     readonly hkl: Vec3,
 
     readonly matrix: Mat4,
@@ -19,15 +27,15 @@ interface SymmetryOperator {
 
 namespace SymmetryOperator {
     export const DefaultName = '1_555'
-    export const Default: SymmetryOperator = create(DefaultName, Mat4.identity());
+    export const Default: SymmetryOperator = create(DefaultName, Mat4.identity(), { id: '', operList: [] });
 
     const RotationEpsilon = 0.0001;
 
-    export function create(name: string, matrix: Mat4, hkl?: Vec3): SymmetryOperator {
+    export function create(name: string, matrix: Mat4, assembly: SymmetryOperator['assembly'], hkl?: Vec3): SymmetryOperator {
         const _hkl = hkl ? Vec3.clone(hkl) : Vec3.zero();
-        if (Mat4.isIdentity(matrix)) return { name, matrix, inverse: Mat4.identity(), isIdentity: true, hkl: _hkl };
+        if (Mat4.isIdentity(matrix)) return { name, assembly, matrix, inverse: Mat4.identity(), isIdentity: true, hkl: _hkl };
         if (!Mat4.isRotationAndTranslation(matrix, RotationEpsilon)) throw new Error(`Symmetry operator (${name}) must be a composition of rotation and translation.`);
-        return { name, matrix, inverse: Mat4.invert(Mat4.zero(), matrix), isIdentity: false, hkl: _hkl };
+        return { name, assembly, matrix, inverse: Mat4.invert(Mat4.zero(), matrix), isIdentity: false, hkl: _hkl };
     }
 
     export function checkIfRotationAndTranslation(rot: Mat3, offset: Vec3) {
@@ -49,13 +57,16 @@ namespace SymmetryOperator {
             }
         }
         Mat4.setTranslation(t, offset);
-        return create(name, t);
+        return create(name, t, { id: '', operList: [] });
     }
 
-    /** Apply the 1st and then 2nd operator. ( = second.matrix * first.matrix). */
+    /**
+     * Apply the 1st and then 2nd operator. ( = second.matrix * first.matrix).
+     * Keep `name`, `assembly` and `hkl` 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.hkl);
+        return create(second.name, matrix, second.assembly, second.hkl);
     }
 
     export interface CoordinateMapper<T extends number> { (index: T, slot: Vec3): Vec3 }

+ 8 - 5
src/mol-model-props/rcsb/assembly-symmetry.ts

@@ -42,6 +42,7 @@ function createDatabaseFromJson(assemblies: ReadonlyArray<AssemblySymmetryGraphQ
     const axisRows: Table.Row<typeof Schema.rcsb_assembly_symmetry_axis>[] = []
 
     let id = 1 // start feature ids at 1
+    let clusterCount = 0
     for (let i = 0, il = assemblies.length; i < il; ++i) {
         const { pdbx_struct_assembly, rcsb_struct_symmetry, rcsb_struct_symmetry_provenance } = assemblies[i]
         if (!pdbx_struct_assembly || !rcsb_struct_symmetry ||!rcsb_struct_symmetry_provenance) continue
@@ -63,20 +64,22 @@ function createDatabaseFromJson(assemblies: ReadonlyArray<AssemblySymmetryGraphQ
             if (clusters) {
                 for (let k = 0, kl = clusters.length; k < kl; ++k) {
                     const c = clusters[k]! // TODO upstream, array members should not be nullable
+                    const cluster_id = clusterCount + k
                     clusterRows.push({
-                        id: k,
+                        id: cluster_id,
                         symmetry_id: id,
                         avg_rmsd: c.avg_rmsd || 0, // TODO upstream, should not be nullable, or???
                     })
                     for (let l = 0, ll = c.members.length; l < ll; ++l) {
                         const m = c.members[l]! // TODO upstream, array members should not be nullable
                         clusterMemberRows.push({
-                            cluster_id: k,
+                            cluster_id: cluster_id,
                             asym_id: m.asym_id,
                             pdbx_struct_oper_list_ids: (m.pdbx_struct_oper_list_ids || []) as string[]
                         })
                     }
                 }
+                clusterCount += clusters.length
             }
 
             const axes = rss.rotation_axes
@@ -156,7 +159,7 @@ const _Descriptor: ModelPropertyDescriptor = {
 export interface AssemblySymmetry {
     '@type': 'rcsb_assembly_symmetry',
     db: AssemblySymmetry.Database
-    getSymmetries(assemblyId: string): Table<AssemblySymmetry.Schema['rcsb_assembly_symmetry']>
+    getSymmetries(assemblyIds: string[]): Table<AssemblySymmetry.Schema['rcsb_assembly_symmetry']>
     getClusters(symmetryId: number): Table<AssemblySymmetry.Schema['rcsb_assembly_symmetry_cluster']>
     getClusterMembers(clusterId: number): Table<AssemblySymmetry.Schema['rcsb_assembly_symmetry_cluster_member']>
     getAxes(symmetryId: number): Table<AssemblySymmetry.Schema['rcsb_assembly_symmetry_axis']>
@@ -171,10 +174,10 @@ export function AssemblySymmetry(db: AssemblySymmetry.Database): AssemblySymmetr
     return {
         '@type': 'rcsb_assembly_symmetry',
         db,
-        getSymmetries: (assemblyId: string) => Table.pick(f, f._schema, i => f.assembly_id.value(i) === assemblyId),
+        getSymmetries: (assemblyIds: string[]) => Table.pick(f, f._schema, i => assemblyIds.includes(f.assembly_id.value(i))),
         getClusters: (symmetryId: number) => Table.pick(c, c._schema, i => c.symmetry_id.value(i) === symmetryId),
         getClusterMembers: (clusterId: number) => Table.pick(cm, cm._schema, i => cm.cluster_id.value(i) === clusterId),
-        getAxes: (symmetryId: number) => Table.pick(a, a._schema, i => a.symmetry_id.value(i) === symmetryId)
+        getAxes: (symmetryId: number) => Table.pick(a, a._schema, i => a.symmetry_id.value(i) === symmetryId),
     }
 }
 

+ 30 - 25
src/mol-model-props/rcsb/representations/assembly-symmetry-axes.ts

@@ -23,36 +23,45 @@ import { LocationIterator } from 'mol-geo/util/location-iterator';
 import { NullLocation } from 'mol-model/location';
 import { PickingId } from 'mol-geo/geometry/picking';
 import { OrderedSet, Interval } from 'mol-data/int';
+import { getSymmetrySelectParam, getAssemblyIds } from '../util';
 
 export const AssemblySymmetryAxesParams = {
     ...ComplexMeshParams,
     sizeFactor: PD.Numeric(0.4, { min: 0, max: 3, step: 0.01 }),
     radialSegments: PD.Numeric(16, { min: 3, max: 56, step: 1 }),
     detail: PD.Numeric(0, { min: 0, max: 3, step: 1 }),
-    symmetryId: PD.Select<number>(-1, []),
+    symmetryId: getSymmetrySelectParam(),
 }
 export type AssemblySymmetryAxesParams = typeof AssemblySymmetryAxesParams
 export function getAssemblySymmetryAxesParams(ctx: ThemeRegistryContext, structure: Structure) {
     const params = PD.clone(AssemblySymmetryAxesParams)
-
-    if (structure.models[0].customProperties.has(AssemblySymmetry.Descriptor)) {
-        const assemblySymmetry = AssemblySymmetry.get(structure.models[0])!
-        const assemblyName = structure.assemblyName
-        const s = assemblySymmetry.db.rcsb_assembly_symmetry
-        if (s._rowCount) {
-            params.symmetryId.options = []
-            for (let i = 0, il = s._rowCount; i < il; ++i) {
-                if (s.assembly_id.value(i) === assemblyName) {
-                    params.symmetryId.options.push([
-                        s.id.value(i), `${s.symbol.value(i)} ${s.kind.value(i)}`
-                    ])
-                }
-            }
-            params.symmetryId.defaultValue = params.symmetryId.options[0][0]
-        }
-    }
-
+    params.symmetryId = getSymmetrySelectParam(structure)
     return params
+
+    // const params = PD.clone(AssemblySymmetryAxesParams)
+
+    // if (structure.models[0].customProperties.has(AssemblySymmetry.Descriptor)) {
+    //     const assemblySymmetry = AssemblySymmetry.get(structure.models[0])!
+    //     const assemblyName = structure.assemblyName
+    //     const s = assemblySymmetry.db.rcsb_assembly_symmetry
+    //     if (s._rowCount) {
+    //         params.symmetryId.options = []
+    //         for (let i = 0, il = s._rowCount; i < il; ++i) {
+    //             if (s.assembly_id.value(i) === assemblyName) {
+    //                 params.symmetryId.options.push([
+    //                     s.id.value(i), `${s.symbol.value(i)} ${s.kind.value(i)}`
+    //                 ])
+    //             }
+    //         }
+    //         if (options.length) {
+    //             params.symmetryId.options = options
+    //             params.symmetryId.defaultValue = options[0][0]
+    //         }
+    //         params.symmetryId.defaultValue = params.symmetryId.options[0][0]
+    //     }
+    // }
+
+    // return params
 }
 
 export type AssemblySymmetryAxesRepresentation = StructureRepresentation<AssemblySymmetryAxesParams>
@@ -126,13 +135,11 @@ export function createAssemblySymmetryAxesMesh(ctx: VisualContext, structure: St
     const symmetry = Table.pickRow(s, i => s.id.value(i) === symmetryId)
     if (!symmetry) return Mesh.createEmpty(mesh)
 
-    // symmetry.assembly_id not available for structure.assemblyName
-    if (symmetry.assembly_id !== structure.assemblyName) return Mesh.createEmpty(mesh)
+    // check if structure.units operators have symmetry.assembly_id
+    if (!getAssemblyIds(structure.units).includes(symmetry.assembly_id)) return Mesh.createEmpty(mesh)
 
     const axes = assemblySymmetry.db.rcsb_assembly_symmetry_axis
     const vectorSpace = AssemblySymmetry.Schema.rcsb_assembly_symmetry_axis.start.space;
-    // const colors: Color[] = []
-    // const labels: string[] = []
 
     const radius = 1 * sizeFactor
     const cylinderProps = { radiusTop: radius, radiusBottom: radius }
@@ -147,8 +154,6 @@ export function createAssemblySymmetryAxesMesh(ctx: VisualContext, structure: St
         addSphere(builderState, start, radius, 2)
         addSphere(builderState, end, radius, 2)
         addCylinder(builderState, start, end, 1, cylinderProps)
-        // colors.push(Color(0xCCEE11))
-        // labels.push(`Axis ${i + 1} for ${symmetry.kind} ${symmetry.type.toLowerCase()} symmetry`)
     }
     return MeshBuilder.getMesh(builderState)
 }

+ 15 - 30
src/mol-model-props/rcsb/themes/assembly-symmetry-cluster.ts

@@ -13,6 +13,7 @@ import { ColorScale, Color } from 'mol-util/color';
 import { Unit, StructureElement, StructureProperties } from 'mol-model/structure';
 import { Location } from 'mol-model/location';
 import { ColorListName, ColorListOptions } from 'mol-util/color/scale';
+import { getSymmetrySelectParam } from '../util';
 
 const DefaultColor = Color(0xCCCCCC)
 
@@ -26,35 +27,18 @@ function getAsymId(unit: Unit): StructureElement.Property<string> {
     }
 }
 
-function clusterMemberKey (asym_id: string, oper_list_ids: string[]) {
-    return `${asym_id}-${oper_list_ids.join('x')}`
+function clusterMemberKey(assemblyId: string, asymId: string, operList: string[]) {
+    return `${assemblyId}-${asymId}-${operList.join('|')}`
 }
 
 export const AssemblySymmetryClusterColorThemeParams = {
     list: PD.Select<ColorListName>('Viridis', ColorListOptions),
-    symmetryId: PD.Select<number>(-1, []),
+    symmetryId: getSymmetrySelectParam(),
 }
 export type AssemblySymmetryClusterColorThemeParams = typeof AssemblySymmetryClusterColorThemeParams
 export function getAssemblySymmetryClusterColorThemeParams(ctx: ThemeDataContext) {
     const params = PD.clone(AssemblySymmetryClusterColorThemeParams)
-
-    if (ctx.structure && ctx.structure.models[0].customProperties.has(AssemblySymmetry.Descriptor)) {
-        const assemblySymmetry = AssemblySymmetry.get(ctx.structure.models[0])!
-        const assemblyName = ctx.structure.assemblyName
-        const s = assemblySymmetry.db.rcsb_assembly_symmetry
-        if (s._rowCount) {
-            params.symmetryId.options = []
-            for (let i = 0, il = s._rowCount; i < il; ++i) {
-                if (s.assembly_id.value(i) === assemblyName) {
-                    params.symmetryId.options.push([
-                        s.id.value(i), `${s.symbol.value(i)} ${s.kind.value(i)}`
-                    ])
-                }
-            }
-            params.symmetryId.defaultValue = params.symmetryId.options[0][0]
-        }
-    }
-
+    params.symmetryId = getSymmetrySelectParam(ctx.structure)
     return params
 }
 
@@ -77,10 +61,10 @@ export function AssemblySymmetryClusterColorTheme(ctx: ThemeDataContext, props:
                 for (let i = 0, il = clusters._rowCount; i < il; ++i) {
                     const clusterMembers = assemblySymmetry.getClusterMembers(clusters.id.value(i))
                     for (let j = 0, jl = clusterMembers._rowCount; j < jl; ++j) {
-                        const asym_id = clusterMembers.asym_id.value(j)
-                        const oper_list_ids = clusterMembers.pdbx_struct_oper_list_ids.value(j)
-                        if (oper_list_ids.length === 0) oper_list_ids.push('1') // TODO hack assuming '1' is the id of the identity operator
-                        clusterByMember.set(clusterMemberKey(asym_id, oper_list_ids), i)
+                        const asymId = clusterMembers.asym_id.value(j)
+                        const operList = clusterMembers.pdbx_struct_oper_list_ids.value(j)
+                        if (operList.length === 0) operList.push('1') // TODO hack assuming '1' is the id of the identity operator
+                        clusterByMember.set(clusterMemberKey(symmetry.assembly_id, asymId, operList), i)
                     }
                 }
 
@@ -88,11 +72,12 @@ export function AssemblySymmetryClusterColorTheme(ctx: ThemeDataContext, props:
 
                 color = (location: Location): Color => {
                     if (StructureElement.isLocation(location)) {
-                        const asym_id = getAsymId(location.unit)
-                        const ns = location.unit.conformation.operator.name.split('-')
-                        const oper_list_ids = ns.length === 2 ? ns[1].split('x') : []
-                        const cluster = clusterByMember.get(clusterMemberKey(asym_id(location), oper_list_ids))
-                        return cluster !== undefined ? scale.color(cluster) : DefaultColor
+                        const { assembly } = location.unit.conformation.operator
+                        if (assembly && assembly.id === symmetry.assembly_id) {
+                            const asymId = getAsymId(location.unit)(location)
+                            const cluster = clusterByMember.get(clusterMemberKey(assembly.id, asymId, assembly.operList))
+                            return cluster !== undefined ? scale.color(cluster) : DefaultColor
+                        }
                     }
                     return DefaultColor
                 }

+ 37 - 0
src/mol-model-props/rcsb/util.ts

@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { Unit, Structure } from 'mol-model/structure';
+import { ParamDefinition as PD } from 'mol-util/param-definition'
+import { AssemblySymmetry } from './assembly-symmetry';
+
+export function getAssemblyIds(units: ReadonlyArray<Unit>) {
+    const ids = new Set<string>()
+    units.forEach(u => {
+        if (u.conformation.operator.assembly) ids.add(u.conformation.operator.assembly.id)
+    })
+    return Array.from(ids)
+}
+
+export function getSymmetrySelectParam(structure?: Structure) {
+    const param = PD.Select<number>(-1, [[-1, 'No Symmetries']])
+    if (structure && structure.models[0].customProperties.has(AssemblySymmetry.Descriptor)) {
+        const assemblySymmetry = AssemblySymmetry.get(structure.models[0])!
+        const assemblyIds = getAssemblyIds(structure.units)
+        const s = assemblySymmetry.getSymmetries(assemblyIds)
+        if (s._rowCount) {
+            const options: [number, string][] = []
+            for (let i = 0, il = s._rowCount; i < il; ++i) {
+                options.push([ s.id.value(i), `${s.assembly_id.value(i)}: ${s.symbol.value(i)} ${s.kind.value(i)}` ])
+            }
+            if (options.length) {
+                param.options = options
+                param.defaultValue = options[0][0]
+            }
+        }
+    }
+    return param
+}

+ 7 - 7
src/mol-model/structure/model/formats/mmcif/assembly.ts

@@ -26,7 +26,7 @@ export function createAssemblies(format: mmCIF_Format): ReadonlyArray<Assembly>
 }
 
 type Matrices = Map<string, Mat4>
-type Generator = { expression: string, asymIds: string[] }
+type Generator = { assemblyId: string, expression: string, asymIds: string[] }
 
 function createAssembly(format: mmCIF_Format, index: number, matrices: Matrices): Assembly {
     const { pdbx_struct_assembly, pdbx_struct_assembly_gen } = format.data;
@@ -40,6 +40,7 @@ function createAssembly(format: mmCIF_Format, index: number, matrices: Matrices)
     for (let i = 0, _i = pdbx_struct_assembly_gen._rowCount; i < _i; i++) {
         if (assembly_id.value(i) !== id) continue;
         generators[generators.length] = {
+            assemblyId: id,
             expression: oper_expression.value(i),
             asymIds: asym_id_list.value(i)
         };
@@ -57,7 +58,7 @@ function operatorGroupsProvider(generators: Generator[], matrices: Matrices): ()
             const gen = generators[i];
             const operatorList = parseOperatorList(gen.expression);
             const operatorNames = expandOperators(operatorList);
-            const operators = getAssemblyOperators(matrices, operatorNames, operatorOffset);
+            const operators = getAssemblyOperators(matrices, operatorNames, operatorOffset, gen.assemblyId);
             const selector = Q.generators.atoms({ chainTest: Q.pred.and(
                 Q.pred.eq(ctx => StructureProperties.unit.operator_name(ctx.element), SymmetryOperator.DefaultName),
                 Q.pred.inSet(ctx => StructureProperties.chain.label_asym_id(ctx.element), gen.asymIds)
@@ -107,18 +108,17 @@ function expandOperators1(operatorNames: string[][], list: string[][], i: number
     }
 }
 
-function getAssemblyOperators(matrices: Matrices, operatorNames: string[][], startIndex: number) {
+function getAssemblyOperators(matrices: Matrices, operatorNames: string[][], startIndex: number, assemblyId: string) {
     const operators: SymmetryOperator[] = [];
 
+    let index = startIndex;
     for (let op of operatorNames) {
         let m = Mat4.identity();
         for (let i = 0; i < op.length; i++) {
             Mat4.mul(m, m, matrices.get(op[i])!);
         }
-        // TODO currently using the original operator name for the symmetry operator to be able
-        // to link it to the original operator but it might be clearer to introduce an extra field???
-        // Operator names are joined together by 'x' to indicate matrix multiplication.
-        operators[operators.length] = SymmetryOperator.create(`A-${op.join('x')}`, m);
+        index++
+        operators[operators.length] = SymmetryOperator.create(`A-${index}`, m, { id: assemblyId, operList: op });
     }
 
     return operators;

+ 1 - 1
src/mol-model/structure/query/queries/generators.ts

@@ -171,7 +171,7 @@ function atomGroupsGrouped({ entityTest, chainTest, residueTest, atomTest, group
 function getRingStructure(unit: Unit.Atomic, ring: UnitRing) {
     const elements = new Int32Array(ring.length) as any as ElementIndex[];
     for (let i = 0, _i = ring.length; i < _i; i++) elements[i] = unit.elements[ring[i]];
-    return Structure.create([unit.getChild(SortedArray.ofSortedArray(elements))], '')
+    return Structure.create([unit.getChild(SortedArray.ofSortedArray(elements))])
 }
 
 export function rings(fingerprints?: ArrayLike<UnitRing.Fingerprint>): StructureQuery {

+ 4 - 4
src/mol-model/structure/query/queries/internal.ts

@@ -35,7 +35,7 @@ export function atomicSequence(): StructureQuery {
 
             units.push(unit);
         }
-        return StructureSelection.Singletons(inputStructure, new Structure(units, inputStructure.assemblyName));
+        return StructureSelection.Singletons(inputStructure, new Structure(units));
     };
 }
 
@@ -54,7 +54,7 @@ export function water(): StructureQuery {
             if (P.entity.type(l) !== 'water') continue;
             units.push(unit);
         }
-        return StructureSelection.Singletons(inputStructure, new Structure(units, inputStructure.assemblyName));
+        return StructureSelection.Singletons(inputStructure, new Structure(units));
     };
 }
 
@@ -84,7 +84,7 @@ export function atomicHet(): StructureQuery {
 
             units.push(unit);
         }
-        return StructureSelection.Singletons(inputStructure, new Structure(units, inputStructure.assemblyName));
+        return StructureSelection.Singletons(inputStructure, new Structure(units));
     };
 }
 
@@ -97,6 +97,6 @@ export function spheres(): StructureQuery {
             if (unit.kind !== Unit.Kind.Spheres) continue;
             units.push(unit);
         }
-        return StructureSelection.Singletons(inputStructure, new Structure(units, inputStructure.assemblyName));
+        return StructureSelection.Singletons(inputStructure, new Structure(units));
     };
 }

+ 1 - 1
src/mol-model/structure/query/selection.ts

@@ -109,7 +109,7 @@ namespace StructureSelection {
                 const { elements } = unit;
                 for (let i = 0, _i = elements.length; i < _i; i++) {
                     // TODO: optimize this somehow???
-                    const s = Structure.create([unit.getChild(SortedArray.ofSingleton(elements[i]))], sel.structure.assemblyName);
+                    const s = Structure.create([unit.getChild(SortedArray.ofSingleton(elements[i]))]);
                     fn(s, idx++);
                 }
             }

+ 2 - 2
src/mol-model/structure/query/utils/structure-set.ts

@@ -80,7 +80,7 @@ export function structureIntersect(sA: Structure, sB: Structure): Structure {
         }
     }
 
-    return Structure.create(units, sA.assemblyName === sB.assemblyName ? sA.assemblyName : '');
+    return Structure.create(units);
 }
 
 export function structureSubtract(a: Structure, b: Structure): Structure {
@@ -100,5 +100,5 @@ export function structureSubtract(a: Structure, b: Structure): Structure {
         }
     }
 
-    return Structure.create(units, a.assemblyName === b.assemblyName ? a.assemblyName : '');
+    return Structure.create(units);
 }

+ 9 - 16
src/mol-model/structure/structure/structure.ts

@@ -49,8 +49,7 @@ class Structure {
         transformHash: number,
         elementCount: number,
         polymerResidueCount: number,
-        assemblyName: string
-    } = { hashCode: -1, transformHash: -1, elementCount: 0, polymerResidueCount: 0, assemblyName: '' };
+    } = { hashCode: -1, transformHash: -1, elementCount: 0, polymerResidueCount: 0 };
 
     subsetBuilder(isSorted: boolean) {
         return new StructureSubsetBuilder(this, isSorted);
@@ -66,11 +65,6 @@ class Structure {
         return this._props.polymerResidueCount;
     }
 
-    /** Name of the assembly given by `_pdbx_struct_assembly.id` when applicable */
-    get assemblyName() {
-        return this._props.assemblyName;
-    }
-
     /** Coarse structure, defined as Containing less than twice as many elements as polymer residues */
     get isCoarse() {
         const ec = this.elementCount
@@ -176,7 +170,7 @@ class Structure {
         return SortedArray.has(this.unitMap.get(e.unit.id).elements, e.element);
     }
 
-    constructor(units: ArrayLike<Unit>, assemblyName: string) {
+    constructor(units: ArrayLike<Unit>) {
         const map = IntMap.Mutable<Unit>();
         let elementCount = 0;
         let polymerResidueCount = 0;
@@ -195,7 +189,6 @@ class Structure {
         this.units = units as ReadonlyArray<Unit>;
         this._props.elementCount = elementCount;
         this._props.polymerResidueCount = polymerResidueCount;
-        this._props.assemblyName = assemblyName
     }
 }
 
@@ -286,7 +279,7 @@ function getUniqueAtomicResidueIndices(structure: Structure): ReadonlyMap<UUID,
 }
 
 namespace Structure {
-    export const Empty = new Structure([], '');
+    export const Empty = new Structure([]);
 
     /** Represents a single structure */
     export interface Loci {
@@ -305,7 +298,7 @@ namespace Structure {
         return a.structure === b.structure
     }
 
-    export function create(units: ReadonlyArray<Unit>, assemblyName: string): Structure { return new Structure(units, assemblyName); }
+    export function create(units: ReadonlyArray<Unit>): Structure { return new Structure(units); }
 
     /**
      * Construct a Structure from a model.
@@ -346,7 +339,7 @@ namespace Structure {
             }
         }
 
-        return builder.getStructure('deposited');
+        return builder.getStructure();
     }
 
     function isWaterChain(model: Model, chainIndex: ChainIndex, indices: SortedArray) {
@@ -384,11 +377,11 @@ namespace Structure {
         const units: Unit[] = [];
         for (const u of s.units) {
             const old = u.conformation.operator;
-            const op = SymmetryOperator.create(old.name, transform, old.hkl);
+            const op = SymmetryOperator.create(old.name, transform, { id: '', operList: [] }, old.hkl);
             units.push(u.applyOperator(u.id, op));
         }
 
-        return new Structure(units, s.assemblyName);
+        return new Structure(units);
     }
 
     export class StructureBuilder {
@@ -407,8 +400,8 @@ namespace Structure {
             return newUnit;
         }
 
-        getStructure(assemblyName: string): Structure {
-            return create(this.units, assemblyName);
+        getStructure(): Structure {
+            return create(this.units);
         }
 
         get isEmpty() {

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

@@ -42,7 +42,7 @@ namespace StructureSymmetry {
                 }
             }
 
-            return assembler.getStructure(asmName);
+            return assembler.getStructure();
         });
     }
 
@@ -118,7 +118,7 @@ function assembleOperators(structure: Structure, operators: ReadonlyArray<Symmet
             assembler.addWithOperator(unit, oper);
         }
     }
-    return assembler.getStructure(structure.assemblyName);
+    return assembler.getStructure();
 }
 
 async function _buildNCS(ctx: RuntimeContext, structure: Structure) {
@@ -173,7 +173,7 @@ async function findMatesRadius(ctx: RuntimeContext, structure: Structure, radius
     }
 
 
-    return assembler.getStructure(structure.assemblyName);
+    return assembler.getStructure();
 }
 
 export default StructureSymmetry;

+ 1 - 1
src/mol-model/structure/structure/util/subset-builder.ts

@@ -90,7 +90,7 @@ export class StructureSubsetBuilder {
             newUnits[newUnits.length] = child;
         }
 
-        return Structure.create(newUnits, this.parent.assemblyName);
+        return Structure.create(newUnits);
     }
 
     getStructure() {

+ 1 - 1
src/mol-model/structure/structure/util/unique-subset-builder.ts

@@ -85,7 +85,7 @@ export class StructureUniqueSubsetBuilder {
             newUnits[newUnits.length] = child;
         }
 
-        return Structure.create(newUnits, this.parent.assemblyName);
+        return Structure.create(newUnits);
     }
 
     get isEmpty() {