Ver Fonte

unique group check

JonStargaryen há 4 anos atrás
pai
commit
40bbd87c4e
2 ficheiros alterados com 46 adições e 33 exclusões
  1. 40 27
      src/mol-io/writer/sdf/encoder.ts
  2. 6 6
      src/servers/model/server/query.ts

+ 40 - 27
src/mol-io/writer/sdf/encoder.ts

@@ -4,7 +4,7 @@
  * @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
  */
 
-import { StringBuilder } from '../../../mol-util';
+import { StringBuilder, deepEqual } from '../../../mol-util';
 import Writer from '../writer';
 import { Encoder, Category, Field } from '../cif/encoder';
 import { getCategoryInstanceData } from '../cif/encoder/util';
@@ -40,7 +40,7 @@ export class SdfEncoder implements Encoder<string> {
     }
 
     startDataBlock() {
-        
+
     }
 
     writeCategory<Ctx>(category: Category<Ctx>, context?: Ctx) {
@@ -71,11 +71,14 @@ export class SdfEncoder implements Encoder<string> {
         const charges = StringBuilder.create();
 
         // write Atom block and gather data for Bonds and Charges
-        // 'Specifies the atomic symbol and any mass difference, charge, stereochemistry, and associated hydrogens for each atom.'
         const { instance, source } = getCategoryInstanceData(category, context);
-        const sortedFields = this.getSortedFields(instance);
-        const label_atom_id = this.getField(instance, 'label_atom_id');
+        const sortedFields = this.getSortedFields(instance, ['Cartn_x', 'Cartn_y', 'Cartn_z', 'type_symbol']);
         const label_comp_id = this.getField(instance, 'label_comp_id');
+        const label_atom_id = this.getField(instance, 'label_atom_id');
+
+        // all of this is used to ensure that only 1 residue is written
+        // TODO potentially we could use a dedicated query mode or use the 'correct' SDF definition and allow an arbitrary number of molecules in a file
+        const auxiliaryFields = this.getSortedFields(instance, ['label_seq_id', 'label_asym_id', 'pdbx_PDB_ins_code', 'pdbx_PDB_model_num']);
 
         // write header
         const name = label_comp_id.value(source[0].keys().move(), source[0].data, 0) as string;
@@ -85,43 +88,44 @@ export class SdfEncoder implements Encoder<string> {
         let bondCount = 0;
 
         // traverse once to determine all actually present atoms
-        const atoms = this.getAtoms(source, sortedFields, label_atom_id, ctab);
+        const atoms = this.getAtoms(source, sortedFields, label_atom_id, auxiliaryFields, ctab);
         for (let i1 = 0, il = atoms.length; i1 < il; i1++) {
-            const name1 = atoms[i1];
-            bondMap.map.get(name1)!.forEach((bv, bk) => {
-                const i2 = atoms.indexOf(bk);
-                const label2 = this.getLabel(bk);
-                if (i1 < i2 && atoms.indexOf(bk) > -1 && !this.skipHydrogen(label2)) {
-                    const { order } = bv;
+            bondMap.map.get(atoms[i1])!.forEach((v, k) => {
+                const i2 = atoms.indexOf(k);
+                const label2 = this.getLabel(k);
+                if (i1 < i2 && atoms.indexOf(k) > -1 && !this.skipHydrogen(label2)) {
+                    const { order } = v;
                     StringBuilder.writeIntegerPadLeft(bonds, i1 + 1, 3);
                     StringBuilder.writeIntegerPadLeft(bonds, i2 + 1, 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
+                    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++;
                 }
             });
         }
 
         // write counts line
-        // '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, atoms.length, 3);
         StringBuilder.writeIntegerPadLeft(this.builder, bondCount, 3);
-        StringBuilder.write(this.builder, '  0     0  0  0  0  0  0999 V2000\n'); // TODO 2nd value: chiral flag: 0=not chiral, 1=chiral 
+        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)); // TODO charges
-        
+        StringBuilder.writeSafe(this.builder, StringBuilder.getString(charges));
+        // TODO charges?
+
         StringBuilder.writeSafe(this.builder, 'M  END\n');
     }
 
-    private getAtoms(source: any, fields: Field<any, any>[], label_atom_id: Field<any, any>, ctab: StringBuilder): string[] {
+    private getAtoms(source: any, fields: Field<any, any>[], label_atom_id: Field<any, any>, auxiliaryFields: Field<any, any>[], ctab: StringBuilder): string[] {
         const atoms = [];
         let index = 0;
+        let id;
 
-        for (let _c = 0; _c < source.length; _c++) {
+        // is this loop needed?
+        l: for (let _c = 0; _c < source.length; _c++) {
             const src = source[_c];
             const data = src.data;
 
@@ -131,6 +135,16 @@ export class SdfEncoder implements Encoder<string> {
             while (it.hasNext)  {
                 const key = it.move();
 
+                // ensure only a single residue is written
+                // TODO fairly certain this can be done at query level
+                if (!id) {
+                    id = auxiliaryFields.map(af => af.value(key, data, 0));
+                } else {
+                    if (!deepEqual(id, auxiliaryFields.map(af => af.value(key, data, index)))) {
+                        break l;
+                    }
+                }
+
                 const lai = label_atom_id.value(key, data, index) as string;
                 const label = this.getLabel(lai);
                 if (this.skipHydrogen(label)) {
@@ -138,13 +152,13 @@ export class SdfEncoder implements Encoder<string> {
                     continue;
                 }
                 atoms.push(lai);
-                
+
                 for (let _f = 0, _fl = fields.length; _f < _fl; _f++) {
                     const f: Field<any, any> = fields[_f]!;
                     const v = f.value(key, data, index);
                     this.writeValue(ctab, v, f.type);
                 }
-                
+
                 StringBuilder.writeSafe(ctab, '  0  0  0  0  0  0  0  0  0  0  0  0\n');
                 index++;
             }
@@ -174,7 +188,7 @@ export class SdfEncoder implements Encoder<string> {
         const key = it.move();
         for (let _f = 0; _f < fields.length; _f++) {
             const f = fields[_f]!;
-    
+
             StringBuilder.writeSafe(sb, `> <${category.name}.${f.name}>\n`);
             const val = f.value(key, data, 0);
             StringBuilder.writeSafe(sb, val as string);
@@ -195,9 +209,8 @@ export class SdfEncoder implements Encoder<string> {
         }
     }
 
-    private getSortedFields<Ctx>(instance: Category.Instance<Ctx>) {
-        return ['Cartn_x', 'Cartn_y', 'Cartn_z', 'type_symbol']
-            .map(n => this.getField(instance, n));
+    private getSortedFields<Ctx>(instance: Category.Instance<Ctx>, names: string[]) {
+        return names.map(n => this.getField(instance, n));
     }
 
     private getField<Ctx>(instance: Category.Instance<Ctx>, name: string) {

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

@@ -54,14 +54,14 @@ function createEncoder(responseFormat: ResponseFormat): Encoder {
     switch (responseFormat.encoding) {
         case 'bcif':
             return CifWriter.createEncoder({
-            binary: true,
-            encoderName: `ModelServer ${Version}`,
-            binaryAutoClassifyEncoding: true
-        });
+                binary: true,
+                encoderName: `ModelServer ${Version}`,
+                binaryAutoClassifyEncoding: true
+            });
         case 'sdf':
-            return SdfWriter.createEncoder({ 
+            return SdfWriter.createEncoder({
                 encoderName: `ModelServer ${Version}`
-            })
+            });
         case 'mol2':
             throw Error('impl me');
         default: