ソースを参照

mmCIF export, mandatory category prefix for model custom props

David Sehnal 6 年 前
コミット
c20577b359

+ 22 - 0
src/mol-model/structure/export/categories/atom_site.ts

@@ -59,4 +59,26 @@ export const _atom_site: CifCategory<CifExportContext> = {
             keys: () => structure.elementLocations()
         };
     }
+}
+
+export function residueIdFields<K, D>(getLocation: (key: K, data: D) => StructureElement): CifField<K, D>[] {
+    return [
+        CifField.str('label_comp_id', (k, d) => P.residue.label_comp_id(getLocation(k, d))),
+        CifField.int('label_seq_id', (k, d) => P.residue.label_seq_id(getLocation(k, d)), {
+            encoder: E.deltaRLE,
+            valueKind: (k, d) => {
+                const e = getLocation(k, d);
+                const m = e.unit.model;
+                return m.atomicHierarchy.residues.label_seq_id.valueKind(m.atomicHierarchy.residueAtomSegments.index[e.element]);
+            }
+        }),
+        CifField.str('pdbx_PDB_ins_code', (k, d) => P.residue.pdbx_PDB_ins_code(getLocation(k, d))),
+
+        CifField.str('label_asym_id', (k, d) => P.chain.label_asym_id(getLocation(k, d))),
+        CifField.str('label_entity_id', (k, d) => P.chain.label_entity_id(getLocation(k, d))),
+
+        CifField.str('auth_comp_id', (k, d) => P.residue.auth_comp_id(getLocation(k, d))),
+        CifField.int('auth_seq_id', (k, d) => P.residue.auth_seq_id(getLocation(k, d)), { encoder: E.deltaRLE }),
+        CifField.str('auth_asym_id', (k, d) => P.chain.auth_asym_id(getLocation(k, d))),
+    ]
 }

+ 2 - 0
src/mol-model/structure/export/mmcif.ts

@@ -98,8 +98,10 @@ export function encode_mmCIF_categories(encoder: CifWriter.Encoder, structure: S
         encoder.writeCategory(cat, ctx);
     }
     for (const customProp of model.customProperties.all) {
+        const prefix = customProp.cifExport.prefix;
         const cats = customProp.cifExport.categories;
         for (const cat of cats) {
+            if (cat.name.indexOf(prefix) !== 0) throw new Error(`Custom category '${cat.name}' name must start with prefix '${prefix}.'`);
             encoder.writeCategory(cat, ctx);
         }
     }

+ 1 - 0
src/mol-model/structure/model/formats/mmcif/bonds/comp.ts

@@ -22,6 +22,7 @@ export namespace ComponentBond {
         isStatic: true,
         name: 'chem_comp_bond',
         cifExport: {
+            prefix: '',
             categories: [{
                 name: 'chem_comp_bond',
                 instance(ctx) {

+ 1 - 0
src/mol-model/structure/model/formats/mmcif/bonds/struct_conn.ts

@@ -27,6 +27,7 @@ export namespace StructConn {
         isStatic: true,
         name: 'struct_conn',
         cifExport: {
+            prefix: '',
             categories: [{
                 name: 'struct_conn',
                 instance(ctx) {

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

@@ -13,6 +13,8 @@ interface ModelPropertyDescriptor<Symbols extends { [name: string]: QuerySymbolR
     readonly name: string,
 
     cifExport: {
+        // Prefix enforced during export.
+        prefix: string,
         categories: CifWriter.Category<CifExportContext>[]
     },
 

+ 1 - 1
src/perf-tests/mol-script.ts

@@ -46,7 +46,7 @@ console.log(result);
 const CustomProp = ModelPropertyDescriptor({
     name: 'test_prop',
     isStatic: true,
-    cifExport: { categories: [ ]},
+    cifExport: { prefix: '', categories: [ ]},
     symbols: {
         residueIndex: QuerySymbolRuntime.Dynamic(CustomPropSymbol('custom.test-prop', 'residue-index', Type.Num), ctx => {
             const e = ctx.element;

+ 3 - 2
src/servers/model/properties.ts

@@ -7,13 +7,14 @@
 
 import { Model } from 'mol-model/structure';
 import { StructureQualityReport } from './properties/structure-quality-report';
-import { SymmetryAnnotation } from './properties/rcsb/symmetry';
+// import { SymmetryAnnotation } from './properties/rcsb/symmetry';
 
 export function attachModelProperties(model: Model): Promise<any>[] {
     // return a list of promises that start attaching the props in parallel
     // (if there are downloads etc.)
     return [
         StructureQualityReport.attachFromPDBeApi(model),
-        SymmetryAnnotation.attachFromRCSB(model)
+        // removed for now because of schema validation error
+        // SymmetryAnnotation.attachFromRCSB(model)
     ];
 }

+ 13 - 12
src/servers/model/properties/rcsb/symmetry.ts

@@ -32,9 +32,9 @@ function getCategory(name: keyof SymmetryAnnotation.Schema) {
 function createDatabase(assemblies: ReadonlyArray<RcsbSymmetry.Assemblies>): SymmetryAnnotation.Database {
     const Schema = SymmetryAnnotation.Schema
 
-    const featureRows: Table.Row<typeof Schema.symmetry_annotation_feature>[] = []
-    const clusterRows: Table.Row<typeof Schema.symmetry_annotation_cluster>[] = []
-    const axisRows: Table.Row<typeof Schema.symmetry_annotation_axis>[] = []
+    const featureRows: Table.Row<typeof Schema.rcsb_symmetry_annotation_feature>[] = []
+    const clusterRows: Table.Row<typeof Schema.rcsb_symmetry_annotation_cluster>[] = []
+    const axisRows: Table.Row<typeof Schema.rcsb_symmetry_annotation_axis>[] = []
 
     let id = 0
     for (let i = 0, il = assemblies.length; i < il; ++i) {
@@ -83,9 +83,9 @@ function createDatabase(assemblies: ReadonlyArray<RcsbSymmetry.Assemblies>): Sym
     }
 
     return _Database.ofTables('symmetry_annotation', Schema, {
-        symmetry_annotation_feature: Table.ofRows(Schema.symmetry_annotation_feature, featureRows),
-        symmetry_annotation_cluster: Table.ofRows(Schema.symmetry_annotation_cluster, clusterRows),
-        symmetry_annotation_axis: Table.ofRows(Schema.symmetry_annotation_axis, axisRows)
+        symmetry_annotation_feature: Table.ofRows(Schema.rcsb_symmetry_annotation_feature, featureRows),
+        symmetry_annotation_cluster: Table.ofRows(Schema.rcsb_symmetry_annotation_cluster, clusterRows),
+        symmetry_annotation_axis: Table.ofRows(Schema.rcsb_symmetry_annotation_axis, axisRows)
     })
 }
 
@@ -93,10 +93,11 @@ const _Descriptor: ModelPropertyDescriptor = {
     isStatic: true,
     name: 'symmetry_annotation',
     cifExport: {
+        prefix: 'rcsb',
         categories: [
-            getCategory('symmetry_annotation_feature'),
-            getCategory('symmetry_annotation_cluster'),
-            getCategory('symmetry_annotation_axis')
+            getCategory('rcsb_symmetry_annotation_feature'),
+            getCategory('rcsb_symmetry_annotation_cluster'),
+            getCategory('rcsb_symmetry_annotation_axis')
         ]
     }
 }
@@ -105,7 +106,7 @@ const client = new GraphQLClient('http://rest-experimental.rcsb.org/graphql')
 
 export namespace SymmetryAnnotation {
     export const Schema = {
-        symmetry_annotation_feature: {
+        rcsb_symmetry_annotation_feature: {
             id: int,
             assembly_id: str,
             source: str,
@@ -113,12 +114,12 @@ export namespace SymmetryAnnotation {
             stoichiometry_value: List(',', x => x),
             stoichiometry_description: str
         },
-        symmetry_annotation_cluster: {
+        rcsb_symmetry_annotation_cluster: {
             feature_id: int,
             avg_rmsd: float,
             members: List(',', x => x)
         },
-        symmetry_annotation_axis: {
+        rcsb_symmetry_annotation_axis: {
             feature_id: int,
             order: int,
             start: Vector(3),

+ 6 - 12
src/servers/model/properties/structure-quality-report.ts

@@ -4,11 +4,12 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { ResidueIndex, ModelPropertyDescriptor, Model, Structure, Unit, StructureElement, StructureProperties as P  } from 'mol-model/structure';
+import { ResidueIndex, ModelPropertyDescriptor, Model, Structure, Unit, StructureElement } from 'mol-model/structure';
 import fetch from 'node-fetch';
 import { CifWriter } from 'mol-io/writer/cif';
 import CifField = CifWriter.Field;
 import { Segmentation } from 'mol-data/int';
+import { residueIdFields } from 'mol-model/structure/export/categories/atom_site';
 
 type IssueMap = Map<ResidueIndex, string[]>
 
@@ -16,8 +17,9 @@ const _Descriptor: ModelPropertyDescriptor = {
     isStatic: true,
     name: 'structure_quality_report',
     cifExport: {
+        prefix: 'pdbe',
         categories: [{
-            name: 'structure_quality_report',
+            name: 'pdbe_structure_quality_report',
             instance(ctx) {
                 const issues = StructureQualityReport.get(ctx.model);
                 if (!issues) return CifWriter.Category.Empty;
@@ -36,16 +38,8 @@ const _Descriptor: ModelPropertyDescriptor = {
 type ExportCtx = { model: Model, residueIndex: ArrayLike<ResidueIndex>, residues: StructureElement[], issues: IssueMap };
 
 const _structure_quality_report_fields: CifField<ResidueIndex, ExportCtx>[] = [
-    CifField.str<ResidueIndex, ExportCtx>('label_comp_id', (i, d) => P.residue.label_comp_id(d.residues[i])),
-    CifField.int<ResidueIndex, ExportCtx>('label_seq_id', (i, d) => P.residue.label_seq_id(d.residues[i])),
-    CifField.str<ResidueIndex, ExportCtx>('pdbx_PDB_ins_code', (i, d) => P.residue.pdbx_PDB_ins_code(d.residues[i])),
-    CifField.str<ResidueIndex, ExportCtx>('label_asym_id', (i, d) => P.chain.label_asym_id(d.residues[i])),
-    CifField.str<ResidueIndex, ExportCtx>('label_entity_id', (i, d) => P.entity.id(d.residues[i])),
-
-    CifField.str<ResidueIndex, ExportCtx>('auth_comp_id', (i, d) => P.residue.auth_comp_id(d.residues[i])),
-    CifField.int<ResidueIndex, ExportCtx>('auth_seq_id', (i, d) => P.residue.auth_seq_id(d.residues[i])),
-    CifField.str<ResidueIndex, ExportCtx>('auth_asym_id', (i, d) => P.chain.auth_asym_id(d.residues[i])),
-
+    CifField.index('id'),
+    ...residueIdFields<ResidueIndex, ExportCtx>((k, d) => d.residues[k]),
     CifField.str<ResidueIndex, ExportCtx>('issues', (i, d) => d.issues.get(d.residueIndex[d.residues[i].element])!.join(','))
 ];