rino 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }