|
@@ -15,6 +15,8 @@ import { Database as _Database, Column, Table } from 'mol-data/db'
|
|
|
import { Category } from 'mol-io/writer/cif/encoder';
|
|
|
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';
|
|
|
|
|
|
const { str, int, float, Aliased, Vector, List } = Column.Schema;
|
|
|
|
|
@@ -38,28 +40,31 @@ function createDatabase(assemblies: ReadonlyArray<AssemblySymmetryGraphQL.Assemb
|
|
|
|
|
|
let id = 0
|
|
|
for (let i = 0, il = assemblies.length; i < il; ++i) {
|
|
|
- const a = assemblies[i]
|
|
|
- const assembly_id = (a.assembly_id!).toString()
|
|
|
- const source = a.rcsb_assembly_symmetry!.source!
|
|
|
- const symmetry_features = a.rcsb_assembly_symmetry!.symmetry_features!
|
|
|
+ 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]!
|
|
|
+ const f = symmetry_features[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[],
|
|
|
- stoichiometry_description: f.stoichiometry!.description!
|
|
|
+ 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
|
|
|
})
|
|
|
|
|
|
const clusters = f.clusters
|
|
|
if (clusters) {
|
|
|
for (let k = 0, kl = clusters.length; k < kl; ++k) {
|
|
|
- const c = clusters[k]!
|
|
|
+ const c = clusters[k]! // TODO upstream, array members should not be nullable
|
|
|
clusterRows.push({
|
|
|
feature_id: id,
|
|
|
- avg_rmsd: c.avg_rmsd!,
|
|
|
+ avg_rmsd: c.avg_rmsd || 0, // TODO upstream, should not be nullable, or???
|
|
|
members: c.members as string[]
|
|
|
})
|
|
|
}
|
|
@@ -71,9 +76,9 @@ function createDatabase(assemblies: ReadonlyArray<AssemblySymmetryGraphQL.Assemb
|
|
|
const a = axes[k]!
|
|
|
axisRows.push({
|
|
|
feature_id: id,
|
|
|
- order: a.order!,
|
|
|
- start: a.start as Tensor.Data,
|
|
|
- end: a.end as Tensor.Data
|
|
|
+ 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
|
|
|
})
|
|
|
}
|
|
|
}
|
|
@@ -83,9 +88,9 @@ function createDatabase(assemblies: ReadonlyArray<AssemblySymmetryGraphQL.Assemb
|
|
|
}
|
|
|
|
|
|
return _Database.ofTables('assembly_symmetry', Schema, {
|
|
|
- assembly_symmetry_feature: Table.ofRows(Schema.rcsb_assembly_symmetry_feature, featureRows),
|
|
|
- assembly_symmetry_cluster: Table.ofRows(Schema.rcsb_assembly_symmetry_cluster, clusterRows),
|
|
|
- assembly_symmetry_axis: Table.ofRows(Schema.rcsb_assembly_symmetry_axis, axisRows)
|
|
|
+ rcsb_assembly_symmetry_feature: Table.ofRows(Schema.rcsb_assembly_symmetry_feature, featureRows),
|
|
|
+ rcsb_assembly_symmetry_cluster: Table.ofRows(Schema.rcsb_assembly_symmetry_cluster, clusterRows),
|
|
|
+ rcsb_assembly_symmetry_axis: Table.ofRows(Schema.rcsb_assembly_symmetry_axis, axisRows)
|
|
|
})
|
|
|
}
|
|
|
|
|
@@ -107,22 +112,39 @@ const client = new GraphQLClient('http://rest-experimental.rcsb.org/graphql')
|
|
|
export namespace AssemblySymmetry {
|
|
|
export const Schema = {
|
|
|
rcsb_assembly_symmetry_feature: {
|
|
|
+ /** Uniquely identifies a record in `rcsb_assembly_symmetry_feature` */
|
|
|
id: int,
|
|
|
+ /** A pointer to `pdbx_struct_assembly.id` */
|
|
|
assembly_id: str,
|
|
|
+ /** Name and version of software used to calculate protein symmetry */
|
|
|
source: str,
|
|
|
+ /** Type of protein symmetry */
|
|
|
type: Aliased<'GLOBAL' | 'LOCAL' | 'PSEUDO'>(str),
|
|
|
+ /** Quantitative description of every individual subunit in a given protein */
|
|
|
stoichiometry_value: List(',', x => x),
|
|
|
- stoichiometry_description: str
|
|
|
+ /** 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
|
|
|
},
|
|
|
rcsb_assembly_symmetry_cluster: {
|
|
|
+ /** A pointer to `rcsb_assembly_symmetry_feature.id` */
|
|
|
feature_id: int,
|
|
|
+ /** Average RMSD between members of a given cluster */
|
|
|
avg_rmsd: float,
|
|
|
+ /** List of `auth_label_id` values */
|
|
|
members: List(',', x => x)
|
|
|
},
|
|
|
rcsb_assembly_symmetry_axis: {
|
|
|
+ /** A pointer to `rcsb_assembly_symmetry_feature.id` */
|
|
|
feature_id: int,
|
|
|
+ /** The order of the symmetry axis */
|
|
|
order: int,
|
|
|
+ /** The x,y,z coordinate of the start point of a symmetry axis */
|
|
|
start: Vector(3),
|
|
|
+ /** The x,y,z coordinate of the end point of a symmetry axis */
|
|
|
end: Vector(3)
|
|
|
}
|
|
|
}
|
|
@@ -131,17 +153,49 @@ export namespace AssemblySymmetry {
|
|
|
|
|
|
export const Descriptor = _Descriptor;
|
|
|
|
|
|
- export async function attachFromRCSB(model: Model) {
|
|
|
+ export async function attachFromCifOrAPI(model: Model) {
|
|
|
if (model.customProperties.has(Descriptor)) return true;
|
|
|
|
|
|
- const variables: AssemblySymmetryGraphQL.Variables = { pdbId: model.label.toLowerCase() };
|
|
|
- const result = await client.request<AssemblySymmetryGraphQL.Query>(query, variables);
|
|
|
- if (!result || !result.assemblies) return false;
|
|
|
+ let db: Database
|
|
|
+
|
|
|
+ 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
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ let result: AssemblySymmetryGraphQL.Query
|
|
|
+ const variables: AssemblySymmetryGraphQL.Variables = { pdbId: model.label.toLowerCase() };
|
|
|
+ try {
|
|
|
+ result = await client.request<AssemblySymmetryGraphQL.Query>(query, variables);
|
|
|
+ } catch (e) {
|
|
|
+ console.error(e)
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (!result || !result.assemblies) return false;
|
|
|
+
|
|
|
+ db = createDatabase(result.assemblies as ReadonlyArray<AssemblySymmetryGraphQL.Assemblies>)
|
|
|
+ }
|
|
|
|
|
|
- const db: Database = createDatabase(result.assemblies as ReadonlyArray<AssemblySymmetryGraphQL.Assemblies>)
|
|
|
model.customProperties.add(Descriptor);
|
|
|
model._staticPropertyData.__AssemblySymmetry__ = db;
|
|
|
-
|
|
|
return true;
|
|
|
}
|
|
|
|