rino 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/README +44 -0
  2. data/Rakefile +123 -0
  3. data/ext/extconf.rb +26 -0
  4. data/ext/ruby_inchi_main.so +0 -0
  5. data/ext/src/aux2atom.h +2786 -0
  6. data/ext/src/comdef.h +148 -0
  7. data/ext/src/e_0dstereo.c +3014 -0
  8. data/ext/src/e_0dstereo.h +31 -0
  9. data/ext/src/e_comdef.h +57 -0
  10. data/ext/src/e_ctl_data.h +147 -0
  11. data/ext/src/e_ichi_io.c +498 -0
  12. data/ext/src/e_ichi_io.h +40 -0
  13. data/ext/src/e_ichi_parms.c +37 -0
  14. data/ext/src/e_ichi_parms.h +41 -0
  15. data/ext/src/e_ichicomp.h +50 -0
  16. data/ext/src/e_ichierr.h +40 -0
  17. data/ext/src/e_ichimain.c +593 -0
  18. data/ext/src/e_ichisize.h +43 -0
  19. data/ext/src/e_inchi_atom.c +75 -0
  20. data/ext/src/e_inchi_atom.h +33 -0
  21. data/ext/src/e_inpdef.h +41 -0
  22. data/ext/src/e_mode.h +706 -0
  23. data/ext/src/e_mol2atom.c +649 -0
  24. data/ext/src/e_readinch.c +58 -0
  25. data/ext/src/e_readmol.c +54 -0
  26. data/ext/src/e_readmol.h +180 -0
  27. data/ext/src/e_readstru.c +251 -0
  28. data/ext/src/e_readstru.h +33 -0
  29. data/ext/src/e_util.c +284 -0
  30. data/ext/src/e_util.h +61 -0
  31. data/ext/src/extr_ct.h +251 -0
  32. data/ext/src/ichi.h +206 -0
  33. data/ext/src/ichi_bns.c +7999 -0
  34. data/ext/src/ichi_bns.h +231 -0
  35. data/ext/src/ichican2.c +5000 -0
  36. data/ext/src/ichicano.c +2195 -0
  37. data/ext/src/ichicano.h +49 -0
  38. data/ext/src/ichicans.c +1625 -0
  39. data/ext/src/ichicant.h +379 -0
  40. data/ext/src/ichicomn.h +260 -0
  41. data/ext/src/ichicomp.h +50 -0
  42. data/ext/src/ichidrp.h +119 -0
  43. data/ext/src/ichierr.h +124 -0
  44. data/ext/src/ichiisot.c +101 -0
  45. data/ext/src/ichilnct.c +286 -0
  46. data/ext/src/ichimain.h +132 -0
  47. data/ext/src/ichimak2.c +1189 -0
  48. data/ext/src/ichimake.c +3812 -0
  49. data/ext/src/ichimake.h +205 -0
  50. data/ext/src/ichimap1.c +851 -0
  51. data/ext/src/ichimap2.c +2856 -0
  52. data/ext/src/ichimap4.c +1609 -0
  53. data/ext/src/ichinorm.c +741 -0
  54. data/ext/src/ichinorm.h +67 -0
  55. data/ext/src/ichiparm.c +45 -0
  56. data/ext/src/ichiparm.h +1441 -0
  57. data/ext/src/ichiprt1.c +3612 -0
  58. data/ext/src/ichiprt2.c +1511 -0
  59. data/ext/src/ichiprt3.c +3011 -0
  60. data/ext/src/ichiqueu.c +1003 -0
  61. data/ext/src/ichiring.c +326 -0
  62. data/ext/src/ichiring.h +49 -0
  63. data/ext/src/ichisize.h +35 -0
  64. data/ext/src/ichisort.c +539 -0
  65. data/ext/src/ichister.c +3538 -0
  66. data/ext/src/ichister.h +35 -0
  67. data/ext/src/ichitaut.c +3843 -0
  68. data/ext/src/ichitaut.h +387 -0
  69. data/ext/src/ichitime.h +74 -0
  70. data/ext/src/inchi_api.h +670 -0
  71. data/ext/src/inchi_dll.c +1480 -0
  72. data/ext/src/inchi_dll.h +34 -0
  73. data/ext/src/inchi_dll_main.c +23 -0
  74. data/ext/src/inchi_dll_main.h +31 -0
  75. data/ext/src/inpdef.h +328 -0
  76. data/ext/src/lreadmol.h +1246 -0
  77. data/ext/src/mode.h +706 -0
  78. data/ext/src/ruby_inchi_main.c +558 -0
  79. data/ext/src/runichi.c +4179 -0
  80. data/ext/src/strutil.c +3861 -0
  81. data/ext/src/strutil.h +182 -0
  82. data/ext/src/util.c +1130 -0
  83. data/ext/src/util.h +85 -0
  84. data/lib/clean_tempfile.rb +220 -0
  85. data/lib/rino.rb +111 -0
  86. data/test/test.rb +386 -0
  87. metadata +130 -0
