Преглед изворни кода

updated rcsb_assembly_symmetry

Alexander Rose пре 6 година
родитељ
комит
07a97e6ec6

+ 1 - 1
data/rcsb-graphql/codegen.js

@@ -8,7 +8,7 @@ generate({
         path.join(basePath, 'symmetry.gql.ts')
     ],
     schema: 'http://rest-experimental.rcsb.org/graphql',
-    template: 'typescript',
+    template: 'graphql-codegen-typescript-template',
     out: path.join(basePath),
     skipSchema: true,
     overwrite: true,

+ 1 - 1
data/rcsb-graphql/codegen.json

@@ -1,5 +1,5 @@
 {
-    "flattenTypes": false,
+    "flattenTypes": true,
     "generatorConfig": {
         "printTime": true,
         "immutableTypes": true,

+ 23 - 24
src/apps/canvas/assembly-symmetry.ts

@@ -16,12 +16,12 @@ import { ColorTheme } from 'mol-theme/color';
 import { Location } from 'mol-model/location';
 import { StructureElement, Unit, StructureProperties } from 'mol-model/structure';
 
-export function getAxesShape(featureId: number, assemblySymmetry: AssemblySymmetry) {
-    const f = assemblySymmetry.db.rcsb_assembly_symmetry_feature
-    const feature = Table.pickRow(f, i => f.id.value(i) === featureId)
-    if (!feature) return
+export function getAxesShape(symmetryId: number, assemblySymmetry: AssemblySymmetry) {
+    const s = assemblySymmetry.db.rcsb_assembly_symmetry
+    const symmetry = Table.pickRow(s, i => s.id.value(i) === symmetryId)
+    if (!symmetry) return
 
-    const axes = assemblySymmetry.getAxes(featureId)
+    const axes = assemblySymmetry.getAxes(symmetryId)
     if (!axes._rowCount) return
 
     const vectorSpace = AssemblySymmetry.Schema.rcsb_assembly_symmetry_axis.start.space;
@@ -41,7 +41,7 @@ export function getAxesShape(featureId: number, assemblySymmetry: AssemblySymmet
         addSphere(meshBuilder, end, radius, 2)
         addCylinder(meshBuilder, start, end, 1, cylinderProps)
         colors.push(Color(0xCCEE11))
-        labels.push(`Axis ${i + 1} for ${feature.symmetry_value} ${feature.type.toLowerCase()} symmetry`)
+        labels.push(`Axis ${i + 1} for ${symmetry.kind} ${symmetry.type.toLowerCase()} symmetry`)
     }
     const mesh = meshBuilder.getMesh()
     const shape = Shape.create('Axes', mesh, colors, labels)
@@ -51,46 +51,45 @@ export function getAxesShape(featureId: number, assemblySymmetry: AssemblySymmet
 function getAsymId(unit: Unit): StructureElement.Property<string> {
     switch (unit.kind) {
         case Unit.Kind.Atomic:
-            return StructureProperties.chain.auth_asym_id // TODO
+            return StructureProperties.chain.label_asym_id
         case Unit.Kind.Spheres:
         case Unit.Kind.Gaussians:
             return StructureProperties.coarse.asym_id
     }
 }
 
-function memberKey (asym_id: string, oper_list_id?: number) {
-    return `${asym_id}|${oper_list_id}`
+function clusterMemberKey (asym_id: string, oper_list_ids: string[]) {
+    return `${asym_id}-${oper_list_ids.join('x')}`
 }
 
-export function getClusterColorTheme(featureId: number, assemblySymmetry: AssemblySymmetry): ColorTheme {
+export function getClusterColorTheme(symmetryId: number, assemblySymmetry: AssemblySymmetry): ColorTheme {
     const DefaultColor = Color(0xCCCCCC)
-    const f = assemblySymmetry.db.rcsb_assembly_symmetry_feature
-    const feature = Table.pickRow(f, i => f.id.value(i) === featureId)
-    if (!feature) return { granularity: 'uniform', color: () => DefaultColor }
+    const s = assemblySymmetry.db.rcsb_assembly_symmetry
+    const symmetry = Table.pickRow(s, i => s.id.value(i) === symmetryId)
+    if (!symmetry) return { granularity: 'uniform', color: () => DefaultColor }
 
-    const clusters = assemblySymmetry.getClusters(featureId)
+    const clusters = assemblySymmetry.getClusters(symmetryId)
     if (!clusters._rowCount) return { granularity: 'uniform', color: () => DefaultColor }
 
     const clusterByMember = new Map<string, number>()
     for (let i = 0, il = clusters._rowCount; i < il; ++i) {
-        clusters.members.value(i).forEach(m => {
-            const ms = m.split('_')
-            const asym_id = ms[0]
-            const oper_list_id = ms.length === 2 ? parseInt(ms[1]) : undefined
-            clusterByMember.set(memberKey(asym_id, oper_list_id), 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)
+            clusterByMember.set(clusterMemberKey(asym_id, oper_list_ids), i)
+        }
     }
-
     const scale = ColorScale.create({ domain: [ 0, clusters._rowCount - 1 ] })
 
     return {
         granularity: 'instance',
         color: (location: Location): Color => {
             if (StructureElement.isLocation(location)) {
-                const ns = location.unit.conformation.operator.name.split('-')
                 const asym_id = getAsymId(location.unit)
-                const oper_list_id = ns.length === 2 ? parseInt(ns[1]) : undefined
-                const cluster = clusterByMember.get(memberKey(asym_id(location), oper_list_id))
+                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
             }
             return DefaultColor

+ 21 - 26
src/apps/canvas/structure-view.ts

@@ -65,14 +65,14 @@ interface StructureViewProps {
 
 export async function StructureView(app: App, viewer: Canvas3D, models: ReadonlyArray<Model>, props: StructureViewProps = {}): Promise<StructureView> {
     const active: { [k: string]: boolean } = {
-        cartoon: false,
+        cartoon: true,
         point: false,
-        surface: true,
+        surface: false,
         ballAndStick: false,
         carbohydrate: false,
         spacefill: false,
         distanceRestraint: false,
-        symmetryAxes: false,
+        symmetryAxes: true,
         // polymerSphere: false,
     }
 
@@ -142,7 +142,7 @@ export async function StructureView(app: App, viewer: Canvas3D, models: Readonly
         } else if (model && model.symmetry.assemblies.length) {
             assemblyId = model.symmetry.assemblies[0].id
         } else if (model) {
-            assemblyId = '0'
+            assemblyId = 'deposited'
         } else {
             assemblyId = '-1'
         }
@@ -152,7 +152,7 @@ export async function StructureView(app: App, viewer: Canvas3D, models: Readonly
 
     function getAssemblyIds() {
         const assemblyIds: { id: string, label: string }[] = [
-            { id: '0', label: '0: model' }
+            { id: 'deposited', label: 'deposited' }
         ]
         if (model) model.symmetry.assemblies.forEach(a => {
             assemblyIds.push({ id: a.id, label: `${a.id}: ${a.details}` })
@@ -165,9 +165,9 @@ export async function StructureView(app: App, viewer: Canvas3D, models: Readonly
         if (newSymmetryFeatureId !== undefined) {
             symmetryFeatureId = newSymmetryFeatureId
         } else if (assemblySymmetry) {
-            const f = assemblySymmetry.getFeatures(assemblyId)
-            if (f._rowCount) {
-                symmetryFeatureId = f.id.value(0)
+            const s = assemblySymmetry.getSymmetries(assemblyId)
+            if (s._rowCount) {
+                symmetryFeatureId = s.id.value(0)
             } else {
                 symmetryFeatureId = -1
             }
@@ -180,13 +180,13 @@ export async function StructureView(app: App, viewer: Canvas3D, models: Readonly
     function getSymmetryFeatureIds() {
         const symmetryFeatureIds: { id: number, label: string }[] = []
         if (assemblySymmetry) {
-            const symmetryFeatures = assemblySymmetry.getFeatures(assemblyId)
-            for (let i = 0, il = symmetryFeatures._rowCount; i < il; ++i) {
-                const id = symmetryFeatures.id.value(i)
-                const symmetry = symmetryFeatures.symmetry_value.value(i)
-                const type = symmetryFeatures.type.value(i)
-                const stoichiometry = symmetryFeatures.stoichiometry_value.value(i)
-                const label = `${id}: ${symmetry} ${type} ${stoichiometry}`
+            const symmetries = assemblySymmetry.getSymmetries(assemblyId)
+            for (let i = 0, il = symmetries._rowCount; i < il; ++i) {
+                const id = symmetries.id.value(i)
+                const kind = symmetries.kind.value(i)
+                const type = symmetries.type.value(i)
+                const stoichiometry = symmetries.stoichiometry.value(i)
+                const label = `${id}: ${kind} ${type} ${stoichiometry}`
                 symmetryFeatureIds.push({ id, label })
             }
         }
@@ -255,20 +255,15 @@ export async function StructureView(app: App, viewer: Canvas3D, models: Readonly
 
     async function createSymmetryRepr() {
         if (assemblySymmetry) {
-            const features = assemblySymmetry.getFeatures(assemblyId)
-            if (features._rowCount) {
+            const symmetries = assemblySymmetry.getSymmetries(assemblyId)
+            if (symmetries._rowCount) {
                 const axesShape = getAxesShape(symmetryFeatureId, assemblySymmetry)
                 if (axesShape) {
                     // const colorTheme = getClusterColorTheme(symmetryFeatureId, assemblySymmetry)
-                    // await cartoon.createOrUpdate({
-                    //     colorTheme: { name: 'custom', color: colorTheme.color, granularity: colorTheme.granularity },
-                    //     sizeTheme: { name: 'uniform', value: 0.2 },
-                    //     useFog: false // TODO fog not working properly
-                    // }).run()
-                    // await ballAndStick.createOrUpdate({
-                    //     colorTheme:  { name: 'custom', color: colorTheme.color, granularity: colorTheme.granularity },
-                    //     sizeTheme: { name: 'uniform', value: 0.1 },
-                    //     useFog: false // TODO fog not working properly
+                    // await structureRepresentations['cartoon'].createOrUpdate({
+                    //     colorTheme: 'custom',
+                    //     colorFunction: colorTheme.color,
+                    //     colorGranularity: colorTheme.granularity,
                     // }).run()
                     await symmetryAxes.createOrUpdate({}, axesShape).run()
                     viewer.add(symmetryAxes)

+ 1 - 1
src/apps/canvas/util.ts

@@ -43,7 +43,7 @@ export async function getModelsFromMmcif(cif: CifBlock) {
 
 export async function getStructureFromModel(model: Model, assembly: string) {
     const assemblies = model.symmetry.assemblies
-    if (assembly === '0') {
+    if (assembly === 'deposited') {
         return Structure.ofModel(model)
     } else if (assemblies.find(a => a.id === assembly)) {
         return await StructureSymmetry.buildAssembly(Structure.ofModel(model), assembly).run()

+ 11 - 6
src/mol-geo/geometry/color-data.ts

@@ -10,7 +10,7 @@ import { Color } from 'mol-util/color';
 import { Vec2, Vec3 } from 'mol-math/linear-algebra';
 import { LocationIterator } from '../util/location-iterator';
 import { NullLocation } from 'mol-model/location';
-import { LocationColor, ColorThemeProps, ColorTheme, ColorThemeName } from 'mol-theme/color';
+import { LocationColor, ColorThemeProps, ColorTheme, ColorThemeName, ScaleLegend, TableLegend } from 'mol-theme/color';
 import { RuntimeContext } from 'mol-task';
 import { getGranularity } from './geometry';
 import { Structure } from 'mol-model/structure';
@@ -27,20 +27,25 @@ export type ColorData = {
 
 export interface ColorProps {
     colorTheme: ColorThemeName
+    colorDomain?: [number, number]
     colorValue?: Color
+    colorFunction?: LocationColor,
+    colorGranularity?: ColorType,
+    colorDescription?: string,
+    colorLegend?: ScaleLegend | TableLegend
     structure?: Structure
 }
 
 export function getColorThemeProps(props: ColorProps): ColorThemeProps {
     return {
         name: props.colorTheme,
-        // domain: [number, number],
+        domain: props.colorDomain,
         value: props.colorValue,
         structure: props.structure,
-        // color?: LocationColor,
-        // granularity?: ColorType,
-        // description?: string,
-        // legend?: ScaleLegend | TableLegend
+        color: props.colorFunction,
+        granularity: props.colorGranularity,
+        description: props.colorDescription,
+        legend: props.colorLegend
     }
 }
 

+ 1 - 1
src/mol-math/geometry/symmetry-operator.ts

@@ -52,7 +52,7 @@ namespace SymmetryOperator {
         return create(name, t);
     }
 
-    // Apply the 1st and then 2nd operator. ( = second.matrix * first.matrix)
+    /** Apply the 1st and then 2nd operator. ( = second.matrix * first.matrix). */
     export function compose(first: SymmetryOperator, second: SymmetryOperator) {
         const matrix = Mat4.mul(Mat4.zero(), second.matrix, first.matrix);
         return create(second.name, matrix, second.hkl);

+ 20 - 21
src/mol-model-props/rcsb/graphql/symmetry.gql.ts

@@ -4,29 +4,28 @@ function gql (strs: TemplateStringsArray) { return strs.raw.join('') }
 export default
 gql`query AssemblySymmetry($pdbId: String!) {
     assemblies(pdbId: $pdbId) {
-        assembly_id
-        rcsb_assembly_symmetry {
-            source
-            symmetry_features {
-                symmetry {
-                    description
-                    value
-                }
-                clusters {
-                    members
-                    avg_rmsd
-                }
-                stoichiometry {
-                    description
-                    value
-                }
-                symmetry_axes {
-                    start
-                    end
-                    order
+        pdbx_struct_assembly {
+            id
+        }
+        rcsb_struct_symmetry {
+            clusters {
+                avg_rmsd
+                members {
+                    asym_id
+                    pdbx_struct_oper_list_ids
                 }
-                type
             }
+            kind
+            oligomeric_state
+            rotation_axes {
+                start
+                end
+                order
+            }
+            stoichiometry
+            symbol
+            type
         }
+        rcsb_struct_symmetry_provenance
     }
 }`

Разлика између датотеке није приказан због своје велике величине
+ 1070 - 37
src/mol-model-props/rcsb/graphql/types.ts


+ 131 - 80
src/mol-model-props/rcsb/symmetry.ts

@@ -17,6 +17,7 @@ import { Tensor } from 'mol-math/linear-algebra';
 import { CifExportContext } from 'mol-model/structure/export/mmcif';
 import { toTable } from 'mol-io/reader/cif/schema';
 import { CifCategory } from 'mol-io/reader/cif';
+import { PropertyWrapper } from 'mol-model-props/common/wrapper';
 
 const { str, int, float, Aliased, Vector, List } = Column.Schema;
 
@@ -31,51 +32,58 @@ function getCategory(name: keyof AssemblySymmetry.Schema) {
     return { name, instance: getInstance(name) }
 }
 
-function createDatabase(assemblies: ReadonlyArray<AssemblySymmetryGraphQL.Assemblies>): AssemblySymmetry.Database {
+function createDatabaseFromJson(assemblies: ReadonlyArray<AssemblySymmetryGraphQL.Assemblies>): AssemblySymmetry.Database {
     const Schema = AssemblySymmetry.Schema
 
-    const featureRows: Table.Row<typeof Schema.rcsb_assembly_symmetry_feature>[] = []
+    const featureRows: Table.Row<typeof Schema.rcsb_assembly_symmetry>[] = []
     const clusterRows: Table.Row<typeof Schema.rcsb_assembly_symmetry_cluster>[] = []
+    const clusterMemberRows: Table.Row<typeof Schema.rcsb_assembly_symmetry_cluster_member>[] = []
     const axisRows: Table.Row<typeof Schema.rcsb_assembly_symmetry_axis>[] = []
 
     let id = 1 // start feature ids at 1
     for (let i = 0, il = assemblies.length; i < il; ++i) {
-        const { assembly_id: _assembly_id, rcsb_assembly_symmetry } = assemblies[i]
-        if (!rcsb_assembly_symmetry) continue
-        const assembly_id = _assembly_id.toString() // TODO type will be fixed to string upstream
-        const source = rcsb_assembly_symmetry.source
-        const symmetry_features = rcsb_assembly_symmetry.symmetry_features
-        for (let j = 0, jl = symmetry_features.length; j < jl; ++j) {
-            const f = symmetry_features[j]! // TODO upstream, array members should not be nullable
+        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
+        const assembly_id = pdbx_struct_assembly.id
+        for (let j = 0, jl = rcsb_struct_symmetry.length; j < jl; ++j) {
+            const rss = rcsb_struct_symmetry[j]! // TODO upstream, array members should not be nullable
             featureRows.push({
                 id,
                 assembly_id,
-                source,
-                type: f.type,
-                stoichiometry_value: f.stoichiometry.value as string[],  // TODO upstream, array members should not be nullable
-                stoichiometry_description: f.stoichiometry.description,
-                symmetry_value: f.symmetry.value,
-                symmetry_description: f.symmetry.description
+                provenance: rcsb_struct_symmetry_provenance,
+                type: rss.type,
+                stoichiometry: rss.stoichiometry as string[],  // TODO upstream, array members should not be nullable
+                kind: rss.kind,
+                symbol: rss.symbol,
+                oligomeric_state: rss.oligomeric_state
             })
 
-            const clusters = f.clusters
+            const clusters = rss.clusters
             if (clusters) {
                 for (let k = 0, kl = clusters.length; k < kl; ++k) {
                     const c = clusters[k]! // TODO upstream, array members should not be nullable
                     clusterRows.push({
-                        feature_id: id,
+                        id: k,
+                        symmetry_id: id,
                         avg_rmsd: c.avg_rmsd || 0, // TODO upstream, should not be nullable, or???
-                        members: c.members as string[] // TODO upstream, array members should not be nullable
                     })
+                    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,
+                            asym_id: m.asym_id,
+                            pdbx_struct_oper_list_ids: (m.pdbx_struct_oper_list_ids || []) as string[]
+                        })
+                    }
                 }
             }
 
-            const axes = f.symmetry_axes
+            const axes = rss.rotation_axes
             if (axes) {
                 for (let k = 0, kl = axes.length; k < kl; ++k) {
                     const a = axes[k]!
                     axisRows.push({
-                        feature_id: id,
+                        symmetry_id: id,
                         order: a.order!,  // TODO upstream, should not be nullable, or???
                         start: a.start as Tensor.Data, // TODO upstream, array members should not be nullable
                         end: a.end as Tensor.Data // TODO upstream, array members should not be nullable
@@ -88,20 +96,57 @@ function createDatabase(assemblies: ReadonlyArray<AssemblySymmetryGraphQL.Assemb
     }
 
     return _Database.ofTables('assembly_symmetry', Schema, {
-        rcsb_assembly_symmetry_feature: Table.ofRows(Schema.rcsb_assembly_symmetry_feature, featureRows),
+        rcsb_assembly_symmetry: Table.ofRows(Schema.rcsb_assembly_symmetry, featureRows),
         rcsb_assembly_symmetry_cluster: Table.ofRows(Schema.rcsb_assembly_symmetry_cluster, clusterRows),
+        rcsb_assembly_symmetry_cluster_member: Table.ofRows(Schema.rcsb_assembly_symmetry_cluster_member, clusterMemberRows),
         rcsb_assembly_symmetry_axis: Table.ofRows(Schema.rcsb_assembly_symmetry_axis, axisRows)
     })
 }
 
+function createDatabaseFromCif(model: Model): AssemblySymmetry.Database {
+    const Schema = AssemblySymmetry.Schema
+
+    const rcsb_assembly_symmetry = toTable(Schema.rcsb_assembly_symmetry, model.sourceData.frame.categories.rcsb_assembly_symmetry_feature)
+
+    let rcsb_assembly_symmetry_cluster
+    if (model.sourceData.frame.categoryNames.includes('rcsb_assembly_symmetry_cluster')) {
+        rcsb_assembly_symmetry_cluster = toTable(Schema.rcsb_assembly_symmetry_cluster, model.sourceData.frame.categories.rcsb_assembly_symmetry_cluster)
+    } else {
+        rcsb_assembly_symmetry_cluster = CifCategory.empty
+    }
+
+    let rcsb_assembly_symmetry_cluster_member
+    if (model.sourceData.frame.categoryNames.includes('rcsb_assembly_symmetry_cluster_member')) {
+        rcsb_assembly_symmetry_cluster_member = toTable(Schema.rcsb_assembly_symmetry_cluster_member, model.sourceData.frame.categories.rcsb_assembly_symmetry_cluster_member)
+    } else {
+        rcsb_assembly_symmetry_cluster_member = CifCategory.empty
+    }
+
+    let rcsb_assembly_symmetry_axis
+    if (model.sourceData.frame.categoryNames.includes('rcsb_assembly_symmetry_axis')) {
+        rcsb_assembly_symmetry_axis = toTable(Schema.rcsb_assembly_symmetry_axis, model.sourceData.frame.categories.rcsb_assembly_symmetry_axis)
+    } else {
+        rcsb_assembly_symmetry_axis = CifCategory.empty
+    }
+
+    return _Database.ofTables('rcsb_assembly_symmetry', Schema, {
+        rcsb_assembly_symmetry,
+        rcsb_assembly_symmetry_cluster,
+        rcsb_assembly_symmetry_cluster_member,
+        rcsb_assembly_symmetry_axis
+    })
+}
+
 const _Descriptor: ModelPropertyDescriptor = {
     isStatic: true,
-    name: 'assembly_symmetry',
+    name: 'rcsb_assembly_symmetry',
     cifExport: {
         prefix: 'rcsb',
         categories: [
-            getCategory('rcsb_assembly_symmetry_feature'),
+            PropertyWrapper.defaultInfoCategory<CifExportContext>('rcsb_assembly_symmetry_info', ctx => PropertyWrapper.createInfo()),
+            getCategory('rcsb_assembly_symmetry'),
             getCategory('rcsb_assembly_symmetry_cluster'),
+            getCategory('rcsb_assembly_symmetry_cluster_member'),
             getCategory('rcsb_assembly_symmetry_axis')
         ]
     }
@@ -111,56 +156,85 @@ const client = new GraphQLClient('http://rest-experimental.rcsb.org/graphql')
 
 export interface AssemblySymmetry {
     db: AssemblySymmetry.Database
-    getFeatures(assemblyId: string): Table<AssemblySymmetry.Schema['rcsb_assembly_symmetry_feature']>
-    getClusters(featureId: number): Table<AssemblySymmetry.Schema['rcsb_assembly_symmetry_cluster']>
-    getAxes(featureId: number): Table<AssemblySymmetry.Schema['rcsb_assembly_symmetry_axis']>
+    getSymmetries(assemblyId: 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']>
 }
 
 export function AssemblySymmetry(db: AssemblySymmetry.Database): AssemblySymmetry {
-    const f = db.rcsb_assembly_symmetry_feature
+    const f = db.rcsb_assembly_symmetry
     const c = db.rcsb_assembly_symmetry_cluster
+    const cm = db.rcsb_assembly_symmetry_cluster_member
     const a = db.rcsb_assembly_symmetry_axis
 
     return {
         db,
-        getFeatures: (assemblyId: string) => Table.pick(f, f._schema, i => f.assembly_id.value(i) === assemblyId),
-        getClusters: (featureId: number) => Table.pick(c, c._schema, i => c.feature_id.value(i) === featureId),
-        getAxes: (featureId: number) => Table.pick(a, a._schema, i => a.feature_id.value(i) === featureId)
+        getSymmetries: (assemblyId: string) => Table.pick(f, f._schema, i => f.assembly_id.value(i) === assemblyId),
+        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)
     }
 }
 
 export namespace AssemblySymmetry {
     export const Schema = {
-        rcsb_assembly_symmetry_feature: {
-            /** Uniquely identifies a record in `rcsb_assembly_symmetry_feature` */
+        rcsb_assembly_symmetry_info: {
+            updated_datetime_utc: Column.Schema.str
+        },
+        rcsb_assembly_symmetry: {
+            /** Uniquely identifies a record in `rcsb_assembly_symmetry` */
             id: int,
-            /** A pointer to `pdbx_struct_assembly.id` */
+            /**
+             * A pointer to `pdbx_struct_assembly.id`.
+             * The value 'deposited' refers to the coordinates as given in the file.
+             * */
             assembly_id: str,
-            /** Name and version of software used to calculate protein symmetry */
-            source: str,
+            /** Name and version of software used to calculate assembly symmetry */
+            provenance: str,
             /** Type of protein symmetry */
-            type: Aliased<'GLOBAL' | 'LOCAL' | 'PSEUDO'>(str),
+            kind: Aliased<'GLOBAL' | 'LOCAL' | 'PSEUDO'>(str),
             /** Quantitative description of every individual subunit in a given protein */
-            stoichiometry_value: List(',', x => x),
-            /** Oligomeric state for a given composition of subunits */
-            stoichiometry_description: str,
-            /** Point group symmetry value */
-            symmetry_value: str,
-            /** Point group symmetry description */
-            symmetry_description: str
+            stoichiometry: List(',', x => x),
+            /**
+             * Symmetry symbol refers to point group or helical symmetry of identical subunits.
+             * Contains point group symbol (e.g., C2, C5, D2, T, O, I) or H for helical symmetry.
+             */
+            symbol: str,
+            /** Point group or helical symmetry */
+            type: Aliased<'ASYMMETRIC' | 'CYCLIC' | 'DIHEDRAL' | 'HELICAL' | 'ICOSAHEDRAL' | 'OCTAHEDRAL' | 'TETRAHEDRAL'>(str),
+            /**
+             * Oligomeric state refers to a composition of subunits in quaternary structure.
+             * Quaternary structure may be composed either exclusively of several copies of identical
+             * subunits, in which case they are termed homo-oligomers, or alternatively by at least
+             * one copy of different subunits (hetero-oligomers). Quaternary structure composed of
+             * a single subunit is demoted as 'Monomer'.
+             */
+            oligomeric_state: str,
         },
         rcsb_assembly_symmetry_cluster: {
-            /** A pointer to `rcsb_assembly_symmetry_feature.id` */
-            feature_id: int,
+            /** Uniquely identifies a record in `rcsb_assembly_symmetry_cluster` */
+            id: int,
+            /** A pointer to `rcsb_assembly_symmetry.id` */
+            symmetry_id: int,
             /** Average RMSD between members of a given cluster */
-            avg_rmsd: float,
-            /** List of `auth_label_id` values  */
-            members: List(',', x => x)
+            avg_rmsd: float
+        },
+        rcsb_assembly_symmetry_cluster_member: {
+            /** A pointer to `rcsb_assembly_symmetry_cluster.id` */
+            cluster_id: int,
+            /** The `label_asym_id` value of the member */
+            asym_id: str,
+            /** List of `pdbx_struct_oper_list_id` values of the member */
+            pdbx_struct_oper_list_ids: List(',', x => x)
         },
         rcsb_assembly_symmetry_axis: {
-            /** A pointer to `rcsb_assembly_symmetry_feature.id` */
-            feature_id: int,
-            /** The order of the symmetry axis */
+            /** A pointer to `rcsb_assembly_symmetry.id` */
+            symmetry_id: int,
+            /**
+             * The number of times (order of rotation) that a subunit can be repeated by a rotation
+             * operation, being transformed into a new state indistinguishable from its starting state.
+             */
             order: int,
             /** The x,y,z coordinate of the start point of a symmetry axis */
             start: Vector(3),
@@ -177,32 +251,9 @@ export namespace AssemblySymmetry {
         if (model.customProperties.has(Descriptor)) return true;
 
         let db: Database
-
-        // TODO: there should be a "meta field" that indicates the property was added (see for example PDBe structure report)
-        // the reason for this is that the feature might not be present and therefore the "default" categories would
-        // not be created. This would result in an unnecessarily failed web request.
-        if (model.sourceData.kind === 'mmCIF' && model.sourceData.frame.categoryNames.includes('rcsb_assembly_symmetry_feature')) {
-            const rcsb_assembly_symmetry_feature = toTable(Schema.rcsb_assembly_symmetry_feature, model.sourceData.frame.categories.rcsb_assembly_symmetry_feature)
-
-            let rcsb_assembly_symmetry_cluster
-            if (model.sourceData.frame.categoryNames.includes('rcsb_assembly_symmetry_cluster')) {
-                rcsb_assembly_symmetry_cluster = toTable(Schema.rcsb_assembly_symmetry_cluster, model.sourceData.frame.categories.rcsb_assembly_symmetry_cluster)
-            } else {
-                rcsb_assembly_symmetry_cluster = CifCategory.empty
-            }
-
-            let rcsb_assembly_symmetry_axis
-            if (model.sourceData.frame.categoryNames.includes('rcsb_assembly_symmetry_axis')) {
-                rcsb_assembly_symmetry_axis = toTable(Schema.rcsb_assembly_symmetry_axis, model.sourceData.frame.categories.rcsb_assembly_symmetry_axis)
-            } else {
-                rcsb_assembly_symmetry_axis = CifCategory.empty
-            }
-
-            db = _Database.ofTables('assembly_symmetry', Schema, {
-                rcsb_assembly_symmetry_feature,
-                rcsb_assembly_symmetry_cluster,
-                rcsb_assembly_symmetry_axis
-            })
+        let info = PropertyWrapper.tryGetInfoFromCif('rcsb_assembly_symmetry_info', model);
+        if (info) {
+            db = createDatabaseFromCif(model)
         } else {
             let result: AssemblySymmetryGraphQL.Query
             const variables: AssemblySymmetryGraphQL.Variables = { pdbId: model.label.toLowerCase() };
@@ -214,15 +265,15 @@ export namespace AssemblySymmetry {
             }
             if (!result || !result.assemblies) return false;
 
-            db = createDatabase(result.assemblies as ReadonlyArray<AssemblySymmetryGraphQL.Assemblies>)
+            db = createDatabaseFromJson(result.assemblies as ReadonlyArray<AssemblySymmetryGraphQL.Assemblies>)
         }
 
         model.customProperties.add(Descriptor);
-        model._staticPropertyData.__AssemblySymmetry__ = AssemblySymmetry(db);
+        model._staticPropertyData.__RCSBAssemblySymmetry__ = AssemblySymmetry(db);
         return true;
     }
 
     export function get(model: Model): AssemblySymmetry | undefined {
-        return model._staticPropertyData.__AssemblySymmetry__;
+        return model._staticPropertyData.__RCSBAssemblySymmetry__;
     }
 }

Неке датотеке нису приказане због велике количине промена