mol.spec.ts 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /**
  2. * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  6. * @author Panagiotis Tourlas <panagiot_tourlov@hotmail.com>
  7. */
  8. import { parseMol, formalChargeMapper } from '../mol/parser';
  9. const MolString = `2244
  10. -OEChem-04072009073D
  11. 21 21 0 0 0 0 0 0 0999 V2000
  12. 1.2333 0.5540 0.7792 O 0 0 0 0 0 0 0 0 0 0 0 0
  13. -0.6952 -2.7148 -0.7502 O 0 0 0 0 0 0 0 0 0 0 0 0
  14. 0.7958 -2.1843 0.8685 O 0 0 0 0 0 0 0 0 0 0 0 0
  15. 1.7813 0.8105 -1.4821 O 0 0 0 0 0 0 0 0 0 0 0 0
  16. -0.0857 0.6088 0.4403 C 0 0 0 0 0 0 0 0 0 0 0 0
  17. -0.7927 -0.5515 0.1244 C 0 0 0 0 0 0 0 0 0 0 0 0
  18. -0.7288 1.8464 0.4133 C 0 0 0 0 0 0 0 0 0 0 0 0
  19. -2.1426 -0.4741 -0.2184 C 0 0 0 0 0 0 0 0 0 0 0 0
  20. -2.0787 1.9238 0.0706 C 0 0 0 0 0 0 0 0 0 0 0 0
  21. -2.7855 0.7636 -0.2453 C 0 0 0 0 0 0 0 0 0 0 0 0
  22. -0.1409 -1.8536 0.1477 C 0 0 0 0 0 0 0 0 0 0 0 0
  23. 2.1094 0.6715 -0.3113 C 0 0 0 0 0 0 0 0 0 0 0 0
  24. 3.5305 0.5996 0.1635 C 0 0 0 0 0 0 0 0 0 0 0 0
  25. -0.1851 2.7545 0.6593 H 0 0 0 0 0 0 0 0 0 0 0 0
  26. -2.7247 -1.3605 -0.4564 H 0 0 0 0 0 0 0 0 0 0 0 0
  27. -2.5797 2.8872 0.0506 H 0 0 0 0 0 0 0 0 0 0 0 0
  28. -3.8374 0.8238 -0.5090 H 0 0 0 0 0 0 0 0 0 0 0 0
  29. 3.7290 1.4184 0.8593 H 0 0 0 0 0 0 0 0 0 0 0 0
  30. 4.2045 0.6969 -0.6924 H 0 0 0 0 0 0 0 0 0 0 0 0
  31. 3.7105 -0.3659 0.6426 H 0 0 0 0 0 0 0 0 0 0 0 0
  32. -0.2555 -3.5916 -0.7337 H 0 0 0 0 0 0 0 0 0 0 0 0
  33. 1 5 1 0 0 0 0
  34. 1 12 1 0 0 0 0
  35. 2 11 1 0 0 0 0
  36. 2 21 1 0 0 0 0
  37. 3 11 2 0 0 0 0
  38. 4 12 2 0 0 0 0
  39. 5 6 1 0 0 0 0
  40. 5 7 2 0 0 0 0
  41. 6 8 2 0 0 0 0
  42. 6 11 1 0 0 0 0
  43. 7 9 1 0 0 0 0
  44. 7 14 1 0 0 0 0
  45. 8 10 1 0 0 0 0
  46. 8 15 1 0 0 0 0
  47. 9 10 2 0 0 0 0
  48. 9 16 1 0 0 0 0
  49. 10 17 1 0 0 0 0
  50. 12 13 1 0 0 0 0
  51. 13 18 1 0 0 0 0
  52. 13 19 1 0 0 0 0
  53. 13 20 1 0 0 0 0
  54. M END`;
  55. const MolStringWithAtomBlockCharge = `
  56. Ketcher 1 72215442D 1 1.00000 0.00000 0
  57. 4 3 0 0 0 0 999 V2000
  58. 0.0000 0.0000 0.0000 C 0 1 0 0 0 0 0 0 0 0 0 0
  59. 0.8660 0.5000 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
  60. -0.8660 0.5000 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0
  61. 0.0000 -1.0000 0.0000 P 0 0 0 0 0 0 0 0 0 0 0 0
  62. 1 4 2 0 0 0 0
  63. 3 1 1 0 0 0 0
  64. 2 1 1 0 0 0 0
  65. M END`;
  66. const MolStringWithPropertyBlockCharge = `
  67. Ketcher 1 72215442D 1 1.00000 0.00000 0
  68. 4 3 0 0 0 0 999 V2000
  69. 0.0000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
  70. 0.8660 0.5000 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
  71. -0.8660 0.5000 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0
  72. 0.0000 -1.0000 0.0000 P 0 0 0 0 0 0 0 0 0 0 0 0
  73. 1 4 2 0 0 0 0
  74. 3 1 1 0 0 0 0
  75. 2 1 1 0 0 0 0
  76. M CHG 3 2 -1 3 1 4 1
  77. M END`;
  78. const MolStringWithMultipleChargeLines = `
  79. Ketcher 1 72215442D 1 1.00000 0.00000 0
  80. 4 3 0 0 0 0 999 V2000
  81. 0.0000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
  82. 0.8660 0.5000 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
  83. -0.8660 0.5000 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0
  84. 0.0000 -1.0000 0.0000 P 0 0 0 0 0 0 0 0 0 0 0 0
  85. 1 4 2 0 0 0 0
  86. 3 1 1 0 0 0 0
  87. 2 1 1 0 0 0 0
  88. M CHG 1 2 -1
  89. M CHG 2 3 1 4 1
  90. M END`;
  91. describe('mol reader', () => {
  92. it('basic', async () => {
  93. const parsed = await parseMol(MolString).run();
  94. if (parsed.isError) {
  95. throw new Error(parsed.message);
  96. }
  97. const { atoms, bonds } = parsed.result;
  98. // number of structures
  99. expect(atoms.count).toBe(21);
  100. expect(bonds.count).toBe(21);
  101. expect(atoms.x.value(0)).toBeCloseTo(1.2333, 0.001);
  102. expect(atoms.y.value(0)).toBeCloseTo(0.5540, 0.0001);
  103. expect(atoms.z.value(0)).toBeCloseTo(0.7792, 0.0001);
  104. expect(atoms.type_symbol.value(0)).toBe('O');
  105. expect(bonds.atomIdxA.value(20)).toBe(13);
  106. expect(bonds.atomIdxB.value(20)).toBe(20);
  107. expect(bonds.order.value(20)).toBe(1);
  108. });
  109. it('property block charges', async () => {
  110. const parsed = await parseMol(MolStringWithPropertyBlockCharge).run();
  111. if (parsed.isError) {
  112. throw new Error(parsed.message);
  113. }
  114. const { formalCharges } = parsed.result;
  115. expect(formalCharges.atomIdx.rowCount).toBe(3);
  116. expect(formalCharges.charge.rowCount).toBe(3);
  117. expect(formalCharges.atomIdx.value(0)).toBe(2);
  118. expect(formalCharges.atomIdx.value(1)).toBe(3);
  119. expect(formalCharges.charge.value(0)).toBe(-1);
  120. expect(formalCharges.charge.value(1)).toBe(1);
  121. });
  122. it('multiple charge lines', async () => {
  123. const parsed = await parseMol(MolStringWithMultipleChargeLines).run();
  124. if (parsed.isError) {
  125. throw new Error(parsed.message);
  126. }
  127. const { formalCharges } = parsed.result;
  128. expect(formalCharges.atomIdx.rowCount).toBe(3);
  129. expect(formalCharges.charge.rowCount).toBe(3);
  130. expect(formalCharges.atomIdx.value(0)).toBe(2);
  131. expect(formalCharges.atomIdx.value(1)).toBe(3);
  132. expect(formalCharges.charge.value(0)).toBe(-1);
  133. expect(formalCharges.charge.value(1)).toBe(1);
  134. });
  135. it('atom block charge mapping', async () => {
  136. expect(formalChargeMapper(7)).toBe(-3);
  137. expect(formalChargeMapper(6)).toBe(-2);
  138. expect(formalChargeMapper(5)).toBe(-1);
  139. expect(formalChargeMapper(0)).toBe(0);
  140. expect(formalChargeMapper(3)).toBe(1);
  141. expect(formalChargeMapper(2)).toBe(2);
  142. expect(formalChargeMapper(1)).toBe(3);
  143. expect(formalChargeMapper(4)).toBe(0);
  144. });
  145. it('atom block charges', async () => {
  146. const parsed = await parseMol(MolStringWithAtomBlockCharge).run();
  147. if (parsed.isError) {
  148. throw new Error(parsed.message);
  149. }
  150. const { atoms, formalCharges } = parsed.result;
  151. /* No property block charges */
  152. expect(formalCharges.atomIdx.rowCount).toBe(0);
  153. expect(formalCharges.charge.rowCount).toBe(0);
  154. expect(atoms.formal_charge.value(0)).toBe(1);
  155. expect(atoms.formal_charge.value(1)).toBe(0);
  156. expect(atoms.formal_charge.value(2)).toBe(0);
  157. expect(atoms.formal_charge.value(3)).toBe(0);
  158. });
  159. });