@@ -0,0 +1,1609 @@
1
+ /*
2
+ * International Union of Pure and Applied Chemistry (IUPAC)
3
+ * International Chemical Identifier (InChI)
4
+ * Version 1
5
+ * Software version 1.00
6
+ * April 13, 2005
7
+ * Developed at NIST
8
+ */
9
+
10
+ #include <stdio.h>
11
+ #include <stdlib.h>
12
+ #include <string.h>
13
+
14
+ #include "mode.h"
15
+
16
+ #include "comdef.h"
17
+ #include "extr_ct.h"
18
+ #include "ichitaut.h"
19
+ #include "ichicant.h"
20
+ #include "ichicomn.h"
21
+
22
+ #include "ichicomp.h"
23
+
24
+
25
+
26
+
27
+ #define SB_DEPTH 6
28
+ /************************************************
29
+ map_stereo_bonds4 and map_stereo_atoms4 use
30
+ the following members of CANON_STAT *pCS:
31
+
32
+ pCS->bKeepSymmRank // ??? almost unused, reolaced with nSymmStereo != NULL ???
33
+ pCS->bFirstCT
34
+ pCS->bStereoIsBetter
35
+ pCS->lNumNeighListIter
36
+ pCS->lNumBreakTies
37
+ pCS->lNumRejectedCT
38
+ pCS->lNumTotCT
39
+ pCS->lNumEqualCT
40
+ pCS->lNumDecreasedCT
41
+ pCS->bExtract (bRELEASE_VERSION == 0)
42
+ pCS->ulTimeOutTime
43
+
44
+ pCS->bRankUsedForStereo
45
+ pCS->bAtomUsedForStereo
46
+
47
+ pCS->LinearCTStereoDble
48
+ pCS->LinearCTStereoCarb
49
+ pCS->nLenLinearCTStereoCarb
50
+ pCS->nLenLinearCTStereoDble
51
+
52
+ pCS->nPrevAtomNumber
53
+ ************************************************/
54
+ /********************************************************************************/
55
+ int map_stereo_bonds4 (
56
+ sp_ATOM *at, int num_atoms, int num_at_tg, int num_max, int bAllene,
57
+ const AT_RANK *nCanonRankFrom, const AT_RANK *nAtomNumberCanonFrom, /* non-stereo canon ranking */
58
+ AT_RANK *nCanonRankTo, /* output canonical stereo numbering*/
59
+ const AT_RANK *nSymmRank, AT_RANK **pRankStack1/*from*/, AT_RANK **pRankStack2/*to*/,
60
+ AT_RANK *nTempRank, int nNumMappedRanksInput,
61
+ AT_RANK *nSymmStereo, NEIGH_LIST *NeighList,
62
+ CANON_STAT *pCS, CUR_TREE *cur_tree, int nNumMappedBonds )
63
+ {
64
+ int nTotSuccess = 0; /* 1=>full mapping has been completed;
65
+ * 2=>obtained a better stereo;
66
+ * 4=>restart (stereo bond or atom removed from the stereo CT)
67
+ */
68
+ int tpos1;
69
+ AT_STEREO_DBLE prevBond;
70
+
71
+ tpos1 = CurTreeGetPos( cur_tree );
72
+
73
+ total_restart:
74
+
75
+ if ( !nNumMappedBonds ) {
76
+
77
+ memset( pCS->bRankUsedForStereo, 0, sizeof( pCS->bRankUsedForStereo[0] )*num_atoms );
78
+ SetUseAtomForStereo( pCS->bAtomUsedForStereo, at, num_atoms );
79
+
80
+ if ( pCS->bFirstCT && nSymmStereo && !pCS->bKeepSymmRank ) {
81
+ int i;
82
+ for ( i = 0; i < num_at_tg; i ++ ) {
83
+ /* nSymmStereo[i] = min. {k | at[k] stereo eq. to at[i]} */
84
+ nSymmStereo[i] = i; /* for union-join to keep track of stereo-equivalent atoms */
85
+ }
86
+ }
87
+ }
88
+
89
+
90
+ if ( nNumMappedBonds < pCS->nLenLinearCTStereoDble ) {
91
+
92
+ int at_rank1, at_rank2, bStereoIsBetterWasSetHere;
93
+ /* AT_RANK *nRankFrom=*pRankStack1++, AT_RANK *nAtomNumberFrom=pRankStack1++; */
94
+ /* AT_RANK *nRankTo =*pRankStack2++, AT_RANK *nAtomNumberTo =pRankStack2++; */
95
+ AT_RANK canon_min1, canon_min2;
96
+ int bFirstCanonRank;
97
+ int i, j, j1, j2, at_from1, at_from2, at_to1, at_to2, iMax, c;
98
+ int nStackPtr[SB_DEPTH], nNumMappedRanks[SB_DEPTH], LastMappedTo1;
99
+ int istk, istk2, istk3, bAddStack, nNumAtTo1Success;
100
+ int ret1, ret2, parity1, parity2;
101
+
102
+ AT_RANK at_rank_canon1; /* = pCS->LinearCTStereoDble[nNumMappedBonds].at_num1; */ /* canonical numbers of atoms */
103
+ AT_RANK at_rank_canon2; /* = pCS->LinearCTStereoDble[nNumMappedBonds].at_num2; */ /* adjacent to the stereogenic bond */
104
+ int nNumChoices, nNumUnkn, nNumUndf, nNumBest, nNumWorse, nNumCalc, sb_parity_calc;
105
+ int stereo_bond_parity, prev_stereo_bond_parity, pass, bAllParitiesIdentical, bAllParitiesIdentical2;
106
+ AT_STEREO_DBLE prevBond2;
107
+
108
+ prevBond = pCS->LinearCTStereoDble[nNumMappedBonds];
109
+ bFirstCanonRank=1;
110
+ canon_min1=canon_min2=0;
111
+ /*
112
+ // find candidates for atom_from1, atom_to1; they must have identical mapping ranks
113
+ at_rank1=pRankStack1[0][at_from1=nAtomNumberCanonFrom[(int)at_rank_canon1 - 1]]; // rank "from" for mapping
114
+ at_rank2=pRankStack1[0][at_from2=nAtomNumberCanonFrom[(int)at_rank_canon2 - 1]]; // rank "from" for mapping
115
+ */
116
+ if ( nNumMappedBonds ) {
117
+ at_rank_canon1 = pCS->LinearCTStereoDble[nNumMappedBonds-1].at_num1;
118
+ at_rank_canon2 = pCS->LinearCTStereoDble[nNumMappedBonds-1].at_num2;
119
+ } else {
120
+ at_rank_canon1 = 0;
121
+ at_rank_canon2 = 0;
122
+ }
123
+ goto bypass_next_canon_ranks_check;
124
+
125
+ next_canon_ranks:
126
+
127
+ /* Save time: avoid calling Next_SB_At_CanonRanks2() */
128
+ if ( !pCS->bStereoIsBetter /* ??? && !pCS->bFirstCT ???*/ &&
129
+ at_rank_canon1 > pCS->LinearCTStereoDble[nNumMappedBonds].at_num1 ||
130
+ at_rank_canon1 == pCS->LinearCTStereoDble[nNumMappedBonds].at_num1 &&
131
+ at_rank_canon2 >= pCS->LinearCTStereoDble[nNumMappedBonds].at_num2 ) {
132
+
133
+ if ( !nTotSuccess ) {
134
+ pCS->LinearCTStereoDble[nNumMappedBonds] = prevBond;
135
+ }
136
+ CurTreeSetPos( cur_tree, tpos1 );
137
+ return nTotSuccess;
138
+ }
139
+
140
+ bypass_next_canon_ranks_check:
141
+
142
+ CurTreeSetPos( cur_tree, tpos1 );
143
+
144
+ /* find next available canon. numbers for a stereogenic bond pair of atoms */
145
+ /* process allenes AFTER all double bonds and odd-number-of-double-bonds cumulenes */
146
+ if ( !(ret1 = Next_SB_At_CanonRanks2( &at_rank_canon1, &at_rank_canon2, /* canonical numbers */
147
+ &canon_min1, &canon_min2,
148
+ &bFirstCanonRank, pCS->bAtomUsedForStereo,
149
+ pRankStack1, pRankStack2,
150
+ nCanonRankFrom, nAtomNumberCanonFrom,
151
+ at, num_atoms, bAllene ) ) ) {
152
+ /* failed to find next stereo bond to assign parity */
153
+ if ( !bAllene && bFirstCanonRank ) {
154
+ /* all stereobond have been processed; try to find allene to continue */
155
+ AT_RANK at_rank_canon1_Allene = 0, canon_min1_Allene = 0;
156
+ AT_RANK at_rank_canon2_Allene = 0, canon_min2_Allene = 0;
157
+ if ( ret1 = Next_SB_At_CanonRanks2( &at_rank_canon1_Allene, &at_rank_canon2_Allene,
158
+ &canon_min1_Allene, &canon_min2_Allene,
159
+ &bFirstCanonRank, pCS->bAtomUsedForStereo,
160
+ pRankStack1, pRankStack2,
161
+ nCanonRankFrom, nAtomNumberCanonFrom,
162
+ at, num_atoms, 1 ) ) {
163
+ at_rank_canon1 = at_rank_canon1_Allene;
164
+ at_rank_canon2 = at_rank_canon2_Allene;
165
+ canon_min1 = canon_min1_Allene;
166
+ canon_min2 = canon_min2_Allene;
167
+ bAllene = 1; /* switch to allenes */
168
+ }
169
+ }
170
+ }
171
+
172
+ if ( !ret1 || !pCS->bStereoIsBetter &&
173
+ (at_rank_canon1 > pCS->LinearCTStereoDble[nNumMappedBonds].at_num1 ||
174
+ at_rank_canon1 == pCS->LinearCTStereoDble[nNumMappedBonds].at_num1 &&
175
+ at_rank_canon2 > pCS->LinearCTStereoDble[nNumMappedBonds].at_num2 ) ) {
176
+ /* new ranks provide greater pCS->LinearCTStereoDble[nNumMappedBonds] and therefore rejected */
177
+ if ( !nTotSuccess ) {
178
+ pCS->LinearCTStereoDble[nNumMappedBonds] = prevBond; /* restore stereo bond CT for the current bond */
179
+ }
180
+ return nTotSuccess;
181
+ }
182
+ /* current stereo bond initialization */
183
+ nNumChoices = 0;
184
+ nNumUnkn = 0;
185
+ nNumUndf = 0;
186
+ nNumBest = 0;
187
+ nNumWorse = 0;
188
+ nNumCalc = 0;
189
+ pass=0;
190
+ prev_stereo_bond_parity = 0;
191
+
192
+ at_rank1=pRankStack1[0][at_from1=nAtomNumberCanonFrom[(int)at_rank_canon1 - 1]]; /* atom 1 rank "from" for mapping */
193
+ at_rank2=pRankStack1[0][at_from2=nAtomNumberCanonFrom[(int)at_rank_canon2 - 1]]; /* atom 2 rank "from" for mapping */
194
+ /* we are going to map bond (at[at_from1], at[at_from2]) and
195
+ canonical ranks of its atoms (at_rank_canon1, at_rank_canon2)
196
+ onto a stereogenic bond (at[at_to1], at[at_to2])
197
+ */
198
+ iMax = at_rank1-1;
199
+ /* test correctness: sorted pRankStack2[0][] and pRankStack1[0][] should have same ranks for both atoms */
200
+ if ( at_rank1 != pRankStack2[0][pRankStack2[1][at_rank1-1]] ||
201
+ at_rank2 != pRankStack2[0][pRankStack2[1][at_rank2-1]] ) {
202
+ /* program error: "from" and "to" mapping ranks are not equal */
203
+ return CT_STEREOCOUNT_ERR; /* <BRKPT> */
204
+ }
205
+ /* -- do not check stereo features of "from" atoms:
206
+ -- in case of "bond/charge isomerism" they may be missing.
207
+ if ( !at[at_from1].stereo_bond_neighbor[0] ||
208
+ !at[at_from2].stereo_bond_neighbor[0] )
209
+ return CT_STEREOCOUNT_ERR; // program error
210
+ */
211
+
212
+ /* find out if we have a choice in mapping: check all possible pairs (at_to1, at_to2)
213
+ such that at_from1 is possibly constitutionally equivalent to at_to1, at_from2 to at_to2 */
214
+ for ( j1 = 0; j1 <= iMax && at_rank1 == pRankStack2[0][at_to1=pRankStack2[1][iMax-j1]]; j1 ++ ) {
215
+ if ( !at[at_to1].stereo_bond_neighbor[0] )
216
+ continue; /* at_to1 does not belong to a stereo bond */
217
+ for( j2 = 0; j2 < MAX_NUM_STEREO_BONDS &&
218
+ (at_to2 =at[at_to1].stereo_bond_neighbor[j2]); j2 ++ ) {
219
+ at_to2 --;
220
+ if ( pRankStack1[0][at_from2] != pRankStack2[0][at_to2] )
221
+ continue; /* at_from2 cannot be mapped on at_to2 */
222
+ stereo_bond_parity = PARITY_VAL(at[at_to1].stereo_bond_parity[j2]);
223
+ i = 0;
224
+ switch(stereo_bond_parity) {
225
+ case AB_PARITY_UNDF: nNumUndf ++; break; /* 4 */
226
+ case AB_PARITY_UNKN: nNumUnkn ++; break; /* 3 */
227
+ case BEST_PARITY: nNumBest ++; break; /* 1 */
228
+ case WORSE_PARITY: nNumWorse ++; break; /* 2 */
229
+ case AB_PARITY_CALC: nNumCalc ++; break; /* 6 */
230
+ case AB_PARITY_NONE: i ++; break; /* 0 */
231
+ }
232
+ nNumChoices += !i;
233
+ }
234
+ }
235
+ if ( nNumChoices != nNumCalc + nNumUndf + nNumUnkn + nNumBest + nNumWorse ) {
236
+ return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
237
+ }
238
+ if ( !nNumChoices ) {
239
+ goto next_canon_ranks;
240
+ }
241
+ /* Determine the first parity to search */
242
+ sb_parity_calc = ( nNumCalc > 0 )? BEST_PARITY : 0;
243
+
244
+ /* ==============================================================
245
+ Search sequence: sb_parity_calc stereo_bond_parity
246
+ ==============================================================
247
+ BEST_PARITY (calc) BEST_PARITY BEST_PARITY
248
+ BEST_PARITY (known) BEST_PARITY WORSE_PARITY or 0
249
+ WORSE_PARITY (calc) WORSE_PARITY WORSE_PARITY
250
+ WORSE_PARITY (known) WORSE_PARITY 0
251
+ AB_PARITY_UNKN(known) AB_PARITY_UNKN 0
252
+ AB_PARITY_UNDF(known) AB_PARITY_UNDF 0
253
+
254
+ if (sb_parity_calc==stereo_bond_parity) then "calc" else "known"
255
+ */
256
+
257
+ repeat_all:
258
+
259
+ if ( !nNumMappedBonds )
260
+ pCS->bStereoIsBetter = 0; /* the first stereo feature in the canonical CT; moved here 7-13-2002 */
261
+
262
+ if ( !pass ++ ) {
263
+ /* select the smallest (best) parity to search */
264
+ if ( sb_parity_calc ) {
265
+ stereo_bond_parity = BEST_PARITY;
266
+ } else {
267
+ stereo_bond_parity = nNumBest? BEST_PARITY :
268
+ nNumWorse? WORSE_PARITY :
269
+ nNumUnkn? AB_PARITY_UNKN :
270
+ nNumUndf? AB_PARITY_UNDF : AB_PARITY_NONE;
271
+ }
272
+ } else {
273
+ /* second pass: since the first pass failed, search for a worse result */
274
+ prev_stereo_bond_parity = stereo_bond_parity;
275
+ i = NextStereoParity2Test( &stereo_bond_parity, &sb_parity_calc,
276
+ nNumBest, nNumWorse, nNumUnkn, nNumUndf, nNumCalc);
277
+ switch ( i ) {
278
+ case 0:
279
+ break; /* obtained next parity to test */
280
+ case 1:
281
+ goto next_canon_ranks;
282
+ default:
283
+ return i; /* program error */
284
+ }
285
+ }
286
+ if ( stereo_bond_parity == AB_PARITY_NONE ) {
287
+ /* error? */
288
+ return CT_STEREOCOUNT_ERR; /* <BRKPT> */
289
+ }
290
+ /* check if the new requested parity is good (small) enough */
291
+ if ( !pCS->bStereoIsBetter ) {
292
+ c = CompareLinCtStereoDoubleToValues( nTotSuccess? pCS->LinearCTStereoDble+nNumMappedBonds : &prevBond,
293
+ at_rank_canon1, at_rank_canon2, (U_CHAR)stereo_bond_parity );
294
+ if ( c < 0 ) {
295
+ if ( !nTotSuccess ) {
296
+ pCS->LinearCTStereoDble[nNumMappedBonds] = prevBond;
297
+ }
298
+ CurTreeSetPos( cur_tree, tpos1 );
299
+ return nTotSuccess;
300
+ }
301
+ }
302
+
303
+ bAllParitiesIdentical = 0;
304
+ bAllParitiesIdentical2 = 0;
305
+ LastMappedTo1 = -1;
306
+ bStereoIsBetterWasSetHere = 0;
307
+ istk = istk2 = istk3 = 0;
308
+
309
+ if ( !nNumMappedBonds && prev_stereo_bond_parity != stereo_bond_parity )
310
+ pCS->bStereoIsBetter = 0; /* the first stereo feature in the canonical CT; moved here 5-24-2002 */
311
+
312
+ if ( prev_stereo_bond_parity != stereo_bond_parity ) {
313
+ CurTreeSetPos( cur_tree, tpos1 ); /* start over */
314
+ }
315
+
316
+ /* Mapping: here at_rank1 = nRankTo, at_to1 = nAtomNumberTo */
317
+ for ( j1 = 0; j1 <= iMax && at_rank1 == pRankStack2[0][at_to1=pRankStack2[1][iMax-j1]]; j1 ++ ) {
318
+ nNumAtTo1Success = 0;
319
+ if ( !at[at_to1].stereo_bond_neighbor[0] )
320
+ continue; /* at_to1 does not belong to a stereo bond */
321
+ if ( tpos1 < CurTreeGetPos( cur_tree ) &&
322
+ 1 == CurTreeIsLastRank( cur_tree, at_rank_canon1 ) &&
323
+ 1 == CurTreeIsLastAtomEqu( cur_tree, at_to1, nSymmStereo ) ) {
324
+ /* at_to1 is known to be stereogenically equivalent to another atom tried with at_rank_canon1 */
325
+ continue;
326
+ }
327
+ bAllParitiesIdentical2 = 0;
328
+ for( j2 = 0; j2 < MAX_NUM_STEREO_BONDS && (at_to2 =at[at_to1].stereo_bond_neighbor[j2]); j2 ++ ) {
329
+ EQ_NEIGH EN1[2], EN2[2];
330
+ int bond_parity, num1, num2;
331
+ AT_RANK at_rank_canon_n1, at_rank_canon_n2;
332
+
333
+ at_to2 --;
334
+ if ( pRankStack1[0][at_from2] != pRankStack2[0][at_to2] )
335
+ continue; /* at_from2 cannot be mapped on at_to2 even without mapping at_from1 to at_to1 */
336
+
337
+ /* check whether the bond parity corresponds to the requested bond parity */
338
+ if ( PARITY_KNOWN(at[at_to1].stereo_bond_parity[j2]) ) {
339
+ if ( stereo_bond_parity == sb_parity_calc ) {
340
+ continue; /* requested parity to be calculated, found known parity */
341
+ }
342
+ if ( stereo_bond_parity != PARITY_VAL(at[at_to1].stereo_bond_parity[j2]) ) {
343
+ continue; /* parity differs from the requested parity */
344
+ }
345
+ } else
346
+ if ( PARITY_CALCULATE( at[at_to1].stereo_bond_parity[j2]) ) {
347
+ if ( stereo_bond_parity != sb_parity_calc ) {
348
+ continue; /* requested known parity, found parity to be calculated */
349
+ }
350
+ } else {
351
+ return CT_STEREOCOUNT_ERR; /* unknown parity type */ /* <BRKPT> */
352
+ }
353
+ /* initialize stack pointer nStackPtr[istk] for "hand-made" recursion */
354
+ /* stacks are pRankStack1[], pRankStack2[], nNumMappedRanks[] */
355
+ istk = 0;
356
+ nStackPtr[0] = 0;
357
+ nNumMappedRanks[0] = nNumMappedRanksInput;
358
+ bAddStack = 0;
359
+ bAllParitiesIdentical = ((at[at_to1].stereo_bond_parity[j2] & KNOWN_PARITIES_EQL )) &&
360
+ PARITY_KNOWN(at[at_to1].stereo_bond_parity[j2]);
361
+
362
+ if ( !bAllParitiesIdentical && !nNumCalc &&
363
+ (!nNumUndf + !nNumUnkn + !nNumBest + !nNumWorse )==3) {
364
+ /* only one kind of bond parity is present; check whether all parities are really same */
365
+ bAllParitiesIdentical = All_SB_Same( at_rank_canon1, at_rank_canon2, /* canonical numbers */
366
+ pRankStack1, pRankStack2,
367
+ nAtomNumberCanonFrom, at );
368
+ if ( bAllParitiesIdentical < 0 ) {
369
+ return CT_STEREOCOUNT_ERR; /* <BRKPT> */
370
+ }
371
+ }
372
+
373
+ /*****************************************************************
374
+ * do the mapping only if parities are not same
375
+ */
376
+ if ( !bAllParitiesIdentical ) {
377
+ /* map atom 1 or reuse previous mapping */
378
+ if ( LastMappedTo1 != at_to1 ) {
379
+ /* avoid repetitve mapping to the same first at_to1 using LastMappedTo1 variable */
380
+ /* map atom 1 */
381
+ ret1 = map_an_atom2( num_at_tg, num_max, at_from1, at_to1,
382
+ nTempRank, nNumMappedRanks[istk], &nNumMappedRanks[istk+1], pCS,
383
+ NeighList, pRankStack1+nStackPtr[istk], pRankStack2+nStackPtr[istk],
384
+ &bAddStack );
385
+ if ( RETURNED_ERROR(ret1) ) {
386
+ return ret1; /* error */
387
+ }
388
+ nStackPtr[istk+1] = nStackPtr[istk]+bAddStack;
389
+ LastMappedTo1 = at_to1;
390
+ if ( bAddStack ) {
391
+ if ( tpos1 == CurTreeGetPos( cur_tree ) ||
392
+ 0 == CurTreeIsLastRank( cur_tree, at_rank_canon1 ) ) {
393
+ CurTreeAddRank( cur_tree, at_rank_canon1 );
394
+ }
395
+ CurTreeAddAtom( cur_tree, at_to1 );
396
+ }
397
+ }
398
+ istk ++; /* = 1 */
399
+ /* check if we can map atom 2 */
400
+ if ( pRankStack1[nStackPtr[istk]][at_from2] != pRankStack2[nStackPtr[istk]][at_to2] ) {
401
+ /*
402
+ * This may happen when:
403
+ * A) Charge/bond isomerism, for example cyclopentadiene(-), or
404
+ * B) possibly stereogenic bond in an alternating ring has heighbors
405
+ * in 2 symmetrically attached rings.
406
+ * Such an alternating bond cannot be mapped on possibly stereogenic bond
407
+ * that has neighbors belonging to 1 of the symmetrically attached rings only.
408
+ * For example:
409
+ * A---B---C---D If all atoms are Carbons then B, C, F, G are constitutionally
410
+ * || || || || equivalent. However, bonds B-C, F-G are not equivalent to
411
+ * || || || || B-F and C-G and cannot be mapped on them.
412
+ * E---F---G---H If at_from1=B, at_from2=F, at_to1=B, then at_from2 cannot be mapped on at_to2=C
413
+ * If at_from1=B, at_from2=F, at_to1=C, then at_from2 cannot be mapped on at_to2=B
414
+ * etc.
415
+ */
416
+ if ( sb_parity_calc != stereo_bond_parity) {
417
+ /* can be passed only once for each bond */
418
+ nNumChoices --;
419
+ nNumUndf -= (stereo_bond_parity == AB_PARITY_UNDF);
420
+ nNumUnkn -= (stereo_bond_parity == AB_PARITY_UNKN);
421
+ nNumBest -= (stereo_bond_parity == BEST_PARITY);
422
+ nNumWorse-= (stereo_bond_parity == WORSE_PARITY);
423
+ /* nNumCalc = nNumChoices - (nNumUndf + nNumUnkn + nNumBest + nNumWorse); */
424
+ } else
425
+ if ( sb_parity_calc == BEST_PARITY ) {
426
+ /* can be passed 2 times: for BEST_PARITY and WORSE_PARITY in this order */
427
+ nNumChoices --; /* do not repeate for WORSE_PARITY */
428
+ nNumCalc --;
429
+ }
430
+ continue; /* Happens for ID=80036,80253,91354,95532,101532,103788 */
431
+ }
432
+ if ( nStackPtr[istk] > nStackPtr[istk-1] ) {
433
+ bAllParitiesIdentical2 = All_SB_Same( at_rank_canon1, at_rank_canon2,
434
+ pRankStack1+nStackPtr[istk], pRankStack2+nStackPtr[istk],
435
+ nAtomNumberCanonFrom, at );
436
+ if ( bAllParitiesIdentical2 < 0 ) {
437
+ return CT_STEREOBOND_ERROR; /* <BRKPT> */
438
+ }
439
+ } else {
440
+ bAllParitiesIdentical2 = 0;
441
+ }
442
+ if ( bAllParitiesIdentical2 ) {
443
+ /* do no mapping when all equivalent bonds have same parity */
444
+ /* stereo_bond_parity = PARITY_VAL(at[at_to1].stereo_bond_parity[j2]); */
445
+ ClearPreviousMappings( pRankStack1+nStackPtr[istk]+2 );
446
+ } else {
447
+ if ( tpos1 < CurTreeGetPos( cur_tree ) &&
448
+ 1 == CurTreeIsLastRank( cur_tree, at_rank_canon2 ) &&
449
+ 1 == CurTreeIsLastAtomEqu( cur_tree, at_to2, nSymmStereo ) ) {
450
+ continue;
451
+ }
452
+ /* map atom 2 */
453
+ ret2 = map_an_atom2( num_at_tg, num_max, at_from2, at_to2,
454
+ nTempRank, nNumMappedRanks[istk], &nNumMappedRanks[istk+1], pCS,
455
+ NeighList, pRankStack1+nStackPtr[istk], pRankStack2+nStackPtr[istk],
456
+ &bAddStack );
457
+ if ( RETURNED_ERROR(ret2) ) {
458
+ return ret2; /* program error */
459
+ }
460
+ nStackPtr[istk+1] = nStackPtr[istk]+bAddStack;
461
+ istk ++; /* = 2 */
462
+ if ( bAddStack ) {
463
+ if ( tpos1 == CurTreeGetPos( cur_tree ) ||
464
+ 0 == CurTreeIsLastRank( cur_tree, at_rank_canon2 ) ) {
465
+ CurTreeAddRank( cur_tree, at_rank_canon2 );
466
+ }
467
+ CurTreeAddAtom( cur_tree, at_to2 );
468
+ }
469
+ }
470
+ } else {
471
+ /* do no mapping when all equivalent bonds have same parity */
472
+ /* stereo_bond_parity = PARITY_VAL(at[at_to1].stereo_bond_parity[j2]); */
473
+ ClearPreviousMappings( pRankStack1+2 );
474
+ }
475
+
476
+ /* we have a precalculated (known) bond parity */
477
+
478
+
479
+ /************************************************************
480
+ *
481
+ * Known Bond Parity case: do not map stereo bond neighbors
482
+ */
483
+ if ( stereo_bond_parity != sb_parity_calc ) /* parity is known */
484
+ {
485
+ /* accept bond parity and do not map the neighbors */
486
+ bond_parity = stereo_bond_parity;
487
+ /* same code as under " make a decision to accept current mapping" comment below */
488
+ /* with one exception: istk instead of istk3 */
489
+ c = CompareLinCtStereoDoubleToValues( pCS->LinearCTStereoDble+nNumMappedBonds,
490
+ at_rank_canon1, at_rank_canon2, (U_CHAR)bond_parity );
491
+ if ( c < 0 && !pCS->bStereoIsBetter ) {
492
+
493
+ /* reject */
494
+
495
+ pCS->lNumRejectedCT ++;
496
+ /* remove failed atom2 from the tree */
497
+ if ( tpos1 < CurTreeGetPos( cur_tree ) &&
498
+ 1 == CurTreeIsLastRank( cur_tree, at_rank_canon2 ) ) {
499
+ CurTreeRemoveIfLastAtom( cur_tree, at_to2 );
500
+ CurTreeRemoveLastRankIfNoAtoms( cur_tree );
501
+ }
502
+ continue; /* to next at_to2; Reject this at_to2: not a minimal CT. */
503
+ } else {
504
+
505
+ /* accept */
506
+
507
+ if ( c > 0 && !pCS->bStereoIsBetter ) {
508
+ /* bond entry is less than the previusly found */
509
+ pCS->bStereoIsBetter = bStereoIsBetterWasSetHere = 1;
510
+ prevBond2 = pCS->LinearCTStereoDble[nNumMappedBonds];
511
+ }
512
+ pCS->LinearCTStereoDble[nNumMappedBonds].at_num1 = at_rank_canon1;
513
+ pCS->LinearCTStereoDble[nNumMappedBonds].at_num2 = at_rank_canon2;
514
+ pCS->LinearCTStereoDble[nNumMappedBonds].parity = bond_parity;
515
+ /* recursive call */
516
+ pCS->bRankUsedForStereo[at_from1] ++;
517
+ pCS->bRankUsedForStereo[at_from2] ++;
518
+ if ( !bAllParitiesIdentical ) {
519
+ pCS->bAtomUsedForStereo[at_to1] --;
520
+ pCS->bAtomUsedForStereo[at_to2] --;
521
+ }
522
+ ret2 = map_stereo_bonds4 ( at, num_atoms, num_at_tg, num_max, bAllene, nCanonRankFrom, nAtomNumberCanonFrom, nCanonRankTo,
523
+ nSymmRank, pRankStack1+nStackPtr[istk], pRankStack2+nStackPtr[istk],
524
+ nTempRank, nNumMappedRanks[istk], nSymmStereo, NeighList,
525
+ pCS, cur_tree, nNumMappedBonds+1 );
526
+ if ( !bAllParitiesIdentical ) {
527
+ pCS->bAtomUsedForStereo[at_to1] ++;
528
+ pCS->bAtomUsedForStereo[at_to2] ++;
529
+ }
530
+ pCS->bRankUsedForStereo[at_from1] --;
531
+ pCS->bRankUsedForStereo[at_from2] --;
532
+ if ( ret2 == 4 ) {
533
+ if ( nNumMappedBonds ) {
534
+ return ret2;
535
+ } else {
536
+ pCS->bFirstCT = 1;
537
+ goto total_restart;
538
+ }
539
+ }
540
+
541
+ if ( RETURNED_ERROR(ret2) ) {
542
+ if ( ret2 == CT_TIMEOUT_ERR )
543
+ return ret2;
544
+ else
545
+ return ret2; /* program error */
546
+ }
547
+ if ( ret2 > 0 ) {
548
+ nTotSuccess |= 1;
549
+ nNumAtTo1Success ++;
550
+ if ( bStereoIsBetterWasSetHere || (ret2 & 2) ) {
551
+ CurTreeKeepLastAtomsOnly( cur_tree, tpos1, 1 ); /* start over */
552
+ nTotSuccess |= 2; /* Obtained a smaller CT */
553
+ }
554
+ } else {
555
+ if ( bStereoIsBetterWasSetHere ) { /* rollback */
556
+ pCS->bStereoIsBetter = 0;
557
+ pCS->LinearCTStereoDble[nNumMappedBonds] = prevBond2;
558
+ }
559
+ /* remove failed atom2 from the tree */
560
+ if ( tpos1 < CurTreeGetPos( cur_tree ) &&
561
+ 1 == CurTreeIsLastRank( cur_tree, at_rank_canon2 ) ) {
562
+ CurTreeRemoveIfLastAtom( cur_tree, at_to2 );
563
+ CurTreeRemoveLastRankIfNoAtoms( cur_tree );
564
+ }
565
+ /*
566
+ if ( 1 == CurTreeIsLastRank( cur_tree, at_rank_canon1 ) ) {
567
+ CurTreeRemoveLastAtom( cur_tree, at_to1 );
568
+ CurTreeRemoveLastRankIfNoAtoms( cur_tree );
569
+ }
570
+ */
571
+ }
572
+ bStereoIsBetterWasSetHere = 0;
573
+ }
574
+ if ( bAllParitiesIdentical || bAllParitiesIdentical2 ) {
575
+ break; /* j2 cycle, at_to2 (no need to repeat) */
576
+ }
577
+ continue; /* to next at_to2 */
578
+ }
579
+ /***************************************************************************
580
+ *
581
+ * Unknown Bond Parity case: may need to map stereo bond neighbors
582
+ *
583
+ ****************************************************************************
584
+ * Ranks are not known in advance
585
+ * check if at_from1/at_to1 half-bond has neighbors with equal mapping ranks
586
+ */
587
+
588
+ parity1 = parity_of_mapped_half_bond( at_from1, at_to1, at_from2, at_to2, at, &EN1[0],
589
+ nCanonRankFrom, pRankStack1[nStackPtr[istk]], pRankStack2[nStackPtr[istk]] );
590
+ /* old approach -- before E/Z parities
591
+ parity1 = parity_of_mapped_atom2( at_from1, at_to1, at, &EN1[0],
592
+ nCanonRankFrom, pRankStack1[nStackPtr[istk]], pRankStack2[nStackPtr[istk]] );
593
+ */
594
+ /* the following commented out statement is not needed here. */
595
+ /* parity2 = parity_of_mapped_atom2( at_from2, at_to2, at, &EN2[0],
596
+ nCanonRankFrom, pRankStack1[nStackPtr[istk]],
597
+ pRankStack2[nStackPtr[istk]] );
598
+ */
599
+ if ( !parity1 ) {
600
+ return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
601
+ }
602
+ num1 = parity1 > 0? 1:2; /* parity < 0 means additional mapping is needed to set parity */
603
+ /* --- try all possible mappings of the stereo bond ending atoms' neighbors --- */
604
+ at_rank_canon_n1 = 0;
605
+ at_rank_canon_n2 = 0;
606
+ for ( i = 0; i < num1; i ++ ) {
607
+ int at_from, at_to;
608
+ istk2 = istk;
609
+ if ( num1 == 2 ) {
610
+ at_rank_canon_n1 = nCanonRankFrom[EN1[0].from_at];
611
+ /* an additional neighbor mapping is necessary; */
612
+ /* we need to map only one at_from1 neighbor to make all neighbors have different ranks */
613
+
614
+ at_from = EN1[0].from_at;
615
+ at_to = EN1[0].to_at[i];
616
+
617
+ if ( tpos1 < CurTreeGetPos( cur_tree ) &&
618
+ 1 == CurTreeIsLastRank( cur_tree, at_rank_canon_n1 ) &&
619
+ 1 == CurTreeIsLastAtomEqu( cur_tree, at_to, nSymmStereo ) )
620
+ continue;
621
+ /*
622
+ if ( nSymmStereo && !pCS->bFirstCT ) {
623
+ if ( i && nSymmStereo[at_to] == nSymmStereo[(int)EN1[0].to_at[0]] ) {
624
+ continue; // do not test stereo equivalent atoms except the first one
625
+ }
626
+ }
627
+ */
628
+ /* neighbors are tied. Untie them by breaking a tie on ONE of them. */
629
+ ret1 = map_an_atom2( num_at_tg, num_max, at_from, at_to,
630
+ nTempRank, nNumMappedRanks[istk2], &nNumMappedRanks[istk2+1], pCS,
631
+ NeighList, pRankStack1+nStackPtr[istk2], pRankStack2+nStackPtr[istk2],
632
+ &bAddStack );
633
+ if ( RETURNED_ERROR(ret1) ) {
634
+ return ret1; /* program error */ /* <BRKPT> */
635
+ }
636
+ nStackPtr[istk2+1] = nStackPtr[istk2] + bAddStack;
637
+ istk2 ++; /* <= 3 */
638
+ /* debug */
639
+ if ( istk2 >= SB_DEPTH ) {
640
+ return CT_OVERFLOW; /* program error */ /* <BRKPT> */
641
+ }
642
+ if ( bAddStack ) {
643
+ if ( tpos1 == CurTreeGetPos( cur_tree ) ||
644
+ 0 == CurTreeIsLastRank( cur_tree, at_rank_canon_n1 ) ) {
645
+ CurTreeAddRank( cur_tree, at_rank_canon_n1 );
646
+ }
647
+ CurTreeAddAtom( cur_tree, at_to );
648
+ }
649
+
650
+
651
+ /* now that all at_from1 neighbors have been mapped the parity must be defined */
652
+ parity1 = parity_of_mapped_half_bond( at_from1, at_to1, at_from2, at_to2, at, &EN1[1],
653
+ nCanonRankFrom, pRankStack1[nStackPtr[istk2]], pRankStack2[nStackPtr[istk2]] );
654
+ if ( parity1 <= 0 )
655
+ return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
656
+ } else {
657
+ nNumMappedRanks[istk2+1] = nNumMappedRanks[istk2];
658
+ nStackPtr[istk2+1] = nStackPtr[istk2];
659
+ istk2 ++; /* <= 3 */
660
+ }
661
+
662
+ /* check if at_from2/at_to2 half-bond has neighbors with equal mapping ranks */
663
+ parity2 = parity_of_mapped_half_bond( at_from2, at_to2, at_from1, at_to1, at, &EN2[0],
664
+ nCanonRankFrom, pRankStack1[nStackPtr[istk2]], pRankStack2[nStackPtr[istk2]] );
665
+ if ( !parity2 ) {
666
+ return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
667
+ }
668
+ num2 = parity2 > 0? 1:2;
669
+ at_rank_canon_n2 = 0;
670
+ for ( j = 0; j < num2; j ++ ) {
671
+ istk3 = istk2;
672
+ if ( num2 == 2 ) {
673
+ at_rank_canon_n2 = nCanonRankFrom[EN2[0].from_at];
674
+ /* we need to map only one at_from2 neighbor to make its neighbors have different ranks */
675
+ at_from = EN2[0].from_at;
676
+ at_to = EN2[0].to_at[j];
677
+
678
+ if ( tpos1 < CurTreeGetPos( cur_tree ) &&
679
+ 1 == CurTreeIsLastRank( cur_tree, at_rank_canon_n2 ) &&
680
+ 1 == CurTreeIsLastAtomEqu( cur_tree, at_to, nSymmStereo ) )
681
+ continue;
682
+
683
+ /*
684
+ if ( nSymmStereo && !pCS->bFirstCT ) {
685
+ if ( j && nSymmStereo[at_to] == nSymmStereo[(int)EN2[0].to_at[0]] ) {
686
+ continue; // do not test stereo equivalent atoms except the first one
687
+ }
688
+ }
689
+ */
690
+ /* neighbors are tied. Untie them by breaking a tie on ONE of them. */
691
+ ret1 = map_an_atom2( num_at_tg, num_max, at_from, at_to,
692
+ nTempRank, nNumMappedRanks[istk3], &nNumMappedRanks[istk3+1], pCS,
693
+ NeighList, pRankStack1+nStackPtr[istk3],
694
+ pRankStack2+nStackPtr[istk3],
695
+ &bAddStack );
696
+ if ( RETURNED_ERROR(ret1) ) {
697
+ return ret1; /* program error */
698
+ }
699
+ nStackPtr[istk3+1] = nStackPtr[istk3]+bAddStack;
700
+ istk3 ++; /* <= 4 */
701
+
702
+ if ( bAddStack ) {
703
+ if ( tpos1 == CurTreeGetPos( cur_tree ) ||
704
+ 0 == CurTreeIsLastRank( cur_tree, at_rank_canon_n2 ) ) {
705
+ CurTreeAddRank( cur_tree, at_rank_canon_n2 );
706
+ }
707
+ CurTreeAddAtom( cur_tree, at_to );
708
+ }
709
+
710
+ parity2 = parity_of_mapped_half_bond( at_from2, at_to2, at_from1, at_to1, at, &EN2[1],
711
+ nCanonRankFrom, pRankStack1[nStackPtr[istk3]], pRankStack2[nStackPtr[istk3]] );
712
+ if ( parity2 <= 0 ) {
713
+ return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
714
+ }
715
+ } else {
716
+ /* no additional mapping is needed to set atom's parity */
717
+ nNumMappedRanks[istk3+1] = nNumMappedRanks[istk3];
718
+ nStackPtr[istk3+1] = nStackPtr[istk3];
719
+ istk3 ++; /* <= 4 */
720
+ }
721
+
722
+ /*******************************************************************
723
+ * at this point the stereo bond is fully mapped to find its parity
724
+ *******************************************************************/
725
+
726
+ if ( parity1 <= 0 || parity2 <= 0 ) {
727
+ return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
728
+ }
729
+
730
+ /* find current bond parity AB_PARITY_ODD */
731
+ if ( ATOM_PARITY_WELL_DEF(parity1) && ATOM_PARITY_WELL_DEF(parity2) ) {
732
+ bond_parity = 2 - (parity1 + parity2)%2;
733
+ } else {
734
+ bond_parity = inchi_max(parity1, parity2);
735
+ }
736
+ if ( ATOM_PARITY_WELL_DEF(bond_parity) && at[at_to1].stereo_bond_z_prod[j2] < 0 )
737
+ bond_parity = 2 - (bond_parity+1)%2; /* invert the bond parity */
738
+
739
+
740
+ /********************************************************
741
+ * make a decision whether to accept the current mapping
742
+ */
743
+ c = CompareLinCtStereoDoubleToValues( pCS->LinearCTStereoDble+nNumMappedBonds,
744
+ at_rank_canon1, at_rank_canon2, (U_CHAR)bond_parity );
745
+ if ( sb_parity_calc != bond_parity ||
746
+ c < 0 && !pCS->bStereoIsBetter ) {
747
+ /* reject */
748
+ pCS->lNumRejectedCT ++;
749
+ /* remove failed atom2 from the tree */
750
+ if ( tpos1 < CurTreeGetPos( cur_tree ) &&
751
+ 1 == CurTreeIsLastRank( cur_tree, at_rank_canon_n2 ) ) {
752
+ CurTreeRemoveIfLastAtom( cur_tree, at_to );
753
+ CurTreeRemoveLastRankIfNoAtoms( cur_tree );
754
+ }
755
+ continue; /* Reject: not a minimal CT. */
756
+
757
+ } else {
758
+
759
+ /* try to accept */
760
+
761
+ if ( c > 0 && !pCS->bStereoIsBetter ) {
762
+ /* bond_parity is less than the previusly found */
763
+ pCS->bStereoIsBetter = bStereoIsBetterWasSetHere = 1;
764
+ prevBond2 = pCS->LinearCTStereoDble[nNumMappedBonds];
765
+ }
766
+ /* accept */
767
+ pCS->LinearCTStereoDble[nNumMappedBonds].at_num1 = at_rank_canon1;
768
+ pCS->LinearCTStereoDble[nNumMappedBonds].at_num2 = at_rank_canon2;
769
+ pCS->LinearCTStereoDble[nNumMappedBonds].parity = bond_parity;
770
+ /* recursive call */
771
+ pCS->bRankUsedForStereo[at_from1] ++;
772
+ pCS->bRankUsedForStereo[at_from2] ++;
773
+ pCS->bAtomUsedForStereo[at_to1] --;
774
+ pCS->bAtomUsedForStereo[at_to2] --;
775
+ ret2 = map_stereo_bonds4 ( at, num_atoms, num_at_tg, num_max, bAllene, nCanonRankFrom, nAtomNumberCanonFrom, nCanonRankTo,
776
+ nSymmRank, pRankStack1+nStackPtr[istk3], pRankStack2+nStackPtr[istk3],
777
+ nTempRank, nNumMappedRanks[istk3], nSymmStereo, NeighList,
778
+ pCS, cur_tree, nNumMappedBonds+1 );
779
+ pCS->bRankUsedForStereo[at_from1] --;
780
+ pCS->bRankUsedForStereo[at_from2] --;
781
+ pCS->bAtomUsedForStereo[at_to1] ++;
782
+ pCS->bAtomUsedForStereo[at_to2] ++;
783
+ if ( ret2 == 4 ) {
784
+ if ( nNumMappedBonds ) {
785
+ return ret2;
786
+ } else {
787
+ pCS->bFirstCT = 1;
788
+ goto total_restart;
789
+ }
790
+ }
791
+ if ( RETURNED_ERROR(ret2) ) {
792
+ if ( ret2 == CT_TIMEOUT_ERR )
793
+ return ret2;
794
+ else
795
+ return ret2; /* program error */
796
+ }
797
+ if ( ret2 > 0 ) {
798
+ nTotSuccess |= 1;
799
+ nNumAtTo1Success ++;
800
+ if ( bStereoIsBetterWasSetHere || (ret2 & 2) ) {
801
+ CurTreeKeepLastAtomsOnly( cur_tree, tpos1, 1 ); /* start over */
802
+ nTotSuccess |= 2; /* Obtained a smaller CT */
803
+ }
804
+ } else {
805
+ if ( bStereoIsBetterWasSetHere ) { /* rollback */
806
+ pCS->bStereoIsBetter = 0;
807
+ pCS->LinearCTStereoDble[nNumMappedBonds] = prevBond2;
808
+ }
809
+ if ( tpos1 < CurTreeGetPos( cur_tree ) &&
810
+ 1 == CurTreeIsLastRank( cur_tree, at_rank_canon_n2 ) ) {
811
+ CurTreeRemoveIfLastAtom( cur_tree, at_to );
812
+ CurTreeRemoveLastRankIfNoAtoms( cur_tree );
813
+ }
814
+ }
815
+ bStereoIsBetterWasSetHere = 0;
816
+ }
817
+ } /* end choices in mapping neighbors of the 2nd half-bond */
818
+ if ( tpos1 < CurTreeGetPos( cur_tree ) &&
819
+ 1 == CurTreeIsLastRank( cur_tree, at_rank_canon_n2 ) ) {
820
+ CurTreeRemoveLastRank( cur_tree );
821
+ }
822
+ } /* end choices in mapping neighbors of the 1st half-bond */
823
+ if ( tpos1 < CurTreeGetPos( cur_tree ) &&
824
+ 1 == CurTreeIsLastRank( cur_tree, at_rank_canon_n1 ) ) {
825
+ CurTreeRemoveLastRank( cur_tree );
826
+ }
827
+ } /* end of choices in mapping at_from2 */
828
+ if ( tpos1 < CurTreeGetPos( cur_tree ) &&
829
+ 1 == CurTreeIsLastRank( cur_tree, at_rank_canon2 ) ) {
830
+ CurTreeRemoveLastRank( cur_tree );
831
+ }
832
+ if ( !nNumAtTo1Success ) {
833
+ if ( tpos1 < CurTreeGetPos( cur_tree ) &&
834
+ 1 == CurTreeIsLastRank( cur_tree, at_rank_canon1 ) ) {
835
+ CurTreeRemoveIfLastAtom( cur_tree, at_to1 );
836
+ CurTreeRemoveLastRankIfNoAtoms( cur_tree );
837
+ }
838
+ }
839
+ if ( bAllParitiesIdentical /*&& !nSymmStereo*/ ) {
840
+ break;
841
+ }
842
+ } /* end of choices in mapping at_from1 */
843
+
844
+ if ( tpos1 < CurTreeGetPos( cur_tree ) &&
845
+ 1 == CurTreeIsLastRank( cur_tree, at_rank_canon1 ) ) {
846
+ CurTreeRemoveLastRank( cur_tree );
847
+ } else
848
+ /* CurTree consistecy check (debug only) */
849
+ if ( tpos1 != CurTreeGetPos( cur_tree ) ) {
850
+ return CT_STEREOCOUNT_ERR; /* <BRKPT> */
851
+ }
852
+
853
+ if ( !nTotSuccess || stereo_bond_parity == sb_parity_calc ) {
854
+ goto repeat_all; /* repeat with next parity if no success or with the same parity, now known */
855
+ }
856
+
857
+ /* Previously the control flow never came here... */
858
+ if ( !nTotSuccess ) {
859
+ pCS->LinearCTStereoDble[nNumMappedBonds] = prevBond;
860
+ CurTreeSetPos( cur_tree, tpos1 );
861
+ /* Occurs when atoms are not really equvalent ( -O= without positive charge in "aromatic" ring) */
862
+ return 0; /* Happens for ID=92439,100318,100319 when EXCL_ALL_AROM_BOND_PARITY=0 and
863
+ * nNumChoices=0.
864
+ * Results from impossible previous mapping of symmetric relatively
865
+ * to a central ring aromatic circles while central ring is not symmetrical due to
866
+ * alternate bonds (in the central ring number of pi-electrons, atoms and bonds
867
+ * are symmetrical).
868
+ * Does not happen when alternate bonds of the central ring
869
+ * are treated as aromatic by attaching a (+) charge to the oxygen.
870
+ */
871
+ }
872
+ } else
873
+
874
+ {
875
+ int ret;
876
+
877
+ if ( !nNumMappedBonds ) {
878
+ pCS->bStereoIsBetter = 0; /* the first stereo feature in the canonical CT has not been processed yet */
879
+ }
880
+
881
+ if ( nNumMappedBonds < pCS->nLenLinearCTStereoDble ) {
882
+ prevBond = pCS->LinearCTStereoDble[nNumMappedBonds];
883
+ }
884
+
885
+ /* all stereo bonds have been mapped; now start processing stereo atoms... */
886
+ ret = map_stereo_atoms4 ( at, num_atoms, num_at_tg, num_max, nCanonRankFrom, nAtomNumberCanonFrom, nCanonRankTo,
887
+ nSymmRank, pRankStack1, pRankStack2, nTempRank, nNumMappedRanksInput,
888
+ nSymmStereo, NeighList, pCS, cur_tree, 0 );
889
+ if ( ret == 4 ) {
890
+ if ( nNumMappedBonds ) {
891
+ return ret;
892
+ } else {
893
+ pCS->bFirstCT = 1;
894
+ goto total_restart;
895
+ }
896
+ }
897
+ if ( RETURNED_ERROR(ret) ) {
898
+ if ( ret == CT_TIMEOUT_ERR )
899
+ return ret;
900
+ else
901
+ return ret; /* program error */
902
+ }
903
+ if ( ret > 0 ) {
904
+ nTotSuccess |= 1;
905
+ if ( ret & 2 ) {
906
+ CurTreeKeepLastAtomsOnly( cur_tree, tpos1, 1 ); /* start over */
907
+ nTotSuccess |= 2; /* Obtained a smaller CT */
908
+ }
909
+ }
910
+ }
911
+ if ( !nTotSuccess && pCS->nLenLinearCTStereoDble &&
912
+ nNumMappedBonds < pCS->nLenLinearCTStereoDble ) {
913
+ pCS->LinearCTStereoDble[nNumMappedBonds] = prevBond;
914
+ }
915
+ return nTotSuccess; /* ok */
916
+ }
917
+
918
+
919
+
920
+
921
+
922
+
923
+
924
+ /****************************************************************************************
925
+ */
926
+ int map_stereo_atoms4 (
927
+ sp_ATOM *at, int num_atoms, int num_at_tg, int num_max,
928
+ const AT_RANK *nCanonRankFrom, const AT_RANK *nAtomNumberCanonFrom, AT_RANK *nCanonRankTo, /* canonical numbering to be mapped */
929
+ const AT_RANK *nSymmRank, AT_RANK **pRankStack1/*from*/, AT_RANK **pRankStack2/*to*/,
930
+ AT_RANK *nTempRank, int nNumMappedRanksInput,
931
+ AT_RANK *nSymmStereo, NEIGH_LIST *NeighList,
932
+ CANON_STAT *pCS, CUR_TREE *cur_tree, int nNumMappedAtoms )
933
+ {
934
+ /*
935
+ * Do not check whether "from" atoms have any stereo features.
936
+ */
937
+ int nTotSuccess = 0;
938
+ AT_STEREO_CARB prevAtom;
939
+ int tpos1;
940
+
941
+ tpos1 = CurTreeGetPos( cur_tree );
942
+
943
+ if ( nNumMappedAtoms < pCS->nLenLinearCTStereoCarb ) {
944
+ /* AT_RANK *nRankFrom=*pRankStack1++, AT_RANK *nAtomNumberFrom=pRankStack1++; */
945
+ /* AT_RANK *nRankTo =*pRankStack2++, AT_RANK *nAtomNumberTo =pRankStack2++; */
946
+ int j1, at_from1, at_to1, /*at_from2, at_to2,*/ iMax, lvl, bStereoIsBetterWasSetHere;
947
+ int istk, istk2, bAddStack, nNumAtTo1Success, c, bFirstTime=1, bAllParitiesIdentical;
948
+ EQ_NEIGH EN[5], *pEN;
949
+ int nStackPtr[5], nMappedRanks[5], j[5], *nSP, *nMR, bLastLvlFailed;
950
+
951
+ AT_RANK at_rank_canon1, cr[5], at_to[5];
952
+ AT_RANK canon_rank1_min = 0;
953
+ int at_rank1; /* rank for mapping */
954
+ int nNumChoices, nNumUnkn, nNumUndf, nNumWorse, nNumBest, nNumCalc;
955
+ int stereo_center_parity, prev_stereo_center_parity, sb_parity_calc, pass;
956
+ AT_STEREO_CARB prevAtom2;
957
+
958
+ prevAtom = pCS->LinearCTStereoCarb[nNumMappedAtoms]; /* save to restore in case of failure */
959
+ at_rank_canon1 = nNumMappedAtoms? pCS->LinearCTStereoCarb[nNumMappedAtoms-1].at_num:0;
960
+
961
+ goto bypass_next_canon_rank_check;
962
+
963
+ next_canon_rank:
964
+
965
+ if ( !pCS->bStereoIsBetter /*??? && !pCS->bFirstCT ???*/ &&
966
+ at_rank_canon1 >= pCS->LinearCTStereoCarb[nNumMappedAtoms].at_num) {
967
+ /* cannot find next available canonical number */
968
+ if ( !nTotSuccess ) {
969
+ pCS->LinearCTStereoCarb[nNumMappedAtoms] = prevAtom; /* restore because of failure */
970
+ }
971
+ CurTreeSetPos( cur_tree, tpos1 );
972
+ return nTotSuccess;
973
+ }
974
+
975
+ bypass_next_canon_rank_check:
976
+
977
+ CurTreeSetPos( cur_tree, tpos1 );
978
+
979
+ /* find next available canon. number for a stereogenic atom */
980
+ if ( !Next_SC_At_CanonRank2( &at_rank_canon1, &canon_rank1_min, &bFirstTime,
981
+ pCS->bAtomUsedForStereo, pRankStack1, pRankStack2,
982
+ nAtomNumberCanonFrom, num_atoms ) ||
983
+ !pCS->bStereoIsBetter &&
984
+ at_rank_canon1 > pCS->LinearCTStereoCarb[nNumMappedAtoms].at_num) {
985
+ /* cannot find next available canonical number */
986
+ if ( !nTotSuccess ) {
987
+ pCS->LinearCTStereoCarb[nNumMappedAtoms] = prevAtom; /* restore because of failure */
988
+ }
989
+ return nTotSuccess;
990
+ }
991
+
992
+ nNumChoices = 0;
993
+ nNumUnkn = 0;
994
+ nNumUndf = 0;
995
+ nNumBest = 0;
996
+ nNumWorse = 0;
997
+ nNumCalc = 0;
998
+ pass = 0;
999
+ prev_stereo_center_parity = 0;
1000
+
1001
+ /* get mapping rank for the canon. number */
1002
+ at_rank1 = pRankStack1[0][at_from1=(int)nAtomNumberCanonFrom[at_rank_canon1 - 1]];
1003
+ iMax = at_rank1-1;
1004
+ /* for debug only */
1005
+ if ( at_rank1 != pRankStack2[0][pRankStack2[1][at_rank1-1]] )
1006
+ return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
1007
+
1008
+ /* count special parities of the not mapped yet "to" atoms */
1009
+ for ( j1 = 0; j1 <= iMax && at_rank1 == pRankStack2[0][at_to1 =pRankStack2[1][iMax-j1]]; j1 ++ ) {
1010
+ if ( !at[at_to1].stereo_bond_neighbor[0] && pCS->bAtomUsedForStereo[at_to1] == STEREO_AT_MARK ) {
1011
+ int no_choice = 0;
1012
+ stereo_center_parity = PARITY_VAL(at[at_to1].stereo_atom_parity);
1013
+ switch(stereo_center_parity) {
1014
+ case AB_PARITY_UNDF: nNumUndf ++; break; /* 4 */
1015
+ case AB_PARITY_UNKN: nNumUnkn ++; break; /* 3 */
1016
+ case BEST_PARITY: nNumBest ++; break; /* 1 */
1017
+ case WORSE_PARITY: nNumWorse ++; break; /* 2 */
1018
+ case AB_PARITY_CALC: nNumCalc ++; break;
1019
+ case AB_PARITY_NONE: no_choice ++; break; /* 0 */
1020
+ }
1021
+ nNumChoices += !no_choice;
1022
+ }
1023
+ }
1024
+ if ( nNumChoices != nNumCalc + nNumUndf + nNumUnkn + nNumBest + nNumWorse ) {
1025
+ return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
1026
+ }
1027
+ if ( !nNumChoices ) {
1028
+ goto next_canon_rank;
1029
+ }
1030
+ /* Determine the first parity to search */
1031
+ sb_parity_calc = ( nNumCalc > 0 )? BEST_PARITY : 0;
1032
+
1033
+ /* ==============================================================
1034
+ Search sequence: sb_parity_calc stereo_center_parity
1035
+ ==============================================================
1036
+ BEST_PARITY (calc) BEST_PARITY BEST_PARITY
1037
+ BEST_PARITY (known) BEST_PARITY WORSE_PARITY or 0
1038
+ WORSE_PARITY (calc) WORSE_PARITY WORSE_PARITY
1039
+ WORSE_PARITY (known) WORSE_PARITY 0
1040
+ AB_PARITY_UNKN(known) AB_PARITY_UNKN 0
1041
+ AB_PARITY_UNDF(known) AB_PARITY_UNDF 0
1042
+
1043
+ if (sb_parity_calc==stereo_center_parity) then "calc" else "known"
1044
+ */
1045
+
1046
+ repeat_all:
1047
+
1048
+ if ( !pass ++ ) {
1049
+ /* select the smallest parity to search */
1050
+ if ( sb_parity_calc ) {
1051
+ stereo_center_parity = BEST_PARITY;
1052
+ } else {
1053
+ stereo_center_parity = nNumBest? BEST_PARITY :
1054
+ nNumWorse? WORSE_PARITY :
1055
+ nNumUnkn? AB_PARITY_UNKN :
1056
+ nNumUndf? AB_PARITY_UNDF : AB_PARITY_NONE;
1057
+ }
1058
+ } else {
1059
+ prev_stereo_center_parity = stereo_center_parity;
1060
+ j1 = NextStereoParity2Test( &stereo_center_parity, &sb_parity_calc,
1061
+ nNumBest, nNumWorse, nNumUnkn, nNumUndf, nNumCalc);
1062
+ switch ( j1 ) {
1063
+ case 0:
1064
+ break; /* obtained next parity to test */
1065
+ case 1:
1066
+ goto next_canon_rank;
1067
+ default:
1068
+ return j1; /* program error */
1069
+ }
1070
+ }
1071
+ if ( stereo_center_parity == AB_PARITY_NONE ) {
1072
+ /* error? */
1073
+ return CT_STEREOCOUNT_ERR; /* <BRKPT> */
1074
+ }
1075
+ /* check if the new requested parity is small enough */
1076
+ if ( !pCS->bStereoIsBetter ) {
1077
+ c = CompareLinCtStereoAtomToValues( nTotSuccess? pCS->LinearCTStereoCarb+nNumMappedAtoms : &prevAtom,
1078
+ at_rank_canon1, (U_CHAR)stereo_center_parity );
1079
+ if ( c < 0 ) {
1080
+ if ( !nTotSuccess ) {
1081
+ pCS->LinearCTStereoCarb[nNumMappedAtoms] = prevAtom;
1082
+ }
1083
+ CurTreeSetPos( cur_tree, tpos1 );
1084
+ return nTotSuccess;
1085
+ }
1086
+ }
1087
+
1088
+
1089
+ bAllParitiesIdentical = 0;
1090
+ bStereoIsBetterWasSetHere = 0;
1091
+ istk = istk2 = 0;
1092
+ CurTreeSetPos( cur_tree, tpos1 ); /* start over */
1093
+ /*
1094
+ if ( prev_stereo_center_parity != stereo_center_parity ) {
1095
+ CurTreeSetPos( cur_tree, tpos1 );
1096
+ }
1097
+ */ /* nRankTo nAtomNumberTo */
1098
+ for ( j1 = 0; j1 <= iMax && at_rank1 == pRankStack2[0][at_to1 =pRankStack2[1][iMax-j1]]; j1 ++ ) {
1099
+ int ret, ret1, ret2, parity1;
1100
+ nNumAtTo1Success = 0;
1101
+ /*
1102
+ if ( !(at[at_to1].stereo_atom_parity && !at[at_to1].stereo_bond_neighbor[0] &&
1103
+ pCS->bAtomUsedForStereo[at_to1] == STEREO_AT_MARK ) )
1104
+ */
1105
+ if ( !at[at_to1].stereo_atom_parity || at[at_to1].stereo_bond_neighbor[0] ||
1106
+ pCS->bAtomUsedForStereo[at_to1] != STEREO_AT_MARK ) /* simplify 12-17-2003 */
1107
+ continue;
1108
+ /* Do not map on non-stereogenic atom constitutionally
1109
+ * equivalent to a steregenic atom. Here
1110
+ * at[at_to1] is not a sterereo center; | |
1111
+ * bonds tautomerism is a usual cause. -P(+)-CH=P-
1112
+ * For example, consider a fragment: | |
1113
+ * The two atoms P may be constitutionally
1114
+ * equivalent, P(+) may be seen as a stereocenter
1115
+ * while another P has a double bond (Now such a P(V) IS a stereocenter).
1116
+ */
1117
+ /* check whether the stereocenter parity corresponds to the requested stereocenter parity */
1118
+ if ( PARITY_KNOWN(at[at_to1].stereo_atom_parity) ) {
1119
+ if ( stereo_center_parity == sb_parity_calc ) {
1120
+ continue; /* requested parity to be calculated, found known parity */
1121
+ }
1122
+ if ( stereo_center_parity != PARITY_VAL(at[at_to1].stereo_atom_parity) ) {
1123
+ continue; /* parity differs from the requested parity */
1124
+ }
1125
+ } else
1126
+ if ( PARITY_CALCULATE( at[at_to1].stereo_atom_parity) ) {
1127
+ if ( stereo_center_parity != sb_parity_calc ) {
1128
+ continue; /* requested known parity, found patity to be calculated */
1129
+ }
1130
+ } else {
1131
+ return CT_STEREOCOUNT_ERR; /* unknown parity type */
1132
+ }
1133
+
1134
+ bAllParitiesIdentical = (( at[at_to1].stereo_atom_parity & KNOWN_PARITIES_EQL ) &&
1135
+ PARITY_KNOWN(at[at_to1].stereo_atom_parity));
1136
+
1137
+ if ( !bAllParitiesIdentical && !nNumCalc &&
1138
+ (!nNumUndf + !nNumUnkn + !nNumBest + !nNumWorse)==3 ) {
1139
+ /* only one kind of stereocenter parity is present; check whether all parities are really same */
1140
+ bAllParitiesIdentical = All_SC_Same( at_rank_canon1, /* canonical number */
1141
+ pRankStack1, pRankStack2,
1142
+ nAtomNumberCanonFrom, at );
1143
+ if ( bAllParitiesIdentical < 0 ) {
1144
+ return CT_STEREOCOUNT_ERR;
1145
+ }
1146
+ }
1147
+ if ( tpos1 < CurTreeGetPos( cur_tree ) &&
1148
+ 1 == CurTreeIsLastRank( cur_tree, at_rank_canon1 ) &&
1149
+ 1 == CurTreeIsLastAtomEqu( cur_tree, at_to1, nSymmStereo ) )
1150
+ continue;
1151
+
1152
+ /* initialize stack pointer nStackPtr[istk] for "hand-made" recursion */
1153
+ /* stacks are pRankStack1[], pRankStack2[], nNumMappedRanks[] */
1154
+ istk = 0;
1155
+ nStackPtr[istk] = 0;
1156
+ nMappedRanks[istk] = nNumMappedRanksInput;
1157
+ bAddStack = 0;
1158
+ /* if all equivalent atoms have same known parity, do not map any of them here */
1159
+ if ( !bAllParitiesIdentical ) {
1160
+ /* map the central atom */
1161
+ /* this mapping is always possible */
1162
+ ret1 = map_an_atom2( num_at_tg, num_max, at_from1, at_to1,
1163
+ nTempRank, nMappedRanks[istk], &nMappedRanks[istk+1], pCS,
1164
+ NeighList, pRankStack1+nStackPtr[istk], pRankStack2+nStackPtr[istk],
1165
+ &bAddStack );
1166
+ if ( RETURNED_ERROR(ret1) ) {
1167
+ return ret1; /* error */
1168
+ }
1169
+ nStackPtr[istk+1] = nStackPtr[istk] + bAddStack;
1170
+ istk ++;
1171
+ } else {
1172
+ ClearPreviousMappings( pRankStack1+2 ); /* precaution */
1173
+ }
1174
+
1175
+ /*********************************************************************************
1176
+ *
1177
+ * Unknown Stereocenter Parity case: possibly need to map stereo bond neighbors
1178
+ */
1179
+ if ( stereo_center_parity == sb_parity_calc )
1180
+ {
1181
+ /* find out the parity */
1182
+ parity1 = parity_of_mapped_atom2( at_from1, at_to1, at, &EN[istk],
1183
+ nCanonRankFrom, pRankStack1[nStackPtr[istk]],
1184
+ pRankStack2[nStackPtr[istk]] );
1185
+ /* if parity is well-defined then returned EN[istk].num_to=0 */
1186
+ if ( !parity1 ) {
1187
+ return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
1188
+ }
1189
+ if ( !EN[istk].num_to && parity1 != sb_parity_calc ) {
1190
+ continue; /* looking for the parity value = sb_parity_calc */
1191
+ }
1192
+
1193
+ } else {
1194
+ /* Known parity */
1195
+ parity1 = stereo_center_parity;
1196
+ EN[istk].num_to = 0;
1197
+ }
1198
+
1199
+ /***********************************************************************
1200
+ * no need to map the neighbors: parity is known or has been calculated
1201
+ */
1202
+ if ( stereo_center_parity == sb_parity_calc && !EN[istk].num_to ||
1203
+ /* now well-defined, but unknown in advance atom parity OR */
1204
+ stereo_center_parity != sb_parity_calc )
1205
+ /* known in advance parity = stereo_center_parity */
1206
+ {
1207
+ /* do not need to map the neighbors */
1208
+ c = CompareLinCtStereoAtomToValues( pCS->LinearCTStereoCarb+nNumMappedAtoms,
1209
+ at_rank_canon1, (U_CHAR)parity1 );
1210
+ if ( c < 0 && !pCS->bStereoIsBetter ) {
1211
+ /* reject */
1212
+ pCS->lNumRejectedCT ++;
1213
+ continue; /* Reject: not a minimal CT. Should not happen */
1214
+ } else {
1215
+ /* accept */
1216
+
1217
+ if ( bAddStack ) {
1218
+ if ( tpos1 == CurTreeGetPos( cur_tree ) ||
1219
+ 0 == CurTreeIsLastRank( cur_tree, at_rank_canon1 ) ) {
1220
+ CurTreeAddRank( cur_tree, at_rank_canon1 );
1221
+ }
1222
+ CurTreeAddAtom( cur_tree, at_to1 );
1223
+ }
1224
+
1225
+ if ( c > 0 && !pCS->bStereoIsBetter ) {
1226
+ /* stereo center entry is less than the previusly found */
1227
+ pCS->bStereoIsBetter = bStereoIsBetterWasSetHere = 1;
1228
+ prevAtom2 = pCS->LinearCTStereoCarb[nNumMappedAtoms];
1229
+ }
1230
+ pCS->LinearCTStereoCarb[nNumMappedAtoms].parity = parity1;
1231
+ pCS->LinearCTStereoCarb[nNumMappedAtoms].at_num = at_rank_canon1;
1232
+ pCS->bRankUsedForStereo[at_from1] = 3;
1233
+ pCS->bAtomUsedForStereo[at_to1] -= STEREO_AT_MARK;
1234
+
1235
+ ret = map_stereo_atoms4 ( at, num_atoms, num_at_tg, num_max, nCanonRankFrom, nAtomNumberCanonFrom, nCanonRankTo,
1236
+ nSymmRank, pRankStack1+nStackPtr[istk], pRankStack2+nStackPtr[istk],
1237
+ nTempRank, nMappedRanks[istk], nSymmStereo, NeighList,
1238
+ pCS, cur_tree, nNumMappedAtoms+1 );
1239
+ pCS->bRankUsedForStereo[at_from1] = 0;
1240
+ pCS->bAtomUsedForStereo[at_to1] += STEREO_AT_MARK;
1241
+ if ( ret == 4 ) {
1242
+ return ret;
1243
+ }
1244
+ if ( RETURNED_ERROR(ret) ) {
1245
+ if ( ret == CT_TIMEOUT_ERR )
1246
+ return ret;
1247
+ else
1248
+ return ret; /* program error */
1249
+ }
1250
+ if ( ret > 0 ) {
1251
+ nTotSuccess |= 1;
1252
+ nNumAtTo1Success ++;
1253
+ if ( bStereoIsBetterWasSetHere || (ret & 2) ) {
1254
+ CurTreeKeepLastAtomsOnly( cur_tree, tpos1, 1 ); /* start over */
1255
+ nTotSuccess |= 2; /* Obtained a smaller CT */
1256
+ }
1257
+ } else {
1258
+ if ( bStereoIsBetterWasSetHere ) {
1259
+ pCS->bStereoIsBetter = 0;
1260
+ pCS->LinearCTStereoCarb[nNumMappedAtoms] = prevAtom2;
1261
+ }
1262
+ /* remove failed atom1 from the tree */
1263
+ if ( tpos1 < CurTreeGetPos( cur_tree ) &&
1264
+ 1 == CurTreeIsLastRank( cur_tree, at_rank_canon1 ) ) {
1265
+ CurTreeRemoveIfLastAtom( cur_tree, at_to1 );
1266
+ CurTreeRemoveLastRankIfNoAtoms( cur_tree );
1267
+ }
1268
+
1269
+ }
1270
+ bStereoIsBetterWasSetHere = 0;
1271
+ }
1272
+ /*
1273
+ if ( (at[at_to1].stereo_atom_parity & KNOWN_PARITIES_EQL ) &&
1274
+ ATOM_PARITY_KNOWN(stereo_center_parity) && !nSymmStereo ) { // ??? add && !nSymmStereo ???
1275
+ break; // do not repeat for the same kind of stereo atom with the parity known in advance
1276
+ }
1277
+ */
1278
+ if ( bAllParitiesIdentical ) {
1279
+ break; /* do not repeat for the same kind of stereo atom with the parity known in advance */
1280
+ }
1281
+ continue;
1282
+
1283
+ }
1284
+
1285
+ /***************************************************
1286
+ *
1287
+ * Need to map the neighbors
1288
+ */
1289
+ if ( stereo_center_parity != sb_parity_calc ) {
1290
+ return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
1291
+ }
1292
+ /* -- has already been calculated --
1293
+ parity1 = parity_of_mapped_atom2( at_from1, at_to1, at, &EN[istk],
1294
+ nCanonRankFrom, pRankStack1[nStackPtr[istk]], pRankStack2[nStackPtr[istk]] );
1295
+ */
1296
+ if ( !parity1 ) {
1297
+ return CT_STEREOCOUNT_ERR; /* 1/25/2002 */ /* <BRKPT> */
1298
+ }
1299
+
1300
+ if ( bAddStack ) {
1301
+ if ( tpos1 == CurTreeGetPos( cur_tree ) ||
1302
+ 0 == CurTreeIsLastRank( cur_tree, at_rank_canon1 ) ) {
1303
+ CurTreeAddRank( cur_tree, at_rank_canon1 );
1304
+ }
1305
+ CurTreeAddAtom( cur_tree, at_to1 );
1306
+ }
1307
+ /******************************************************
1308
+ * Need to fix the neighbors to define the atom parity
1309
+ ******************************************************/
1310
+ /* a recursion replaced with the hand-made stack */
1311
+ lvl = 0; /* the "recursion" depth level */
1312
+ nSP = &nStackPtr[istk];
1313
+ nMR = &nMappedRanks[istk];
1314
+ pEN = &EN[istk];
1315
+ bLastLvlFailed = 0;
1316
+
1317
+ /* entering "recursion" depth level lvl */
1318
+ next_lvl:
1319
+ if ( pEN[lvl].num_to ) {
1320
+ /* Found tied neighbors. Try all transpositions of the tied neighbors.
1321
+ * j is a number of the "to" tied neighbor in the pEN[lvl].to_at[*] to
1322
+ * which the pEN[lvl].from_at "from" neighbor's canonical number is mapped
1323
+ */
1324
+ j[lvl] = 0;
1325
+ next_j:
1326
+ cr[lvl] = nCanonRankFrom[pEN[lvl].from_at];
1327
+ at_to[lvl] = pEN[lvl].to_at[j[lvl]];
1328
+ if ( j[lvl] && tpos1 < CurTreeGetPos( cur_tree ) &&
1329
+ 1 == CurTreeIsLastRank( cur_tree, cr[lvl] ) &&
1330
+ 1 == CurTreeIsLastAtomEqu( cur_tree, at_to[lvl], nSymmStereo ) ) {
1331
+ lvl ++;
1332
+ bLastLvlFailed = 0;
1333
+ goto backup; /* do not test stereo equivalent atoms except the first one */
1334
+ }
1335
+
1336
+ ret2 = map_an_atom2( num_at_tg, num_max,
1337
+ pEN[lvl].from_at, /* from */
1338
+ pEN[lvl].to_at[j[lvl]], /* to */
1339
+ nTempRank, nMR[lvl], &nMR[lvl+1], pCS,
1340
+ NeighList, pRankStack1+nSP[lvl], pRankStack2+nSP[lvl],
1341
+ &bAddStack );
1342
+ if ( RETURNED_ERROR(ret2) ) {
1343
+ return ret2; /* program error */
1344
+ }
1345
+
1346
+ /* next recursion depth level */
1347
+ if ( bAddStack ) {
1348
+ if ( tpos1 == CurTreeGetPos( cur_tree ) ||
1349
+ 0 == CurTreeIsLastRank( cur_tree, cr[lvl] ) ) {
1350
+ CurTreeAddRank( cur_tree, cr[lvl] );
1351
+ }
1352
+ CurTreeAddAtom( cur_tree, at_to[lvl] );
1353
+ }
1354
+ nSP[lvl+1] = nSP[lvl] + bAddStack;
1355
+ lvl ++; /* upon increment lvl = number of additionally mapped neighbors
1356
+ * (entering next recursion level) */
1357
+ /* check if the mapping has defined the parity */
1358
+ parity1 = parity_of_mapped_atom2( at_from1, at_to1, at, &pEN[lvl],
1359
+ nCanonRankFrom, pRankStack1[nSP[lvl]], pRankStack2[nSP[lvl]] );
1360
+ if ( !parity1 ) {
1361
+ return CT_STEREOCOUNT_ERR; /* 1/25/2002 */ /* <BRKPT> */
1362
+ }
1363
+ if ( parity1 < 0 ) {
1364
+ goto next_lvl; /* we need at least one more mapping to define the parity */
1365
+ }
1366
+
1367
+ /**********************************************************
1368
+ *
1369
+ * Check the parity
1370
+ *
1371
+ **********************************************************
1372
+ * make a decision whether to accept the current mapping */
1373
+
1374
+ c = CompareLinCtStereoAtomToValues( pCS->LinearCTStereoCarb+nNumMappedAtoms,
1375
+ at_rank_canon1, (U_CHAR)parity1 );
1376
+ if ( sb_parity_calc != parity1 ||
1377
+ c < 0 && !pCS->bStereoIsBetter ) {
1378
+ pCS->lNumRejectedCT ++;
1379
+ bLastLvlFailed = 1;
1380
+ } else
1381
+ /* the parity has been defined (all neighbors have untied ranks) */
1382
+ /* if ( bAcceptAllParities || parity1 == BEST_PARITY ) */
1383
+ {
1384
+ /*********************************************************************
1385
+ *
1386
+ * Process the parity here. We are at the top of the recursion stack.
1387
+ *
1388
+ *********************************************************************/
1389
+ /* try to accept current neighbors mapping */
1390
+ if ( c > 0 && !pCS->bStereoIsBetter ) {
1391
+ pCS->bStereoIsBetter = bStereoIsBetterWasSetHere = 1;
1392
+ prevAtom2 = pCS->LinearCTStereoCarb[nNumMappedAtoms];
1393
+ }
1394
+ pCS->LinearCTStereoCarb[nNumMappedAtoms].parity = parity1;
1395
+ pCS->LinearCTStereoCarb[nNumMappedAtoms].at_num = at_rank_canon1;
1396
+ pCS->bRankUsedForStereo[at_from1] = 3;
1397
+ pCS->bAtomUsedForStereo[at_to1] -= STEREO_AT_MARK;
1398
+
1399
+ ret = map_stereo_atoms4 ( at, num_atoms, num_at_tg, num_max, nCanonRankFrom, nAtomNumberCanonFrom, nCanonRankTo,
1400
+ nSymmRank, pRankStack1+nSP[lvl], pRankStack2+nSP[lvl],
1401
+ nTempRank, nMR[lvl], nSymmStereo, NeighList,
1402
+ pCS, cur_tree, nNumMappedAtoms+1 );
1403
+ pCS->bRankUsedForStereo[at_from1] = 0;
1404
+ pCS->bAtomUsedForStereo[at_to1] += STEREO_AT_MARK;
1405
+ if ( ret == 4 ) {
1406
+ return ret;
1407
+ }
1408
+ if ( RETURNED_ERROR(ret) ) {
1409
+ if ( ret == CT_TIMEOUT_ERR )
1410
+ return ret;
1411
+ else
1412
+ return ret; /* program error */
1413
+ }
1414
+ if ( ret > 0 ) {
1415
+ nTotSuccess |= 1;
1416
+ nNumAtTo1Success ++;
1417
+ if ( bStereoIsBetterWasSetHere || (ret & 2) ) {
1418
+ CurTreeKeepLastAtomsOnly( cur_tree, tpos1, 1 ); /* start over */
1419
+ nTotSuccess |= 2; /* Obtained a smaller CT */
1420
+ }
1421
+ } else {
1422
+ if ( bStereoIsBetterWasSetHere ) {
1423
+ pCS->bStereoIsBetter = 0;
1424
+ pCS->LinearCTStereoCarb[nNumMappedAtoms] = prevAtom2;
1425
+ }
1426
+ bLastLvlFailed = 1;
1427
+ }
1428
+ bStereoIsBetterWasSetHere = 0;
1429
+
1430
+ /* avoid redundant repetitions: */
1431
+ /* check if neighbors mappings have altered another stereo center parity */
1432
+ if ( !nSymmStereo && !might_change_other_atom_parity( at, num_atoms, at_to1,
1433
+ pRankStack2[nSP[lvl]] /* ranks after neigbors mapping */,
1434
+ pRankStack2[nStackPtr[istk]] /* ranks before the mapping neighbors */) ) {
1435
+ goto done;
1436
+ }
1437
+ }
1438
+ /* Continue the cycle. Go to the previous "recursion" level */
1439
+ backup:
1440
+ while (lvl -- > 0 ) {
1441
+
1442
+ j[lvl] ++; /* next neighbor at this level */
1443
+ if ( j[lvl] < pEN[lvl].num_to ) {
1444
+ if ( bLastLvlFailed ) {
1445
+ if ( tpos1 < CurTreeGetPos( cur_tree ) &&
1446
+ 1 == CurTreeIsLastRank( cur_tree, cr[lvl] ) ) {
1447
+ CurTreeRemoveIfLastAtom( cur_tree, at_to[lvl] );
1448
+ CurTreeRemoveLastRankIfNoAtoms( cur_tree );
1449
+ }
1450
+ bLastLvlFailed = 0;
1451
+ }
1452
+ /* Done with this level. Go back one level */
1453
+ goto next_j;
1454
+ }
1455
+ /* remove failed atom from the tree */
1456
+ if ( tpos1 < CurTreeGetPos( cur_tree ) &&
1457
+ 1 == CurTreeIsLastRank( cur_tree, cr[lvl] ) ) {
1458
+ CurTreeRemoveLastRank( cur_tree );
1459
+ }
1460
+ }
1461
+ goto done;
1462
+ } else {
1463
+ cr[lvl] = 0;
1464
+ }
1465
+
1466
+ done:; /* at this point lvl=0. */
1467
+ if ( !nNumAtTo1Success ) {
1468
+ if ( tpos1 < CurTreeGetPos( cur_tree ) &&
1469
+ 1 == CurTreeIsLastRank( cur_tree, at_rank_canon1 ) ) {
1470
+ CurTreeRemoveIfLastAtom( cur_tree, at_to1 );
1471
+ CurTreeRemoveLastRankIfNoAtoms( cur_tree );
1472
+ }
1473
+ }
1474
+ } /* end of stereo atom mapping cycle */
1475
+
1476
+ if ( tpos1 < CurTreeGetPos( cur_tree ) &&
1477
+ 1 == CurTreeIsLastRank( cur_tree, at_rank_canon1 ) ) {
1478
+ CurTreeRemoveLastRank( cur_tree );
1479
+ } else
1480
+ /* CurTree consistency check (debug only) */
1481
+ if ( tpos1 != CurTreeGetPos( cur_tree ) ) {
1482
+ return CT_STEREOCOUNT_ERR; /* <BRKPT> */
1483
+ }
1484
+
1485
+ if ( !nTotSuccess || stereo_center_parity == sb_parity_calc ) {
1486
+ goto repeat_all; /* repeat with next parity if no success or with the same parity, now known */
1487
+ }
1488
+
1489
+ } else {
1490
+
1491
+ /****************************************************
1492
+ *
1493
+ * All stereogenic atoms and bonds have been mapped
1494
+ *
1495
+ ****************************************************/
1496
+
1497
+ if ( UserAction && USER_ACTION_QUIT == (*UserAction)() ||
1498
+ ConsoleQuit && (*ConsoleQuit)() ) {
1499
+ return CT_USER_QUIT_ERR;
1500
+ }
1501
+
1502
+ if ( pCS->bStereoIsBetter || pCS->bFirstCT ) {
1503
+ /* All stereo atoms have been mapped. Current stereo name is better than all previous.
1504
+ * Create new numbering for the new CT
1505
+ * break all remaining "from" ties
1506
+ */
1507
+ int i1, ret;
1508
+ AT_RANK rc, n1, n2;
1509
+ ret=BreakAllTies( num_at_tg, num_max, pRankStack1, NeighList, nTempRank, pCS);
1510
+ if ( RETURNED_ERROR( ret ) ) {
1511
+ return ret;
1512
+ }
1513
+ /* break all remaining "from" ties */
1514
+ ret=BreakAllTies( num_at_tg, num_max, pRankStack2, NeighList, nTempRank, pCS);
1515
+ if ( RETURNED_ERROR( ret ) ) {
1516
+ return ret;
1517
+ }
1518
+ /* move stack pointers to the "nAtomNumber[*]" after all ties are broken */
1519
+ pRankStack1 += 2;
1520
+ pRankStack2 += 2;
1521
+ /* Now final mapping ranks of "to" atom (*pRankStack2)[i] and "from" atom (*pRankStack1)[i]
1522
+ * are equal and all ranks are different, that is, we have a full mapping
1523
+ * Copy so far best canonical numbering from "from" to "to".
1524
+ */
1525
+ memset( pCS->nPrevAtomNumber, 0, num_at_tg*sizeof(pCS->nPrevAtomNumber[0]) );
1526
+ for ( i1 = 0; i1 < num_at_tg; i1 ++ ) {
1527
+ n1 = pRankStack1[1][i1];
1528
+ rc = nCanonRankFrom[n1]; /* new canon. rank */
1529
+ n2 = pRankStack2[1][i1]; /* orig. atom number */
1530
+ nCanonRankTo[n2] = rc; /* assign new canon. number to the atom */
1531
+ /* use this array to find stereo-equivalent atoms */
1532
+ pCS->nPrevAtomNumber[rc-1] = n2; /* ord. number of the atom having canon. rank = rc */
1533
+ nSymmStereo[i1] = i1; /* restart search for stereo equivalent atoms */
1534
+ /* check mapping correctness */
1535
+ if ( pRankStack1[0][n1] != pRankStack2[0][n2] ||
1536
+ nSymmRank[n1] != nSymmRank[n2] ) {
1537
+ return CT_STEREO_CANON_ERR; /* stereo mapping error */
1538
+ }
1539
+ }
1540
+ /* statistics */
1541
+ pCS->lNumTotCT ++;
1542
+ pCS->lNumEqualCT = 1;
1543
+ pCS->lNumDecreasedCT ++;
1544
+ pCS->bStereoIsBetter = 0; /* prepare to start over */
1545
+ nTotSuccess = 1;
1546
+ pCS->bFirstCT = 0;
1547
+ #if( REMOVE_CALC_NONSTEREO == 1 ) /* { */
1548
+ if ( !(pCS->nMode & CMODE_REDNDNT_STEREO ) ) {
1549
+ i1 = RemoveCalculatedNonStereo( at, num_atoms, num_at_tg,
1550
+ pRankStack1, pRankStack2, nTempRank, NeighList,
1551
+ nSymmRank, nCanonRankTo, pCS->nPrevAtomNumber, pCS );
1552
+ if ( RETURNED_ERROR( i1 ) ) {
1553
+ return i1;
1554
+ }
1555
+ if ( i1 < 0 ) {
1556
+ #if( bRELEASE_VERSION == 0 )
1557
+ pCS->bExtract |= EXTR_REMOVE_PARITY_WARNING;
1558
+ #endif
1559
+ i1 = -(1+i1);
1560
+ }
1561
+ if ( i1 > 0 ) {
1562
+ return 4; /* total restart: due to newly found stereo equivalence */
1563
+ /* the length of the stereo CT has changed */
1564
+ }
1565
+ }
1566
+ #endif /* } REMOVE_CALC_NONSTEREO */
1567
+ pRankStack1 -= 2;
1568
+ pRankStack2 -= 2;
1569
+ } else {
1570
+ /* current stereo name is same as previous. We do not need a full mapping. */
1571
+ if ( nSymmStereo ) {
1572
+ int num_changes = 0;
1573
+ AT_RANK r, n1, n2, r_max, cr;
1574
+ r_max = (AT_RANK)num_at_tg;
1575
+ for ( r = 1; r <= r_max; r ++ ) {
1576
+ if ( bUniqueAtNbrFromMappingRank( pRankStack1, r, &n1 ) ) {
1577
+ if ( bUniqueAtNbrFromMappingRank( pRankStack2, r, &n2 ) ) {
1578
+ /* atoms at[n1], at[n2] have identical untied mapping rank r */
1579
+ cr = nCanonRankFrom[(int)n1]-1; /* (new at[n2] canonical rank)-1 */
1580
+ /* pCS->nPrevAtomNumber[(int)cr] = */
1581
+ /* previous ordering number of an atom with the canon. rank = cr+1; */
1582
+ /* make this atom equivalent to atom at[n2]: */
1583
+ num_changes += nJoin2Mcrs( nSymmStereo, pCS->nPrevAtomNumber[(int)cr], n2 );
1584
+ } else {
1585
+ return CT_MAPCOUNT_ERR; /* mapping ranks must be either both tied or untied. */ /* <BRKPT> */
1586
+ }
1587
+ }
1588
+ }
1589
+ if ( num_changes ) { /* compress trees to stars */
1590
+ for ( r = r_max-1; r; r -- ) {
1591
+ nGetMcr( nSymmStereo, r );
1592
+ }
1593
+ }
1594
+ }
1595
+ /* statistics */
1596
+ pCS->lNumEqualCT ++;
1597
+ pCS->lNumTotCT ++;
1598
+ nTotSuccess = 1;
1599
+ }
1600
+ if ( bInchiTimeIsOver( pCS->ulTimeOutTime ) ) {
1601
+ return CT_TIMEOUT_ERR;
1602
+ }
1603
+ }
1604
+ if ( !nTotSuccess && nNumMappedAtoms < pCS->nLenLinearCTStereoCarb ) {
1605
+ pCS->LinearCTStereoCarb[nNumMappedAtoms] = prevAtom;
1606
+ CurTreeSetPos( cur_tree, tpos1 );
1607
+ }
1608
+ return nTotSuccess; /* return to the previous level of the recursion. */
1609
+ }