Branch data Line data Source code
1 : : /*
2 : : * SPDX-License-Identifier: MIT
3 : : * Copyright (c) 2024 IUPAC and InChI Trust
4 : : */
5 : :
6 : : #include <stdio.h>
7 : : #include <stdlib.h>
8 : : #include <string.h>
9 : : #include <ctype.h>
10 : : #include <time.h>
11 : : #include <sys/timeb.h>
12 : : #include <limits.h>
13 : :
14 : : #include "mode.h"
15 : : #include "ichicano.h"
16 : :
17 : : #include "ichitime.h"
18 : : #include "ichi.h"
19 : : #include "ichicomn.h"
20 : :
21 : : #include "bcf_s.h"
22 : :
23 : : /****************************************************************************
24 : : *
25 : : * Globals for sorting
26 : : ****************************************************************************/
27 : :
28 : : #define tsort insertions_sort
29 : :
30 : : /* local prototypes */
31 : :
32 : : void FillOutAtomInvariant( sp_ATOM* at,
33 : : int num_atoms,
34 : : int num_at_tg,
35 : : ATOM_INVARIANT* pAtomInvariant,
36 : : CANON_STAT* pCS );
37 : :
38 : : int Canon_INChI1( int num_atoms,
39 : : int num_at_tg,
40 : : sp_ATOM* at,
41 : : CANON_STAT* pCS,
42 : : INCHI_MODE nMode );
43 : :
44 : : int Canon_INChI2( int num_atoms,
45 : : int num_at_tg,
46 : : sp_ATOM* at,
47 : : CANON_STAT* pCS,
48 : : INCHI_MODE nMode );
49 : :
50 : : int Canon_INChI3( INCHI_CLOCK *ic,
51 : : int num_atoms,
52 : : int num_at_tg,
53 : : sp_ATOM* at,
54 : : CANON_STAT* pCS,
55 : : CANON_GLOBALS *pCG,
56 : : INCHI_MODE nMode,
57 : : int bTautFtcn );
58 : :
59 : :
60 : : #ifdef COMPILE_ANSI_ONLY
61 : :
62 : : static clock_t InchiClock( void );
63 : :
64 : : #ifdef INCHI_USETIMES
65 : : static clock_t InchiClock( void )
66 : : {
67 : : struct tms buf;
68 : : clock_t c = times( &buf );
69 : : if (c != (clock_t) -1)
70 : : {
71 : : return buf.tms_utime;
72 : : }
73 : : return 0;
74 : : }
75 : : #else
76 : 1856 : static clock_t InchiClock( void )
77 : : {
78 : 1856 : clock_t c = clock( );
79 [ + - ]: 1856 : if (c != (clock_t) -1)
80 : : {
81 : 1856 : return c;
82 : : }
83 : 0 : return 0;
84 : : }
85 : : #endif
86 : :
87 : : #define INCHI_MSEC(X) (long)((1000.0/(double)CLOCKS_PER_SEC)*(X))
88 : : #define INCHI_CLOCK_T(X) (clock_t)( (double)(X) / 1000.0 * (double)CLOCKS_PER_SEC )
89 : : const clock_t FullMaxClock = (clock_t) ( -1 );
90 : : const clock_t HalfMaxClock = (clock_t) ( -1 ) / 2;
91 : :
92 : : static void FillMaxMinClock( INCHI_CLOCK *ic ); /* keep compiler happy */
93 : 1424 : static void FillMaxMinClock( INCHI_CLOCK *ic )
94 : : {
95 [ + + ]: 1424 : if (!ic->m_MaxPositiveClock)
96 : : {
97 : 123 : clock_t valPos = 0, val1 = 1;
98 [ + + ]: 7749 : while (0 < ( ( val1 <<= 1 ), ( val1 |= 1 ) )) /* djb-rwth: ignoring GH issue #59.3 -- LLONG_MIN/LLONG_MAX not found in <limits.h> on Linux */
99 : : {
100 : 7626 : valPos = val1;
101 : : }
102 : 123 : ic->m_MaxPositiveClock = valPos;
103 : 123 : ic->m_MinNegativeClock = -valPos;
104 : 123 : ic->m_HalfMaxPositiveClock = ic->m_MaxPositiveClock / 2;
105 : 123 : ic->m_HalfMinNegativeClock = ic->m_MinNegativeClock / 2;
106 : : }
107 : 1424 : }
108 : :
109 : :
110 : : /******** get current process time ****************************************/
111 : 1856 : void InchiTimeGet( inchiTime *TickEnd )
112 : : {
113 : 1856 : TickEnd->clockTime = InchiClock( );
114 : 1856 : }
115 : : /******** returns difference TickEnd - TickStart in milliseconds **********/
116 : 928 : long InchiTimeMsecDiff( INCHI_CLOCK *ic, inchiTime *TickEnd, inchiTime *TickStart )
117 : : {
118 [ - + ]: 928 : if (FullMaxClock > 0)
119 : : {
120 : : clock_t delta;
121 [ # # # # ]: 0 : if (!TickEnd || !TickStart)
122 : 0 : return 0;
123 : : /* clock_t is unsigned */
124 [ # # ]: 0 : if (TickEnd->clockTime > TickStart->clockTime)
125 : : {
126 [ # # ]: 0 : if (TickEnd->clockTime > HalfMaxClock &&
127 [ # # ]: 0 : TickEnd->clockTime - TickStart->clockTime > HalfMaxClock)
128 : : {
129 : : /* overflow in TickStart->clockTime, actually TickStart->clockTime was later */
130 : 0 : delta = ( FullMaxClock - TickEnd->clockTime ) + TickStart->clockTime;
131 : 0 : return -INCHI_MSEC( delta );
132 : : }
133 : 0 : delta = TickEnd->clockTime - TickStart->clockTime;
134 : 0 : return INCHI_MSEC( delta );
135 : : }
136 [ # # ]: 0 : else if (TickEnd->clockTime < TickStart->clockTime)
137 : : {
138 [ # # ]: 0 : if (TickStart->clockTime > HalfMaxClock &&
139 [ # # ]: 0 : TickStart->clockTime - TickEnd->clockTime > HalfMaxClock)
140 : : {
141 : : /* overflow in TickEnd->clockTime, actually TickEnd->clockTime was later */
142 : 0 : delta = ( FullMaxClock - TickStart->clockTime ) + TickEnd->clockTime;
143 : 0 : return INCHI_MSEC( delta );
144 : : }
145 : 0 : delta = TickStart->clockTime - TickEnd->clockTime;
146 : 0 : return -INCHI_MSEC( delta );
147 : : }
148 : 0 : return 0; /* TickEnd->clockTime == TickStart->clockTime */
149 : : }
150 : : else
151 : : {
152 : : /* may happen under Win32 only where clock_t is SIGNED long */
153 : : clock_t delta;
154 : 928 : FillMaxMinClock( ic );
155 [ + - - + ]: 928 : if (!TickEnd || !TickStart)
156 : 0 : return 0;
157 [ + - - + ]: 928 : if ((TickEnd->clockTime >= 0 && TickStart->clockTime >= 0) ||
158 [ # # # # ]: 0 : (TickEnd->clockTime <= 0 && TickStart->clockTime <= 0)) /* djb-rwth: addressing LLVM warnings */
159 : : {
160 : 928 : delta = TickEnd->clockTime - TickStart->clockTime;
161 : : }
162 : : else
163 [ # # ]: 0 : if (TickEnd->clockTime >= ic->m_HalfMaxPositiveClock &&
164 [ # # ]: 0 : TickStart->clockTime <= ic->m_HalfMinNegativeClock)
165 : : {
166 : : /* end is earlier than start */
167 : 0 : delta = ( ic->m_MaxPositiveClock - TickEnd->clockTime ) + ( TickStart->clockTime - ic->m_MinNegativeClock );
168 : 0 : delta = -delta;
169 : : }
170 : : else
171 [ # # ]: 0 : if (TickEnd->clockTime <= ic->m_HalfMinNegativeClock &&
172 [ # # ]: 0 : TickStart->clockTime >= ic->m_HalfMaxPositiveClock)
173 : : {
174 : : /* start was earlier than end */
175 : 0 : delta = ( ic->m_MaxPositiveClock - TickStart->clockTime ) + ( TickEnd->clockTime - ic->m_MinNegativeClock );
176 : : }
177 : : else
178 : : {
179 : : /* there was no overflow, clock passed zero */
180 : 0 : delta = TickEnd->clockTime - TickStart->clockTime;
181 : : }
182 : 928 : return INCHI_MSEC( delta );
183 : : }
184 : : }
185 : :
186 : :
187 : : /******************* get elapsed time from TickStart ************************/
188 : 767 : long InchiTimeElapsed( INCHI_CLOCK *ic, inchiTime *TickStart )
189 : : {
190 : : inchiTime TickEnd;
191 [ - + ]: 767 : if (!TickStart)
192 : 0 : return 0;
193 : 767 : InchiTimeGet( &TickEnd );
194 : 767 : return InchiTimeMsecDiff( ic, &TickEnd, TickStart );
195 : : }
196 : :
197 : :
198 : : /******************* add number of milliseconds to time *********************/
199 : 0 : void InchiTimeAddMsec( INCHI_CLOCK *ic, inchiTime *TickEnd, unsigned long nNumMsec )
200 : : {
201 : : clock_t delta;
202 [ # # ]: 0 : if (!TickEnd)
203 : 0 : return;
204 [ # # ]: 0 : if (FullMaxClock > 0)
205 : : {
206 : : /* clock_t is unsigned */
207 : 0 : delta = INCHI_CLOCK_T( nNumMsec );
208 : 0 : TickEnd->clockTime += delta;
209 : : }
210 : : else
211 : : {
212 : : /* may happen under Win32 only where clock_t is SIGNED long */
213 : : /* clock_t is unsigned */
214 : 0 : FillMaxMinClock( ic );
215 : 0 : delta = INCHI_CLOCK_T( nNumMsec );
216 : 0 : TickEnd->clockTime += delta;
217 : : }
218 : : }
219 : :
220 : :
221 : : /******************* check whether time has expired *********************/
222 : 496 : int bInchiTimeIsOver( INCHI_CLOCK *ic, inchiTime *TickStart )
223 : : {
224 [ - + ]: 496 : if (FullMaxClock > 0)
225 : : {
226 : : clock_t clockCurrTime;
227 [ # # ]: 0 : if (!TickStart)
228 : 0 : return 0;
229 : 0 : clockCurrTime = InchiClock( );
230 : : /* clock_t is unsigned */
231 [ # # ]: 0 : if (TickStart->clockTime > clockCurrTime)
232 : : {
233 [ # # ]: 0 : if (TickStart->clockTime > HalfMaxClock &&
234 [ # # ]: 0 : TickStart->clockTime - clockCurrTime > HalfMaxClock)
235 : : {
236 : : /* overflow in clockCurrTime, actually clockCurrTime was later */
237 : 0 : return 1;
238 : : }
239 : 0 : return 0;
240 : : }
241 [ # # ]: 0 : else if (TickStart->clockTime < clockCurrTime)
242 : : {
243 [ # # ]: 0 : if (clockCurrTime > HalfMaxClock &&
244 [ # # ]: 0 : clockCurrTime - TickStart->clockTime > HalfMaxClock)
245 : : {
246 : : /* overflow in TickStart->clockTime, actually TickStart->clockTime was later */
247 : 0 : return 0;
248 : : }
249 : 0 : return 1;
250 : : }
251 : 0 : return 0; /* TickStart->clockTime == clockCurrTime */
252 : : }
253 : : else
254 : : {
255 : : /* may happen under Win32 only where clock_t is SIGNED long */
256 : : clock_t clockCurrTime;
257 : 496 : FillMaxMinClock( ic );
258 [ + - ]: 496 : if (!TickStart)
259 : 496 : return 0;
260 : 0 : clockCurrTime = InchiClock( );
261 [ # # # # : 0 : if ((clockCurrTime >= 0 && TickStart->clockTime >= 0) ||
# # ]
262 [ # # ]: 0 : (clockCurrTime <= 0 && TickStart->clockTime <= 0)) /* djb-rwth: addressing LLVM warning */
263 : : {
264 : 0 : return ( clockCurrTime > TickStart->clockTime );
265 : : }
266 : : else
267 [ # # ]: 0 : if (clockCurrTime >= ic->m_HalfMaxPositiveClock &&
268 [ # # ]: 0 : TickStart->clockTime <= ic->m_HalfMinNegativeClock)
269 : : {
270 : : /* curr is earlier than start */
271 : 0 : return 0;
272 : : }
273 : : else
274 [ # # ]: 0 : if (clockCurrTime <= ic->m_HalfMinNegativeClock &&
275 [ # # ]: 0 : TickStart->clockTime >= ic->m_HalfMaxPositiveClock)
276 : : {
277 : : /* start was earlier than curr */
278 : 0 : return 1;
279 : : }
280 : : else
281 : : {
282 : : /* there was no overflow, clock passed zero */
283 : 0 : return ( clockCurrTime > TickStart->clockTime );
284 : : }
285 : : }
286 : : }
287 : :
288 : :
289 : :
290 : : #else
291 : :
292 : : /******** get current process time ****************************************/
293 : : void InchiTimeGet( inchiTime *TickEnd )
294 : : {
295 : : if (TickEnd)
296 : : {
297 : : struct _timeb timeb;
298 : : _ftime( &timeb );
299 : : TickEnd->clockTime = (unsigned long) timeb.time;
300 : : TickEnd->millitime = (long) timeb.millitm;
301 : : }
302 : : }
303 : :
304 : :
305 : : /******** returns difference TickEnd - TickStart in milliseconds **********/
306 : : long InchiTimeMsecDiff( INCHI_CLOCK *ic, inchiTime *TickEnd, inchiTime *TickStart )
307 : : {
308 : : long delta;
309 : : if (!TickEnd || !TickStart)
310 : : {
311 : : return 0;
312 : : }
313 : : if (TickEnd->clockTime >= TickStart->clockTime)
314 : : {
315 : : delta = (long) ( TickEnd->clockTime - TickStart->clockTime );
316 : : delta *= 1000;
317 : : delta += TickEnd->millitime - TickStart->millitime;
318 : : }
319 : : else
320 : : {
321 : : delta = -(long) ( TickStart->clockTime - TickEnd->clockTime );
322 : : delta *= 1000;
323 : : delta += TickEnd->millitime - TickStart->millitime;
324 : : }
325 : : return delta;
326 : : }
327 : :
328 : :
329 : : /******************* get elapsed time from TickStart ************************/
330 : : long InchiTimeElapsed( INCHI_CLOCK *ic, inchiTime *TickStart )
331 : : {
332 : : inchiTime TickEnd;
333 : : if (!TickStart)
334 : : {
335 : : return 0;
336 : : }
337 : : InchiTimeGet( &TickEnd );
338 : : return InchiTimeMsecDiff( ic, &TickEnd, TickStart );
339 : : }
340 : :
341 : :
342 : : /******************* add number of milliseconds to time *********************/
343 : : void InchiTimeAddMsec( INCHI_CLOCK *ic, inchiTime *TickEnd, unsigned long nNumMsec )
344 : : {
345 : : long delta;
346 : : if (!TickEnd)
347 : : {
348 : : return;
349 : : }
350 : : TickEnd->clockTime += nNumMsec / 1000;
351 : : delta = nNumMsec % 1000 + TickEnd->millitime;
352 : : TickEnd->clockTime += delta / 1000;
353 : : TickEnd->millitime = delta % 1000;
354 : : }
355 : :
356 : :
357 : : /******************* check whether time has expired *********************/
358 : : int bInchiTimeIsOver( INCHI_CLOCK *ic, inchiTime *TickEnd )
359 : : {
360 : : struct _timeb timeb;
361 : : if (!TickEnd)
362 : : {
363 : : return 0;
364 : : }
365 : : _ftime( &timeb );
366 : : if (TickEnd->clockTime > (unsigned long) timeb.time)
367 : : {
368 : : return 0;
369 : : }
370 : : if (TickEnd->clockTime < (unsigned long) timeb.time || TickEnd->millitime < (long) timeb.millitm)
371 : : {
372 : : return 1;
373 : : }
374 : : return 0;
375 : : }
376 : :
377 : : #endif
378 : :
379 : :
380 : : /****************************************************************************
381 : : length of canonic representation in sizeof(AT_NUMB) units
382 : : ****************************************************************************/
383 : 161 : int GetCanonLengths( int num_at,
384 : : sp_ATOM* at,
385 : : ATOM_SIZES *s,
386 : : T_GROUP_INFO *t_group_info )
387 : : {
388 : : /* include taut. groups as additional "atoms" to the connection table 07-22-2002 */
389 : :
390 : 161 : int i, nNumCT, nNumBonds, nNumTBonds = 0, nNumDblBondsStereo = 0, nNumAsymCarbStereo = 0, nNumIsotopic = 0;
391 [ + + + - ]: 161 : T_GROUP *t_group = ( s->nLenLinearCTTautomer && t_group_info ) ? t_group_info->t_group : NULL;
392 : :
393 [ + + ]: 971 : for (nNumBonds = 0, i = 0; i < num_at; i++)
394 : : {
395 : 810 : nNumBonds += at[i].valence;
396 [ - + ]: 810 : if (at[i].iso_sort_key)
397 : : {
398 : 0 : nNumIsotopic++; /* not including tautomeric endpoints that are isotopic only due to mobile atoms */
399 : : }
400 : :
401 [ + + ]: 810 : if (at[i].parity > 0)
402 : : {
403 : : /* ignore hydrogen isotope parities in at[i].parity2 */
404 : 201 : int j = 0, nStereoBondsToAtom = 0; /* number of stereo double bonds at this atom */
405 : : int k;
406 [ + - - + ]: 201 : for (; j < MAX_NUM_STEREO_BONDS && ( k = at[i].stereo_bond_neighbor[j] ); j++)
407 : : {
408 : 0 : nStereoBondsToAtom += ( at[k - 1].parity > 0 );
409 : : }
410 : 201 : nNumDblBondsStereo += nStereoBondsToAtom;
411 : 201 : nNumAsymCarbStereo += !j;
412 : : }
413 : : }
414 : :
415 : 161 : nNumDblBondsStereo /= 2;
416 : 161 : nNumBonds /= 2;
417 : :
418 : 161 : s->nLenBonds = inchi_max( s->nLenBonds, nNumBonds );
419 : 161 : nNumCT = nNumBonds; /* total number of neighbors in the CT */
420 : :
421 : : #if ( CT_ATOMID != CT_ATOMID_DONTINCLUDE )
422 : 161 : nNumCT += num_at;
423 : : #endif
424 : :
425 : 161 : s->nLenCTAtOnly = inchi_max( s->nLenCTAtOnly, nNumCT );
426 : :
427 [ + + ]: 161 : if (t_group)
428 : : {
429 [ + + ]: 26 : for (i = 0; i < t_group_info->num_t_groups; i++)
430 : : {
431 : 12 : nNumTBonds += t_group[i].nNumEndpoints;
432 : : }
433 : 14 : nNumCT += nNumTBonds;
434 : :
435 : : #if ( CT_ATOMID != CT_ATOMID_DONTINCLUDE )
436 : 14 : nNumCT += t_group_info->num_t_groups;
437 : : #endif
438 : : }
439 : :
440 : 161 : nNumCT = inchi_max( 1, nNumCT ); /* keep GetBaseCanonRanking() happy */
441 : 161 : s->nLenCT = inchi_max( s->nLenCT, nNumCT );
442 : 161 : s->nLenIsotopic = inchi_max( s->nLenIsotopic, nNumIsotopic );
443 : 161 : s->nLenLinearCTStereoDble = inchi_max( s->nLenLinearCTStereoDble, nNumDblBondsStereo );
444 : 161 : s->nLenLinearCTStereoCarb = inchi_max( s->nLenLinearCTStereoCarb, nNumAsymCarbStereo );
445 : :
446 [ + - ]: 161 : if (t_group_info)
447 : : {
448 : 161 : s->nLenIsotopicEndpoints = inchi_max( s->nLenIsotopicEndpoints, t_group_info->nNumIsotopicEndpoints );
449 : : }
450 : :
451 : 161 : return 0;
452 : : }
453 : :
454 : :
455 : : /****************************************************************************/
456 : 161 : int DeAllocateCS( CANON_STAT *pCS )
457 : : {
458 : : #define LOCAL_FREE( X) do{if(X){inchi_free( X); X=NULL;}}while(0)
459 : :
460 : : /* connection table */
461 [ + - + - ]: 161 : LOCAL_FREE( pCS->LinearCT );
462 [ + - + - ]: 161 : LOCAL_FREE( pCS->nCanonOrd );
463 [ + - + - ]: 161 : LOCAL_FREE( pCS->nSymmRank );
464 [ + - + - ]: 161 : LOCAL_FREE( pCS->nNum_H );
465 [ + - + - ]: 161 : LOCAL_FREE( pCS->nNum_H_fixed );
466 [ + - + - ]: 161 : LOCAL_FREE( pCS->nExchgIsoH );
467 : : /* isotopic */
468 [ - + - - ]: 161 : LOCAL_FREE( pCS->LinearCTIsotopic );
469 [ - + - - ]: 161 : LOCAL_FREE( pCS->nSymmRankIsotopic );
470 [ - + - - ]: 161 : LOCAL_FREE( pCS->nCanonOrdIsotopic );
471 : : /* isotopic tautomeric */
472 [ - + - - ]: 161 : LOCAL_FREE( pCS->LinearCTIsotopicTautomer );
473 [ - + - - ]: 161 : LOCAL_FREE( pCS->nCanonOrdIsotopicTaut );
474 [ - + - - ]: 161 : LOCAL_FREE( pCS->nSymmRankIsotopicTaut );
475 : : /* stereo */
476 [ - + - - ]: 161 : LOCAL_FREE( pCS->LinearCTStereoDble );
477 [ + + + - ]: 161 : LOCAL_FREE( pCS->LinearCTStereoCarb );
478 [ - + - - ]: 161 : LOCAL_FREE( pCS->LinearCTStereoDbleInv );
479 [ + + + - ]: 161 : LOCAL_FREE( pCS->LinearCTStereoCarbInv );
480 [ + + + - ]: 161 : LOCAL_FREE( pCS->nCanonOrdStereo );
481 [ + + + - ]: 161 : LOCAL_FREE( pCS->nCanonOrdStereoInv );
482 [ + + + - ]: 161 : LOCAL_FREE( pCS->nCanonOrdStereoTaut );
483 : : /* isotopic stereo */
484 [ - + - - ]: 161 : LOCAL_FREE( pCS->LinearCTIsotopicStereoDble );
485 [ - + - - ]: 161 : LOCAL_FREE( pCS->LinearCTIsotopicStereoCarb );
486 [ - + - - ]: 161 : LOCAL_FREE( pCS->LinearCTIsotopicStereoDbleInv );
487 [ - + - - ]: 161 : LOCAL_FREE( pCS->LinearCTIsotopicStereoCarbInv );
488 [ + + + - ]: 161 : LOCAL_FREE( pCS->bRankUsedForStereo );
489 [ + + + - ]: 161 : LOCAL_FREE( pCS->bAtomUsedForStereo );
490 : :
491 [ - + - - ]: 161 : LOCAL_FREE( pCS->nCanonOrdIsotopicStereo );
492 [ - + - - ]: 161 : LOCAL_FREE( pCS->nCanonOrdIsotopicStereoInv );
493 [ - + - - ]: 161 : LOCAL_FREE( pCS->nCanonOrdIsotopicStereoTaut );
494 : : /* tautomeric part of the connection table */
495 [ + + + - ]: 161 : LOCAL_FREE( pCS->LinearCTTautomer );
496 [ + + + - ]: 161 : LOCAL_FREE( pCS->nCanonOrdTaut );
497 [ + + + - ]: 161 : LOCAL_FREE( pCS->nSymmRankTaut );
498 : :
499 [ + - + - ]: 161 : LOCAL_FREE( pCS->LinearCT2 );
500 : :
501 : : /* for establishing constitutional equivalence */
502 [ + - + - ]: 161 : LOCAL_FREE( pCS->nPrevAtomNumber );
503 : :
504 : 161 : FreeNeighList( pCS->NeighList );
505 : 161 : pCS->NeighList = NULL;
506 : :
507 : : /* set zero lengths */
508 : 161 : pCS->nMaxLenLinearCTStereoDble = 0;
509 : 161 : pCS->nLenLinearCTStereoDble = 0;
510 : 161 : pCS->nMaxLenLinearCTStereoCarb = 0;
511 : 161 : pCS->nLenLinearCTStereoCarb = 0;
512 : 161 : pCS->nMaxLenLinearCTIsotopicStereoDble = 0;
513 : 161 : pCS->nLenLinearCTIsotopicStereoDble = 0;
514 : 161 : pCS->nMaxLenLinearCTIsotopicStereoCarb = 0;
515 : 161 : pCS->nLenLinearCTIsotopicStereoCarb = 0;
516 : 161 : pCS->nMaxLenLinearCTTautomer = 0;
517 : 161 : pCS->nLenLinearCTTautomer = 0;
518 : 161 : pCS->nMaxLenLinearCTIsotopic = 0;
519 : 161 : pCS->nLenLinearCTIsotopic = 0;
520 : 161 : pCS->nMaxLenLinearCTIsotopicTautomer = 0;
521 : 161 : pCS->nLenLinearCTIsotopicTautomer = 0;
522 : :
523 : : /* set canon numbering lengths to zero */
524 : 161 : pCS->nLenCanonOrd = 0;
525 : 161 : pCS->nLenCanonOrdIsotopic = 0;
526 : 161 : pCS->nLenCanonOrdIsotopicTaut = 0;
527 : 161 : pCS->nLenCanonOrdStereo = 0;
528 : 161 : pCS->nLenCanonOrdStereoTaut = 0;
529 : 161 : pCS->nLenCanonOrdIsotopicStereo = 0;
530 : 161 : pCS->nLenCanonOrdIsotopicStereoTaut = 0;
531 : 161 : pCS->nLenCanonOrdTaut = 0;
532 : :
533 : 161 : return 0;
534 : :
535 : : #undef LOCAL_FREE
536 : : }
537 : :
538 : :
539 : : /****************************************************************************/
540 : 161 : int AllocateCS( CANON_STAT *pCS,
541 : : int num_at,
542 : : int num_at_tg,
543 : : int nLenCT,
544 : : int nLenCTAtOnly,
545 : : int nLenLinearCTStereoDble,
546 : : int nLenLinearCTIsotopicStereoDble,
547 : : int nLenLinearCTStereoCarb,
548 : : int nLenLinearCTIsotopicStereoCarb,
549 : : int nLenLinearCTTautomer,
550 : : int nLenLinearCTIsotopicTautomer,
551 : : int nLenIsotopic,
552 : : INCHI_MODE nMode,
553 : : BCN *pBCN )
554 : : {
555 : : #define pCS_CALLOC( PTR,TYPE,LEN) (pCS->PTR=(TYPE*)inchi_calloc( (size_t)(LEN),sizeof(*pCS->PTR)))
556 : :
557 : 161 : int num_err = 0;
558 : 161 : int num_t_groups = num_at_tg - num_at;
559 : :
560 : 161 : pCS->nMode = nMode;
561 : :
562 : : /* connection table */
563 [ + - + - ]: 161 : if (( nMode & CMODE_CT ) && nLenCT > 0)
564 : : {
565 : 161 : num_err += !pCS_CALLOC( LinearCT, AT_NUMB, nLenCT );
566 : 161 : pCS->nMaxLenLinearCT =
567 : 161 : pCS->nLenLinearCT = nLenCT;
568 : 161 : pCS->nLenLinearCTAtOnly = nLenCTAtOnly;
569 : 161 : num_err += !pCS_CALLOC( nCanonOrd, AT_RANK, num_at_tg );
570 : 161 : num_err += !pCS_CALLOC( nSymmRank, AT_RANK, num_at_tg );
571 [ + - ]: 161 : if (pBCN)
572 : : {
573 : 161 : num_err += !pCS_CALLOC( nNum_H, S_CHAR, num_at );
574 : 161 : num_err += !pCS_CALLOC( nNum_H_fixed, S_CHAR, num_at );
575 : 161 : num_err += !pCS_CALLOC( nExchgIsoH, S_CHAR, num_at );
576 : : }
577 : : }
578 : :
579 : : /* isotopic */
580 [ - + - - ]: 161 : if (( nMode & CMODE_ISO ) && nLenIsotopic > 0)
581 : : {
582 : 0 : num_err += !pCS_CALLOC( LinearCTIsotopic, AT_ISOTOPIC, nLenIsotopic );
583 : 0 : pCS->nMaxLenLinearCTIsotopic =
584 : 0 : pCS->nLenLinearCTIsotopic = nLenIsotopic;
585 : : }
586 : :
587 : : /* isotopic tautomeric */
588 [ - + - - ]: 161 : if (( nMode & CMODE_ISO ) && CANON_MODE_TAUT == ( nMode & CANON_MODE_TAUT ))
589 : : {
590 [ # # ]: 0 : if (nLenLinearCTIsotopicTautomer > 0)
591 : : {
592 : 0 : num_err += !pCS_CALLOC( LinearCTIsotopicTautomer, AT_ISO_TGROUP, nLenLinearCTIsotopicTautomer );
593 : 0 : pCS->nMaxLenLinearCTIsotopicTautomer =
594 : 0 : pCS->nLenLinearCTIsotopicTautomer = nLenLinearCTIsotopicTautomer;
595 : : }
596 [ # # ]: 0 : if (num_t_groups > 0)
597 : : {
598 : 0 : num_err += !pCS_CALLOC( nCanonOrdIsotopicTaut, AT_RANK, num_t_groups );
599 : 0 : num_err += !pCS_CALLOC( nSymmRankIsotopicTaut, AT_RANK, num_t_groups );
600 : : }
601 : : }
602 : : /* isotopic atoms & t-groups */
603 [ + - ]: 161 : if (( nMode & CMODE_ISO ) /*&& nLenIsotopic > 0*/ ||
604 [ - + - - : 161 : (( nMode & CMODE_ISO ) && CANON_MODE_TAUT == ( nMode & CANON_MODE_TAUT ) && nLenLinearCTIsotopicTautomer > 0
- - ]
605 : : )) /* djb-rwth: addressing LLVM warning */
606 : : {
607 : 0 : num_err += !pCS_CALLOC( nSymmRankIsotopic, AT_RANK, num_at_tg );
608 : 0 : num_err += !pCS_CALLOC( nCanonOrdIsotopic, AT_RANK, num_at_tg );
609 : : }
610 : : /* stereo */
611 [ + + - + ]: 161 : if (( nMode & CMODE_STEREO ) && nLenLinearCTStereoDble > 0)
612 : : {
613 : 0 : num_err += !pCS_CALLOC( LinearCTStereoDble, AT_STEREO_DBLE, nLenLinearCTStereoDble );
614 : 0 : num_err += !pCS_CALLOC( LinearCTStereoDbleInv, AT_STEREO_DBLE, nLenLinearCTStereoDble );
615 : 0 : pCS->nLenLinearCTStereoDbleInv =
616 : 0 : pCS->nMaxLenLinearCTStereoDble =
617 : 0 : pCS->nLenLinearCTStereoDble = nLenLinearCTStereoDble;
618 : : }
619 [ + + + + ]: 161 : if (( nMode & CMODE_STEREO ) && nLenLinearCTStereoCarb > 0)
620 : : {
621 : 58 : num_err += !pCS_CALLOC( LinearCTStereoCarb, AT_STEREO_CARB, nLenLinearCTStereoCarb );
622 : 58 : num_err += !pCS_CALLOC( LinearCTStereoCarbInv, AT_STEREO_CARB, nLenLinearCTStereoCarb );
623 : 58 : pCS->nLenLinearCTStereoCarbInv =
624 : 58 : pCS->nMaxLenLinearCTStereoCarb =
625 : 58 : pCS->nLenLinearCTStereoCarb = nLenLinearCTStereoCarb;
626 : : }
627 [ + + + - : 161 : if (( nMode & CMODE_STEREO ) && ( nLenLinearCTStereoDble > 0 || nLenLinearCTStereoCarb > 0 ))
+ + ]
628 : : {
629 : 58 : num_err += !pCS_CALLOC( nCanonOrdStereo, AT_RANK, num_at_tg );
630 : 58 : num_err += !pCS_CALLOC( nCanonOrdStereoInv, AT_RANK, num_at_tg );
631 [ + + + - : 58 : if (( nMode & CMODE_TAUT ) && nLenLinearCTTautomer > 0 && num_t_groups > 0)
+ - ]
632 : : {
633 : 2 : num_err += !pCS_CALLOC( nCanonOrdStereoTaut, AT_RANK, num_t_groups );
634 : : }
635 : : }
636 : : /* isotopic stereo */
637 [ - + - - ]: 161 : if (( nMode & CMODE_ISO_STEREO ) && nLenLinearCTIsotopicStereoDble > 0)
638 : : {
639 : 0 : num_err += !pCS_CALLOC( LinearCTIsotopicStereoDble, AT_STEREO_DBLE, nLenLinearCTIsotopicStereoDble );
640 : 0 : num_err += !pCS_CALLOC( LinearCTIsotopicStereoDbleInv, AT_STEREO_DBLE, nLenLinearCTIsotopicStereoDble );
641 : 0 : pCS->nLenLinearCTIsotopicStereoDbleInv =
642 : 0 : pCS->nMaxLenLinearCTIsotopicStereoDble =
643 : 0 : pCS->nLenLinearCTIsotopicStereoDble = nLenLinearCTIsotopicStereoDble;
644 : : }
645 [ - + - - ]: 161 : if (( nMode & CMODE_ISO_STEREO ) && nLenLinearCTIsotopicStereoCarb > 0)
646 : : {
647 : 0 : num_err += !pCS_CALLOC( LinearCTIsotopicStereoCarb, AT_STEREO_CARB, nLenLinearCTIsotopicStereoCarb );
648 : 0 : num_err += !pCS_CALLOC( LinearCTIsotopicStereoCarbInv, AT_STEREO_CARB, nLenLinearCTIsotopicStereoCarb );
649 : 0 : pCS->nLenLinearCTIsotopicStereoCarbInv =
650 : 0 : pCS->nMaxLenLinearCTIsotopicStereoCarb =
651 : 0 : pCS->nLenLinearCTIsotopicStereoCarb = nLenLinearCTIsotopicStereoCarb;
652 : : }
653 [ - + - - : 161 : if (( nMode & CMODE_ISO_STEREO ) && ( nLenLinearCTIsotopicStereoDble > 0 || nLenLinearCTIsotopicStereoCarb > 0 ))
- - ]
654 : : {
655 : 0 : num_err += !pCS_CALLOC( nCanonOrdIsotopicStereo, AT_RANK, num_at_tg );
656 : 0 : num_err += !pCS_CALLOC( nCanonOrdIsotopicStereoInv, AT_RANK, num_at_tg );
657 [ # # # # : 0 : if (( nMode & CMODE_TAUT ) && nLenLinearCTTautomer > 0 && num_t_groups > 0)
# # ]
658 : : {
659 : 0 : num_err += !pCS_CALLOC( nCanonOrdIsotopicStereoTaut, AT_RANK, num_t_groups );
660 : : }
661 : : }
662 [ + + + - : 161 : if ((( nMode & CMODE_STEREO ) && ( nLenLinearCTStereoDble > 0 || nLenLinearCTStereoCarb > 0 )) ||
+ + ]
663 [ - + - - : 103 : (( nMode & CMODE_ISO_STEREO ) && ( nLenLinearCTIsotopicStereoDble > 0 || nLenLinearCTIsotopicStereoCarb > 0 ))) /* djb-rwth: addressing LLVM warning */
- - ]
664 : : {
665 : 58 : num_err += !pCS_CALLOC( bRankUsedForStereo, S_CHAR, num_at );
666 : 58 : num_err += !pCS_CALLOC( bAtomUsedForStereo, S_CHAR, num_at );
667 : : }
668 : : /* tautomeric part of the connection table */
669 [ + - + + : 161 : if (( nMode & CMODE_CT ) && ( nMode & CMODE_TAUT ) && nLenLinearCTTautomer > 0)
+ - ]
670 : : {
671 : 14 : num_err += !pCS_CALLOC( LinearCTTautomer, AT_TAUTOMER, nLenLinearCTTautomer );
672 : 14 : pCS->nMaxLenLinearCTTautomer =
673 : 14 : pCS->nLenLinearCTTautomer = nLenLinearCTTautomer;
674 [ + + ]: 14 : if (num_t_groups > 0)
675 : : {
676 : 7 : num_err += !pCS_CALLOC( nCanonOrdTaut, AT_RANK, num_t_groups );
677 : 7 : num_err += !pCS_CALLOC( nSymmRankTaut, AT_RANK, num_t_groups );
678 : : }
679 : : }
680 : :
681 [ + - ]: 161 : if (nMode & CMODE_CT)
682 : : {
683 : 161 : num_err += !pCS_CALLOC( LinearCT2, AT_NUMB, nLenCT );
684 : : }
685 : :
686 : : /* for establishing constitutional equivalence */
687 : 161 : num_err += !pCS_CALLOC( nPrevAtomNumber, AT_RANK, num_at_tg );
688 : :
689 : : /* set canon numbering lengths to zero */
690 : 161 : pCS->nLenCanonOrd = 0;
691 : 161 : pCS->nLenCanonOrdIsotopic = 0;
692 : 161 : pCS->nLenCanonOrdIsotopicTaut = 0;
693 : 161 : pCS->nLenCanonOrdStereo = 0;
694 : 161 : pCS->nLenCanonOrdStereoTaut = 0;
695 : 161 : pCS->nLenCanonOrdIsotopicStereo = 0;
696 : 161 : pCS->nLenCanonOrdIsotopicStereoTaut = 0;
697 : 161 : pCS->nLenCanonOrdTaut = 0;
698 : :
699 : :
700 [ - + ]: 161 : if (num_err)
701 : : {
702 : 0 : DeAllocateCS( pCS );
703 : 0 : return CT_OUT_OF_RAM; /* <BRKPT> */
704 : : }
705 : 161 : return 0;
706 : :
707 : : #undef pCS_CALLOC
708 : : }
709 : :
710 : :
711 : : /****************************************************************************/
712 : :
713 : :
714 : : #define COMPARE_WITH_CT(CT, CTLEN, VALUE, CONDITION) \
715 : : if ( CONDITION ) { \
716 : : if ( (VALUE) CT_GREATER_THAN (CT)[CTLEN] ) \
717 : : return 1; /* not a minimal CT */ \
718 : : (CONDITION) = (VALUE) == (CT)[CTLEN]; \
719 : : } \
720 : : (CT)[CTLEN] = VALUE; \
721 : : (CTLEN)++
722 : :
723 : : #define COMPARE_WITH_CTVAL(CTVAL, VALUE, CONDITION) \
724 : : if ( CONDITION ) { \
725 : : if ( (VALUE) CT_GREATER_THAN (CTVAL) ) \
726 : : return 1; /* not a minimal CT */ \
727 : : (CONDITION) = (VALUE) == (CTVAL); \
728 : : } \
729 : : (CTVAL) = VALUE
730 : :
731 : : #define COMPARE_WITH_CT2(CT, CTLEN, VALUE, CONDITION, OPER) \
732 : : if ( CONDITION ) { \
733 : : if ( (VALUE) CT_GREATER_THAN (CT)[CTLEN] ) { \
734 : : (OPER); \
735 : : return 1; /* not a minimal CT */ \
736 : : } \
737 : : (CONDITION) = (VALUE) == (CT)[CTLEN]; \
738 : : } \
739 : : (CT)[CTLEN] = VALUE; \
740 : : (CTLEN)++
741 : :
742 : :
743 : :
744 : : /****************************************************************************/
745 : 0 : int FillIsotopicAtLinearCT( int num_atoms,
746 : : sp_ATOM* at,
747 : : const AT_RANK *nAtomNumber,
748 : : AT_ISOTOPIC *LinearCTIsotopic,
749 : : int nMaxLenLinearCTIsotopic,
750 : : int *pnLenLinearCTIsotopic )
751 : : {
752 : : /* at[i].init_rank = initial ranks before canonizing */
753 : : /* nRank[i] = new ordering number for atoms: nRank=1,2,.. */
754 : : /* nAtomNumber[r] = orig. atom number= 0,1,... for r = nRank-1 */
755 : : /* nRank[nAtomNumber[r]] = r; r = 0,1,... */
756 : : /* nAtomNumber[nRank[i]-1] = i; */
757 : :
758 : : int i, k, rank;
759 : 0 : int nLinearCTIsotopicLen = 0;
760 : :
761 : : /* the following parts of the "name" should be compared */
762 : : /* after the connection table comparison is done */
763 : : /* to avoid wrong difference sign. So, these parts */
764 : : /* go to a separate buffers. */
765 [ # # # # ]: 0 : if (LinearCTIsotopic && nMaxLenLinearCTIsotopic > 0)
766 : : {
767 : 0 : memset( LinearCTIsotopic, 0, nMaxLenLinearCTIsotopic * sizeof( LinearCTIsotopic[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
768 : : }
769 : : else
770 : : {
771 : 0 : return 0;
772 : : }
773 : :
774 : : /* rank = nRank[nAtomNumber[rank-1]] -- proposed atoms canon. numbers */
775 [ # # ]: 0 : for (rank = 1; rank <= num_atoms; rank++)
776 : : {
777 : :
778 : 0 : i = (int) nAtomNumber[rank - 1]; /* current atom */
779 : :
780 : : /****************************************************
781 : : add isotopic atom info to LinearCTIsotopic
782 : : *****************************************************/
783 : :
784 : : /* if the atom itself is not isotopic then add it only if */
785 : : /* the atom is not an endpoint AND has attached T or D or 1H. */
786 [ # # # # : 0 : k = ( !at[i].endpoint && !( at[i].cFlags & AT_FLAG_ISO_H_POINT ) && ( at[i].num_iso_H[0] || at[i].num_iso_H[1] || at[i].num_iso_H[2] ) );
# # # # #
# ]
787 [ # # # # ]: 0 : if (at[i].iso_atw_diff || k)
788 : : {
789 [ # # ]: 0 : if (CHECK_OVERFLOW( nLinearCTIsotopicLen, nMaxLenLinearCTIsotopic ))
790 : : {
791 : 0 : return CT_OVERFLOW; /* <BRKPT> */
792 : : }
793 : 0 : LinearCTIsotopic[nLinearCTIsotopicLen].at_num = (AT_RANK) rank;
794 : 0 : LinearCTIsotopic[nLinearCTIsotopicLen].iso_atw_diff = at[i].iso_atw_diff;
795 [ # # ]: 0 : LinearCTIsotopic[nLinearCTIsotopicLen].num_1H = (NUM_H) ( k ? at[i].num_iso_H[0] : 0 );
796 [ # # ]: 0 : LinearCTIsotopic[nLinearCTIsotopicLen].num_D = (NUM_H) ( k ? at[i].num_iso_H[1] : 0 );
797 [ # # ]: 0 : LinearCTIsotopic[nLinearCTIsotopicLen].num_T = (NUM_H) ( k ? at[i].num_iso_H[2] : 0 );
798 : 0 : nLinearCTIsotopicLen++;
799 : : }
800 : : } /* end of cycle over all atoms. */
801 : :
802 [ # # ]: 0 : if (LinearCTIsotopic)
803 : : {
804 [ # # ]: 0 : if (*pnLenLinearCTIsotopic)
805 : : {
806 [ # # ]: 0 : if (*pnLenLinearCTIsotopic != nLinearCTIsotopicLen)
807 : : {
808 : 0 : return CT_LEN_MISMATCH; /* <BRKPT> */
809 : : }
810 : : }
811 : : else
812 : : {
813 : 0 : *pnLenLinearCTIsotopic = nLinearCTIsotopicLen;
814 : : }
815 : : }
816 : :
817 : : /* Return value: >0 => OK */
818 : 0 : return nLinearCTIsotopicLen;
819 : : }
820 : :
821 : :
822 : : /****************************************************************************/
823 : 7 : int FillTautLinearCT2( CANON_GLOBALS *pCG,
824 : : int num_atoms,
825 : : int num_at_tg,
826 : : int bIsoTaut,
827 : : const AT_RANK *nRank,
828 : : const AT_RANK *nAtomNumber,
829 : : const AT_RANK *nSymmRank,
830 : : const AT_RANK *nRankIso,
831 : : const AT_RANK *nAtomNumberIso,
832 : : const AT_RANK *nSymmRankIso,
833 : : AT_TAUTOMER *LinearCTTautomer,
834 : : int nMaxLenLinearCTTautomer,
835 : : int *pnLenLinearCTTautomer,
836 : : AT_ISO_TGROUP *LinearCTIsotopicTautomer,
837 : : int nMaxLenLinearCTIsotopicTautomer,
838 : : int *pnLenLinearCTIsotopicTautomer,
839 : : T_GROUP_INFO *t_group_info )
840 : : {
841 : : /* nRank[i] = Canonical numbers of atoms,.. */
842 : : /* nAtomNumber[r] = orig. atom number= 0,1,... for r = nRank-1 */
843 : : /* nRank[nAtomNumber[r]] = r; r = 0,1,... */
844 : : /* nAtomNumber[nRank[i]-1] = i; */
845 : :
846 : : T_GROUP *t_group;
847 : :
848 : 7 : int i, j, len = 0, g, offset, max_len = 0, len_iso = 0; /* djb-rwth: removing redundant variable */
849 : : static const int max_num_num = sizeof( t_group->num ) / sizeof( t_group->num[0] );
850 : : static const int max_num_iso = sizeof( LinearCTIsotopicTautomer->num ) / sizeof( LinearCTIsotopicTautomer->num[0] ) + T_NUM_NO_ISOTOPIC;
851 : :
852 : : /****************************************************************************
853 : :
854 : : Tautomeric groups 07-22-2002, modified 12-2003
855 : :
856 : : ****************************************************************************/
857 : :
858 [ + - + - : 7 : if (num_at_tg > num_atoms && t_group_info && t_group_info->num_t_groups)
+ - ]
859 : : {
860 : 7 : int num_t_groups = t_group_info->num_t_groups;
861 : 7 : AT_NUMB *tGroupNumber = t_group_info->tGroupNumber;
862 : 7 : AT_NUMB *tSymmRank = tGroupNumber + TGSO_SYMM_RANK*num_t_groups; /* equivalence */
863 : 7 : AT_NUMB *tiSymmRank = tGroupNumber + TGSO_SYMM_IRANK*(long long)num_t_groups; /* djb-rwth: cast operator added */
864 : 7 : AT_NUMB *tiGroupNumber = tGroupNumber + TGSO_SYMM_IORDER*(long long)num_t_groups; /* djb-rwth: cast operator added */
865 : 7 : AT_RANK nOffset = (AT_RANK) num_atoms;
866 : :
867 : : /* Fill Canonical ranks and Symmetry Ranks */
868 : : /* memcpy( tPrevGroupNumber, tGroupNumber, num_t_groups*sizeof(tPrevGroupNumber[0])); */
869 [ + + ]: 19 : for (i = num_atoms, j = 0; i < num_at_tg; i++, j++)
870 : : {
871 : : /* tPrevGroupNumber[j] = */
872 : 12 : tGroupNumber[j] = nAtomNumber[i] - nOffset;
873 : 12 : tSymmRank[j] = nSymmRank[i] - nOffset;
874 [ - + ]: 12 : if (bIsoTaut)
875 : : {
876 : 0 : tiGroupNumber[j] = nAtomNumberIso[i] - nOffset;
877 : 0 : tiSymmRank[j] = nSymmRankIso[i] - nOffset;
878 : : }
879 : : }
880 : :
881 : : /* Sort enpoints within each tautomeric group according to the canonical ranks */
882 : 7 : pCG->m_pn_RankForSort = nRank;
883 [ + + ]: 19 : for (i = 0; i < num_t_groups; i++)
884 : : {
885 : 12 : inchi_qsort( pCG,
886 : 12 : t_group_info->nEndpointAtomNumber + (int) t_group_info->t_group[i].nFirstEndpointAtNoPos,
887 : 12 : t_group_info->t_group[i].nNumEndpoints,
888 : : sizeof( t_group_info->nEndpointAtomNumber[0] ),
889 : : CompRank );
890 : : }
891 : : /* fill out LinearCTTautomer */
892 [ + - ]: 7 : if (nMaxLenLinearCTTautomer)
893 : : {
894 : 7 : max_len = T_GROUP_HDR_LEN * t_group_info->num_t_groups + t_group_info->nNumEndpoints + 1;
895 [ - + ]: 7 : if (max_len > nMaxLenLinearCTTautomer)
896 : : {
897 : 0 : return CT_OVERFLOW; /* <BRKPT> */
898 : : }
899 : : }
900 : :
901 : : /****************************************************************
902 : : * tautomer group format (#: is an offset)
903 : : ****************************************************************
904 : : * HEADER (T_GROUP_HDR_LEN=3+3iso)
905 : : * 0: N = number of endpoints ( t_group->nNumEndpoints )
906 : : * 1: number of mobile groups ( t_group->num[0] )
907 : : * 2: number of neg. charges ( t_group->num[1] ) {note: T_NUM_NO_ISOTOPIC=2}
908 : : * ENDPOINT RANKS
909 : : * 3..N+2: sorted tautomer group endpoint ranks; the sorting order is in
910 : : * t_group_info->nEndpointAtomNumber[t_group->nFirstEndpointAtNoPos+j], j=0..N-1
911 : : *
912 : : * End mark : N==0
913 : : ****************************************************************/
914 : : /* num_num = t_group_info->bIgnoreIsotopic? T_NUM_NO_ISOTOPIC : max_num_num; */
915 : : /* num_num = max_num_num; always include isotopic info; ignore it at the CT comparison step. */ /* djb-rwth: removing redundant code */
916 [ + + ]: 19 : for (i = 0; i < t_group_info->num_t_groups; i++)
917 : : {
918 : 12 : g = tGroupNumber[i]; /* ith tautomeric group number in canonical order */
919 : 12 : t_group = t_group_info->t_group + g;
920 : : /*******************************************************
921 : : * Tautomer non-isotopic part: LinearCTTautomer
922 : : *******************************************************/
923 : : /* check length */
924 [ - + ]: 12 : if (CHECK_OVERFLOW( len + T_GROUP_HDR_LEN + t_group->nNumEndpoints, max_len ))
925 : : {
926 : 0 : return CT_OVERFLOW; /* <BRKPT> */
927 : : }
928 : :
929 : : /* t_group header: number of endpoints */
930 : 12 : LinearCTTautomer[len++] = t_group->nNumEndpoints;
931 : : /* t_group header: */
932 : : /* (a) number of mobile groups in the t_group (number of H + number of (-) ) and */
933 : : /* (b) number of mobile negative charges (-) in the t_group */
934 [ + + ]: 36 : for (j = 0; j < T_NUM_NO_ISOTOPIC; j++)
935 : : {
936 : 24 : LinearCTTautomer[len++] = t_group->num[j];
937 : : }
938 : : /* t_group endpoint ranks link the group to the tautomeric endpoint atoms in the structure */
939 : : /* according to their ranks */
940 [ + + ]: 40 : for (j = 0, offset = t_group->nFirstEndpointAtNoPos; j < t_group->nNumEndpoints; j++)
941 : : {
942 : 28 : LinearCTTautomer[len++] = nRank[(int) t_group_info->nEndpointAtomNumber[offset + j]];
943 : : }
944 : : }
945 [ + - ]: 7 : if (nMaxLenLinearCTTautomer)
946 : : {
947 : 7 : LinearCTTautomer[len++] = 0; /* or CT_INITVALUE ??? */
948 [ - + ]: 7 : if (len != max_len)
949 : : {
950 : 0 : len = -len; /* program error */ /* <BRKPT> */
951 : : }
952 [ + - - + ]: 7 : else if (*pnLenLinearCTTautomer && *pnLenLinearCTTautomer != len)
953 : : {
954 : 0 : return CT_LEN_MISMATCH;
955 : : }
956 : : else
957 : : {
958 : 7 : *pnLenLinearCTTautomer = len;
959 : : }
960 : : }
961 : : else
962 : : {
963 : 0 : *pnLenLinearCTTautomer = 0;
964 : : }
965 : :
966 : : /******************************************************************
967 : : * Isotopic Tautomeric mobile groups part: LinearCTIsotopicTautomer
968 : : ******************************************************************/
969 [ - + - - ]: 7 : if (nMaxLenLinearCTIsotopicTautomer && !t_group_info->nNumIsotopicEndpoints)
970 : : {
971 [ # # ]: 0 : for (i = 0; i < t_group_info->num_t_groups; i++)
972 : : {
973 : 0 : g = tiGroupNumber[i]; /* ith tautomeric group number in canonical order */
974 : 0 : t_group = t_group_info->t_group + g;
975 : : /* find if mobile hydrogens are isotopic */
976 [ # # ]: 0 : if (!t_group->iWeight)
977 : : {
978 : 0 : continue; /* no isotopic H */
979 : : }
980 [ # # ]: 0 : if (CHECK_OVERFLOW( len_iso, nMaxLenLinearCTIsotopicTautomer ))
981 : : {
982 : 0 : return CT_OVERFLOW; /* <BRKPT> */
983 : : }
984 [ # # # # ]: 0 : for (j = T_NUM_NO_ISOTOPIC; j < max_num_num && j < max_num_iso; j++)
985 : : {
986 : : /* num_T, num_D, num_1H */
987 : 0 : LinearCTIsotopicTautomer[len_iso].num[j - T_NUM_NO_ISOTOPIC] = t_group->num[j];
988 : : }
989 : : /* link to tautomer group LinearCTTautomer[i]: */
990 : 0 : LinearCTIsotopicTautomer[len_iso++].tgroup_num = (AT_NUMB) ( i + 1 ); /* t_group isotopic rank */
991 : : }
992 : : }
993 [ - + ]: 7 : if (nMaxLenLinearCTIsotopicTautomer)
994 : : {
995 [ # # # # ]: 0 : if (*pnLenLinearCTIsotopicTautomer && *pnLenLinearCTIsotopicTautomer != len_iso)
996 : : {
997 : 0 : return CT_LEN_MISMATCH;
998 : : }
999 : 0 : *pnLenLinearCTIsotopicTautomer = len_iso;
1000 : : }
1001 : : else
1002 : : {
1003 : 7 : *pnLenLinearCTIsotopicTautomer = 0;
1004 : : }
1005 : : }
1006 : :
1007 : 7 : return len;
1008 : : }
1009 : :
1010 : :
1011 : : /****************************************************************************
1012 : : *
1013 : : * Update a linear connection table out of final ranks
1014 : : */
1015 : 161 : int UpdateFullLinearCT( int num_atoms,
1016 : : int num_at_tg,
1017 : : sp_ATOM* at,
1018 : : AT_RANK *nRank,
1019 : : AT_RANK *nAtomNumber,
1020 : : CANON_STAT* pCS,
1021 : : CANON_GLOBALS *pCG,
1022 : : int bFirstTime )
1023 : : {
1024 : : /* at[i].init_rank = initial ranks before canonizing */
1025 : : /* nRank[i] = new ordering number for atoms: nRank=1,2,.. */
1026 : : /* nAtomNumber[r] = orig. atom number= 0,1,... for r = nRank-1 */
1027 : : /* nRank[nAtomNumber[r]] = r; r = 0,1,... */
1028 : : /* nAtomNumber[nRank[i]-1] = i; */
1029 : :
1030 : : AT_NUMB nNeighborNumber[MAXVAL];
1031 : : int i, j, k, num_neigh, rank, bCompare; /*, nRetVal; */
1032 : :
1033 : 161 : T_GROUP_INFO *t_group_info = NULL;
1034 : 161 : T_GROUP *t_group = NULL;
1035 : 161 : AT_NUMB *nEndpointAtomNumber = NULL;
1036 : :
1037 : 161 : int nCTLen = 0, nCTLenAtOnly = 0;
1038 : :
1039 : :
1040 : : AT_NUMB r_neigh;
1041 : 161 : AT_NUMB *LinearCT = pCS->LinearCT;
1042 : :
1043 : : /* the following parts of the "name" should be compared */
1044 : : /* after the connection table comparison is done */
1045 : : /* to avoid wrong difference sign. So, these parts */
1046 : : /* go to a separate buffers. */
1047 : : /* -- currently not used at all at all -- */
1048 : :
1049 : : #if CT_ATOMID != CT_ATOMID_DONTINCLUDE
1050 : : AT_NUMB r0_at_type;
1051 : : #endif
1052 : :
1053 : 161 : num_neigh = 0; /* Moved from above 2024-09-01 DT; djb-rwth: num_neigh initialisation added */
1054 : :
1055 : 161 : bCompare = bFirstTime ? 0 : 1;
1056 : :
1057 [ + + ]: 161 : if (num_at_tg > num_atoms)
1058 : : {
1059 : 7 : t_group_info = pCS->t_group_info;
1060 : 7 : t_group = t_group_info->t_group;
1061 : : }
1062 : : else
1063 : : {
1064 : 154 : t_group_info = NULL;
1065 : 154 : t_group = NULL;
1066 : : }
1067 : :
1068 : : /**********************************************************************/
1069 : : /* */
1070 : : /* CYCLE 1: FILL OUT CONNECTION TABLE(S) FOR ALL ATOMS */
1071 : : /* ** NOT INCLUDING ISOTOPIC ATOMS AND 1H, 2H(D), 3H(T) ** */
1072 : : /* */
1073 : : /* rank = nRank[nAtomNumber[rank-1]] -- proposed atoms canon. numbers */
1074 : : /**********************************************************************/
1075 [ + + ]: 971 : for (rank = 1; rank <= num_atoms; rank++)
1076 : : {
1077 : 810 : i = (int) nAtomNumber[rank - 1]; /* current atom */
1078 : :
1079 : : #if ( CT_ATOMID == CT_ATOMID_IS_CURRANK )
1080 : 810 : r0_at_type = (AT_NUMB) rank; /* current Rank */
1081 : : #else
1082 : : #if ( CT_ATOMID == CT_ATOMID_IS_INITRANK )
1083 : : r0_at_type = (AT_NUMB) at[i].init_rank; /* chemical + neighborhood ID */
1084 : : #else
1085 : : #if ( CT_ATOMID == CT_ATOMID_DONTINCLUDE )
1086 : : #else
1087 : : #error Undefined or wrong definition of CT_ATOMID
1088 : : #endif
1089 : : #endif
1090 : : #endif
1091 : :
1092 : : /* add atom to the CT */
1093 : : #if ( CT_ATOMID != CT_ATOMID_DONTINCLUDE )
1094 [ - + ]: 810 : if (CHECK_OVERFLOW( nCTLen, pCS->nMaxLenLinearCT ))
1095 : : {
1096 : 0 : return CT_OVERFLOW; /* <BRKPT> */
1097 : : }
1098 [ + - - + ]: 810 : COMPARE_WITH_CT( LinearCT, nCTLen, r0_at_type, bCompare );
1099 : : #endif
1100 : :
1101 : : /*******************************************************
1102 : : add neighbors and (if required) bonds to CT
1103 : : ********************************************************/
1104 : :
1105 : : /* sort neighbors */
1106 : 810 : num_neigh = at[i].valence;
1107 [ + + ]: 2160 : for (k = 0; k < num_neigh; k++)
1108 : : {
1109 : 1350 : nNeighborNumber[k] = (AT_NUMB) k;
1110 : : }
1111 : 810 : pCG->m_pNeighborsForSort = at[i].neighbor;
1112 : 810 : pCG->m_pn_RankForSort = nRank;
1113 : 810 : insertions_sort( pCG, nNeighborNumber, (size_t) num_neigh, sizeof( nNeighborNumber[0] ), CompNeighborsAT_NUMBER );
1114 : :
1115 [ + + ]: 2160 : for (k = 0; k < num_neigh; k++)
1116 : : {
1117 : : /* rank = (new current atom Rank) */
1118 [ + + ]: 1350 : if ((int) ( r_neigh = (AT_NUMB) nRank[(int) at[i].neighbor[(int) nNeighborNumber[k]]] )
1119 : : CT_NEIGH_SMALLER_THAN rank)
1120 : : {
1121 [ - + ]: 675 : if (CHECK_OVERFLOW( nCTLen, pCS->nMaxLenLinearCT ))
1122 : : {
1123 : 0 : return CT_OVERFLOW; /* <BRKPT> */
1124 : : }
1125 [ + - - + ]: 675 : COMPARE_WITH_CT( LinearCT, nCTLen, r_neigh, bCompare );
1126 : : }
1127 : : }
1128 : :
1129 : : /* add CT row delimiter */
1130 : : } /* end of cycle over all atoms. */
1131 : :
1132 : 161 : nCTLenAtOnly = nCTLen;
1133 : :
1134 : : /**************************************************************
1135 : :
1136 : : Tautomeric groups 07-22-2002
1137 : :
1138 : : ***************************************************************/
1139 : :
1140 [ + + ]: 173 : for (rank = num_atoms + 1; rank <= num_at_tg; rank++)
1141 : : {
1142 : 12 : j = (int) nAtomNumber[rank - 1]; /* current "atom" */
1143 : 12 : i = j - num_atoms; /* current t-group */
1144 : :
1145 : : #if ( CT_ATOMID == CT_ATOMID_IS_CURRANK )
1146 : 12 : r0_at_type = (AT_NUMB) rank; /* current Rank */
1147 : : #else
1148 : : #if ( CT_ATOMID == CT_ATOMID_IS_INITRANK )
1149 : : r0_at_type = (AT_NUMB) rank; /* current Rank or (AT_NUMB)at[i].init_rank; ==> chemical + neighborhood ID */
1150 : : #else
1151 : : #if ( CT_ATOMID == CT_ATOMID_DONTINCLUDE )
1152 : : #else
1153 : : #error Undefined or wrong definition of CT_ATOMID
1154 : : #endif
1155 : : #endif
1156 : : #endif
1157 : :
1158 : : /* add atom to the CT */
1159 : : #if ( CT_ATOMID != CT_ATOMID_DONTINCLUDE )
1160 [ - + ]: 12 : if (CHECK_OVERFLOW( nCTLen, pCS->nMaxLenLinearCT ))
1161 : 0 : return CT_OVERFLOW; /* <BRKPT> */
1162 [ + - - + ]: 12 : COMPARE_WITH_CT( LinearCT, nCTLen, r0_at_type, bCompare );
1163 : : #endif
1164 : :
1165 : : /*******************************************************
1166 : : add neighbors and (if required) bonds to CT
1167 : : ********************************************************/
1168 : :
1169 : : /* sort endpoints */
1170 [ + - ]: 12 : if (t_group_info)
1171 : 12 : nEndpointAtomNumber = t_group_info->nEndpointAtomNumber + (int) t_group[i].nFirstEndpointAtNoPos; /* djb-rwth: fixing a NULL pointer dereference */
1172 : 12 : pCG->m_pn_RankForSort = nRank;
1173 [ + - ]: 12 : if (t_group + i) /* djb-rwth: ignoring GCC warning */
1174 : 12 : num_neigh = (int)t_group[i].nNumEndpoints;
1175 : 12 : insertions_sort( pCG, nEndpointAtomNumber, (size_t) num_neigh, sizeof( nEndpointAtomNumber[0] ), CompRank );
1176 : :
1177 [ + + ]: 40 : for (k = 0; k < num_neigh; k++)
1178 : : {
1179 : : /* rank = (new current atom Rank) */
1180 [ + - ]: 28 : if (nEndpointAtomNumber + k) /* djb-rwth: fixing a NULL pointer dereference; ignoring GCC warning */
1181 : : {
1182 [ + - ]: 28 : if ((int)(r_neigh = (AT_NUMB)nRank[(int)nEndpointAtomNumber[k]]) CT_NEIGH_SMALLER_THAN rank)
1183 : : {
1184 [ - + ]: 28 : if (CHECK_OVERFLOW(nCTLen, pCS->nMaxLenLinearCT))
1185 : : {
1186 : 0 : return CT_OVERFLOW; /* <BRKPT> */
1187 : : }
1188 [ + - - + ]: 28 : COMPARE_WITH_CT(LinearCT, nCTLen, r_neigh, bCompare);
1189 : : }
1190 : : }
1191 : : }
1192 : : } /* end of cycle over all tautomeric groups. */
1193 : :
1194 : : /* compare bonds types */
1195 : : /* compare elements */
1196 : :
1197 [ + - ]: 161 : if (LinearCT)
1198 : : {
1199 : :
1200 [ + - ]: 161 : if (pCS->nLenLinearCT)
1201 : : {
1202 [ - + ]: 161 : if (pCS->nLenLinearCT != nCTLen)
1203 : : {
1204 : 0 : return CT_LEN_MISMATCH; /* <BRKPT> */
1205 : : }
1206 : : }
1207 : : else
1208 : : {
1209 : 0 : pCS->nLenLinearCT = nCTLen;
1210 : : }
1211 : :
1212 [ + - ]: 161 : if (pCS->nLenLinearCT)
1213 : : {
1214 [ - + ]: 161 : if (pCS->nLenLinearCTAtOnly != nCTLenAtOnly)
1215 : : {
1216 : 0 : return CT_LEN_MISMATCH; /* <BRKPT> */
1217 : : }
1218 : : }
1219 : : else
1220 : : {
1221 : 0 : pCS->nLenLinearCTAtOnly = nCTLenAtOnly;
1222 : : }
1223 : : }
1224 : :
1225 : : /* Return: 0=> identical CT; -1=> new CT is smaller than the previous one */
1226 : 161 : return ( bCompare - 1 );
1227 : : }
1228 : :
1229 : :
1230 : : /****************************************************************************
1231 : : If (*bChanged & 1) then nSymmRank has been rearranged because for some r
1232 : : min{i: r=nSymmRank[nAtomNumber[i]]}+1 != r
1233 : : If (*bChanged & 2) then ranks nTempRank[]
1234 : : from nSymmRank[] differ from input nCurrRank[]
1235 : :
1236 : : On exit:
1237 : : nSymmRank[] have been updated if (*bChanged & 1)
1238 : : nCurrRank[] have been updated if (*bChanged & 1)
1239 : : nTempRank[] is always same as nCurrRank[]
1240 : : nAtomNumber[] have been sorted so that
1241 : : (i < j) <=> (nSymmRank[nAtomNumber[i]] <= nSymmRank[nAtomNumber[j]])
1242 : : ****************************************************************************/
1243 : 219 : int FixCanonEquivalenceInfo( CANON_GLOBALS *pCG,
1244 : : int num_at_tg,
1245 : : AT_RANK *nSymmRank,
1246 : : AT_RANK *nCurrRank,
1247 : : AT_RANK *nTempRank,
1248 : : AT_NUMB *nAtomNumber,
1249 : : int *bChanged )
1250 : : {
1251 : 219 : int nNumDiffRanks, bChangeSymmRank, bChangeCurrRank = 0;
1252 : : /* sort equivalence information */
1253 : : /*
1254 : : int i;
1255 : : for ( i = 0; i < num_at_tg; i ++ )
1256 : : {
1257 : : nAtomNumber[i] = i;
1258 : : }
1259 : : */
1260 : :
1261 : 219 : pCG->m_pn_RankForSort = nSymmRank; /* minimal class representatives: min ranks for equiv. atoms */
1262 : 219 : inchi_qsort( pCG, nAtomNumber, num_at_tg, sizeof( nAtomNumber[0] ), CompRanksOrd );
1263 : :
1264 : : /* convert equivalence information nSymmRank[] into ranks array nTempRank[] */
1265 : : /* eq. info contains min. possible ranks for eq. atoms; nCurrRank contains max. possible ranks */
1266 : 219 : nNumDiffRanks = SortedEquInfoToRanks( nSymmRank/*inp*/, nTempRank/*out*/, nAtomNumber, num_at_tg, &bChangeSymmRank );
1267 : :
1268 : : /* check whether nCurrRank is same as new initial ranks calculated from nSymmRank[] */
1269 : 219 : bChangeCurrRank = memcmp( nCurrRank, nTempRank, num_at_tg * sizeof( nTempRank[0] ) );
1270 : :
1271 : : /*-----------------------------------------------------------------------
1272 : : if ( bChangeSymmRank || bChangeCurrRank ) {
1273 : : This is the case when the initial equitable partitioning does not produce
1274 : : constitutionally equivalent classes of atoms.
1275 : : Rebuild nSymmRank[] according to the new nCurrRank[] := nTempRank[]
1276 : : For such structures the found canonical numbers of the constitutionally equivalent atoms
1277 : : are not contiguous (see nCanonRank and nSymmRank examples below). Here arrays
1278 : : nCurrRank, nAtomNumber, and nSymmRank are changed so that later the
1279 : : contiguous canonical numbers for equivalent atoms can be obtained
1280 : : (see GetCanonRanking under
1281 : : "III. Get final canonical numbering (no stereo, no isotopic)".
1282 : :
1283 : : Example: for CAS=37520-11-9 (ID=21247: Ethane, 1,2-dicyclopropyl-),
1284 : :
1285 : : the numbers are the "final canon. numbers, nCanonRank"
1286 : : 1
1287 : :
1288 : : HC 7 5 3
1289 : : | \
1290 : : | >CH--CH2 CH
1291 : : | / \ / |
1292 : : HC H2C--CH< |
1293 : : \ |
1294 : : 2 6 8 CH
1295 : :
1296 : : 4
1297 : :
1298 : : the arrays (arranged according to ordering in nAtomNumberTemp) are:
1299 : : before SortedEquInfoToRanks after SortedRanksToEquInfo
1300 : : orig. atom nos.,nAtomNumberTemp: {4 5 6 7 0 1 2 3} {4 5 6 7 0 1 2 3}
1301 : : order numbers for sorted ranks: {0 1 2 3 4 5 6 7} {0 1 2 3 4 5 6 7}
1302 : : canonical numbering, nCanonRank: {1 2 5 6 3 4 7 8} {1 2 5 6 3 4 7 8}
1303 : : constit. equivalence, nSymmRank: {1 1 1 1 3 3 7 7} {1 1 1 1 5 5 7 7} used later
1304 : : initial equivalence, nCurrRank: {6 6 6 6 6 6 8 8} {4 4 4 4 6 6 8 8} used later
1305 : : initial numbering, nAtomNumber: {2 3 4 7 0 1 6 7} {0 1 2 3 4 5 6 7} used later
1306 : : final, no stereo, no isotopic, after III. GetCanonRanking:
1307 : : final canon. numbers, nCanonRank: {1 2 3 4 5 6 7 8} final
1308 : : }
1309 : : ----------------------------------------------------------------------------------*/
1310 [ + + ]: 219 : if (bChangeCurrRank)
1311 : : {
1312 : 10 : memcpy(nCurrRank, nTempRank, num_at_tg * sizeof(nCurrRank[0]));
1313 : : }
1314 [ - + ]: 219 : if (bChangeSymmRank)
1315 : : {
1316 : 0 : SortedRanksToEquInfo( nSymmRank/*out*/, nTempRank/*inp*/, nAtomNumber, num_at_tg );
1317 : : }
1318 [ + + ]: 219 : if (bChanged)
1319 : : {
1320 [ - + ]: 161 : *bChanged = ( 0 != bChangeSymmRank ) | 2 * ( 0 != bChangeCurrRank );
1321 : : }
1322 : :
1323 : 219 : return nNumDiffRanks;
1324 : : }
1325 : :
1326 : :
1327 : : /* Isotopic canonicalization */
1328 : :
1329 : :
1330 : : /****************************************************************************
1331 : :
1332 : : Canon_INChI (former GetCanonRankingUsingEquivInfo)
1333 : :
1334 : : ****************************************************************************/
1335 : 161 : int Canon_INChI3( INCHI_CLOCK *ic,
1336 : : int num_atoms,
1337 : : int num_at_tg,
1338 : : sp_ATOM* at,
1339 : : CANON_STAT* pCS,
1340 : : CANON_GLOBALS *pCG,
1341 : : INCHI_MODE nMode,
1342 : : int bTautFtcn )
1343 : : {
1344 : :
1345 : : /****************************************************************
1346 : :
1347 : : 0. Initiation, Prepare initial ranks for GetCanonRanking()
1348 : :
1349 : : I. Find constitutionally equivalent atoms and possibly canonical numbering
1350 : : I.1 Set tautomer=On, stereo=isotopic=Off
1351 : : I.2 GetCanonRanking(): Find constitutionally equivalent atoms and possibly canonical numbering
1352 : : 1.3 Fix canonical equivalence info if needed (if the fix is needed then the numbering is not canonical)
1353 : :
1354 : : II. Get final non-isotopic canonical numbering. Simultaneously obtain non-minimal isotopic and stereo CTs
1355 : : GetCanonRanking() with pCS->bKeepSymmRank = 1
1356 : : FillOutStereoParities() (create initial stereo descriptors)
1357 : : save non-isotopic canonicalization final results
1358 : : hide isotopic and tautomeric results (for historical reasons only)
1359 : :
1360 : :
1361 : : III. Find constitutionally equivalent isotopic atoms (for isotopic stereo canonicalization)
1362 : : III.1 Allocate more memory
1363 : : III.2 fill allocated memory with the initial data
1364 : : III.3 duplicate, save old and add isotopic info to the new pCS->t_group_info
1365 : : III.4 Prepare initial isotopic ranks for GetCanonRanking()
1366 : : III.5 GetCanonRanking() to Find constitutionally equivalent ISOTOPIC atoms and tautomer groups
1367 : : III.6 Fix canonical isotopic equivalence information and derive ranks out of it
1368 : :
1369 : : IV. Prepare a second Rank/AtomNumber Stack for mapping.
1370 : :
1371 : : V. Optimize isotopic part (optimized)
1372 : : map_isotopic_atoms2()
1373 : : save isotopic canonical numbering
1374 : :
1375 : : VI. Optimize stereo descriptors (optimized)
1376 : : map_stereo_bonds4()
1377 : :
1378 : :
1379 : : VII. Optimize isotopic stereo descriptors (optimized)
1380 : : SwitchAtomStereoAndIsotopicStereo()
1381 : : SetCtToIsotopicStereo()
1382 : : FillOutStereoParities()
1383 : : SetUseAtomForStereo()
1384 : : map_stereo_bonds4()
1385 : :
1386 : : SwitchAtomStereoAndIsotopicStereo()
1387 : : SetCtToNonIsotopicStereo()
1388 : :
1389 : :
1390 : :
1391 : :
1392 : : *****************************************************************/
1393 : :
1394 : 161 : int nRet = 0, i, n;
1395 : :
1396 : :
1397 : : /********************************************************
1398 : : input non-stereo canonical info
1399 : : ********************************************************/
1400 : 161 : BCN *pBCN = pCS->pBCN;
1401 : 161 : FTCN *ftcn = pBCN->ftcn + bTautFtcn;
1402 : :
1403 : : /********************************************************
1404 : : set mode flags
1405 : : ********************************************************/
1406 : :
1407 : : /* tautomeric structure */
1408 [ + + + - : 161 : int bTaut = ( num_at_tg > num_atoms ) && pCS->t_group_info && pCS->t_group_info->num_t_groups && pCS->t_group_info->t_group;
+ - + - ]
1409 : :
1410 : : /* special case: induced by exchangable isotopic H inequivalence of atoms in formally non-tautomeric structure */
1411 [ - + ]: 161 : int bIsoXchgH = pCS->t_group_info && pCS->t_group_info->nNumIsotopicEndpoints > 1 &&
1412 [ + - - - : 322 : pCS->t_group_info->nIsotopicEndpointAtomNumber && pCS->t_group_info->nIsotopicEndpointAtomNumber[0] &&
- - ]
1413 [ # # ]: 0 : ( pCS->t_group_info->bTautFlagsDone & ( TG_FLAG_FOUND_ISOTOPIC_H_DONE | TG_FLAG_FOUND_ISOTOPIC_ATOM_DONE ) )
1414 : : /* && (ftcn->nCanonFlags & CANON_FLAG_ISO_TAUT_DIFF)*/;
1415 [ - + - - : 161 : int bHasIsotopicCanonData = ( ftcn->PartitionCtIso.AtNumber && ftcn->PartitionCtIso.Rank && ftcn->nSymmRankCtIso );
- - ]
1416 : :
1417 : : /* bHasIsotopicCanonData==0 means
1418 : : * (1) No isotopic atoms in the component OR
1419 : : * (2) the component has only exchangable isotopic H that do not change canonical numbering and equivalence.
1420 : : */
1421 [ + + ]: 161 : T_GROUP_INFO *t_group_info1 = bTaut ? pCS->t_group_info : NULL;
1422 : :
1423 : : /*int bIsoXchgH = t_group_info1 && t_group_info1->nNumIsotopicEndpoints && t_group_info1->nIsotopicEndpointAtomNumber;*/
1424 : : /* isotopic canonicalization */
1425 [ - + - - : 161 : int bCanonIsotopic = bHasIsotopicCanonData && ( nMode & CMODE_ISO ) && ( pCS->LinearCTIsotopic || pCS->LinearCTIsotopicTautomer || bIsoXchgH );
- - - - -
- ]
1426 : :
1427 : : /* stereo canonicalization */
1428 [ + + + - : 161 : int bCanonStereo = ( nMode & CMODE_STEREO ) && ( pCS->LinearCTStereoDble || pCS->LinearCTStereoCarb );
+ + ]
1429 : :
1430 : : /* stereo isotopic canonicalization */
1431 [ - + - - : 161 : int bCanonIsoStereo = bHasIsotopicCanonData && ( nMode & CMODE_ISO_STEREO ) && ( pCS->LinearCTIsotopicStereoDble || pCS->LinearCTIsotopicStereoCarb ) && bCanonIsotopic;
- - - - -
- ]
1432 [ + + - + ]: 161 : int bIsoTaut = ( bTaut && bCanonIsotopic );
1433 : :
1434 : : int bIgnoreIsotopicInputGroups;
1435 : : int bIgnoreIsotopicInputAtoms;
1436 : :
1437 : 161 : AT_RANK **pRankStack1 = pBCN->pRankStack;
1438 : 161 : int nRankStackLen = pBCN->nMaxLenRankStack;
1439 : 161 : int num_max = pBCN->num_max; /* allocation lengths in *pRankStack1[] */
1440 : 161 : NEIGH_LIST *NeighList = ftcn->NeighList;
1441 : :
1442 : 161 : int nNumCurrRanks = 0;
1443 : 161 : AT_RANK *nTempRank = NULL;
1444 : :
1445 : 161 : AT_RANK *nSymmRank = NULL;
1446 : :
1447 : 161 : AT_RANK *nAtomNumber = NULL;
1448 : 161 : AT_RANK *nRank = NULL;
1449 : :
1450 : 161 : AT_RANK **pRankStack2 = NULL;
1451 : 161 : AT_RANK *nCanonRankStereo = NULL;
1452 : 161 : AT_RANK *nCanonRankStereoInv = NULL;
1453 : 161 : AT_RANK *nSymmStereo = NULL;
1454 : :
1455 : 161 : AT_RANK *nCanonRankIsotopicStereo = NULL;
1456 : 161 : AT_RANK *nCanonRankIsotopicStereoInv = NULL;
1457 : :
1458 : 161 : CUR_TREE *cur_tree = NULL;
1459 : : CUR_TREE CurrentTree;
1460 : :
1461 : :
1462 : : /*AT_ISO_TGROUP *LinearCTIsotopicTautomer = NULL; */
1463 : :
1464 : :
1465 : : CANON_STAT CS2;
1466 : 161 : CANON_STAT* pCS2 = &CS2;
1467 : :
1468 : : inchiTime ulStartTime, ulEndTime;
1469 : : /*=========== Mode Bits (low 8 bits, bit 0 is Least Significant Bit) ===========
1470 : :
1471 : : Mode Bits Description
1472 : : '0' c 0 Only one connection table canonicalization
1473 : : '1' C 1 Recalculate CT using fixed nSymmRank
1474 : : '2' i 1|2 Isotopic canonicalization (internal)
1475 : : '3' I 1|2|4 Isotopic canonicalization (output)
1476 : : '4' s 1|8 Stereo canonicalization
1477 : : '5' S 1|2|4|16 Stereo isotopic canonicalization
1478 : : '6' A 1|2|4|8|16 Output All
1479 : :
1480 : : --- high 8 bits ----
1481 : : --- obsolete, only historical interest. ------
1482 : : 1-2 : 0 => at[i].init_rank from Morgan+NeighList
1483 : : 1 => at[i].init_rank from Atom Invariants
1484 : : 2 => at[i].init_rank from nSymmRank[]
1485 : : (at[i].init_rank is included in LinearCT
1486 : : depending on CT_ATOMID definition)
1487 : : 3 : 1 => Get Stereo canonical info
1488 : : 4 : 1 => Get Isotopic canonical info
1489 : : 5 : 1 => Get Charge/Radical canonical info
1490 : : ==================================================================*/
1491 : : /*int nOutputMode = 0;*/ /* obsolete */
1492 : :
1493 : :
1494 : 161 : int bSwitchedAtomToIsotopic = 0;
1495 : :
1496 : :
1497 : : /* vABParityUnknown holds actual value of an internal constant signifying */
1498 : : /* unknown parity: either the same as for undefined parity (default==standard) */
1499 : : /* or a specific one (non-std; requested by SLUUD switch). */
1500 : 161 : int vABParityUnknown = AB_PARITY_UNDF;
1501 [ - + ]: 161 : if (0 != ( nMode & REQ_MODE_DIFF_UU_STEREO ))
1502 : : {
1503 : : /* Make labels for unknown and undefined stereo different */
1504 : 0 : vABParityUnknown = AB_PARITY_UNKN;
1505 : : }
1506 : :
1507 : 161 : InchiTimeGet( &ulStartTime );
1508 : :
1509 : 161 : *pCS2 = *pCS; /* save input information and pointers to allocated memory */
1510 : :
1511 : : /* Set "ignore isotopic differences in tautomer groups" true */
1512 [ + + ]: 161 : if (bTaut)
1513 : : {
1514 : : /* save request for isotopic tautomeric groups */
1515 : 7 : bIgnoreIsotopicInputGroups = pCS->t_group_info->bIgnoreIsotopic;
1516 : 7 : pCS->t_group_info->bIgnoreIsotopic = 1;
1517 : : }
1518 : : else
1519 : : {
1520 : 154 : bIgnoreIsotopicInputGroups = 1;
1521 : : }
1522 : : /* Save request for isotopic name */
1523 : 161 : bIgnoreIsotopicInputAtoms = pCS->bIgnoreIsotopic;
1524 : : /* set "ignore isotopic differences in atoms" true */
1525 : 161 : pCS->bIgnoreIsotopic = 1;
1526 : :
1527 : :
1528 : : /* Save non-isotopic and isotopic canonicalization results */
1529 : 161 : pCS->nCanonFlags = ftcn->nCanonFlags;
1530 : : /* 1. non-isotopic */
1531 : :
1532 : : /* linear CT, H */
1533 : 161 : memcpy(pCS->LinearCT, ftcn->LinearCt, ftcn->nLenLinearCt * sizeof(pCS->LinearCT[0]));
1534 [ + - + - ]: 161 : if (pCS->nNum_H && ftcn->nNumH)
1535 : : {
1536 [ + + ]: 971 : for (i = 0; i < num_atoms; i++)
1537 : : {
1538 : 810 : pCS->nNum_H[i] = /*(S_CHAR)*/( CHAR_MASK & ftcn->nNumH[i] );
1539 : : }
1540 : : }
1541 [ + - - + ]: 161 : if (pCS->nNum_H_fixed && ftcn->nNumHFixH)
1542 : : {
1543 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
1544 : : {
1545 : 0 : pCS->nNum_H_fixed[i] = /*(S_CHAR)*/( CHAR_MASK & ftcn->nNumHFixH[i] );
1546 : : }
1547 : : }
1548 : 161 : pCS->nLenLinearCT = ftcn->nLenLinearCt;
1549 : 161 : pCS->nLenLinearCTAtOnly = ftcn->nLenLinearCtAtOnly;
1550 : :
1551 : : /* save non-isotopic atoms equivalence and numbering */
1552 [ + - ]: 161 : if (pCS->nSymmRank)
1553 : : {
1554 : 161 : memcpy(pCS->nSymmRank, ftcn->nSymmRankCt, num_at_tg * sizeof(pCS->nSymmRank[0]));
1555 : : }
1556 [ + - ]: 161 : if (pCS->nCanonOrd)
1557 : : {
1558 : 161 : memcpy(pCS->nCanonOrd, ftcn->PartitionCt.AtNumber, num_at_tg * sizeof(pCS->nCanonOrd[0]));
1559 : 161 : pCS->nLenCanonOrd = num_atoms;
1560 : : }
1561 [ - + - - ]: 161 : if (ftcn->iso_exchg_atnos && pCS->nExchgIsoH)
1562 : : {
1563 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
1564 : : {
1565 : 0 : pCS->nExchgIsoH[i] = !ftcn->iso_exchg_atnos[i]; /* (pCS->nExchgIsoH[i]==1) => tautomeric or hetero atoms that may exchange isotopic H */
1566 : : }
1567 : : }
1568 : : /* 2. isotopic */
1569 : :
1570 [ - + ]: 161 : if (bCanonIsotopic)
1571 : : {
1572 : : /* linear CT, num_H are same as non-isotopic */
1573 : : /* save atoms equivalence and numbering */
1574 [ # # ]: 0 : if (pCS->nSymmRankIsotopic)
1575 : : {
1576 : 0 : memcpy(pCS->nSymmRankIsotopic, ftcn->nSymmRankCtIso, num_at_tg * sizeof(pCS->nSymmRankIsotopic[0]));
1577 : : }
1578 [ # # ]: 0 : if (pCS->nCanonOrdIsotopic)
1579 : : {
1580 : 0 : memcpy(pCS->nCanonOrdIsotopic, ftcn->PartitionCtIso.AtNumber, num_at_tg * sizeof(pCS->nCanonOrdIsotopic[0]));
1581 : 0 : pCS->nLenCanonOrdIsotopic = num_at_tg;
1582 : : }
1583 : :
1584 : 0 : nRet = FillIsotopicAtLinearCT( num_atoms, at,
1585 : 0 : ftcn->PartitionCtIso.AtNumber,
1586 : : pCS->LinearCTIsotopic,
1587 : : pCS->nMaxLenLinearCTIsotopic,
1588 : : &pCS->nLenLinearCTIsotopic );
1589 : :
1590 [ # # # # ]: 0 : if (RETURNED_ERROR( nRet ))
1591 : : {
1592 : 0 : goto exit_function;
1593 : : }
1594 [ # # ]: 0 : if (nRet < 0)
1595 : : {
1596 : 0 : nRet = CT_TAUCOUNT_ERR;
1597 : 0 : goto exit_function;
1598 : : }
1599 : : }
1600 : : else
1601 : : {
1602 : 161 : pCS->nMaxLenLinearCTIsotopic = 0;
1603 : 161 : pCS->nMaxLenLinearCTIsotopicTautomer = 0;
1604 : : }
1605 : :
1606 : : /* fill out tautomeric groups, isotopic and non-isotopic tautomeric CT and t_group_info1->tGroupNumber */
1607 [ + + ]: 161 : if (bTaut)
1608 : : {
1609 [ # # ]: 0 : bIsoTaut = bIsoTaut && ftcn->PartitionCtIso.Rank &&
1610 [ - + - - : 7 : ftcn->PartitionCtIso.AtNumber && ftcn->nSymmRankCtIso;
- - ]
1611 : :
1612 : 7 : nRet = FillTautLinearCT2( pCG, num_atoms, num_at_tg, bIsoTaut,
1613 : 7 : ftcn->PartitionCt.Rank, ftcn->PartitionCt.AtNumber, ftcn->nSymmRankCt,
1614 : 7 : ftcn->PartitionCtIso.Rank, ftcn->PartitionCtIso.AtNumber, ftcn->nSymmRankCtIso,
1615 : : pCS->LinearCTTautomer, pCS->nMaxLenLinearCTTautomer, &pCS->nLenLinearCTTautomer,
1616 : : pCS->LinearCTIsotopicTautomer, pCS->nMaxLenLinearCTIsotopicTautomer, &pCS->nLenLinearCTIsotopicTautomer,
1617 : : t_group_info1 );
1618 : :
1619 [ + - - + ]: 7 : if (RETURNED_ERROR( nRet ))
1620 : : {
1621 : 0 : goto exit_function;
1622 : : }
1623 [ - + ]: 7 : if (nRet <= 0)
1624 : : {
1625 : 0 : nRet = CT_TAUCOUNT_ERR;
1626 : 0 : goto exit_function;
1627 : : }
1628 : : else
1629 : : {
1630 : : /* tautomeric groups: save non-isotopic symmetry & t_group order */
1631 : 7 : int num_t_groups = t_group_info1->num_t_groups;
1632 : 7 : AT_NUMB *tGroupNumber = t_group_info1->tGroupNumber;
1633 : 7 : AT_NUMB *tSymmRank = tGroupNumber + TGSO_SYMM_RANK*num_t_groups;
1634 [ + - ]: 7 : if (pCS->nSymmRankTaut)
1635 : : {
1636 : 7 : memcpy(pCS->nSymmRankTaut, tSymmRank, num_t_groups * sizeof(pCS->nSymmRank[0])); /* fixed 5-23-02 */
1637 : : }
1638 [ + - ]: 7 : if (pCS->nCanonOrdTaut)
1639 : : {
1640 : 7 : memcpy(pCS->nCanonOrdTaut, tGroupNumber, num_t_groups * sizeof(pCS->nCanonOrdTaut[0]));
1641 : 7 : pCS->nLenCanonOrdTaut = num_t_groups;
1642 : : }
1643 [ - + ]: 7 : if (bCanonIsotopic /*&& pCS->nLenLinearCTIsotopicTautomer*/)
1644 : : {
1645 : : /* tautomeric groups: save isotopic symmetry & t_group order */
1646 : : /*AT_NUMB ntRankOffset = (AT_RANK)num_atoms;*/
1647 : 0 : AT_NUMB *tiSymmRank = tGroupNumber + TGSO_SYMM_IRANK*(long long)num_t_groups; /* djb-rwth: cast operator added */
1648 : 0 : AT_NUMB *tiGroupNumber = tGroupNumber + TGSO_SYMM_IORDER*(long long)num_t_groups; /* djb-rwth: cast operator added */
1649 [ # # ]: 0 : if (pCS->nSymmRankIsotopicTaut)
1650 : : {
1651 : 0 : memcpy(pCS->nSymmRankIsotopicTaut, tiSymmRank, num_t_groups * sizeof(pCS->nSymmRankIsotopicTaut[0]));
1652 : : }
1653 : 0 : memcpy(pCS->nCanonOrdIsotopicTaut, tiGroupNumber, num_t_groups * sizeof(pCS->nCanonOrdIsotopicTaut[0]));
1654 : 0 : pCS->nLenCanonOrdIsotopicTaut = num_t_groups;
1655 : : }
1656 : : }
1657 : : }
1658 : : /* save connection table if requested */
1659 [ + - ]: 161 : if (pCS->LinearCT2)
1660 : : {
1661 : 161 : memcpy(pCS->LinearCT2, pCS->LinearCT, sizeof(pCS->LinearCT2[0])* pCS->nLenLinearCT);
1662 : 161 : pCS->nLenLinearCT2 = pCS->nLenLinearCT;
1663 : 161 : pCS->nLenLinearCTAtOnly2 = pCS->nLenLinearCTAtOnly;
1664 : : }
1665 : :
1666 [ + + ]: 161 : if (num_atoms <= 1)
1667 : : {
1668 : 84 : bCanonStereo = 0; /* a sinle atom + possibly terminal hydrogen atoms */
1669 [ + - + - ]: 84 : if (num_atoms < 1 || !at[0].parity2)
1670 : : {
1671 : 84 : bCanonIsoStereo = 0; /* structure; for example Cl- or CH4 */
1672 : : }
1673 : : }
1674 : :
1675 [ + + - + : 161 : if (!bCanonStereo && !( bCanonIsotopic && bCanonIsoStereo ))
- - ]
1676 : : {
1677 : 103 : goto exit_function; /* skip stereo canonicalization */
1678 : : }
1679 : :
1680 : :
1681 : :
1682 : : /**********************************************************
1683 : : Mode
1684 : : ***********************************************************/
1685 : 58 : nMode = nMode & CANON_MODE_MASK;
1686 : :
1687 : : /* memory allocation */
1688 : :
1689 : 58 : nAtomNumber = (AT_RANK *) qmalloc( num_max * sizeof( *nAtomNumber ) );
1690 : 58 : nRank = (AT_RANK *) qmalloc( num_max * sizeof( *nRank ) );
1691 : 58 : nTempRank = (AT_RANK *) qmalloc( num_max * sizeof( *nTempRank ) );
1692 : 58 : nSymmRank = (AT_RANK *) qmalloc( num_max * sizeof( *nSymmRank ) );
1693 : :
1694 : : /***********************************************
1695 : : 0.1 Initialization
1696 : : ************************************************/
1697 : :
1698 : :
1699 [ + - + - : 58 : if (!NeighList || !nAtomNumber || !nTempRank ||
+ - + - ]
1700 [ - + ]: 58 : !nRank || !pCS->LinearCT)
1701 : : {
1702 : 0 : nRet = CT_OUT_OF_RAM; /* program error */ /* <BRKPT> */
1703 : 0 : goto exit_function;
1704 : : }
1705 : :
1706 : 58 : pCS->NeighList = NeighList;
1707 : :
1708 : 58 : *pCS2 = *pCS; /* save input information and pointers to allocated memory */
1709 : :
1710 [ + - - + : 58 : if (!( nMode & CMODE_NOEQ_STEREO ) && ( bCanonStereo || bCanonIsoStereo ))
- - ]
1711 : : {
1712 : : /* will be used to discover vertex equivalences in stereo canonicalization */
1713 : 58 : memset( &CurrentTree, 0, sizeof( CurrentTree ) ); /* djb-rwth: memset_s C11/Annex K variant? */
1714 : 58 : cur_tree = &CurrentTree;
1715 : : }
1716 : :
1717 : :
1718 : 58 : pCS->bCmpStereo = 0;
1719 : 58 : pCS->bCmpIsotopicStereo = 0;
1720 : :
1721 : :
1722 [ - + - - ]: 58 : if (bCanonStereo || bCanonIsoStereo)
1723 : : {
1724 : : int ii, nn;
1725 : :
1726 : : /* stereo or isotopic canonicalization: we need a second set of ranks for mapping */
1727 : : /* (isotopic atoms or stereo can only increase nNumCurrRanks) */
1728 : 58 : pRankStack2 = (AT_RANK **) inchi_calloc( nRankStackLen, sizeof( AT_RANK * ) );
1729 [ + - ]: 58 : if (pRankStack2)
1730 : : {
1731 : : /* prepare for ranks reuse */
1732 [ + - + + ]: 120 : for (nn = 2; nn < nRankStackLen && pRankStack1[nn]; nn++)
1733 : : {
1734 : 62 : pRankStack1[nn][0] = 0; /* means ranks have to be calculated */
1735 : : }
1736 : : /* reuse memory to reduce number of allocations: */
1737 : : /* move last half of pointers from pRankStack1 to pRankStack2 */
1738 : : /* The first 2 elements will be assigned separately */
1739 [ + + ]: 58 : if (( nn = ( nn - 2 ) / 2 ) > 0)
1740 : : {
1741 [ + - + + ]: 41 : for (ii = 2 + nn; ii < nRankStackLen && pRankStack1[ii]; ii++)
1742 : : {
1743 : 31 : pRankStack2[ii - nn] = pRankStack1[ii];
1744 : 31 : pRankStack1[ii] = NULL;
1745 : : }
1746 : : }
1747 : : }
1748 : : else
1749 : : {
1750 : 0 : nRet = CT_OUT_OF_RAM; /* <BRKPT> */
1751 : 0 : goto exit_function; /* program error */
1752 : : }
1753 : : }
1754 : :
1755 [ + - ]: 58 : if (bCanonStereo)
1756 : : {
1757 : :
1758 : : /* *pCS2 = *pCS; */ /* save input information and pointers to allocated memory */
1759 : :
1760 : : /* initial ranking for non-isotopic mapping */
1761 : 58 : memcpy(nAtomNumber, ftcn->PartitionCt.AtNumber, num_at_tg * sizeof(nAtomNumber[0]));
1762 : 58 : memcpy(nRank, ftcn->PartitionCt.Rank, num_at_tg * sizeof(nRank[0]));
1763 : 58 : memcpy(nSymmRank, ftcn->nSymmRankCt, num_at_tg * sizeof(nSymmRank[0]));
1764 : :
1765 : : /* nSymmRank changes if canonical numbers of constitutionally equivalent atoms are not contiguous */
1766 : 58 : nNumCurrRanks = FixCanonEquivalenceInfo( pCG, num_at_tg,
1767 : : nSymmRank /* in&out*/,
1768 : : nRank, nTempRank /* out */,
1769 : : nAtomNumber /* in&out */,
1770 : : NULL );
1771 : : /* atom numbers in canonical order */
1772 : 58 : memcpy(pCS->nPrevAtomNumber, ftcn->PartitionCt.AtNumber, num_at_tg * sizeof(nAtomNumber[0]));
1773 : :
1774 : : /* fill stereo part of the connection table with initial (not optimized) parities */
1775 : : /* input
1776 : : pCS->LinearCTStereoDble
1777 : : pCS->LinearCTStereoCarb
1778 : : pCS->nMaxLenLinearCTStereoCarb
1779 : : pCS->nMaxLenLinearCTStereoDble
1780 : : */
1781 : :
1782 : 58 : nRet = FillOutStereoParities( at, num_atoms, ftcn->PartitionCt.Rank, ftcn->PartitionCt.AtNumber,
1783 : : nRank, nAtomNumber, pCS, pCG, 0 /* bIsotopic */ );
1784 : :
1785 : : /* output
1786 : : pCS->LinearCTStereoDble
1787 : : pCS->LinearCTStereoCarb
1788 : : pCS2->nLenLinearCTStereoCarb
1789 : : pCS2->nLenLinearCTStereoDble
1790 : : */
1791 : :
1792 [ + - - + ]: 58 : if (RETURNED_ERROR( nRet ))
1793 : : {
1794 : 0 : goto exit_function;
1795 : : }
1796 [ - + ]: 58 : if (nRet < 0)
1797 : : {
1798 : 0 : nRet = CT_STEREOCOUNT_ERR;
1799 : 0 : goto exit_function;
1800 : : }
1801 : :
1802 : : /***************************************************************
1803 : : *
1804 : : * VI. Optimize non-isotopic stereo descriptors (optimized)
1805 : : *
1806 : : ***************************************************************/
1807 : :
1808 : : /* allocate memory for stereo canonicalization */
1809 : :
1810 [ + - ]: 58 : if (!nCanonRankStereo)
1811 : : {
1812 : 58 : nCanonRankStereo = (AT_RANK *) qmalloc( num_max * sizeof( *nCanonRankStereo ) );
1813 : : }
1814 [ + - + - ]: 58 : if (!nSymmStereo && !( nMode & CMODE_NOEQ_STEREO ))
1815 : : {
1816 : 58 : nSymmStereo = (AT_RANK *) qmalloc( ( (long long)num_max + 1 ) * sizeof( *nSymmStereo ) ); /* djb-rwth: cast operator added */
1817 : : }
1818 : :
1819 [ + - - + ]: 58 : if (!( nMode & CMODE_NOEQ_STEREO ) && 0 > CurTreeAlloc( cur_tree, num_at_tg ))
1820 : : {
1821 : 0 : nRet = CT_OUT_OF_RAM; /* <BRKPT> */
1822 : 0 : goto exit_function;
1823 : : }
1824 : : /* check allocations and assign first 2 elements of pRankStack2 */
1825 [ + - + - : 58 : if (pRankStack1 && pRankStack2 &&
+ - ]
1826 [ - + ]: 58 : nCanonRankStereo &&
1827 : : /* nCurrRankStereo && nAtomNumberCurrStereo &&*/
1828 [ # # ]: 0 : ( nSymmStereo || ( nMode & CMODE_NOEQ_STEREO ) ))
1829 : : {
1830 : 58 : pRankStack1[0] = pRankStack2[0] = nRank;
1831 : 58 : pRankStack1[1] = pRankStack2[1] = nAtomNumber;
1832 : : }
1833 : : else
1834 : : {
1835 : 0 : nRet = CT_OUT_OF_RAM; /* <BRKPT> */
1836 : 0 : goto exit_function;
1837 : : }
1838 : :
1839 : : /****************************************************************
1840 : : *
1841 : : * VI-A. Optimize non-isotopic non-inverted stereo descriptors
1842 : : *
1843 : : ****************************************************************/
1844 : :
1845 : : /* set the 1st ranks in the rest of the stack to zero: prepare for ranks reuse */
1846 [ + - + + ]: 89 : for (n = 2; n < nRankStackLen && pRankStack1[n]; n++)
1847 : : {
1848 : 31 : pRankStack1[n][0] = 0; /* means ranks have to be recalculated */
1849 : : }
1850 : : /* set the 1st ranks to zero: prepare for ranks reuse */
1851 [ + - + + ]: 89 : for (n = 2; n < nRankStackLen && pRankStack2[n]; n++)
1852 : : {
1853 : 31 : pRankStack2[n][0] = 0; /* means ranks have to be recalculated */
1854 : : }
1855 : :
1856 : : /* for debugging or statistics */
1857 : 58 : pCS->lNumBreakTies =
1858 : 58 : pCS->lNumNeighListIter =
1859 : 58 : pCS->lNumTotCT =
1860 : 58 : pCS->lNumDecreasedCT =
1861 : 58 : pCS->lNumRejectedCT =
1862 : 58 : pCS->lNumEqualCT = 0;
1863 : 58 : pCS->bKeepSymmRank = 0;
1864 : 58 : pCS->bFirstCT = 1; /* To fill out nCanonRankStereo[] in map_stero_atoms2() */
1865 : :
1866 : : /******************************************************************************
1867 : : nCanonRank contains input canonical numbering
1868 : : nCanonRankStereo will be filled with a transposition of canonical numbering
1869 : : which (1) keeps connection table unchanged and
1870 : : (2) provides minimal stereo descriptors in
1871 : : pCS->LinearCTStereoDble (length=pCS->nLenLinearCTStereoDble)
1872 : : pCS->LinearCTStereoCarb (length=pCS->nLenLinearCTStereoCarb)
1873 : : */
1874 : :
1875 : 58 : nRet = map_stereo_bonds4( ic, pCG, at, num_atoms, num_at_tg, num_max, 0,
1876 : 58 : ftcn->PartitionCt.Rank, ftcn->PartitionCt.AtNumber,
1877 : : nCanonRankStereo, nSymmRank,
1878 : : pRankStack1, pRankStack2,
1879 : : nTempRank, nNumCurrRanks,nSymmStereo,
1880 : : NeighList, pCS, cur_tree, 0 /* nNumMappedBonds */,
1881 : : vABParityUnknown );
1882 : :
1883 [ + - - + ]: 58 : if (RETURNED_ERROR( nRet ))
1884 : : {
1885 [ # # ]: 0 : if (nRet == CT_TIMEOUT_ERR)
1886 : : {
1887 : 0 : goto exit_function;
1888 : : }
1889 : : else
1890 : : {
1891 : 0 : goto exit_function; /* program error */
1892 : : }
1893 : : }
1894 : : else
1895 : : {
1896 : 58 : int bFailed = 0;
1897 [ - + ]: 58 : if (!nRet)
1898 : : {
1899 : : /* djb-rwth: removing redundant code */
1900 : 0 : pCS2->nLenLinearCTStereoCarb =
1901 : 0 : pCS->nLenLinearCTStereoCarb = -abs( pCS->nLenLinearCTStereoCarb );
1902 : 0 : pCS2->nLenLinearCTStereoDble =
1903 : 0 : pCS->nLenLinearCTStereoDble = -abs( pCS->nLenLinearCTStereoDble );
1904 : 0 : nRet = CT_STEREOCOUNT_ERR; /* <BRKPT> */
1905 : 0 : goto exit_function; /* program error */
1906 : : }
1907 : : else
1908 : : {
1909 : : /* save non-isotopic lengths */
1910 : 58 : pCS2->nLenLinearCTStereoDble = pCS->nLenLinearCTStereoDble;
1911 : 58 : pCS2->nLenLinearCTStereoCarb = pCS->nLenLinearCTStereoCarb;
1912 : : /* djb-rwth: removing redundant code */
1913 : : }
1914 : :
1915 : : /* save stereo canonical numbering */
1916 [ + - ]: 58 : if (pCS->nCanonOrdStereo)
1917 : : {
1918 [ + + ]: 648 : for (i = 0; i < num_at_tg; i++) /* djb-rwth: removing redundant code */
1919 : : {
1920 [ + - + - ]: 590 : if (nCanonRankStereo[i] && (int) nCanonRankStereo[i] <= num_at_tg)
1921 : : {
1922 : 590 : pCS->nCanonOrdStereo[(int) nCanonRankStereo[i] - 1] = (AT_NUMB) i;
1923 : : }
1924 : : else
1925 : : {
1926 : 0 : bFailed++;
1927 : : }
1928 : : }
1929 [ - + ]: 58 : pCS->nLenCanonOrdStereo = ( bFailed ) ? -num_atoms : num_atoms;
1930 : : }
1931 : :
1932 : : /* save stereo tautomer groups numbering */
1933 [ + + + - ]: 58 : if (bTaut && pCS->nCanonOrdStereoTaut)
1934 : : {
1935 [ + - ]: 2 : if (0 < ( nRet = SortTautomerGroupsAndEndpoints( pCG, t_group_info1, num_atoms, num_at_tg, nCanonRankStereo ) ))
1936 : : {
1937 : : /*non-isotopic contains symmetry ranks */
1938 : 2 : int num_t_groups = t_group_info1->num_t_groups;
1939 : 2 : AT_NUMB *tGroupNumber = t_group_info1->tGroupNumber;
1940 : : /*AT_NUMB *tiSymmRank = tGroupNumber + TGSO_SYMM_IRANK*num_t_groups; */
1941 : 2 : memcpy(pCS->nCanonOrdStereoTaut, tGroupNumber, num_t_groups * sizeof(pCS->nCanonOrdStereoTaut[0]));
1942 : 2 : pCS->nLenCanonOrdStereoTaut = ( bFailed ) ? -num_t_groups
1943 [ - + ]: 2 : : num_t_groups;
1944 : : }
1945 : : else
1946 : : {
1947 [ # # # # ]: 0 : if (RETURNED_ERROR(nRet))
1948 : : {
1949 : 0 : goto exit_function;
1950 : : }
1951 : : }
1952 : : /* djb-rwth: removing redundant code */
1953 : : /*SortTautomerGroupsAndEndpoints( t_group_info1, nCanonRank ); */ /* ??? return to non-isotopic canonical numbering */
1954 : : }
1955 : : }
1956 : :
1957 : :
1958 : : /****************************************************
1959 : : *
1960 : : * VI-B. Optimize INVERTED stereo descriptors
1961 : : *
1962 : : ****************************************************/
1963 [ + - ]: 58 : if (!nCanonRankStereoInv)
1964 : : {
1965 : 58 : nCanonRankStereoInv = (AT_RANK *) qmalloc( num_max * sizeof( *nCanonRankStereoInv ) );
1966 : : }
1967 [ - + ]: 58 : if (!nCanonRankStereoInv)
1968 : : {
1969 : 0 : nRet = CT_OUT_OF_RAM; /* <BRKPT> */
1970 : 0 : goto exit_function;
1971 : : }
1972 : :
1973 : : /* copy previous non-isotopic stereo canonicalization results to Inv initial data */
1974 : : /* assign pointers */
1975 : 58 : pCS->LinearCTStereoDble = pCS2->LinearCTStereoDbleInv;
1976 : 58 : pCS->LinearCTStereoCarb = pCS2->LinearCTStereoCarbInv;
1977 : :
1978 : : /* copy the lengths */
1979 : 58 : pCS2->nLenLinearCTStereoDbleInv =
1980 : 58 : pCS->nLenLinearCTStereoDbleInv =
1981 : 58 : pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTStereoDble;
1982 : :
1983 : 58 : pCS2->nLenLinearCTStereoCarbInv =
1984 : 58 : pCS->nLenLinearCTStereoCarbInv =
1985 : 58 : pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTStereoCarb;
1986 : :
1987 [ + - + + ]: 58 : if (pCS->nLenLinearCTStereoDble > 0 || pCS->nLenLinearCTStereoCarb > 0)
1988 : : {
1989 : : /* copy previous results, the canonical stereo CT */
1990 : 55 : memcpy(pCS->LinearCTStereoDble, pCS2->LinearCTStereoDble, pCS->nLenLinearCTStereoDble * sizeof(pCS->LinearCTStereoDble[0]));
1991 : 55 : memcpy(pCS->LinearCTStereoCarb, pCS2->LinearCTStereoCarb, pCS->nLenLinearCTStereoCarb * sizeof(pCS->LinearCTStereoCarb[0]));
1992 : : }
1993 : 58 : memcpy(nCanonRankStereoInv, nCanonRankStereo, num_max * sizeof(nCanonRankStereoInv[0]));
1994 [ + - + - ]: 58 : if (pCS->nCanonOrdStereoInv && pCS->nCanonOrdStereo)
1995 : : {
1996 : : /* in case there is nothing to invert */
1997 : 58 : memcpy(pCS->nCanonOrdStereoInv, pCS->nCanonOrdStereo, num_at_tg * sizeof(pCS->nCanonOrdStereoInv[0]));
1998 : : }
1999 : :
2000 : : /******************************
2001 : : *
2002 : : * Invert stereo
2003 : : *
2004 : : ******************************/
2005 : :
2006 : : /*********************************************************************************
2007 : : * Create initial approximation for the minimization of the stereo descriptors:
2008 : : * invert stereogenic atom parities, one parity in each allene, all parities in
2009 : : * pCS->LinearCTStereoCarb and allene parities in pCS->nLenLinearCTStereoDble
2010 : : */
2011 : 58 : nRet = InvertStereo( at, num_at_tg, nCanonRankStereo, nTempRank, pCS, 1 /* bInvertLinearCTStereo */ );
2012 [ + - - + ]: 58 : if (RETURNED_ERROR( nRet ))
2013 : : {
2014 : 0 : goto exit_function;
2015 : : }
2016 [ + + ]: 58 : else if (nRet > 0)
2017 : : {
2018 : : /* InvertStereo() has done some changes */
2019 : : /* djb-rwth: removing redundant code */
2020 : : /* FillOutStereoParities() has already been called to fill out these 2 LinearCTs */
2021 : :
2022 : : /* set the 1st ranks in the rest of the stack to zero: prepare for ranks reuse */
2023 [ + - + + ]: 155 : for (n = 2; n < nRankStackLen && pRankStack1[n]; n++)
2024 : : {
2025 : 104 : pRankStack1[n][0] = 0; /* means ranks have to be recalculated */
2026 : : }
2027 : : /* set the 1st ranks to zero: prepare for ranks reuse */
2028 [ + - + + ]: 155 : for (n = 2; n < nRankStackLen && pRankStack2[n]; n++)
2029 : : {
2030 : 104 : pRankStack2[n][0] = 0; /* means ranks have to be recalculated */
2031 : : }
2032 : :
2033 : : /* for debugging or statistics */
2034 : 51 : pCS->lNumBreakTies =
2035 : 51 : pCS->lNumNeighListIter =
2036 : 51 : pCS->lNumTotCT =
2037 : 51 : pCS->lNumDecreasedCT =
2038 : 51 : pCS->lNumRejectedCT =
2039 : 51 : pCS->lNumEqualCT = 0;
2040 : 51 : pCS->bKeepSymmRank = 0;
2041 : 51 : pCS->bFirstCT = 1; /* To fill out nCanonRankStereo[] in map_stero_atoms2() */
2042 : :
2043 : : #ifdef FIX_STEREOCOUNT_ERR
2044 : 51 : CurTreeSetPos( cur_tree, 0 );
2045 : : #endif
2046 : :
2047 : : /******************************************************************************
2048 : : ftcn->PartitionCt.Rank contains input canonical numbering
2049 : : nCanonRankStereoInv will be filled with a transposition of canonical numbering
2050 : : which (1) keeps connection table unchanged and
2051 : : (2) provides minimal stereo descriptors in
2052 : : pCS->LinearCTStereoDble (length=pCS->nLenLinearCTStereoDble)
2053 : : pCS->LinearCTStereoCarb (length=pCS->nLenLinearCTStereoCarb)
2054 : : ******************************************************************************/
2055 : :
2056 : 51 : nRet = map_stereo_bonds4( ic,pCG, at, num_atoms, num_at_tg, num_max, 0,
2057 : 51 : ftcn->PartitionCt.Rank,
2058 : 51 : ftcn->PartitionCt.AtNumber,
2059 : : nCanonRankStereoInv,
2060 : : nSymmRank, pRankStack1, pRankStack2,
2061 : : nTempRank, nNumCurrRanks, nSymmStereo,
2062 : : NeighList, pCS, cur_tree, 0,
2063 : : vABParityUnknown );
2064 : :
2065 [ + - - + ]: 51 : if (RETURNED_ERROR( nRet ))
2066 : : {
2067 [ # # ]: 0 : if (nRet == CT_TIMEOUT_ERR)
2068 : : {
2069 : 0 : goto exit_function;
2070 : : }
2071 : : else
2072 : : {
2073 : 0 : goto exit_function; /* program error */
2074 : : }
2075 : : }
2076 : : else
2077 : : {
2078 : 51 : int bFailed = 0;
2079 [ - + ]: 51 : if (!nRet)
2080 : : {
2081 : : /* djb-rwth: removing redundant code */
2082 : 0 : pCS2->nLenLinearCTStereoCarb =
2083 : 0 : pCS->nLenLinearCTStereoCarb = -abs( pCS->nLenLinearCTStereoCarb );
2084 : 0 : pCS2->nLenLinearCTStereoDble =
2085 : 0 : pCS->nLenLinearCTStereoDble = -abs( pCS->nLenLinearCTStereoDble );
2086 : 0 : nRet = CT_STEREOCOUNT_ERR; /* <BRKPT> */
2087 : 0 : goto exit_function; /* program error */
2088 : : }
2089 : :
2090 : : /* save non-isotopic pointers & lengths for INVERTED stereo */
2091 : 51 : pCS->nLenLinearCTStereoDbleInv =
2092 : 51 : pCS2->nLenLinearCTStereoDbleInv = pCS->nLenLinearCTStereoDble;
2093 : 51 : pCS->nLenLinearCTStereoCarbInv =
2094 : 51 : pCS2->nLenLinearCTStereoCarbInv = pCS->nLenLinearCTStereoCarb;
2095 : :
2096 : : /* restore pointers and lengths to non-inverted stereo */
2097 : : /* -- this is needed for InvertStereo() back, see below */
2098 : 51 : pCS->LinearCTStereoDble = pCS2->LinearCTStereoDble;
2099 : 51 : pCS->LinearCTStereoCarb = pCS2->LinearCTStereoCarb;
2100 : 51 : pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTStereoDble;
2101 : 51 : pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTStereoCarb;
2102 : : /* consistency check */
2103 [ + - ]: 51 : if (pCS->nLenLinearCTStereoDbleInv != pCS->nLenLinearCTStereoDble ||
2104 [ - + ]: 51 : pCS->nLenLinearCTStereoCarbInv != pCS->nLenLinearCTStereoCarb)
2105 : : {
2106 : 0 : nRet = CT_CALC_STEREO_ERR;
2107 : 0 : goto exit_function; /* program error */
2108 : : }
2109 : :
2110 : : /******************************
2111 : : *
2112 : : * Invert stereo back
2113 : : *
2114 : : ******************************
2115 : : * (make sure that pointers
2116 : : * pCS->LinearCTStereoCarb,
2117 : : * pCS->LinearCTStereoDble
2118 : : * and corresponding lengths
2119 : : * have been restored)
2120 : : ******************************/
2121 : : /*********************************************************************************
2122 : : * invert only stereogenic atom parities and one parity in each allene, DO NOT
2123 : : * change parities in pCS->LinearCTStereoCarb and pCS->nLenLinearCTStereoDble
2124 : : */
2125 : 51 : nRet = InvertStereo( at,
2126 : : num_at_tg,
2127 : : nCanonRankStereo,
2128 : : nTempRank,
2129 : : pCS,
2130 : : 0 );
2131 : :
2132 [ + - - + ]: 51 : if (RETURNED_ERROR( nRet ))
2133 : : {
2134 : 0 : goto exit_function;
2135 : : }
2136 : 51 : nRet = 0;
2137 : :
2138 : :
2139 : : /* save stereo canonical numbering */
2140 [ + - ]: 51 : if (pCS->nCanonOrdStereoInv)
2141 : : {
2142 [ + + ]: 573 : for (i = 0; i < num_at_tg; i++) /* djb-rwth: removing redundant code */
2143 : : {
2144 [ + - + - ]: 522 : if (nCanonRankStereoInv[i] && (int) nCanonRankStereoInv[i] <= num_at_tg)
2145 : : {
2146 : 522 : pCS->nCanonOrdStereoInv[(int) nCanonRankStereoInv[i] - 1] = (AT_NUMB) i;
2147 : : }
2148 : : else
2149 : : {
2150 : 0 : bFailed++;
2151 : : }
2152 : : }
2153 [ - + ]: 51 : pCS->nLenCanonOrdStereo = ( bFailed ) ? -num_atoms : num_atoms;
2154 : : }
2155 : :
2156 : : /* compare inverted and non-inverted stereo */
2157 : 51 : pCS->bCmpStereo = 2 + CompareLinCtStereo(
2158 : : pCS->LinearCTStereoDbleInv, pCS->nLenLinearCTStereoDbleInv,
2159 : : pCS->LinearCTStereoCarbInv, pCS->nLenLinearCTStereoCarbInv,
2160 : : pCS->LinearCTStereoDble, pCS->nLenLinearCTStereoDble,
2161 : : pCS->LinearCTStereoCarb, pCS->nLenLinearCTStereoCarb
2162 : : );
2163 : : }
2164 : : }
2165 [ + - ]: 7 : else if (0 == nRet)
2166 : : {
2167 : : /* nothing has been done, restore pointers and lengths for stereo */
2168 : 7 : pCS->LinearCTStereoDble = pCS2->LinearCTStereoDble;
2169 : 7 : pCS->LinearCTStereoCarb = pCS2->LinearCTStereoCarb;
2170 : 7 : pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTStereoDble;
2171 : 7 : pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTStereoCarb;
2172 : : }
2173 : : }
2174 : :
2175 : : /* restore "ignore isotopic differences in tautomer groups" */
2176 [ + + ]: 58 : if (bTaut)
2177 : : {
2178 : : /* save request for isotopic tautomeric groups */
2179 : 2 : pCS->t_group_info->bIgnoreIsotopic = bIgnoreIsotopicInputGroups;
2180 : : }
2181 : :
2182 : : /* restore request for isotopic name */
2183 : 58 : pCS->bIgnoreIsotopic = bIgnoreIsotopicInputAtoms;
2184 : :
2185 [ + - - - ]: 58 : if (bCanonIsoStereo && bCanonIsotopic)
2186 : : {
2187 : :
2188 : : /****************************************************************
2189 : : *
2190 : : * VII. Optimize isotopic stereo descriptors (optimized)
2191 : : *
2192 : : ****************************************************************/
2193 : : /*
2194 : : pCS->LinearCTIsotopic = NULL;
2195 : : */
2196 : :
2197 : : /* Initial ranking for isotopic mapping */
2198 : 0 : memcpy(nAtomNumber, ftcn->PartitionCtIso.AtNumber, num_at_tg * sizeof(nAtomNumber[0]));
2199 : 0 : memcpy(nRank, ftcn->PartitionCtIso.Rank, num_at_tg * sizeof(nRank[0]));
2200 : 0 : memcpy(nSymmRank, ftcn->nSymmRankCtIso, num_at_tg * sizeof(nSymmRank[0]));
2201 : : /* nSymmRank will change if canonical numbers of of constitutionally equivalent atoms are not contiguous */
2202 : 0 : nNumCurrRanks = FixCanonEquivalenceInfo( pCG, num_at_tg, nSymmRank /* in&out*/,
2203 : : nRank, nTempRank /* out */, nAtomNumber /* in&out */, NULL );
2204 : 0 : memcpy(pCS->nPrevAtomNumber, ftcn->PartitionCtIso.AtNumber, num_at_tg * sizeof(nAtomNumber[0]));
2205 : : /* Allocate memory for optimized stereo canonicalization */
2206 : : /* for stereo canonical numbering to be found. */
2207 [ # # ]: 0 : if (!nCanonRankIsotopicStereo)
2208 : : {
2209 : 0 : nCanonRankIsotopicStereo = (AT_RANK *) qmalloc( num_max * sizeof( *nCanonRankIsotopicStereo ) );
2210 : : }
2211 [ # # # # ]: 0 : if (!nSymmStereo && !( nMode & CMODE_NOEQ_STEREO ))
2212 : : {
2213 : 0 : nSymmStereo = (AT_RANK *) qmalloc( ( (long long)num_max + 1 ) * sizeof( *nSymmStereo ) ); /* djb-rwth: cast operator added */
2214 : : }
2215 [ # # # # ]: 0 : if (!( nMode & CMODE_NOEQ_STEREO ) && CurTreeAlloc( cur_tree, num_at_tg ))
2216 : : {
2217 : 0 : nRet = CT_OUT_OF_RAM; /* <BRKPT> */
2218 : 0 : goto exit_function;
2219 : : }
2220 : :
2221 : : /* Check allocations and assign first 2 elements of pRankStack2 */
2222 [ # # # # : 0 : if (pRankStack1 && pRankStack2 &&
# # ]
2223 [ # # ]: 0 : nCanonRankIsotopicStereo &&
2224 [ # # ]: 0 : ( nSymmStereo || ( nMode & CMODE_NOEQ_STEREO ) ))
2225 : : {
2226 : :
2227 : 0 : pRankStack1[0] = pRankStack2[0] = nRank; /* pRankStack1[0,1] shall be unchanged */
2228 : 0 : pRankStack1[1] = pRankStack2[1] = nAtomNumber;
2229 : : }
2230 : : else
2231 : : {
2232 : 0 : nRet = CT_OUT_OF_RAM; /* <BRKPT> */
2233 : 0 : goto exit_function;
2234 : : }
2235 : :
2236 : : /******************************************************************
2237 : : Important: fill out a list of stereo atoms and bonds including
2238 : : those which are stereo due to isotopic atoms only and create
2239 : : LinearCT stereo descriptors for the canonical numbering
2240 : : ******************************************************************/
2241 : :
2242 : :
2243 : : /* at[] has certain members for non-isotopic and isotopic stereo; switch them */
2244 : 0 : SwitchAtomStereoAndIsotopicStereo( at, num_atoms, &bSwitchedAtomToIsotopic );
2245 : :
2246 : : /* Prepare stereo connection tables' pointers */
2247 : 0 : SetCtToIsotopicStereo( pCS, pCS2 );
2248 : :
2249 : 0 : nRet = FillOutStereoParities( at, num_atoms,
2250 : 0 : ftcn->PartitionCtIso.Rank,
2251 : 0 : ftcn->PartitionCtIso.AtNumber,
2252 : : nRank, nAtomNumber,
2253 : : pCS, pCG, 1 /* bIsotopic */ );
2254 : :
2255 : :
2256 [ # # # # ]: 0 : if (RETURNED_ERROR( nRet ))
2257 : : {
2258 : 0 : goto exit_function; /* program error */
2259 : : }
2260 : : else
2261 : : {
2262 [ # # ]: 0 : if (!nRet)
2263 : : {
2264 : : /* no isotopic stereo */
2265 : 0 : pCS2->nLenLinearCTIsotopicStereoDble = pCS->nLenLinearCTIsotopicStereoDble = 0;
2266 : 0 : pCS2->nLenLinearCTIsotopicStereoCarb = pCS->nLenLinearCTIsotopicStereoCarb = 0;
2267 : 0 : pCS->nLenCanonOrdIsotopicStereo = 0;
2268 : 0 : pCS->nLenCanonOrdIsotopicStereoTaut = 0;
2269 : 0 : pCS2->nLenLinearCTIsotopicStereoDbleInv = pCS->nLenLinearCTIsotopicStereoDbleInv = 0;
2270 : 0 : pCS2->nLenLinearCTIsotopicStereoCarbInv = pCS->nLenLinearCTIsotopicStereoCarbInv = 0;
2271 : 0 : goto bypass_isotopic_stereo;
2272 : : }
2273 : : }
2274 : :
2275 : : /* djb-rwth: removing redundant code */
2276 : :
2277 : :
2278 : : /*************************************************************
2279 : : *
2280 : : * VII-A. Optimize non-inverted isotopic stereo descriptors
2281 : : *
2282 : : *************************************************************/
2283 : :
2284 : : /* set the 1st ranks in the rest of the stack to zero: prepare for ranks reuse */
2285 [ # # # # ]: 0 : for (n = 2; n < nRankStackLen && pRankStack1[n]; n++)
2286 : : {
2287 : 0 : pRankStack1[n][0] = 0; /* means ranks have to be recalculated */
2288 : : }
2289 : : /* set the 1st ranks to zero: prepare for ranks reuse */
2290 [ # # # # ]: 0 : for (n = 2; n < nRankStackLen && pRankStack2[n]; n++)
2291 : : {
2292 : 0 : pRankStack2[n][0] = 0; /* means ranks have to be recalculated */
2293 : : }
2294 : :
2295 : : /* for debugging or statistics */
2296 : 0 : pCS->lNumBreakTies =
2297 : 0 : pCS->lNumNeighListIter =
2298 : 0 : pCS->lNumTotCT =
2299 : 0 : pCS->lNumDecreasedCT =
2300 : 0 : pCS->lNumRejectedCT =
2301 : 0 : pCS->lNumEqualCT = 0;
2302 : 0 : pCS->bKeepSymmRank = 0;
2303 : 0 : pCS->bFirstCT = 1; /* To fill out nCanonRankStereo[] in map_stero_atoms2() */
2304 : :
2305 : : /**************************************************************************************
2306 : : nCanonRankIsotopic contains input canonical numbering
2307 : : nCanonRankIsotopicStereo will be filled with a transposition of canonical numbering
2308 : : that (1) keeps connection table unchanged and
2309 : : (2) provides minimal stereo descriptors in
2310 : : pCS->LinearCTStereoDble (length=pCS->nLenLinearCTStereoDble)
2311 : : pCS->LinearCTStereoCarb (length=pCS->nLenLinearCTStereoCarb)
2312 : : ***************************************************************************************/
2313 : :
2314 : 0 : nRet = map_stereo_bonds4( ic, pCG,at, num_atoms, num_at_tg, num_max, 0,
2315 : 0 : ftcn->PartitionCtIso.Rank,
2316 : 0 : ftcn->PartitionCtIso.AtNumber,
2317 : : nCanonRankIsotopicStereo,
2318 : : nSymmRank, pRankStack1, pRankStack2,
2319 : : nTempRank, nNumCurrRanks, nSymmStereo,
2320 : : NeighList, pCS, cur_tree,
2321 : : 0, vABParityUnknown );
2322 : :
2323 [ # # # # ]: 0 : if (RETURNED_ERROR( nRet ))
2324 : : {
2325 : 0 : goto exit_function;
2326 : : }
2327 : : else
2328 : : {
2329 : 0 : int bFailed = 0;
2330 : :
2331 [ # # ]: 0 : if (!nRet)
2332 : : {
2333 : : /* djb-rwth: removing redundant code */
2334 : 0 : pCS2->nLenLinearCTIsotopicStereoDble =
2335 : 0 : pCS->nLenLinearCTIsotopicStereoDble = -abs( pCS->nLenLinearCTStereoDble );
2336 : 0 : pCS2->nLenLinearCTIsotopicStereoCarb =
2337 : 0 : pCS->nLenLinearCTIsotopicStereoCarb = -abs( pCS->nLenLinearCTStereoCarb );
2338 : 0 : nRet = CT_STEREOCOUNT_ERR; /* <BRKPT> */
2339 : 0 : goto exit_function; /* program error */
2340 : : }
2341 : : else
2342 : : {
2343 : : /* save isotopic lengths */
2344 : 0 : pCS->nLenLinearCTIsotopicStereoDble =
2345 : 0 : pCS2->nLenLinearCTIsotopicStereoDble = pCS->nLenLinearCTStereoDble;
2346 : 0 : pCS->nLenLinearCTIsotopicStereoCarb =
2347 : 0 : pCS2->nLenLinearCTIsotopicStereoCarb = pCS->nLenLinearCTStereoCarb;
2348 : :
2349 : : /* save stereo canonical numbering */
2350 [ # # ]: 0 : if (pCS->nCanonOrdIsotopicStereo)
2351 : : {
2352 [ # # ]: 0 : for (i = 0; i < num_at_tg; i++) /* djb-rwth: removing redundant code */
2353 : : {
2354 [ # # # # ]: 0 : if (nCanonRankIsotopicStereo[i] && (int) nCanonRankIsotopicStereo[i] <= num_at_tg)
2355 : : {
2356 : 0 : pCS->nCanonOrdIsotopicStereo[(int) nCanonRankIsotopicStereo[i] - 1] = (AT_NUMB) i;
2357 : : }
2358 : : else
2359 : : {
2360 : 0 : bFailed++;
2361 : : }
2362 : : }
2363 [ # # ]: 0 : pCS->nLenCanonOrdIsotopicStereo = bFailed ? -num_atoms : num_atoms;
2364 : : }
2365 : :
2366 : : /* save stereo tautomer groups numbering */
2367 [ # # ]: 0 : if (pCS->nCanonOrdIsotopicStereoTaut)
2368 : : {
2369 [ # # ]: 0 : if (0 < ( nRet = SortTautomerGroupsAndEndpoints( pCG, t_group_info1, num_atoms, num_at_tg, nCanonRankIsotopicStereo ) ))
2370 : : {
2371 : : /*non-isotopic contains symmetry ranks */
2372 : 0 : int num_t_groups = t_group_info1->num_t_groups;
2373 : 0 : AT_NUMB *tGroupNumber = t_group_info1->tGroupNumber;
2374 : : /*AT_NUMB *tiSymmRank = tGroupNumber + TGSO_SYMM_IRANK*num_t_groups; */
2375 : 0 : memcpy(pCS->nCanonOrdIsotopicStereoTaut, tGroupNumber, num_t_groups * sizeof(pCS->nCanonOrdIsotopicStereoTaut[0]));
2376 [ # # ]: 0 : pCS->nLenCanonOrdIsotopicStereoTaut = bFailed ? -num_t_groups : num_t_groups;
2377 : :
2378 : : /*SortTautomerGroupsAndEndpoints( t_group_info1, nCanonRank ); */ /* ??? return to non-isotopic canonical numbering */
2379 : : }
2380 : : else
2381 : : {
2382 [ # # # # ]: 0 : if (RETURNED_ERROR(nRet))
2383 : : {
2384 : 0 : goto exit_function;
2385 : : }
2386 : : }
2387 : : /* djb-rwth: removing redundant code */
2388 : : }
2389 : : }
2390 : : }
2391 : :
2392 : : /**********************************************************
2393 : : *
2394 : : * VII-B. Optimize INVERTED isotopic stereo descriptors
2395 : : *
2396 : : **********************************************************/
2397 [ # # ]: 0 : if (!nCanonRankIsotopicStereoInv)
2398 : 0 : nCanonRankIsotopicStereoInv = (AT_RANK *) qmalloc( num_max * sizeof( *nCanonRankIsotopicStereoInv ) );
2399 [ # # ]: 0 : if (!nCanonRankIsotopicStereoInv)
2400 : : {
2401 : 0 : nRet = CT_OUT_OF_RAM; /* <BRKPT> */
2402 : 0 : goto exit_function;
2403 : : }
2404 : :
2405 : : /* copy previous isotopic stereo canonicalization results to Inv initial data */
2406 : : /* assign pointers */
2407 : 0 : pCS->LinearCTStereoDble = pCS2->LinearCTIsotopicStereoDbleInv; /* enable stereo */
2408 : 0 : pCS->LinearCTStereoCarb = pCS2->LinearCTIsotopicStereoCarbInv;
2409 : :
2410 : : /* copy the lengths */
2411 : 0 : pCS2->nLenLinearCTIsotopicStereoDbleInv =
2412 : 0 : pCS->nLenLinearCTStereoDbleInv =
2413 : 0 : pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTIsotopicStereoDble;
2414 : :
2415 : 0 : pCS2->nLenLinearCTIsotopicStereoCarbInv =
2416 : 0 : pCS->nLenLinearCTStereoCarbInv =
2417 : 0 : pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTIsotopicStereoCarb;
2418 : :
2419 [ # # # # ]: 0 : if (pCS->nLenLinearCTStereoDble > 0 || pCS->nLenLinearCTStereoCarb > 0)
2420 : : {
2421 : : /* copy previous results, the canonical stereo CT */
2422 : 0 : memcpy(pCS->LinearCTStereoDble, pCS2->LinearCTIsotopicStereoDble, pCS->nLenLinearCTStereoDble * sizeof(pCS->LinearCTStereoDble[0]));
2423 : 0 : memcpy(pCS->LinearCTStereoCarb, pCS2->LinearCTIsotopicStereoCarb, pCS->nLenLinearCTStereoCarb * sizeof(pCS->LinearCTStereoCarb[0]));
2424 : : }
2425 : 0 : memcpy(nCanonRankIsotopicStereoInv, nCanonRankIsotopicStereo, num_max * sizeof(nCanonRankIsotopicStereoInv[0]));
2426 [ # # # # ]: 0 : if (pCS->nCanonOrdIsotopicStereoInv && pCS->nCanonOrdIsotopicStereo)
2427 : : {
2428 : : /* in case there is nothing to invert */
2429 : 0 : memcpy(pCS->nCanonOrdIsotopicStereoInv, pCS->nCanonOrdIsotopicStereo, num_at_tg * sizeof(pCS->nCanonOrdIsotopicStereoInv[0]));
2430 : : }
2431 : :
2432 : : /******************************
2433 : : *
2434 : : * Invert isotopic stereo
2435 : : *
2436 : : ******************************/
2437 : :
2438 : : /*********************************************************************************
2439 : : * Create initial approximation for the minimization of the stereo descriptors:
2440 : : * invert stereogenic atom parities, one parity in each allene, all parities in
2441 : : * pCS->LinearCTStereoCarb and allene parities in pCS->nLenLinearCTStereoDble
2442 : : */
2443 : :
2444 : 0 : nRet = InvertStereo( at,
2445 : : num_at_tg,
2446 : : nCanonRankIsotopicStereo,
2447 : : nTempRank,
2448 : : pCS,
2449 : : 1 );
2450 : :
2451 [ # # # # ]: 0 : if (RETURNED_ERROR( nRet ))
2452 : : {
2453 : 0 : goto exit_function;
2454 : : }
2455 [ # # ]: 0 : else if (nRet > 0)
2456 : : {
2457 : : /* InvertStereo() has done some changes */
2458 : : /* djb-rwth: removing redundant code */
2459 : : /* FillOutStereoParities() has already been called to fill out these 2 LinearCTs */
2460 : :
2461 : : /* set the 1st ranks in the rest of the stack to zero: prepare for ranks reuse */
2462 [ # # # # ]: 0 : for (n = 2; n < nRankStackLen && pRankStack1[n]; n++)
2463 : : {
2464 : 0 : pRankStack1[n][0] = 0; /* means ranks have to be recalculated */
2465 : : }
2466 : : /* set the 1st ranks to zero: prepare for ranks reuse */
2467 [ # # # # ]: 0 : for (n = 2; n < nRankStackLen && pRankStack2[n]; n++)
2468 : : {
2469 : 0 : pRankStack2[n][0] = 0; /* means ranks have to be recalculated */
2470 : : }
2471 : : /* for debugging or statistics */
2472 : 0 : pCS->lNumBreakTies =
2473 : 0 : pCS->lNumNeighListIter =
2474 : 0 : pCS->lNumTotCT =
2475 : 0 : pCS->lNumDecreasedCT =
2476 : 0 : pCS->lNumRejectedCT =
2477 : 0 : pCS->lNumEqualCT = 0;
2478 : 0 : pCS->bKeepSymmRank = 0;
2479 : 0 : pCS->bFirstCT = 1; /* To fill out nCanonRankStereo[] in map_stero_atoms2() */
2480 : :
2481 : : /**************************************************************************************
2482 : : nCanonRankIsotopic contains input canonical numbering
2483 : : nCanonRankIsotopicStereo will be filled with a transposition of canonical numbering
2484 : : that (1) keeps connection table unchanged and
2485 : : (2) provides minimal stereo descriptors in
2486 : : pCS->LinearCTStereoDble (length=pCS->nLenLinearCTStereoDble)
2487 : : pCS->LinearCTStereoCarb (length=pCS->nLenLinearCTStereoCarb)
2488 : : */
2489 : 0 : nRet = map_stereo_bonds4( ic, pCG,
2490 : : at,
2491 : : num_atoms,
2492 : : num_at_tg,
2493 : : num_max,
2494 : : 0,
2495 : 0 : ftcn->PartitionCtIso.Rank,
2496 : 0 : ftcn->PartitionCtIso.AtNumber,
2497 : : nCanonRankIsotopicStereoInv,
2498 : : nSymmRank,
2499 : : pRankStack1,
2500 : : pRankStack2,
2501 : : nTempRank,
2502 : : nNumCurrRanks,
2503 : : nSymmStereo,
2504 : : NeighList,
2505 : : pCS,
2506 : : cur_tree,
2507 : : 0,
2508 : : vABParityUnknown );
2509 : :
2510 [ # # # # ]: 0 : if (RETURNED_ERROR( nRet ))
2511 : : {
2512 [ # # ]: 0 : if (nRet == CT_TIMEOUT_ERR)
2513 : 0 : goto exit_function;
2514 : : else
2515 : 0 : goto exit_function; /* program error */
2516 : : }
2517 : : else
2518 : : {
2519 : 0 : int bFailed = 0;
2520 : :
2521 [ # # ]: 0 : if (!nRet)
2522 : : {
2523 : : /* djb-rwth: removing redundant code */
2524 : 0 : pCS2->nLenLinearCTIsotopicStereoDble =
2525 : 0 : pCS->nLenLinearCTIsotopicStereoDble = -abs( pCS->nLenLinearCTStereoDble );
2526 : 0 : pCS2->nLenLinearCTIsotopicStereoCarb =
2527 : 0 : pCS->nLenLinearCTIsotopicStereoCarb = -abs( pCS->nLenLinearCTStereoCarb );
2528 : 0 : nRet = CT_STEREOCOUNT_ERR; /* <BRKPT> */
2529 : 0 : goto exit_function; /* program error */
2530 : : }
2531 : :
2532 : : /* save isotopic pointers & lengths for INVERTED stereo */
2533 : :
2534 : : /* save isotopic lengths */
2535 : 0 : pCS->nLenLinearCTIsotopicStereoDbleInv =
2536 : 0 : pCS2->nLenLinearCTIsotopicStereoDbleInv = pCS->nLenLinearCTStereoDble;
2537 : 0 : pCS->nLenLinearCTIsotopicStereoCarbInv =
2538 : 0 : pCS2->nLenLinearCTIsotopicStereoCarbInv = pCS->nLenLinearCTStereoCarb;
2539 : :
2540 : : /* restore pointers and lengths to non-inverted isotopic stereo */
2541 : : /* -- this is needed for InvertStereo() back, see below */
2542 : 0 : pCS->LinearCTStereoDble = pCS2->LinearCTIsotopicStereoDble;
2543 : 0 : pCS->LinearCTStereoCarb = pCS2->LinearCTIsotopicStereoCarb;
2544 : 0 : pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTIsotopicStereoDble;
2545 : 0 : pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTIsotopicStereoCarb;
2546 : :
2547 : : /* consistency check */
2548 [ # # ]: 0 : if (pCS->nLenLinearCTIsotopicStereoDbleInv != pCS->nLenLinearCTIsotopicStereoDble ||
2549 [ # # ]: 0 : pCS->nLenLinearCTIsotopicStereoCarbInv != pCS->nLenLinearCTIsotopicStereoCarb)
2550 : : {
2551 : 0 : nRet = CT_CALC_STEREO_ERR;
2552 : 0 : goto exit_function; /* program error */
2553 : : }
2554 : :
2555 : : /******************************
2556 : : *
2557 : : * Invert stereo back
2558 : : *
2559 : : ******************************
2560 : : * (make sure that pointers
2561 : : * pCS->LinearCTStereoCarb,
2562 : : * pCS->LinearCTStereoDble
2563 : : * and corresponding lengths
2564 : : * have been restored)
2565 : : ******************************/
2566 : :
2567 : 0 : nRet = InvertStereo( at, num_at_tg, nCanonRankIsotopicStereo,
2568 : : nTempRank, pCS, 0 );
2569 : :
2570 [ # # # # ]: 0 : if (RETURNED_ERROR( nRet ))
2571 : : {
2572 : 0 : goto exit_function;
2573 : : }
2574 : 0 : nRet = 0;
2575 : :
2576 : : /* save stereo canonical numbering */
2577 [ # # ]: 0 : if (pCS->nCanonOrdIsotopicStereoInv)
2578 : : {
2579 [ # # ]: 0 : for (i = 0; i < num_at_tg; i++) /* djb-rwth: removing redundant code */
2580 : : {
2581 [ # # # # ]: 0 : if (nCanonRankIsotopicStereoInv[i] && (int) nCanonRankIsotopicStereoInv[i] <= num_at_tg)
2582 : : {
2583 : 0 : pCS->nCanonOrdIsotopicStereoInv[(int) nCanonRankIsotopicStereoInv[i] - 1] = (AT_NUMB) i;
2584 : : }
2585 : : else
2586 : : {
2587 : 0 : bFailed++;
2588 : : }
2589 : : }
2590 [ # # ]: 0 : pCS->nLenCanonOrdIsotopicStereo = bFailed ? -num_atoms : num_atoms;
2591 : : }
2592 : :
2593 : : /* compare inverted and non-inverted isotopic stereo */
2594 : 0 : pCS->bCmpIsotopicStereo = 2 + CompareLinCtStereo(
2595 : : pCS->LinearCTIsotopicStereoDbleInv, pCS->nLenLinearCTIsotopicStereoDbleInv,
2596 : : pCS->LinearCTIsotopicStereoCarbInv, pCS->nLenLinearCTIsotopicStereoCarbInv,
2597 : : pCS->LinearCTIsotopicStereoDble, pCS->nLenLinearCTIsotopicStereoDble,
2598 : : pCS->LinearCTIsotopicStereoCarb, pCS->nLenLinearCTIsotopicStereoCarb
2599 : : );
2600 : : }
2601 : : }
2602 [ # # ]: 0 : else if (0 == nRet)
2603 : : {
2604 : : /* nothing has been done, restore pointers and lengths for stereo */
2605 : 0 : pCS->LinearCTStereoDble = pCS2->LinearCTIsotopicStereoDble;
2606 : 0 : pCS->LinearCTStereoCarb = pCS2->LinearCTIsotopicStereoCarb;
2607 : 0 : pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTIsotopicStereoDble;
2608 : 0 : pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTIsotopicStereoCarb;
2609 : : }
2610 : :
2611 : :
2612 : 0 : bypass_isotopic_stereo:; /* ??? */
2613 : :
2614 : 0 : pCS->LinearCTIsotopic = pCS2->LinearCTIsotopic;
2615 : : }
2616 : :
2617 : :
2618 : :
2619 : 58 : exit_function:
2620 : :
2621 [ - + ]: 161 : if (bSwitchedAtomToIsotopic)
2622 : : {
2623 : 0 : SwitchAtomStereoAndIsotopicStereo( at, num_atoms, &bSwitchedAtomToIsotopic );
2624 : 0 : SetCtToNonIsotopicStereo( pCS, pCS2 ); /* ??? */
2625 : : }
2626 : :
2627 : : /* restore non-isotopic connection table */
2628 [ + - ]: 161 : if (pCS->LinearCT2)
2629 : : {
2630 : 161 : inchi_swap( (char*) &pCS->LinearCT, (char*) &pCS->LinearCT2, sizeof( pCS->LinearCT ) );
2631 : 161 : inchi_swap( (char*) &pCS->nLenLinearCT, (char*) &pCS->nLenLinearCT2, sizeof( pCS->nLenLinearCT ) );
2632 : 161 : inchi_swap( (char*) &pCS->nLenLinearCTAtOnly, (char*) &pCS->nLenLinearCTAtOnly2, sizeof( pCS->nLenLinearCTAtOnly ) );
2633 : : }
2634 : :
2635 : : /* free memory */
2636 : 161 : i = 2;
2637 [ + - ]: 161 : if (pRankStack1)
2638 : : {
2639 : 161 : pRankStack1[0] =
2640 : 161 : pRankStack1[1] = NULL; /* deallocated separately */
2641 [ + - + + ]: 378 : for (; i < nRankStackLen && pRankStack1[i]; i++)
2642 : : {
2643 : : ;
2644 : : }
2645 : : }
2646 [ + - + + ]: 161 : if (pRankStack1 && pRankStack2)
2647 : : {
2648 [ + - + + ]: 185 : for (n = 2; n < nRankStackLen && pRankStack2[n]; n++)
2649 : : {
2650 [ + - ]: 127 : if (i < nRankStackLen - 1)
2651 : : {
2652 : 127 : pRankStack1[i++] = pRankStack2[n];
2653 : : }
2654 : : else
2655 : : {
2656 [ # # ]: 0 : inchi_free( pRankStack2[n] );
2657 : : }
2658 : : }
2659 : : }
2660 : :
2661 [ + + ]: 161 : inchi_free(pRankStack2); /* djb-rwth: fixing coverity ID #499631 */
2662 : :
2663 : 161 : pCS->NeighList = NULL; /* keep the pointer in pBCN->ftcn[bTaut].NeighList for further deallocation */
2664 [ + + + - ]: 161 : qfree( nAtomNumber );
2665 [ + + + - ]: 161 : qfree( nTempRank );
2666 [ + + + - ]: 161 : qfree( nRank );
2667 [ + + + - ]: 161 : qfree( nSymmRank );
2668 : :
2669 [ + + + - ]: 161 : qfree( nSymmStereo );
2670 : 161 : CurTreeFree( cur_tree );
2671 : : /* memory leak fix */
2672 : : /*
2673 : : qfree ( nCurrRankIsotopicStereo );
2674 : : qfree ( nAtomNumberCurrIsotopicStereo);
2675 : : */
2676 [ - + - - ]: 161 : qfree( nCanonRankIsotopicStereo );
2677 [ - + - - ]: 161 : qfree( nCanonRankIsotopicStereoInv );
2678 : :
2679 [ + + + - ]: 161 : qfree( nCanonRankStereo );
2680 [ + + + - ]: 161 : qfree( nCanonRankStereoInv );
2681 : :
2682 : 161 : InchiTimeGet( &ulEndTime );
2683 : :
2684 : 161 : pCS->lTotalTime = InchiTimeMsecDiff( ic, &ulEndTime, &ulStartTime );
2685 : :
2686 [ + - ]: 161 : return ( nRet >= -1 ) ? num_atoms : nRet;
2687 : : /* cannot easily get number of ranks for now */
2688 : : }
2689 : :
2690 : :
2691 : : /****************************************************************************/
2692 : 161 : int Canon_INChI( INCHI_CLOCK *ic,
2693 : : int num_atoms,
2694 : : int num_at_tg,
2695 : : sp_ATOM* at,
2696 : : CANON_STAT* pCS,
2697 : : CANON_GLOBALS *pCG,
2698 : : INCHI_MODE nMode,
2699 : : int bTautFtcn )
2700 : : {
2701 [ + - + - ]: 161 : if (pCS->pBCN && !pCS->NeighList)
2702 : : {
2703 : 161 : return Canon_INChI3( ic, num_atoms, num_at_tg, at, pCS, pCG, nMode, bTautFtcn );
2704 : : }
2705 : :
2706 : 0 : return CT_CANON_ERR;
2707 : : }
|