Browse Source

stub for sdf writing

JonStargaryen 5 years ago
parent
commit
087d5fbb68
2 changed files with 57 additions and 14 deletions
  1. 51 13
      src/mol-io/writer/sdf/encoder.ts
  2. 6 1
      src/servers/model/server/query.ts

+ 51 - 13
src/mol-io/writer/sdf/encoder.ts

@@ -8,14 +8,19 @@ import { StringBuilder } from '../../../mol-util';
 import Writer from '../writer';
 import { Encoder, Category, Field } from '../cif/encoder';
 import { getCategoryInstanceData } from '../cif/encoder/util';
+import { ComponentBond } from '../../../mol-model-formats/structure/property/bonds/comp';
 
 // specification: http://c4.cabrillo.edu/404/ctfile.pdf
 export class SdfEncoder implements Encoder<string> {
     private builder: StringBuilder;
     private meta: StringBuilder;
     private encoded = false;
-    private dataBlockCreated = false;
     private error = false;
+    private componentData: ComponentBond;
+
+    setComponentBondData(componentData: ComponentBond) {
+        this.componentData = componentData;
+    }
 
     writeTo(stream: Writer) {
         const chunks = StringBuilder.getChunks(this.builder);
@@ -32,9 +37,8 @@ export class SdfEncoder implements Encoder<string> {
         return StringBuilder.getString(this.builder);
     }
 
-    startDataBlock(name: string) {
-        this.dataBlockCreated = true;
-        StringBuilder.write(this.builder, `${name}\nCreated by ${this.encoder}\n\n`);
+    startDataBlock() {
+        
     }
 
     writeCategory<Ctx>(category: Category<Ctx>, context?: Ctx) {
@@ -42,10 +46,6 @@ export class SdfEncoder implements Encoder<string> {
             throw new Error('The writer contents have already been encoded, no more writing.');
         }
 
-        if (!this.dataBlockCreated) {
-            throw new Error('No data block created.');
-        }
-
         if (!this.hideMetaInformation && (category.name === 'model_server_result' || category.name === 'model_server_params' || category.name === 'model_server_stats' || category.name === 'model_server_error')) {
             this.writeFullCategory(this.meta, category, context);
             // if error: force writing of meta information
@@ -69,7 +69,15 @@ export class SdfEncoder implements Encoder<string> {
         // 'Specifies the atomic symbol and any mass difference, charge, stereochemistry, and associated hydrogens for each atom.'
         const { instance, source, rowCount: atomCount } = getCategoryInstanceData(category, context);
         const fields = this.getSortedFields(instance);
+        const label_atom_id = this.getField(instance, 'label_atom_id');
+        const label_comp_id = this.getField(instance, 'label_comp_id');
         const fieldCount = fields.length;
+
+        // write header
+        const name = label_comp_id.value(source[0].keys().move(), source[0].data, 0) as string;
+        StringBuilder.write(this.builder, `${name}\nCreated by ${this.encoder}\n\n`);
+
+        const bondMap = this.componentData.entries.get(name)!;
         let bondCount = 0;
 
         let index = 0;
@@ -82,14 +90,33 @@ export class SdfEncoder implements Encoder<string> {
             const it = src.keys();
             while (it.hasNext)  {
                 const key = it.move();
-
                 for (let _f = 0; _f < fieldCount; _f++) {
                     const f: Field<any, any> = fields[_f]!;
                     const val = f.value(key, data, index);
+                    if (f.name === 'type_symbol') {
+                        const lai = label_atom_id.value(key, data, index) as string;
+                        const { id, label } = this.split(lai);
+                        if (label.startsWith('H')) { // TODO consider hydrogen option
+                            continue;
+                        }
+
+                        bondMap.map.get(lai)!.forEach((v, k) => {
+                            const { id: partnerId, label: partnerLabel } = this.split(k);
+                            if (id <= partnerId && !partnerLabel.startsWith('H')) { // TODO consider hydrogen option
+                                const { order } = v;
+                                StringBuilder.writeIntegerPadLeft(bonds, id, 3);
+                                StringBuilder.writeIntegerPadLeft(bonds, partnerId, 3);
+                                StringBuilder.writeIntegerPadLeft(bonds, order, 3);
+                                StringBuilder.writeSafe(bonds, '  0  0  0  0\n'); 
+                                // TODO 2nd value: Single bonds: 0 = not stereo, 1 = Up, 4 = Either, 6 = Down, Double bonds: 0 = Use x-, y-, z-coords from atom block to determine cis or trans, 3 = Cis or trans (either) double bond
+                                bondCount++;
+                            }
+                        });
+                    }
                     this.writeValue(ctab, val, f.type);
                 }
                 
-                StringBuilder.writeSafe(ctab, '  0  0  0  0  0\n');
+                StringBuilder.writeSafe(ctab, '  0  0  0  0  0  0  0  0  0  0  0  0\n');
 
                 index++;
             }
@@ -99,15 +126,22 @@ export class SdfEncoder implements Encoder<string> {
         // 'Important specifications here relate to the number of atoms, bonds, and atom lists, the chiral flag setting, and the Ctab version.'
         StringBuilder.writeIntegerPadLeft(this.builder, atomCount, 3);
         StringBuilder.writeIntegerPadLeft(this.builder, bondCount, 3);
-        StringBuilder.write(this.builder, '  0  0  0  0  0  0  0  0999 V2000\n');
+        StringBuilder.write(this.builder, '  0     0  0  0  0  0  0999 V2000\n'); // TODO 2nd value: chiral flag: 0=not chiral, 1=chiral 
 
         StringBuilder.writeSafe(this.builder, StringBuilder.getString(ctab));
         StringBuilder.writeSafe(this.builder, StringBuilder.getString(bonds));
-        StringBuilder.writeSafe(this.builder, StringBuilder.getString(charges));
+        StringBuilder.writeSafe(this.builder, StringBuilder.getString(charges)); // TODO charges
         
         StringBuilder.writeSafe(this.builder, 'M  END\n');
     }
 
+    private split(s: string) {
+        return {
+            id: Number.parseInt(s.replace(/[^0-9]+/, '')),
+            label: s.replace(/[^A-Z]+/, '')
+        }
+    }
+
     private writeFullCategory<Ctx>(sb: StringBuilder, category: Category<Ctx>, context?: Ctx) {
         const { instance, source } = getCategoryInstanceData(category, context);
         const fields = instance.fields;
@@ -141,7 +175,11 @@ export class SdfEncoder implements Encoder<string> {
 
     private getSortedFields<Ctx>(instance: Category.Instance<Ctx>) {
         return ['Cartn_x', 'Cartn_y', 'Cartn_z', 'type_symbol']
-            .map(n => instance.fields.find(f => f.name === n));
+            .map(n => this.getField(instance, n));
+    }
+
+    private getField<Ctx>(instance: Category.Instance<Ctx>, name: string) {
+        return instance.fields.find(f => f.name === name)!;
     }
 
     readonly isBinary = false;

+ 6 - 1
src/servers/model/server/query.ts

@@ -23,6 +23,8 @@ import CifField = CifWriter.Field
 import { splitCamelCase } from '../../../mol-util/string';
 import { Encoder } from '../../../mol-io/writer/cif/encoder';
 import { Encoding } from './api';
+import { ComponentBond } from '../../../mol-model-formats/structure/property/bonds/comp';
+import { SdfEncoder } from '../../../mol-io/writer/sdf/encoder';
 
 export interface Stats {
     structure: StructureWrapper,
@@ -195,7 +197,10 @@ async function resolveJobEntry(entry: JobEntry, structure: StructureWrapper, enc
         // TODO: this actually needs to "reversible" in case of error.
         encoder.writeCategory(_model_server_result, entry);
         encoder.writeCategory(_model_server_params, entry);
-        console.log(structure.models[0]._staticPropertyData['chem_comp_data'].entries['THA']);
+
+        if (encoder instanceof SdfEncoder) {
+            encoder.setComponentBondData(ComponentBond.Provider.get(structure.models[0])!);
+        }
 
         if (!entry.copyAllCategories && entry.queryDefinition.filter) encoder.setFilter(entry.queryDefinition.filter);
         if (result.length > 0) encode_mmCIF_categories(encoder, result, { copyAllCategories: entry.copyAllCategories });