ligand-encoder.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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 { StringBuilder } from '../../mol-util';
  7. import Writer from './writer';
  8. import { Encoder, Category, Field } from './cif/encoder';
  9. import { ComponentAtom } from '../../mol-model-formats/structure/property/atoms/chem_comp';
  10. import { ComponentBond } from '../../mol-model-formats/structure/property/bonds/chem_comp';
  11. interface Atom {
  12. Cartn_x: number,
  13. Cartn_y: number,
  14. Cartn_z: number,
  15. type_symbol: string,
  16. index: number
  17. }
  18. function Atom(partial: any): Atom {
  19. return { ...partial };
  20. }
  21. export abstract class LigandEncoder implements Encoder<string> {
  22. protected builder: StringBuilder;
  23. protected meta: StringBuilder;
  24. protected componentAtomData: ComponentAtom;
  25. protected componentBondData: ComponentBond;
  26. protected error = false;
  27. protected encoded = false;
  28. readonly isBinary = false;
  29. binaryEncodingProvider = void 0;
  30. abstract encode(): void;
  31. protected abstract _writeCategory<Ctx>(category: Category<Ctx>, context?: Ctx): void;
  32. protected abstract writeFullCategory<Ctx>(sb: StringBuilder, category: Category<Ctx>, context?: Ctx): void;
  33. writeCategory<Ctx>(category: Category<Ctx>, context?: Ctx) {
  34. if (this.encoded) {
  35. throw new Error('The writer contents have already been encoded, no more writing.');
  36. }
  37. if (this.metaInformation && (category.name === 'model_server_result' || category.name === 'model_server_params' || category.name === 'model_server_stats')) {
  38. this.writeFullCategory(this.meta, category, context);
  39. return;
  40. }
  41. // if error: force writing of meta information
  42. if (category.name === 'model_server_error') {
  43. this.writeFullCategory(this.meta, category, context);
  44. this.error = true;
  45. return;
  46. }
  47. // only care about atom_site category when writing SDF
  48. if (category.name !== 'atom_site') {
  49. return;
  50. }
  51. this._writeCategory(category, context);
  52. }
  53. setComponentAtomData(componentAtomData: ComponentAtom) {
  54. this.componentAtomData = componentAtomData;
  55. }
  56. setComponentBondData(componentBondData: ComponentBond) {
  57. this.componentBondData = componentBondData;
  58. }
  59. writeTo(stream: Writer) {
  60. const chunks = StringBuilder.getChunks(this.builder);
  61. for (let i = 0, _i = chunks.length; i < _i; i++) {
  62. stream.writeString(chunks[i]);
  63. }
  64. }
  65. getSize() {
  66. return StringBuilder.getSize(this.builder);
  67. }
  68. getData() {
  69. return StringBuilder.getString(this.builder);
  70. }
  71. protected getAtoms<Ctx>(instance: Category.Instance<Ctx>, source: any): Map<string, Atom> {
  72. const sortedFields = this.getSortedFields(instance, ['Cartn_x', 'Cartn_y', 'Cartn_z']);
  73. const label_atom_id = this.getField(instance, 'label_atom_id');
  74. const type_symbol = this.getField(instance, 'type_symbol');
  75. return this._getAtoms(source, sortedFields, label_atom_id, type_symbol);
  76. }
  77. private _getAtoms(source: any, fields: Field<any, any>[], label_atom_id: Field<any, any>, type_symbol: Field<any, any>): Map<string, Atom> {
  78. const atoms = new Map<string, Atom>();
  79. let index = 0;
  80. // is outer loop even needed?
  81. for (let _c = 0; _c < source.length; _c++) {
  82. const src = source[_c];
  83. const data = src.data;
  84. if (src.rowCount === 0) continue;
  85. const it = src.keys();
  86. while (it.hasNext) {
  87. const key = it.move();
  88. const lai = label_atom_id.value(key, data, index) as string;
  89. const ts = type_symbol.value(key, data, index) as string;
  90. if (this.skipHydrogen(ts)) {
  91. index++;
  92. continue;
  93. }
  94. const a: { [k: string]: (string | number) } = {};
  95. for (let _f = 0, _fl = fields.length; _f < _fl; _f++) {
  96. const f: Field<any, any> = fields[_f]!;
  97. a[f.name] = f.value(key, data, index);
  98. }
  99. a[type_symbol.name] = ts;
  100. a['index'] = index;
  101. atoms.set(lai, Atom(a));
  102. index++;
  103. }
  104. }
  105. return atoms;
  106. }
  107. protected skipHydrogen(type_symbol: string) {
  108. if (this.hydrogens) {
  109. return false;
  110. }
  111. return type_symbol === 'H';
  112. }
  113. private getSortedFields<Ctx>(instance: Category.Instance<Ctx>, names: string[]) {
  114. return names.map(n => this.getField(instance, n));
  115. }
  116. private getField<Ctx>(instance: Category.Instance<Ctx>, name: string) {
  117. return instance.fields.find(f => f.name === name)!;
  118. }
  119. protected getName<Ctx>(instance: Category.Instance<Ctx>, source: any): string {
  120. const label_comp_id = this.getField(instance, 'label_comp_id');
  121. return label_comp_id.value(source[0].keys().move(), source[0].data, 0) as string;
  122. }
  123. startDataBlock() {}
  124. setFilter() {}
  125. setFormatter() {}
  126. isCategoryIncluded() {
  127. return true;
  128. }
  129. constructor(readonly encoder: string, readonly metaInformation: boolean, readonly hydrogens: boolean) {
  130. this.builder = StringBuilder.create();
  131. this.meta = StringBuilder.create();
  132. }
  133. }