encoder.ts 4.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. /**
  2. * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
  5. */
  6. import { Category } from '../cif/encoder';
  7. import { LigandEncoder } from '../ligand-encoder';
  8. import { StringBuilder } from '../../../mol-util';
  9. import { getCategoryInstanceData } from '../cif/encoder/util';
  10. import { BondType } from '../../../mol-model/structure/model/types';
  11. // specification: http://chemyang.ccnu.edu.cn/ccb/server/AIMMS/mol2.pdf
  12. // TODO amide (and real sp/sp2/sp3) support for bonds and SYBYL atom types: see https://www.sdsc.edu/CCMS/Packages/cambridge/pluto/atom_types.html
  13. export class Mol2Encoder extends LigandEncoder {
  14. private out: StringBuilder;
  15. _writeCategory<Ctx>(category: Category<Ctx>, context?: Ctx): void {
  16. const a = StringBuilder.create();
  17. const b = StringBuilder.create();
  18. const { instance, source } = getCategoryInstanceData(category, context);
  19. // write header
  20. const name = this.getName(instance, source);
  21. StringBuilder.writeSafe(this.builder, `# Name: ${name}\n# Created by ${this.encoder}\n\n`);
  22. const bondMap = this.componentBondData.entries.get(name)!;
  23. let bondCount = 0;
  24. const atoms = this.getAtoms(instance, source);
  25. StringBuilder.writeSafe(a, '@<TRIPOS>ATOM\n');
  26. StringBuilder.writeSafe(b, '@<TRIPOS>BOND\n');
  27. for (let i1 = 0, il = atoms.length; i1 < il; i1++) {
  28. const atom = atoms[i1];
  29. let aromatic = false;
  30. bondMap.map.get(atom.label_atom_id)!.forEach((v, k) => {
  31. const i2 = atoms.findIndex(e => e.label_atom_id === k);
  32. const label2 = this.getLabel(k);
  33. if (i1 < i2 && atoms.findIndex(e => e.label_atom_id === k) > -1 && !this.skipHydrogen(label2)) {
  34. const { order, flags } = v;
  35. const ar = flags === BondType.Flag.Aromatic;
  36. if (ar) aromatic = true;
  37. StringBuilder.writeSafe(b, `${++bondCount} ${i1 + 1} ${i2 + 1} ${ar ? 'ar' : order}`);
  38. StringBuilder.newline(b);
  39. }
  40. });
  41. const sub = aromatic ? '.ar' : '';
  42. StringBuilder.writeSafe(a, `${i1 + 1} ${atom.type_symbol} ${atom.Cartn_x.toFixed(3)} ${atom.Cartn_y.toFixed(3)} ${atom.Cartn_z.toFixed(3)} ${atom.type_symbol}${sub} 1 ${name} 0.000\n`);
  43. }
  44. StringBuilder.writeSafe(this.out, `@<TRIPOS>MOLECULE\n${name}\n${atoms.length} ${bondCount} 0 0 0\nSMALL\nNO_CHARGES\n\n`);
  45. StringBuilder.writeSafe(this.out, StringBuilder.getString(a));
  46. StringBuilder.writeSafe(this.out, StringBuilder.getString(b));
  47. StringBuilder.writeSafe(this.out, `@<TRIPOS>SUBSTRUCTURE\n${name} ${name} 1\n`);
  48. }
  49. protected writeFullCategory<Ctx>(sb: StringBuilder, category: Category<Ctx>, context?: Ctx) {
  50. const { instance, source } = getCategoryInstanceData(category, context);
  51. const fields = instance.fields;
  52. const src = source[0];
  53. const data = src.data;
  54. const it = src.keys();
  55. const key = it.move();
  56. for (let _f = 0; _f < fields.length; _f++) {
  57. const f = fields[_f]!;
  58. StringBuilder.writeSafe(sb, `# ${category.name}.${f.name}: `);
  59. const val = f.value(key, data, 0);
  60. StringBuilder.writeSafe(sb, val as string);
  61. StringBuilder.newline(sb);
  62. }
  63. StringBuilder.newline(sb);
  64. }
  65. encode(): void {
  66. // write meta-information, do so after ctab
  67. if (this.error || this.metaInformation) {
  68. StringBuilder.writeSafe(this.builder, StringBuilder.getString(this.meta));
  69. }
  70. StringBuilder.writeSafe(this.builder, StringBuilder.getString(this.out));
  71. this.encoded = true;
  72. }
  73. constructor(encoder: string, metaInformation: boolean, hydrogens: boolean) {
  74. super(encoder, metaInformation, hydrogens);
  75. this.out = StringBuilder.create();
  76. }
  77. }