2
* International Chemical Identifier (InChI)
4
* Software version 1.04
7
* The InChI library and programs are free software developed under the
8
* auspices of the International Union of Pure and Applied Chemistry (IUPAC).
9
* Originally developed at NIST. Modifications and additions by IUPAC
10
* and the InChI Trust.
12
* IUPAC/InChI-Trust Licence for the International Chemical Identifier (InChI)
13
* Software version 1.0.
14
* Copyright (C) IUPAC and InChI Trust Limited
16
* This library is free software; you can redistribute it and/or modify it under the
17
* terms of the IUPAC/InChI Trust Licence for the International Chemical Identifier
18
* (InChI) Software version 1.0; either version 1.0 of the License, or
19
* (at your option) any later version.
21
* This library is distributed in the hope that it will be useful,
22
* but WITHOUT ANY WARRANTY; without even the implied warranty of
23
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
24
* See the IUPAC/InChI Trust Licence for the International Chemical Identifier (InChI)
25
* Software version 1.0 for more details.
27
* You should have received a copy of the IUPAC/InChI Trust Licence for the
28
* International Chemical Identifier (InChI) Software version 1.0 along with
29
* this library; if not, write to:
32
* c/o FIZ CHEMIE Berlin
55
#define MAP_MODE_STD 0 /* Standard approach: switch 2 neighbors */
56
#define MAP_MODE_C2v 1 /* Check for C2v reflection leading to parity inversion */
57
#define MAP_MODE_C2 2 /* Check for C2 rotation preserving parities */
58
#define MAP_MODE_S4 3 /* Check for S4 rotation/reflection leading to parity inversion */
59
/* important: MAP_MODE_STD < (MAP_MODE_C2v, MAP_MODE_C2) < MAP_MODE_S4 */
61
/* local prototypes */
62
void DeAllocateForNonStereoRemoval( AT_RANK **nAtomNumberCanon1, AT_RANK **nAtomNumberCanon2,
63
NEIGH_LIST **nl, NEIGH_LIST **nl1, NEIGH_LIST **nl2, AT_RANK **nVisited1, AT_RANK **nVisited2 );
64
int AllocateForNonStereoRemoval( sp_ATOM *at, int num_atoms, const AT_RANK *nSymmRank, AT_RANK *nCanonRank,
65
AT_RANK **nAtomNumberCanon1, AT_RANK **nAtomNumberCanon2,
66
NEIGH_LIST **nl, NEIGH_LIST **nl1, NEIGH_LIST **nl2, AT_RANK **nVisited1, AT_RANK **nVisited2 );
67
AT_RANK GetMinNewRank(AT_RANK *nAtomRank, AT_RANK *nAtomNumb, AT_RANK nRank1 );
68
int BreakNeighborsTie( sp_ATOM *at, int num_atoms, int num_at_tg, int ib, int ia,
69
AT_RANK *neigh_num, int in1, int in2, int mode,
70
AT_RANK **pRankStack1, AT_RANK **pRankStack2, AT_RANK *nTempRank, NEIGH_LIST *NeighList,
71
const AT_RANK *nSymmRank, AT_RANK *nCanonRank, NEIGH_LIST *nl1, NEIGH_LIST *nl2, long *lNumIter );
72
int CheckNextSymmNeighborsAndBonds( sp_ATOM *at, AT_RANK cur1, AT_RANK cur2, AT_RANK n1, AT_RANK n2,
73
AT_RANK *nAvoidCheckAtom, AT_RANK *nVisited1, AT_RANK *nVisited2,
74
AT_RANK *nVisitOrd1, AT_RANK *nVisitOrd2, const AT_RANK *nRank1, const AT_RANK *nRank2 );
75
int CreateCheckSymmPaths( sp_ATOM *at, AT_RANK prev1, AT_RANK cur1, AT_RANK prev2, AT_RANK cur2,
76
AT_RANK *nAvoidCheckAtom, AT_RANK *nVisited1, AT_RANK *nVisited2,
77
AT_RANK *nVisitOrd1, AT_RANK *nVisitOrd2,
78
NEIGH_LIST *nl1, NEIGH_LIST *nl2, const AT_RANK *nRank1, const AT_RANK *nRank2,
79
AT_RANK *nCanonRank, AT_RANK *nLength, int *bParitiesInverted, int mode );
80
int CalculatedPathsParitiesAreIdentical( sp_ATOM *at, int num_atoms, const AT_RANK *nSymmRank,
81
AT_RANK *nCanonRank, AT_RANK *nAtomNumberCanon, AT_RANK *nAtomNumberCanon1, AT_RANK *nAtomNumberCanon2,
82
AT_RANK *nVisited1, AT_RANK *nVisited2,
83
AT_RANK prev_sb_neigh, AT_RANK cur, AT_RANK next1, AT_RANK next2, int nNeighMode,
84
int bParitiesInverted, int mode, CANON_STAT *pCS,
85
int vABParityUnknown);
86
int RemoveCalculatedNonStereoBondParities( sp_ATOM *at, int num_atoms, int num_at_tg,
87
AT_RANK **pRankStack1, AT_RANK **pRankStack2, AT_RANK *nTempRank, NEIGH_LIST *NeighList,
88
AT_RANK *nCanonRank, const AT_RANK *nSymmRank,
89
AT_RANK *nAtomNumberCanon, AT_RANK *nAtomNumberCanon1, AT_RANK *nAtomNumberCanon2,
90
NEIGH_LIST *nl, NEIGH_LIST *nl1, NEIGH_LIST *nl2,
91
AT_RANK *nVisited1, AT_RANK *nVisited2, CANON_STAT *pCS,
92
int vABParityUnknown);
93
int RemoveCalculatedNonStereoCenterParities( sp_ATOM *at, int num_atoms, int num_at_tg,
94
AT_RANK **pRankStack1, AT_RANK **pRankStack2, AT_RANK *nTempRank, NEIGH_LIST *NeighList,
95
AT_RANK *nCanonRank, const AT_RANK *nSymmRank,
96
AT_RANK *nAtomNumberCanon, AT_RANK *nAtomNumberCanon1, AT_RANK *nAtomNumberCanon2,
97
NEIGH_LIST *nl, NEIGH_LIST *nl1, NEIGH_LIST *nl2,
98
AT_RANK *nVisited1, AT_RANK *nVisited2, CANON_STAT *pCS,
99
int vABParityUnknown);
101
int SortNeighLists3( int num_atoms, AT_RANK *nRank, NEIGH_LIST *NeighList, AT_RANK *nAtomNumber );
107
/**************************************************************************************
109
* Convert sorted equivalence information (nSymmRank) to ranks (nRank)
110
* nSymmRank and nRank may point to the same array
113
int SortedEquInfoToRanks( const AT_RANK* nSymmRank, AT_RANK* nRank, const AT_RANK* nAtomNumber, int num_atoms, int *bChanged )
115
AT_RANK rNew, rOld, nNumDiffRanks;
116
int i, j, nNumChanges = 0;
117
for ( i = num_atoms-1, j = (int)nAtomNumber[i],
118
rOld = nSymmRank[j], rNew = nRank[j] = (AT_RANK)num_atoms,
123
j = (int)nAtomNumber[i-1];
125
if ( nSymmRank[j] != rOld ) {
128
nNumChanges += (rOld != rNew+1);
135
*bChanged = (0 != nNumChanges);
137
return nNumDiffRanks;
139
/**************************************************************************************
141
* Convert sorted ranks (nRank) to sorted equivalence information (nSymmRank)
142
* nSymmRank and nRank may point to the same array
145
int SortedRanksToEquInfo( AT_RANK* nSymmRank, const AT_RANK* nRank, const AT_RANK* nAtomNumber, int num_atoms )
147
AT_RANK rNew, rOld, nNumDiffRanks;
149
for ( i = 1, j = (int)nAtomNumber[0],
150
rOld = nRank[j], rNew = nSymmRank[j] = 1,
154
j = (int)nAtomNumber[i];
155
if ( nRank[j] != rOld ) {
157
rNew = (AT_RANK)(i+1);
162
return nNumDiffRanks;
165
/**************************************************************************************/
166
void switch_ptrs( AT_RANK **p1, AT_RANK **p2 )
173
/**************************************************************************************/
174
/* Set ranks from the products vector and previous ranks */
175
/* nRank[] and nNewRank[] should refer to different arrays for now */
176
/**************************************************************************************/
177
int SetNewRanksFromNeighLists3( int num_atoms, NEIGH_LIST *NeighList, AT_RANK *nRank,
178
AT_RANK *nNewRank, AT_RANK *nAtomNumber )
180
int i, j, nNumDiffRanks, nNumNewRanks;
182
/* -- nAtomNumber[] is already properly set --
183
for ( i = 0; i < num_atoms; i++ ) {
184
nAtomNumber[i] = (AT_RANK)i;
187
/* set globals for qsort */
188
pNeighList_RankForSort = NeighList;
189
pn_RankForSort = nRank;
193
memset(nNewRank, 0, num_atoms*sizeof(nNewRank[0]));
196
for ( i = 0, r1 = 1; i < num_atoms; r1++ ) {
197
if ( r1 == (r2 = nRank[j=(int)nAtomNumber[i]]) ) {
204
insertions_sort_AT_NUMBERS( nAtomNumber+i, (int)r2-i, CompNeighLists );
205
/*insertions_sort( nAtomNumber+i, r2-i, sizeof( nAtomNumber[0] ), CompNeighLists );*/
207
nNewRank[(int)nAtomNumber[j]] = r2;
210
if ( CompareNeighListLex( NeighList[(int)nAtomNumber[j-1]],
211
NeighList[(int)nAtomNumber[j]], nRank ) ) {
217
nNewRank[(int)nAtomNumber[j]] = r2;
221
return nNumNewRanks? -nNumDiffRanks : nNumDiffRanks;
223
/**************************************************************************************/
224
/* Set ranks from the products vector and previous ranks */
225
/* When comparing neigh lists ignore ranks > max_at_no */
226
/* nRank[] and nNewRank[] should refer to different arrays for now */
227
/**************************************************************************************/
228
int SetNewRanksFromNeighLists4( int num_atoms, NEIGH_LIST *NeighList, AT_RANK *nRank,
229
AT_RANK *nNewRank, AT_RANK *nAtomNumber, AT_RANK nMaxAtRank )
231
int i, j, nNumDiffRanks, nNumNewRanks;
233
/* -- nAtomNumber[] is already properly set --
234
for ( i = 0; i < num_atoms; i++ ) {
235
nAtomNumber[i] = (AT_RANK)i;
238
/* set globals for CompNeighListsUpToMaxRank */
239
pNeighList_RankForSort = NeighList;
240
pn_RankForSort = nRank;
243
nMaxAtNeighRankForSort = nMaxAtRank;
245
memset(nNewRank, 0, num_atoms*sizeof(nNewRank[0]));
248
for ( i = 0, r1 = 1; i < num_atoms; r1++ ) {
249
if ( r1 == (r2 = nRank[j=(int)nAtomNumber[i]]) ) {
250
/* non-tied rank: singleton */
257
r2-i atoms have rank r2
258
next atom after them is in position r2
261
insertions_sort_AT_NUMBERS( nAtomNumber+i, (int)r2-i, CompNeighListsUpToMaxRank );
262
/*insertions_sort( nAtomNumber+i, r2-i, sizeof( nAtomNumber[0] ), CompNeighListsUpToMaxRank );*/
263
j = r2-1; /* prepare cycle backward, from j to i step -1 */
264
nNewRank[(int)nAtomNumber[j]] = r2;
267
if ( CompareNeighListLexUpToMaxRank( NeighList[nAtomNumber[j-1]],
268
NeighList[nAtomNumber[j]], nRank, nMaxAtRank ) ) {
274
nNewRank[(int)nAtomNumber[j]] = r2;
278
return nNumNewRanks? -nNumDiffRanks : nNumDiffRanks;
280
/**************************************************************************************/
281
/* Set ranks from the products vector and previous ranks */
282
/* nRank[] and nNewRank[] should refer to different arrays for now */
283
/**************************************************************************************/
284
int SetNewRanksFromNeighLists( int num_atoms, NEIGH_LIST *NeighList, AT_RANK *nRank, AT_RANK *nNewRank,
285
AT_RANK *nAtomNumber, int bUseAltSort, int ( *comp )(const void *, const void *) )
287
int i, nNumDiffRanks;
288
AT_RANK nCurrentRank;
289
/* -- nAtomNumber[] is already properly set --
290
for ( i = 0; i < num_atoms; i++ ) {
291
nAtomNumber[i] = (AT_RANK)i;
294
/* set globals for qsort */
295
pNeighList_RankForSort = NeighList;
296
pn_RankForSort = nRank;
299
if ( bUseAltSort & 1 )
300
tsort( nAtomNumber, num_atoms, sizeof( nAtomNumber[0] ), comp /*CompNeighListRanksOrd*/ );
302
qsort( nAtomNumber, num_atoms, sizeof( nAtomNumber[0] ), comp /*CompNeighListRanksOrd*/ );
304
for ( i=num_atoms-1, nCurrentRank=nNewRank[(int)nAtomNumber[i]] = (AT_RANK)num_atoms, nNumDiffRanks = 1;
307
/* Note: CompNeighListRanks() in following line implicitly reads nRank pointed by pn_RankForSort */
308
if ( CompNeighListRanks( &nAtomNumber[i-1], &nAtomNumber[i] ) ) {
310
nCurrentRank = (AT_RANK)i;
312
nNewRank[(int)nAtomNumber[i - 1]] = nCurrentRank;
315
return nNumDiffRanks;
317
/**************************************************************************************/
318
/* Sort NeighList[] lists of neighbors according to the ranks of the neighbors */
319
/**************************************************************************************/
320
void SortNeighListsBySymmAndCanonRank( int num_atoms, NEIGH_LIST *NeighList, const AT_RANK *nSymmRank, const AT_RANK *nCanonRank )
323
for ( i = 0; i < num_atoms; i ++ ) {
324
insertions_sort_NeighListBySymmAndCanonRank( NeighList[i], nSymmRank, nCanonRank );
327
/**************************************************************************************/
328
int SortNeighLists2( int num_atoms, AT_RANK *nRank, NEIGH_LIST *NeighList, AT_RANK *nAtomNumber )
331
AT_RANK nPrevRank = 0;
333
* on entry nRank[nAtomNumber[k]] <= nRank[nAtomNumber[k+1]] ( k < num_atoms-1 )
334
* nRank[nAtomNumber[k]] >= k+1 ( k < num_atoms )
335
* nRank[nAtomNumber[k]] == k+1 if this nRank value is not tied OR if
336
* nRank[nAtomNumber[k]] < nRank[nAtomNumber[k+1]] OR if k = num_atoms-1.
339
for ( k = 0; k < num_atoms; k ++ ) {
341
if ( (nRank[i] != k+1 || nRank[i] == nPrevRank) && NeighList[i][0] > 1 ) {
342
/* nRank[i] is tied (duplicated) */
343
insertions_sort_NeighList_AT_NUMBERS( NeighList[i], nRank );
345
nPrevRank = nRank[i];
349
/**************************************************************************************/
350
int SortNeighLists3( int num_atoms, AT_RANK *nRank, NEIGH_LIST *NeighList, AT_RANK *nAtomNumber )
353
AT_RANK nPrevRank = 0;
355
* on entry nRank[nAtomNumber[k]] <= nRank[nAtomNumber[k+1]] ( k < num_atoms-1 )
356
* nRank[nAtomNumber[k]] >= k+1 ( k < num_atoms )
357
* nRank[nAtomNumber[k]] == k+1 if this nRank value is not tied OR if
358
* nRank[nAtomNumber[k]] < nRank[nAtomNumber[k+1]] OR if k = num_atoms-1.
361
for ( k = 0; k < num_atoms; k ++ ) {
363
if ( (nRank[i] != k+1 || nRank[i] == nPrevRank) && NeighList[i][0] > 1 ) {
364
/* nRank[i] is tied (duplicated) */
365
insertions_sort_NeighList_AT_NUMBERS3( NeighList[i], nRank );
367
nPrevRank = nRank[i];
371
/**************************************************************************************
375
* Note: on entry nAtomNumber[] must contain a valid transposition of num_atoms length
376
* for example, nAtomNumber[i] = i;
377
* Note2: this version does not calculate neighbor lists for non-tied ranks
379
int DifferentiateRanks2( int num_atoms, NEIGH_LIST *NeighList,
380
int nNumCurrRanks, AT_RANK *pnCurrRank, AT_RANK *pnPrevRank,
381
AT_RANK *nAtomNumber, long *lNumIter, int bUseAltSort )
383
/*int nNumPrevRanks;*/
385
/* SortNeighLists2 needs sorted ranks */
386
pn_RankForSort = pnCurrRank;
387
if ( bUseAltSort & 1 )
388
tsort( nAtomNumber, num_atoms, sizeof(nAtomNumber[0]), CompRank /* CompRanksOrd*/ );
390
qsort( nAtomNumber, num_atoms, sizeof(nAtomNumber[0]), CompRanksOrd );
394
/*nNumPrevRanks = nNumCurrRanks;*/
395
switch_ptrs( &pnCurrRank, &pnPrevRank );
396
SortNeighLists2( num_atoms, pnPrevRank, NeighList, nAtomNumber );
397
/* the following call creates pnCurrRank out of pnPrevRank */
398
nNumCurrRanks = SetNewRanksFromNeighLists( num_atoms, NeighList, pnPrevRank, pnCurrRank, nAtomNumber,
399
1, CompNeighListRanksOrd );
400
} while ( /*nNumPrevRanks != nNumCurrRanks ||*/ memcmp( pnPrevRank, pnCurrRank, num_atoms*sizeof(pnCurrRank[0]) ) );
402
return nNumCurrRanks;
404
/**************************************************************************************
408
* Note: on entry nAtomNumber[] must contain a valid transposition of num_atoms length
409
* for example, nAtomNumber[i] = i;
410
* Note2: this version does not calculate neighbor lists for non-tied ranks
412
int DifferentiateRanks3( int num_atoms, NEIGH_LIST *NeighList,
413
int nNumCurrRanks, AT_RANK *pnCurrRank, AT_RANK *pnPrevRank,
414
AT_RANK *nAtomNumber, long *lNumIter )
417
static long count = 0;
419
if ( count == 103 ) {
424
/* SortNeighLists3 needs sorted ranks: ranks/atnumbers must have been already sorted */
427
switch_ptrs( &pnCurrRank, &pnPrevRank );
428
SortNeighLists3( num_atoms, pnPrevRank, NeighList, nAtomNumber );
429
/* the following call creates pnCurrRank out of pnPrevRank */
430
nNumCurrRanks = SetNewRanksFromNeighLists3( num_atoms, NeighList, pnPrevRank,
431
pnCurrRank, nAtomNumber);
432
} while ( nNumCurrRanks < 0 /* memcmp( pnPrevRank, pnCurrRank, num_atoms*sizeof(pnCurrRank[0]) )*/ );
434
return nNumCurrRanks;
436
/**************************************************************************************
438
* Differentiate4: ignore neighbors with rank > num_atoms
440
* Note: on entry nAtomNumber[] must contain a valid transposition of num_atoms length
441
* for example, nAtomNumber[i] = i;
442
* Note2: this version does not sort neighbor lists for non-tied ranks
444
int DifferentiateRanks4( int num_atoms, NEIGH_LIST *NeighList,
445
int nNumCurrRanks, AT_RANK *pnCurrRank, AT_RANK *pnPrevRank,
446
AT_RANK *nAtomNumber, AT_RANK nMaxAtRank, long *lNumIter )
449
static long count = 0;
451
if ( count == 103 ) {
455
/* SortNeighLists4 needs sorted ranks: ranks/atnumbers must have been already sorted */
458
switch_ptrs( &pnCurrRank, &pnPrevRank );
459
SortNeighLists3( num_atoms, pnPrevRank, NeighList, nAtomNumber );
460
/* the following call creates pnCurrRank out of pnPrevRank */
461
nNumCurrRanks = SetNewRanksFromNeighLists4( num_atoms, NeighList, pnPrevRank,
462
pnCurrRank, nAtomNumber, nMaxAtRank );
463
} while ( nNumCurrRanks < 0 /* memcmp( pnPrevRank, pnCurrRank, num_atoms*sizeof(pnCurrRank[0]) )*/ );
465
return nNumCurrRanks;
467
/**************************************************************************************
469
* DifferentiateBasic (sort according to ranks only)
471
* Note: on entry nAtomNumber[] must contain a valid transposition of num_atoms length
472
* for example, nAtomNumber[i] = i;
473
* Note2: this version does not calculate neighbor lists for non-tied ranks
475
int DifferentiateRanksBasic( int num_atoms, NEIGH_LIST *NeighList,
476
int nNumCurrRanks, AT_RANK *pnCurrRank, AT_RANK *pnPrevRank,
477
AT_RANK *nAtomNumber, long *lNumIter, int bUseAltSort )
481
/* SortNeighLists2 needs sorted ranks */
482
pn_RankForSort = pnCurrRank;
483
if ( bUseAltSort & 1 )
484
tsort( nAtomNumber, num_atoms, sizeof(nAtomNumber[0]), CompRank );
486
qsort( nAtomNumber, num_atoms, sizeof(nAtomNumber[0]), CompRank );
490
nNumPrevRanks = nNumCurrRanks;
491
switch_ptrs( &pnCurrRank, &pnPrevRank );
492
SortNeighLists2( num_atoms, pnPrevRank, NeighList, nAtomNumber );
493
/* the following call creates pnCurrRank out of pnPrevRank */
494
nNumCurrRanks = SetNewRanksFromNeighLists( num_atoms, NeighList, pnPrevRank, pnCurrRank, nAtomNumber, bUseAltSort, CompNeighListRanks );
495
} while ( nNumPrevRanks != nNumCurrRanks || memcmp( pnPrevRank, pnCurrRank, num_atoms*sizeof(pnCurrRank[0]) ) );
496
return nNumCurrRanks;
499
/**************************************************************************************
500
* For the purpose of mapping an atom to an atom:
501
* (a) find number of tied ranks
502
* (b) if number of tied ranks > 1 then:
503
* 1) find the rank for breaking a tie
504
* 2) allocate memory for breaking the tie if it has not been allocated
505
* 3) find out if atom 1 ("from") has already been mapped
508
* = 1: has already been mapped, to tie to break
509
* > 1: we need to break a tie
511
int NumberOfTies( AT_RANK **pRankStack1, AT_RANK **pRankStack2, int length,
512
int at_no1, int at_no2, AT_RANK *nNewRank, int *bAddStack, int *bMapped1 )
515
AT_RANK *nRank1 = *pRankStack1++;
516
AT_RANK *nAtomNumber1 = *pRankStack1++; /* ranks for mapping "1", "from" */
518
AT_RANK *nRank2 = *pRankStack2++;
519
AT_RANK *nAtomNumber2 = *pRankStack2++; /* ranks for mapping "2", "to" */
521
AT_RANK r, *pTempArray;
529
if ( r != nRank2[at_no2] )
530
return CT_MAPCOUNT_ERR; /* atoms cannot be mapped onto each other: they have different ranks */ /* <BRKPT> */
532
/* find i1 and i2 = numbers of ranks in nRank1[] and nRank2[] equal to r: */
533
for ( i1 = 1; i1 <= iMax && r == nRank1[nAtomNumber1[iMax-i1]]; i1 ++ )
535
for ( i2 = 1; i2 <= iMax && r == nRank2[nAtomNumber2[iMax-i2]]; i2 ++ )
538
return CT_MAPCOUNT_ERR; /* program error: must be identical number of equal ranks */ /* <BRKPT> */
539
/* found i1 equal rank(s); preceding (smaller) non-equal rank is r-i1 */
540
/* To break the tie we have to reduce the rank r to r-i1+1 */
542
/************ Note *******************************
543
* IF ( i=r-1 && 0 <= i && i < num_atoms AND
544
* nRank[nAtomNumber1[i]] == r )
546
* nRank[nAtomNumber1[i+1]] > r; (if i+1 < num_atoms)
547
* nRank[nAtomNumber1[i-1]] <= r; (if i > 0)
549
* IF r = nRank[i] THEN
550
* nRank[nAtomNumber1[r-1]] == r
551
* nRank[nAtomNumber1[r-i-1]] <= nRank[nAtomNumber1[r-i]] (for 1 <= i < r )
554
/* int bAtFromHasAlreadyBeenMapped = 0; */
555
*nNewRank = r - i1 + 1;
556
/* grab an existing or allocate a new array */
557
/* we need 4 arrays: 2 for ranks + 2 for numbers */
558
for ( i = 0; i < 4; i ++ ) {
560
pTempArray = *pRankStack1;
561
*bMapped1 += (pTempArray && pTempArray[0]);
563
pTempArray = *pRankStack2;
565
if ( !pTempArray && !(pTempArray = (AT_RANK *) inchi_malloc(length)))
566
return CT_OUT_OF_RAM; /* out of RAM */ /* <BRKPT> */
567
/* copy "to" contents */
570
memcpy( pTempArray, nRank2, length );
573
memcpy( pTempArray, nAtomNumber2, length );
577
*pRankStack1 ++ = pTempArray;
579
*pRankStack2 ++ = pTempArray;
582
*bAddStack = 2; /* to break the tie we added 2 more arrays to pRankStack1 and pRankStack2 */
588
/**************************************************************************************
596
**************************************************************************************/
598
/**************************************************************************************
599
* Parity for a half of a stereo bond. If both halfs have the same parity
600
* then the bond is "trans" (E,-,1), otherwise it is "cis" (Z,+,2).
601
* The advantage of this approach is: The bond parity does not depend on the
602
* rank of the atom located on the opposite end of the stereogenic bond.
603
* As the result all bond parities of, for example, benzene, can be calculated
604
* from equivalence ranks only, without any mappings.
606
* Input: at_no1 = number of atom for which the half-bond parity is calculated
607
* i_sb_neigh = ordering number of the stereo bond in at->stereo_bond_neighbor[]
609
* Returns: 0=> no parity can be found; 1=> odd parity; 2=> even parity
612
int HalfStereoBondParity( sp_ATOM *at, int at_no1, int i_sb_neigh, const AT_RANK *nRank )
615
Suppose neighbors #0,#1,#2 have ranks a, b, c. Remove rank of the neighbor connected
616
by the stereogenic bond (NCSB) from the a, b, c list and denote the two left as r[0], r[1],
617
in the same order. Let iNCSB be an ordering number (0,1,or 2) of the NCSB.
618
Assume the neighbor connected by the stereogenic bond has infinite positive rank.
619
Position the half-bond so that the stereogenic bond neighbor is to the right from the atom (see below)
623
if rank(X) != rank(Y) then Half-bond parity = (rank(X) > rank(Y)), that is,
625
\ if ( rank(X) < rank(Y) ) then Half-bond parity is Even
626
C==NCSB if ( rank(X) > rank(Y) ) then Half-bond parity is Odd
627
/ if ( rank(X) = rank(Y) ) then Half-bond parity cannot be defined
632
C==NCSB C==NCSB C==NCSB C==NCSB
636
Parity = 1 Parity = 1 Parity = 2 Parity = 2
637
(Odd) (Odd) (Even) or 0 (Even) or 0
639
Half-bond parity = (iNCSB + (r[0] > r[1]) + (Atom C geometric parity))%2
641
Consider the following cases to prove the formula:
643
Case 1: 3 explicit neighbors
644
============================
645
If (1) atom's geometric parity = even (which means neighbors #0, #1, #2 are located clockwise),
646
and (2) neighbors other than NCSB have different ranks, then,
647
assuming that NCSB always has the largest (infinite) rank (this is consistent with
648
the assumption that implicit hydrogens have smallest ranks), we have 3 possibilities:
657
Half-bond parity = b>c a<c a>b (0=even, 1=odd)
658
r[0]>r[1] r[0]<r[1] r[0]>r[1]
660
for all 3 cases = (iNCSB + (r[0] > r[1]))%2
662
The following slight modification will work for both odd and even geometric parity:
664
Half-bond parity = (iNCSB + (r[0] > r[1]) + (Atom C geometric parity))%2
666
even parity (0) => atom above the bond has lower rank than the atom below the bond.
669
Case 2: 2 explicit neighbors
670
============================
671
One implicit hydrogen atom H or hydrogen isotope (implicit rank=0). Assume r[1]=0
673
H a Note. The same method
680
Half-bond parity = b>0 a<0
681
(r[1]=0, r[0]>0) r[0]>r[1] r[0]<r[1]
683
Half-bond parity = (iNCSB + (r[0] > r[1]) + (Atom C geometric parity))%2
685
Case 3: 1 explicit neighbor (NCSB)
686
==================================
687
Two implicit hydrogens, (number of neighbors on non-streogenic bonds)==0:
689
Atom C geometric parity: Even Odd Note. The same method
698
Half-bond parity = (0<0)=0 (0<0)+1 = 1
699
(r[1]=0, r[0]=0) r[1]<r[0] (r[1]<r[0])+atom_parity
702
for this case = (iNCSB + (r[0] > r[1]) + (Atom C geometric parity))%2
705
int i, j, k, iNeigh, parity, at1_parity, at_no2;
706
AT_RANK r[MAX_NUM_STEREO_BOND_NEIGH];
708
if ( at[at_no1].valence > MAX_NUM_STEREO_BOND_NEIGH || ( at1_parity = at[at_no1].parity ) <= 0 ) {
711
if ( !PARITY_WELL_DEF( at1_parity ) ) {
712
if ( PARITY_KNOWN( at1_parity ) ) {
717
if ( 0 > i_sb_neigh || i_sb_neigh >= MAX_NUM_STEREO_BOND_NEIGH ) {
718
return CT_STEREOBOND_ERROR; /* <BRKPT> */
720
for ( i = 0; i <= i_sb_neigh; i ++ ) {
721
if ( !at[at_no1].stereo_bond_neighbor[i] ) {
722
return CT_STEREOBOND_ERROR; /* <BRKPT> */
725
at_no2 = at[at_no1].neighbor[(int)at[at_no1].stereo_bond_ord[i_sb_neigh]];
726
memset( r, 0, sizeof( r ) );
727
for ( i = j = 0, iNeigh = -1; i < at[at_no1].valence; i ++ ) {
728
if ( (k = (int)at[at_no1].neighbor[i]) == at_no2 ) {
734
if ( iNeigh < 0 || iNeigh != at[at_no1].stereo_bond_ord[i_sb_neigh] ) {
735
return CT_STEREOBOND_ERROR; /* <BRKPT> */
737
if ( j > 0 && !r[0] || j > 1 && !r[1] )
738
return 0; /* undefined ranks */
740
if ( j == 2 && r[0] == r[1] || iNeigh < 0 ) {
741
parity = AB_PARITY_CALC; /* cannot calculate bond parity without additional breaking ties. */
743
parity = 2 - (at[at_no1].parity + iNeigh + (r[1] < r[0])) % 2;
747
/**************************************************************************************/
748
int parity_of_mapped_half_bond( int from_at, int to_at, int from_neigh, int to_neigh,
749
sp_ATOM *at, EQ_NEIGH *pEN,
750
const AT_RANK *nCanonRankFrom, const AT_RANK *nRankFrom, const AT_RANK *nRankTo )
752
int i, j, k, num_neigh;
753
int to_sb_neigh_ord, from_sb_neigh_ord, parity;
754
AT_RANK r_to[MAX_NUM_STEREO_BOND_NEIGH], at_no_to[MAX_NUM_STEREO_BOND_NEIGH];
755
AT_RANK r_canon_from[MAX_NUM_STEREO_BOND_NEIGH], at_no_from[MAX_NUM_STEREO_BOND_NEIGH];
756
AT_RANK r, r_sb_neigh;
758
for ( i = 0; i < MAX_NUM_STEREO_BOND_NEIGH; i ++ ) {
759
r_to[i] = r_canon_from[i] = 0;
763
memset( pEN, 0, sizeof(*pEN));
767
if ( nRankFrom[from_at] != nRankTo[to_at] ||
768
nRankFrom[from_neigh] != nRankTo[to_neigh] ||
769
at[to_at].valence != at[from_at].valence ) {
770
return 0; /* program error: both atoms must be mapped */ /* <BRKPT> */
773
parity = PARITY_VAL(at[to_at].parity);
774
num_neigh = at[to_at].valence;
776
if ( num_neigh > MAX_NUM_STEREO_BOND_NEIGH || num_neigh < MIN_NUM_STEREO_BOND_NEIGH ) {
777
/* 2 neighbors are possible in case of stereo bond with implicit H */
778
/* or a stereocenter -CHD- with an implicit H */
779
if ( num_neigh == 1 && at[to_at].stereo_bond_neighbor[0] ) {
780
/* 1 neighbor can happen in case of a terminal =CHD */
781
if ( PARITY_WELL_DEF(parity) )
782
return 2 - parity % 2;
787
return AB_PARITY_UNDF; /* undefined parity */
789
return 0; /* program error */ /* <BRKPT> */
791
if ( ATOM_PARITY_KNOWN(parity) ) {
792
if ( !ATOM_PARITY_WELL_DEF(parity) )
796
return 0; /* parity; */
798
return 0; /* AB_PARITY_UNDF; */ /* possibly program error: undefined parity */
800
/* locate at[to_at].stereo_bond_neighbor[] ordering numbers */
801
for ( i = 0, to_sb_neigh_ord=-1; i < MAX_NUM_STEREO_BONDS && (k=(int)at[to_at].stereo_bond_neighbor[i]); i ++ ) {
802
if ( k == to_neigh+1 ) {
807
if ( to_sb_neigh_ord < 0 ) {
808
return 0; /* program error: not a stereo bond */ /* <BRKPT> */
810
to_sb_neigh_ord = (int)at[to_at].stereo_bond_ord[to_sb_neigh_ord];
811
r_sb_neigh = nRankTo[(int)at[to_at].neighbor[to_sb_neigh_ord]];
812
for ( i = j = 0; i < num_neigh; i ++ ) {
813
if ( i != to_sb_neigh_ord ) {
814
r_to[j] = nRankTo[(int)(at_no_to[j]=at[to_at].neighbor[i])];
815
if ( r_sb_neigh == r_to[j] ) {
816
return 0; /* stereo bond atoms are not fully mapped */
821
if ( j+1 != num_neigh ) {
822
return 0; /* program error */ /* <BRKPT> */
825
/* only one neighbor; no mapping needed */
826
return 2-(parity+1+to_sb_neigh_ord)%2;
829
return 0; /* program error: j can be only 0, 1, or 2 */ /* <BRKPT> */
832
if ( r_to[0] == r_to[1] ) {
833
/* double bond neighbors need to be mapped */
835
from_sb_neigh_ord = -1;
836
for ( i = 0; i < num_neigh; i ++ ) {
837
k = at[from_at].neighbor[i];
839
if ( r == r_sb_neigh ) {
840
from_sb_neigh_ord = i; /* we need this value only for error-checking */
842
if ( r == r_to[0] ) {
843
r_canon_from[j] = nCanonRankFrom[k];
844
at_no_from[j] = (AT_RANK)k;
847
return 0; /* program error: unexpected rank, not fully mapped adjacent to the stereo bond atoms */ /* <BRKPT> */
850
if ( from_sb_neigh_ord < 0 || j != 2 ) {
851
return 0; /* program error: rank of a neighbor not found */ /* <BRKPT> */
853
if ( pEN ) { /* j == 2 */
854
pEN->to_at[0] = at_no_to[0];
855
pEN->to_at[1] = at_no_to[1];
856
pEN->num_to = 2; /* number of stored in pEN->to_at[] central atom neighbors */
857
pEN->rank = r_to[0]; /* mapping rank of the tied neighbors */
858
/* i := index of the smaller out of r_canon_from[1] and r_canon_from[0] */
859
i = (r_canon_from[1] < r_canon_from[0]);
860
pEN->from_at = at_no_from[i];
861
pEN->canon_rank = r_canon_from[i];
863
return -((int)r_to[0]);
865
/* double bond neighbors a mapped: r_to[0] != r_to[1] */
866
from_sb_neigh_ord = -1;
867
for ( i = 0; i < num_neigh; i ++ ) {
868
k = at[from_at].neighbor[i];
870
if ( r == r_sb_neigh ) {
871
from_sb_neigh_ord = i; /* we need this value only for error-checking */
873
if ( r == r_to[0] ) {
874
r_canon_from[0] = nCanonRankFrom[k];
875
/* at_no_from[0] = (AT_RANK)k; */
877
if ( r == r_to[1] ) {
878
r_canon_from[1] = nCanonRankFrom[k];
879
/* at_no_from[1] = (AT_RANK)k; */
881
return 0; /* program error: unexpected rank, not fully mapped adjacent to the stereo bond atoms */ /* <BRKPT> */
884
if ( !r_canon_from[0] || !r_canon_from[1] || from_sb_neigh_ord < 0 ) {
885
return 0; /* program error: neighbor rank not found */ /* <BRKPT> */
887
return 2 - (parity + to_sb_neigh_ord + (r_canon_from[1]<r_canon_from[0]))%2;
890
/**************************************************************************************/
891
int parity_of_mapped_atom2( int from_at, int to_at, const sp_ATOM *at, EQ_NEIGH *pEN,
892
const AT_RANK *nCanonRankFrom, const AT_RANK *nRankFrom, const AT_RANK *nRankTo )
894
AT_RANK nNeighRankFrom[4], nNeighNumberFrom[4], nNeighRankTo[4], nNeighNumberTo[4];
895
AT_RANK nNeighRankFromCanon[4], nNeighRankToCanon[4];
896
int i, j, k, num_neigh;
897
int r1, r2, r, r_canon_from_min, neigh_canon_from_min, r_canon_from;
898
int num_trans_to, num_trans_from, neigh1, neigh2;
901
num_neigh = at[to_at].valence;
904
memset( pEN, 0, sizeof(*pEN));
908
if ( nRankFrom[from_at] != nRankTo[to_at] )
909
return 0; /* program error */ /* <BRKPT> */
910
if ( num_neigh > MAX_NUM_STEREO_ATOM_NEIGH || num_neigh < 2 ) {
911
/* 2 neighbors are possible in case of stereo bond with implicit H */
912
/* or a stereocenter >CHD with two implicit H */
913
if ( num_neigh == 1 ) {
914
/* 1 neighbor can happen in case of a terminal -CHDT or =CHD */
915
if ( at[to_at].parity )
916
return at[to_at].parity;
918
return AB_PARITY_UNDF; /* undefined parity */
920
return 0; /* program error */ /* <BRKPT> */
922
for ( i = 0; i < num_neigh; i ++ ) { /* initialization of locals */
924
nNeighNumberFrom[i] = i;
925
nNeighRankTo[i] = nRankTo[(int)at[to_at].neighbor[i]]; /* mapping rank */
926
nNeighRankFrom[i] = nRankFrom[j=(int)at[from_at].neighbor[i]]; /* mapping rank */
927
nNeighRankFromCanon[i] = nCanonRankFrom[j]; /* canonical number */
930
pn_RankForSort = nNeighRankFrom;
931
nNumCompNeighborsRanksCountEql = 0; /* sort mapping ranks-from */
932
num_trans_from = insertions_sort( nNeighNumberFrom, num_neigh, sizeof(nNeighNumberFrom[0]), CompNeighborsRanksCountEql );
934
if ( nNumCompNeighborsRanksCountEql ) {
935
/* At least 2 neighbors have equal mapping ranks (are tied). */
936
/* Find tied from-neighbors with minimal canonical rank (nCanonRankFrom[]) */
937
r_canon_from_min = MAX_ATOMS+1; /* max possible rank + 1 */
938
for ( i = 1, r = 0, r1 = nNeighRankFrom[neigh1=nNeighNumberFrom[0]]; i < num_neigh; i ++, r1 = r2, neigh1 = neigh2 ) {
939
r2 = nNeighRankFrom[neigh2=nNeighNumberFrom[i]];
941
/* found neighbors with tied ranks */
943
/* the 1st pair of neighbor with this rank */
945
if ( (r_canon_from=nNeighRankFromCanon[neigh1]) < r_canon_from_min ) {
946
r_canon_from_min = r_canon_from; /* min canon rank */
947
neigh_canon_from_min = neigh1; /* neighbor number */
950
if ( (r_canon_from=nNeighRankFromCanon[neigh2]) < r_canon_from_min ) {
951
r_canon_from_min = r_canon_from;
952
neigh_canon_from_min = neigh2;
957
/* neighbors with tied ranks have been found => parity cannot be determined without additional mapping */
958
/* find to-neighbors on which neigh_canon_from_min can be mapped */
959
r1 = nNeighRankFrom[neigh_canon_from_min];
961
for ( i = j = 0; i < num_neigh; i ++ ) {
962
if ( r1 == nNeighRankTo[i] ) {
963
pEN->to_at[j++] = at[to_at].neighbor[i];
966
insertions_sort( pEN->to_at, j, sizeof(pEN->to_at[0]), CompRanksInvOrd );
967
pEN->num_to = j; /* number of stored in pEN->to_at[] central atom neighbors */
968
pEN->from_at = at[from_at].neighbor[neigh_canon_from_min]; /* neighbor with min. canon number */
969
pEN->rank = r1; /* mapping rank of the tied neighbors */
970
pEN->canon_rank = r_canon_from_min; /* canon. rank of the pEN->from_at */
973
for ( i = j = 0; i < num_neigh; i ++ ) {
974
if ( r1 == nNeighRankTo[i] ) {
980
if ( j <= 1 || !r1 || r_canon_from_min > MAX_ATOMS ) {
981
return 0; /* program error */ /* <BRKPT> */
983
return -r; /* means parity cannot be determined */
985
return 0; /* program error */
987
/* All neighbors have different mapping ranks; */
988
/* therefore no additional mapping of the neighbors is necessary */
989
if ( !ATOM_PARITY_WELL_DEF(at[to_at].parity) )
990
return at[to_at].parity; /* unknown parity or cannot be determined */
992
pn_RankForSort = nNeighRankTo;
993
num_trans_to = insertions_sort( nNeighNumberTo, num_neigh, sizeof(nNeighNumberTo[0]), CompNeighborsRanksCountEql );
995
/* Map canonical ranks of neighbors. Mapped on each other "to" and "from" atoms have equal mapping ranks */
996
for ( i = 0; i < num_neigh; i ++ ) {
997
if ( nNeighRankTo[j=nNeighNumberTo[i]] != nNeighRankFrom[k=nNeighNumberFrom[i]] )
998
return 0; /* program error: mapping ranks not equal, from_at neigborhood cannot be mapped on to_at neighbood. */ /* <BRKPT> */
999
nNeighRankToCanon[j] = nNeighRankFromCanon[k]; /* potential problem: other atom(s) may have same mapping rank and */
1000
/* different canon. rank(s). */
1001
/* we may save some memory by eliminating nNeighRankFromCanon[]: */
1002
/* nNeighRankToCanon[j] = nCanonRankFrom[at[from_at].neighbor[k]] */
1005
pn_RankForSort = nNeighRankToCanon;
1006
num_trans_to += insertions_sort( nNeighNumberTo, num_neigh, sizeof(nNeighNumberTo[0]), CompNeighborsRanksCountEql );
1007
#ifndef CT_NEIGH_INCREASE
1008
num_trans_to += ((num_neigh*(num_neigh-1))/2)%2; /* get correct parity for ascending order of canon. numbers */
1011
return 2 - (num_trans_to + at[to_at].parity)%2;
1014
/**************************************************************************************
1016
* Phase II: map canonicaly numbrered structure onto itself
1017
* to obtain a minimal or maximal stereo part of the CT
1019
**************************************************************************************/
1021
int ClearPreviousMappings( AT_RANK **pRankStack1 )
1024
for ( i = 0; pRankStack1[i]; i ++ ) {
1025
pRankStack1[i][0] = 0;
1030
/**************************************************************************************/
1031
/* map one atom ("from") onto another ("to"): untie their mapping ranks if they are tied. */
1032
int map_an_atom2( int num_atoms, int num_max, int at_no1/*from*/, int at_no2/*to*/,
1034
int nNumMappedRanks, int *pnNewNumMappedRanks,
1036
NEIGH_LIST *NeighList,
1037
AT_RANK **pRankStack1, AT_RANK **pRankStack2, int *bAddStack )
1039
AT_RANK *nRank1, *nAtomNumber1; /* ranks for mapping "1", "from" */
1040
AT_RANK *nRank2, *nAtomNumber2; /* ranks for mapping "2", "to" */
1041
AT_RANK *nNewRank1=NULL, *nNewAtomNumber1=NULL; /* ranks for mapping "1", "from" */
1042
AT_RANK *nNewRank2=NULL, *nNewAtomNumber2=NULL; /* ranks for mapping "2", "to" */
1043
int length = num_max*sizeof(AT_RANK);
1044
int nNewNumRanks2, nNewNumRanks1;
1045
int i, bAtFromHasAlreadyBeenMapped, nNumTies;
1048
nNumTies = NumberOfTies( pRankStack1, pRankStack2, length, at_no1, at_no2, &nNewRank, bAddStack, &bAtFromHasAlreadyBeenMapped );
1050
if ( RETURNED_ERROR(nNumTies) )
1051
return nNumTies; /* error */
1053
nRank1 = *pRankStack1++;
1054
nAtomNumber1 = *pRankStack1++; /* ranks for mapping "1", "from" */
1056
nRank2 = *pRankStack2++;
1057
nAtomNumber2 = *pRankStack2++; /* ranks for mapping "2", "to" */
1059
if ( nNumTies > 1 ) {
1061
nNewRank1 = *pRankStack1++;
1062
nNewAtomNumber1 = *pRankStack1++; /* ranks for mapping "1", "from" */
1064
nNewRank2 = *pRankStack2++;
1065
nNewAtomNumber2 = *pRankStack2++; /* ranks for mapping "2", "to" */
1066
/* break a tie for "to" */
1067
memcpy( nNewRank2, nRank2, length );
1068
memcpy( nNewAtomNumber2, nAtomNumber2, length );
1069
nNewRank2[at_no2] = nNewRank;
1070
nNewNumRanks2 = DifferentiateRanks2( num_atoms, NeighList,
1071
nNumMappedRanks, nNewRank2, nTempRank,
1072
nNewAtomNumber2, &pCS->lNumNeighListIter, 1 );
1073
pCS->lNumBreakTies ++;
1075
/* Check whether the old mapping can be reused */
1076
if ( 2 == bAtFromHasAlreadyBeenMapped && nNewRank == nNewRank1[at_no1] ) {
1077
for ( i = 0; i < num_atoms; i ++ ) {
1078
if ( nNewRank1[nNewAtomNumber1[i]] != nNewRank2[nNewAtomNumber2[i]] ) {
1079
bAtFromHasAlreadyBeenMapped = 0; /* It cannot. */
1084
bAtFromHasAlreadyBeenMapped = 0;
1086
if ( 2 != bAtFromHasAlreadyBeenMapped ) {
1087
/* break a tie for "from" */
1088
for ( i = 0; pRankStack1[i]; i ++ ) {
1089
pRankStack1[i][0] = 0;
1091
memcpy( nNewRank1, nRank1, length );
1092
memcpy( nNewAtomNumber1, nAtomNumber1, length ); /* GPF: bad nAtomNumber1 */
1093
nNewRank1[at_no1] = nNewRank;
1094
nNewNumRanks1 = DifferentiateRanks2( num_atoms, NeighList,
1095
nNumMappedRanks, nNewRank1, nTempRank,
1096
nNewAtomNumber1, &pCS->lNumNeighListIter, 1 );
1097
pCS->lNumBreakTies ++;
1099
nNewNumRanks1 = nNewNumRanks2;
1102
if ( nNewNumRanks1 != nNewNumRanks2 )
1103
return CT_MAPCOUNT_ERR; /* program error */ /* <BRKPT> */
1104
*pnNewNumMappedRanks = nNewNumRanks2;
1106
for ( i = 0; i < num_atoms; i ++ ) {
1107
if ( nNewRank1[nNewAtomNumber1[i]] != nNewRank2[nNewAtomNumber2[i]] ) {
1108
return CT_MAPCOUNT_ERR; /* program error */ /* <BRKPT> */
1112
*pnNewNumMappedRanks = nNumMappedRanks;
1114
return ( nNewRank1 )? nNewRank1[at_no1] : nRank1[at_no1]; /* mapping rank value */
1117
/**************************************************************************************/
1118
int might_change_other_atom_parity( sp_ATOM *at, int num_atoms, int at_no, AT_RANK *nRank2, AT_RANK *nRank1 )
1120
int i, j, neighbor_no;
1121
for ( i = 0; i < num_atoms; i ++ ) {
1122
if ( nRank2[i] != nRank1[i] ) {
1123
if ( i != at_no /*&& ATOM_PARITY_WELL_DEF(at[i].parity)*/
1124
&& at[i].bHasStereoOrEquToStereo
1125
&& !(at[i].stereo_atom_parity & KNOWN_PARITIES_EQL )
1126
&& !at[i].stereo_bond_neighbor[0]
1129
return 1; /* may have changed stereo atoms order */
1131
for ( j = 0; j < at[i].valence; j ++ ) {
1132
neighbor_no = at[i].neighbor[j];
1133
if ( neighbor_no != at_no
1134
/*&& ATOM_PARITY_WELL_DEF(at[neighbor_no].parity)*/
1135
&& at[neighbor_no].bHasStereoOrEquToStereo
1136
&& !(at[neighbor_no].stereo_atom_parity & KNOWN_PARITIES_EQL )
1137
&& !at[neighbor_no].stereo_bond_neighbor[0]
1139
return 1; /* may have changed stereo atom parity */
1145
/**************************************************************************************/
1146
#if ( REMOVE_CALC_NONSTEREO == 1 ) /* { */
1147
/**************************************************************************************/
1148
void DeAllocateForNonStereoRemoval( AT_RANK **nAtomNumberCanon1, AT_RANK **nAtomNumberCanon2,
1149
NEIGH_LIST **nl, NEIGH_LIST **nl1, NEIGH_LIST **nl2, AT_RANK **nVisited1, AT_RANK **nVisited2 )
1151
if ( *nAtomNumberCanon1 ) {
1152
inchi_free( *nAtomNumberCanon1 );
1153
*nAtomNumberCanon1 = NULL;
1155
if ( *nAtomNumberCanon2 ) {
1156
inchi_free( *nAtomNumberCanon2 );
1157
*nAtomNumberCanon2 = NULL;
1160
FreeNeighList( *nl );
1164
FreeNeighList( *nl1 );
1168
FreeNeighList( *nl2 );
1172
inchi_free( *nVisited1 );
1176
inchi_free( *nVisited2 );
1181
/**************************************************************************************/
1182
int AllocateForNonStereoRemoval( sp_ATOM *at, int num_atoms, const AT_RANK *nSymmRank, AT_RANK *nCanonRank,
1183
AT_RANK **nAtomNumberCanon1, AT_RANK **nAtomNumberCanon2,
1184
NEIGH_LIST **nl, NEIGH_LIST **nl1, NEIGH_LIST **nl2, AT_RANK **nVisited1, AT_RANK **nVisited2 )
1186
DeAllocateForNonStereoRemoval( nAtomNumberCanon1, nAtomNumberCanon2, nl, nl1, nl2, nVisited1, nVisited2 );
1187
*nAtomNumberCanon1 = (AT_RANK *) inchi_malloc( num_atoms * sizeof(**nAtomNumberCanon1) );
1188
*nAtomNumberCanon2 = (AT_RANK *) inchi_malloc( num_atoms * sizeof(**nAtomNumberCanon2) );
1189
*nl = CreateNeighList( num_atoms, num_atoms, at, 0, NULL );
1190
*nl1 = CreateNeighList( num_atoms, num_atoms, at, 0, NULL );
1191
*nl2 = CreateNeighList( num_atoms, num_atoms, at, 0, NULL );
1192
*nVisited1 = (AT_RANK *) inchi_malloc( num_atoms * sizeof(**nVisited1) );
1193
*nVisited2 = (AT_RANK *) inchi_malloc( num_atoms * sizeof(**nVisited2) );
1195
if ( !*nl || !*nl1 || !*nl2 || !*nVisited1 || !*nVisited2 || !*nAtomNumberCanon1 || !*nAtomNumberCanon2 ) {
1196
DeAllocateForNonStereoRemoval( nAtomNumberCanon1, nAtomNumberCanon2, nl, nl1, nl2, nVisited1, nVisited2 );
1199
/* Sort neighbors according to symm. ranks (primary key) and canon. ranks (secondary key), in descending order */
1200
SortNeighListsBySymmAndCanonRank( num_atoms, *nl, nSymmRank, nCanonRank );
1201
SortNeighListsBySymmAndCanonRank( num_atoms, *nl1, nSymmRank, nCanonRank );
1202
SortNeighListsBySymmAndCanonRank( num_atoms, *nl2, nSymmRank, nCanonRank );
1205
/**************************************************************************************/
1206
AT_RANK GetMinNewRank(AT_RANK *nAtomRank, AT_RANK *nAtomNumb, AT_RANK nRank1 )
1210
for ( i = (int)nRank1-1; 0 <= i && nRank1 == (nRank2 = nAtomRank[(int)nAtomNumb[i]]); i -- )
1218
/**************************************************************************************/
1219
int BreakNeighborsTie( sp_ATOM *at, int num_atoms, int num_at_tg, int ib, int ia,
1220
AT_RANK *neigh_num, int in1, int in2, int mode,
1221
AT_RANK **pRankStack1, AT_RANK **pRankStack2, AT_RANK *nTempRank, NEIGH_LIST *NeighList,
1222
const AT_RANK *nSymmRank, AT_RANK *nCanonRank, NEIGH_LIST *nl1, NEIGH_LIST *nl2, long *lNumIter )
1224
AT_RANK nRank1, nRank2;
1225
int nNumDiffRanks, nNumDiffRanks1, nNumDiffRanks2, i;
1226
int n1 = (int)neigh_num[in1];
1227
int n2 = (int)neigh_num[in2];
1228
int other_neigh[2], other_neig_ord[2], num_other_neigh;
1229
/* asymmetric calculation */
1231
if ( mode == MAP_MODE_S4 && in1 || /* for S4 we need only (in1,in2) = (0,1) (0,2) (0,3) pairs of neighbors */
1232
mode != MAP_MODE_STD && at[ia].valence != MAX_NUM_STEREO_ATOM_NEIGH ||
1233
mode != MAP_MODE_STD && nSymmRank[n1] != nSymmRank[n2] ) {
1236
/* 1. Create initial ranks from equivalence information stored in nSymmRank */
1237
memcpy( pRankStack1[0], nSymmRank, num_at_tg * sizeof(pRankStack1[0][0]) );
1238
pn_RankForSort = pRankStack1[0];
1239
tsort( pRankStack1[1], num_at_tg, sizeof(pRankStack1[1][0]), CompRanksOrd );
1240
nNumDiffRanks = SortedEquInfoToRanks( pRankStack1[0]/*inp*/, pRankStack1[0]/*out*/, pRankStack1[1], num_at_tg, NULL );
1242
/* other neighbors */
1243
num_other_neigh = 0;
1244
if ( at[ia].valence <= MAX_NUM_STEREO_ATOM_NEIGH && mode ) {
1245
for ( i = 0; i < at[ia].valence; i ++ ) {
1246
if ( i != in1 && i != in2 ) {
1247
other_neigh[num_other_neigh] = (int)neigh_num[i];
1248
other_neig_ord[num_other_neigh] = i;
1253
if ( mode != MAP_MODE_STD && nSymmRank[other_neigh[0]] != nSymmRank[other_neigh[1]] ||
1254
mode == MAP_MODE_S4 && nSymmRank[n1] != nSymmRank[other_neigh[1]] ) {
1259
if ( pRankStack1[0][ia] != nSymmRank[ia] ) {
1260
/* at[ia] is constitutionally equivalent to some other atom. Fix at[ia]. */
1261
pRankStack1[0][ia] = nSymmRank[ia];
1262
nNumDiffRanks = DifferentiateRanksBasic( num_at_tg, NeighList,
1263
nNumDiffRanks, pRankStack1[0], nTempRank,
1264
pRankStack1[1], lNumIter, 1 );
1266
/* 3. In case of a double bond/cumulene only: */
1267
/* fix at[ib] -- the opposite double bond/cumulene atom */
1268
if ( ib < num_atoms ) {
1269
/* find the smallest possible rank */
1270
nRank1 = pRankStack1[0][ib];
1271
nRank2 = GetMinNewRank(pRankStack1[0], pRankStack1[1], nRank1 );
1272
/* if the rank is smaller than pRankStack1[0][ib] then fix at[ib] */
1273
if ( nRank2 != nRank1 ) {
1274
pRankStack1[0][ib] = nRank2;
1275
nNumDiffRanks = DifferentiateRanksBasic( num_at_tg, NeighList,
1276
nNumDiffRanks, pRankStack1[0], nTempRank,
1277
pRankStack1[1], lNumIter, 1 );
1281
/**************************************************************************************
1282
* Note: It may (or may not?) make sense to fix "other neighbors":
1283
* in case of a stereo center fix neighbors other than n1, n2
1284
* in case of a double bond/cumulene fix the opposite atom neighbors
1285
* The ranks assigned to the other neighbors in case of their equivalence
1286
* should be in the ascending order of their canonical ranks ????
1287
* *** For now we do not fix other neighbors ***
1288
**************************************************************************************/
1290
/* 4. Check whether the neighbors still have equal ranks */
1291
if ( pRankStack1[0][n1] != pRankStack1[0][n2] ) {
1292
return 0; /* the two neighbors are not constitutionally equivalent */
1294
/* 5. Find new smallest possible rank for n1 and n2 */
1295
nRank1 = pRankStack1[0][n1];
1296
nRank2 = GetMinNewRank(pRankStack1[0], pRankStack1[1], nRank1 );
1298
/* 6. Copy the results to the 2nd eq. rank arrays */
1299
memcpy( pRankStack2[0], pRankStack1[0], num_at_tg * sizeof(pRankStack2[0][0]) );
1300
memcpy( pRankStack2[1], pRankStack1[1], num_at_tg * sizeof(pRankStack2[0][0]) );
1302
/* 7. Break neighbor tie: map n1(1) <--> n2(2) */
1303
pRankStack1[0][n1] = nRank2;
1304
nNumDiffRanks1 = DifferentiateRanksBasic( num_at_tg, NeighList,
1305
nNumDiffRanks, pRankStack1[0], nTempRank,
1306
pRankStack1[1], lNumIter, 1 );
1308
pRankStack2[0][n2] = nRank2;
1309
nNumDiffRanks2 = DifferentiateRanksBasic( num_at_tg, NeighList,
1310
nNumDiffRanks, pRankStack2[0], nTempRank,
1311
pRankStack2[1], lNumIter, 1 );
1313
if ( nNumDiffRanks1 != nNumDiffRanks2 ) {
1314
return -1; /* <BRKPT> */
1316
if ( mode == MAP_MODE_C2v || mode == MAP_MODE_C2 ) {
1317
/* Check for C2v reflection leading to parity inversion (mode=1) or C2 rotation (mode=2) */
1318
AT_RANK nRank10, nRank20;
1322
* n1(1) <--> n2(2) -- at this point already done
1323
* n1(2) <--> n2(1) --> do at i = 0
1325
* C2v: other neighbors must be unmoved: map
1326
* other_neigh[0](1) <--> other_neigh[0](2)
1327
* other_neigh[1](1) <--> other_neigh[1](2)
1329
* C2: other neighbors should be mapped on each other
1330
* other_neigh[0](1) <--> other_neigh[1](2)
1331
* other_neigh[1](1) <--> other_neigh[0](2)
1333
for ( i = 0; i <= 2; i ++ ) {
1335
/* C2v & C2. Map n2(1) <--> n1(2) */
1339
if ( mode == MAP_MODE_C2v ) { /* was '=', pointed by WDI */
1341
* C2v. Other neighbors must be unmoved: map
1342
* i=1: other_neigh[0](1) <--> other_neigh[0](2)
1343
* i=2: other_neigh[1](1) <--> other_neigh[1](2)
1345
nn1 = other_neigh[i-1]; /* 0 or 1 */
1346
nn2 = other_neigh[i-1]; /* 0 or 1 */
1348
if ( mode == MAP_MODE_C2 ) { /* was '=', pointed by WDI */
1350
* C2. Other neighbors should be mapped on each other
1351
* i=1: other_neigh[0](1) <--> other_neigh[1](2)
1352
* i=2: other_neigh[1](1) <--> other_neigh[0](2)
1354
nn1 = other_neigh[i-1]; /* 0 or 1 */
1355
nn2 = other_neigh[2-i]; /* 1 or 0 */
1357
return -1; /* program error */
1359
/* map nn1(1) <--> nn2(2) */
1360
nRank10 = pRankStack1[0][nn1];
1361
nRank20 = pRankStack2[0][nn2];
1362
nRank1 = GetMinNewRank(pRankStack1[0], pRankStack1[1], nRank10 );
1363
nRank2 = GetMinNewRank(pRankStack2[0], pRankStack2[1], nRank20 );
1364
if ( nRank10 == nRank20 && nRank1 == nRank2 ) {
1365
if ( nRank10 == nRank1 ) {
1366
;/* atoms are already mapped */
1368
/* need additional mapping: ranks are not fixed yet */
1369
pRankStack1[0][nn1] = nRank1;
1370
nNumDiffRanks1 = DifferentiateRanksBasic( num_at_tg, NeighList,
1371
nNumDiffRanks, pRankStack1[0], nTempRank,
1372
pRankStack1[1], lNumIter, 1 );
1373
pRankStack2[0][nn2] = nRank2;
1374
nNumDiffRanks2 = DifferentiateRanksBasic( num_at_tg, NeighList,
1375
nNumDiffRanks, pRankStack2[0], nTempRank,
1376
pRankStack2[1], lNumIter, 1 );
1377
if ( nNumDiffRanks1 != nNumDiffRanks2 ) {
1378
return -1; /* <BRKPT> */
1382
return 0; /* mapping is not possible */
1386
if ( mode == MAP_MODE_S4 ) {
1388
* Check for S4 reflection/rotation leading to parity inversion (mode=3)
1390
* At this point n1(1) <--> n2(2) have been mapped and n1 has index in1 = 0
1391
* Below indexes in neigh_num[] are in brackets; [i] means neigh_num[i].
1392
* Numbers (#) in parentheses refer to pRankStack#
1394
* in2=1: [0](1) <--> [1](2) mapping has been done; add more mappings:
1395
* [1](1) <--> [2](2) [x]=[2]
1396
* [2](1) <--> [3](2) [y]=[3]
1397
* [3](1) <--> [0](2)
1398
* this will succeed if C2 axis crosses middle of [0]-[2] and [1]-[3] lines
1400
* in2=2: [0](1) <--> [2](2) mapping has been done; add more mappings:
1401
* [2](1) <--> [3](2) [x]=[3]
1402
* [3](1) <--> [1](2) [y]=[1]
1403
* [1](1) <--> [0](2)
1404
* this will succeed if C2 axis crosses middle of [0]-[3] and [1]-[2] lines
1406
* in2=3: [0](1) <--> [3](2) mapping has been done; add more mappings:
1407
* [3](1) <--> [1](2) [x]=[1]
1408
* [1](1) <--> [2](2) [y]=[2]
1409
* [2](1) <--> [0](2)
1410
* this will succeed if C2 axis crosses middle of [0]-[1] and [2]-[3] lines
1413
* [in1](1) <--> [in2](2)
1414
* [in2](1) <--> [x] (2) i=0
1415
* [x] (1) <--> [y] (2) i=1
1416
* [y] (1) <--> [in1](2) i=2
1419
* ===== how to find x, y from in2 ====
1420
* in2=1 => x,y = 2, 3 or [x] = other_neigh[0], [y] = other_neigh[1]
1421
* in2=2 => x,y = 3, 1 or [x] = other_neigh[1], [y] = other_neigh[0]
1422
* in2=3 => x,y = 1, 2 or [x] = other_neigh[0], [y] = other_neigh[1]
1423
* ====================================
1425
AT_RANK nRank10, nRank20;
1427
for ( i = 0; i <= 2; i ++ ) {
1429
case 0: /* [in2](1) <--> [x](2); */
1430
nn1 = n2; /* [in2] */
1431
nn2 = other_neigh[1-in2%2]; /* [x] */
1433
case 1: /* [x](1) <--> [y](2) */
1434
nn1 = other_neigh[1-in2%2]; /* [x] */
1435
nn2 = other_neigh[ in2%2]; /* [y] */
1438
nn1 = other_neigh[ in2%2]; /* [y] */
1439
nn2 = n1; /* [in1] */
1442
return -1; /* program error */
1444
/* map nn1(1) <--> nn2(2) */
1445
nRank10 = pRankStack1[0][nn1];
1446
nRank20 = pRankStack2[0][nn2];
1447
nRank1 = GetMinNewRank(pRankStack1[0], pRankStack1[1], nRank10 );
1448
nRank2 = GetMinNewRank(pRankStack2[0], pRankStack2[1], nRank20 );
1449
if ( nRank10 == nRank20 && nRank1 == nRank2 ) {
1450
if ( nRank10 == nRank1 ) {
1451
;/* atoms are already mapped */
1453
/* need additional mapping: ranks are not fixed yet */
1454
pRankStack1[0][nn1] = nRank1;
1455
nNumDiffRanks1 = DifferentiateRanksBasic( num_at_tg, NeighList,
1456
nNumDiffRanks, pRankStack1[0], nTempRank,
1457
pRankStack1[1], lNumIter, 1 );
1458
pRankStack2[0][nn2] = nRank2;
1459
nNumDiffRanks2 = DifferentiateRanksBasic( num_at_tg, NeighList,
1460
nNumDiffRanks, pRankStack2[0], nTempRank,
1461
pRankStack2[1], lNumIter, 1 );
1462
if ( nNumDiffRanks1 != nNumDiffRanks2 ) {
1463
return -1; /* <BRKPT> */
1467
return 0; /* mapping is not possible */
1474
#if ( BREAK_ONE_MORE_SC_TIE == 1 ) /* { */
1475
/* Check for a very highly symmetrical stereo center 12-06-2002 */
1476
if ( ib >= num_atoms && at[ia].valence == MAX_NUM_STEREO_ATOM_NEIGH ) {
1478
nRank1 = pRankStack1[0][n2];
1479
for ( i = 0, num_eq = 0; i < at[ia].valence; i ++ ) {
1480
num_eq += ( nRank1 == pRankStack1[0][at[ia].neighbor[i]]);
1482
if ( num_eq == MAX_NUM_STEREO_ATOM_NEIGH-1 ) {
1483
for ( i = (int)nRank1-1; 0 <= i && nRank1 == (nRank2 = pRankStack1[0][(int)pRankStack1[1][i]]); i -- )
1490
/* 7a. Break another neighbor tie */
1492
nNumDiffRanks = nNumDiffRanks1;
1494
pRankStack1[0][n2] = nRank2;
1495
nNumDiffRanks1 = DifferentiateRanksBasic( num_at_tg, NeighList,
1496
nNumDiffRanks, pRankStack1[0], nTempRank,
1497
pRankStack1[1], lNumIter, 1 );
1499
pRankStack2[0][n1] = nRank2;
1500
nNumDiffRanks2 = DifferentiateRanksBasic( num_at_tg, NeighList,
1501
nNumDiffRanks, pRankStack2[0], nTempRank,
1502
pRankStack2[1], lNumIter, 1 );
1506
if ( nNumDiffRanks1 != nNumDiffRanks2 ) {
1507
return -1; /* <BRKPT> */
1509
#endif /* } BREAK_ONE_MORE_SC_TIE */
1511
#if ( BREAK_ALSO_NEIGH_TIE == 1 )
1512
/* check whether neighbor's neighbors are tied and untie them */
1513
if ( at[n1].nRingSystem == at[n2].nRingSystem && ib >= num_atoms ) {
1514
AT_RANK NeighNeighList[MAX_NUM_STEREO_ATOM_NEIGH+1];
1515
int m, neigh1=-1, neigh2=-1;
1516
nRank1 = nRank2 = 0;
1518
NeighNeighList[0] = at[n1].valence-1; /* for insertions_sort_NeighListBySymmAndCanonRank() */
1519
for ( i = 0, m = 1; i < at[n1].valence; i ++ ) {
1520
int neigh = at[n1].neighbor[i];
1521
if ( neigh != ia ) {
1522
NeighNeighList[m ++] = neigh;
1525
insertions_sort_NeighListBySymmAndCanonRank( NeighNeighList, pRankStack1[0], nCanonRank );
1526
for ( m = 2; m < at[n1].valence; m ++ ) {
1527
if ( pRankStack1[0][NeighNeighList[m]] == pRankStack1[0][NeighNeighList[m-1]] ) {
1528
neigh1 = NeighNeighList[m-1];
1533
NeighNeighList[0] = at[n2].valence-1; /* for insertions_sort_NeighListBySymmAndCanonRank() */
1534
for ( i = 0, m = 1; i < at[n2].valence; i ++ ) {
1535
int neigh = at[n2].neighbor[i];
1536
if ( neigh != ia ) {
1537
NeighNeighList[m ++] = neigh;
1540
insertions_sort_NeighListBySymmAndCanonRank( NeighNeighList, pRankStack2[0], nCanonRank );
1541
for ( m = 2; m < at[n2].valence; m ++ ) {
1542
if ( pRankStack2[0][NeighNeighList[m]] == pRankStack2[0][NeighNeighList[m-1]] ) {
1543
#if ( BREAK_ALSO_NEIGH_TIE_ROTATE == 1 )
1544
neigh2 = NeighNeighList[m]; /* [m] to obtain same axis orientation around ia<neigh */
1546
neigh2 = NeighNeighList[m-1]; /* [m-1] to obtain reflection ??? */
1551
if ( neigh1 >= 0 && neigh2 >= 0 && pRankStack1[0][neigh1] == pRankStack2[0][neigh2] ) {
1552
/* neighbors' neighbors are tied */
1553
nRank1 = pRankStack1[0][neigh1];
1554
nRank2 = GetMinNewRank(pRankStack1[0], pRankStack1[1], nRank1 );
1556
/* Break neighbor's neighbor tie */
1558
nNumDiffRanks = nNumDiffRanks1;
1560
pRankStack1[0][neigh1] = nRank2;
1561
nNumDiffRanks1 = DifferentiateRanksBasic( num_at_tg, NeighList,
1562
nNumDiffRanks, pRankStack1[0], nTempRank,
1563
pRankStack1[1], lNumIter, 1 );
1565
pRankStack2[0][neigh2] = nRank2;
1566
nNumDiffRanks2 = DifferentiateRanksBasic( num_at_tg, NeighList,
1567
nNumDiffRanks, pRankStack2[0], nTempRank,
1568
pRankStack2[1], lNumIter, 1 );
1574
/* for debug only */
1575
for ( i = 0; i < num_at_tg; i ++ ) {
1576
if ( pRankStack1[0][(int)pRankStack1[1][i]] != pRankStack2[0][(int)pRankStack2[1][i]] ) {
1577
return -1; /* <BRKPT> */
1580
/* Resort lists of neighbors */
1581
SortNeighListsBySymmAndCanonRank( num_atoms, nl1, pRankStack1[0], nCanonRank );
1582
SortNeighListsBySymmAndCanonRank( num_atoms, nl2, pRankStack2[0], nCanonRank );
1584
return nNumDiffRanks1+1;
1587
/**************************************************************************************/
1588
int CheckNextSymmNeighborsAndBonds( sp_ATOM *at, AT_RANK cur1, AT_RANK cur2, AT_RANK n1, AT_RANK n2,
1589
AT_RANK *nAvoidCheckAtom, AT_RANK *nVisited1, AT_RANK *nVisited2,
1590
AT_RANK *nVisitOrd1, AT_RANK *nVisitOrd2, const AT_RANK *nRank1, const AT_RANK *nRank2 )
1594
if ( nRank1[n1] != nRank2[n2] ) {
1595
return -1; /* parallel traversal in stereo removal failed */ /* <BRKPT> */
1597
switch ( !nVisited1[n1] + !nVisited2[n2] ) {
1599
if ( nVisited1[n1] != n2+1 || nVisited2[n2] != n1+1 ) {
1600
return -1; /* 0; */ /* possibly error???: we have come to an alreardy traversed pair and */
1601
/* found that the pair previously has not been traversed synchroneously. */
1602
} /* -- Happens in C60. */
1605
return -1; /* 0; */ /* possibly error: one is zero, another is not a zero. Happens in C60 */
1608
/* both are zero, OK. */
1611
if ( nVisitOrd1[n1] != nVisitOrd2[n2] ) {
1612
return -1; /* 0; */ /* different DFS trees */
1614
/* at[n1] and at[n2] are next to at[cur1] and at[cur2] respectively */
1615
/* Even though the bond might have already been checked, check whether */
1616
/* it is a stereo bond/cumulene. If it is, check the bond/cumulene parity. */
1618
/* Even though the bond or cumulene might have already been checked, check it: this is */
1619
/* the only place we can check stereo bonds and cumulenes that are not edges of the DFS tree */
1620
/* The code works both for a stereo bond and a stereogenic cumulene. */
1622
for ( i1 = 0, k1 = 0; i1 < MAX_NUM_STEREO_BONDS &&
1623
(s1=at[cur1].stereo_bond_neighbor[i1]) &&
1624
!(k1=(at[cur1].neighbor[(int)at[cur1].stereo_bond_ord[i1]] == n1)); i1 ++ )
1626
for ( i2 = 0, k2 = 0; i2 < MAX_NUM_STEREO_BONDS &&
1627
(s2=at[cur2].stereo_bond_neighbor[i2]) &&
1628
!(k2=(at[cur2].neighbor[(int)at[cur2].stereo_bond_ord[i2]] == n2)); i2 ++ )
1631
/* -- this does not work in case of cumulenes --
1632
for ( i1 = 0, k1 = 0; i1 < MAX_NUM_STEREO_BONDS && (s1=at[cur1].stereo_bond_neighbor[i1]) && !(k1=(s1-1 == n1)); i1 ++ )
1634
for ( i2 = 0, k2 = 0; i2 < MAX_NUM_STEREO_BONDS && (s2=at[cur2].stereo_bond_neighbor[i2]) && !(k2=(s2-1 == n2)); i2 ++ )
1639
return 0; /* not an error: a stereo bond and not a stereo bond */
1643
int bCheckBond1, bCheckBond2;
1647
bCheckBond1 = (cur1 != nAvoidCheckAtom[0] || s1 != nAvoidCheckAtom[1]) &&
1648
(cur1 != nAvoidCheckAtom[1] || s1 != nAvoidCheckAtom[0]);
1649
bCheckBond2 = (cur2 != nAvoidCheckAtom[0] || s2 != nAvoidCheckAtom[1]) &&
1650
(cur2 != nAvoidCheckAtom[1] || s2 != nAvoidCheckAtom[0]);
1652
if ( bCheckBond1 != bCheckBond2 )
1655
if ( !bCheckBond1 && !bCheckBond2 ) {
1656
return 1; /* do not go any further in this direction */
1659
if ( at[cur1].stereo_bond_parity[i1] != at[cur2].stereo_bond_parity[i2] ) {
1660
/* different values of at[].stereo_bond_parity: definitely different bonds */
1661
/* known parities */
1662
if ( PARITY_KNOWN(at[cur1].stereo_bond_parity[i1] ) &&
1663
PARITY_KNOWN(at[cur2].stereo_bond_parity[i2] ) ) {
1664
return 0; /* different currently known stereo bond parities */
1666
#if ( PROPAGATE_ILL_DEF_STEREO != 1 )
1667
/* well defined and to be calculated from the ranks */
1668
if ( !(PARITY_CALCULATE(at[cur1].stereo_bond_parity[i1]) && PARITY_WELL_DEF (at[cur2].stereo_bond_parity[i2]) ||
1669
PARITY_WELL_DEF (at[cur1].stereo_bond_parity[i1]) && PARITY_CALCULATE(at[cur2].stereo_bond_parity[i2]) ||
1670
PARITY_CALCULATE(at[cur1].stereo_bond_parity[i1]) && PARITY_CALCULATE(at[cur2].stereo_bond_parity[i2]) ) ) {
1671
/* do not reject if: "well defined" and "calculate" or "calculate" and "calculate" */
1677
#if ( PROPAGATE_ILL_DEF_STEREO != 1 )
1678
if ( (cur1 != cur2 || s1 != s2) && (cur1 != s2 || cur2 != s1) ) {
1679
/* two different stereo bonds */
1680
if ( PARITY_ILL_DEF( at[cur1].stereo_bond_parity[i1] ) ||
1681
PARITY_ILL_DEF( at[cur2].stereo_bond_parity[i2] ) ) {
1687
return 1; /* stereo bonds to n1 and n2 have same known parities or are not stereo bonds */
1689
/**************************************************************************************/
1690
int CreateCheckSymmPaths( sp_ATOM *at, AT_RANK prev1, AT_RANK cur1, AT_RANK prev2, AT_RANK cur2,
1691
AT_RANK *nAvoidCheckAtom, AT_RANK *nVisited1, AT_RANK *nVisited2,
1692
AT_RANK *nVisitOrd1, AT_RANK *nVisitOrd2,
1693
NEIGH_LIST *nl1, NEIGH_LIST *nl2, const AT_RANK *nRank1, const AT_RANK *nRank2,
1694
AT_RANK *nCanonRank, AT_RANK *nLength, int *bParitiesInverted, int mode )
1696
int k, k1, k2, ret=0, bParitiesInvertedZero=0, *pbParitiesInverted;
1699
nVisited1[cur1] = cur2+1; /* symmetrically exchange atom numbers */
1700
nVisited2[cur2] = cur1+1;
1704
nVisitOrd1[cur1] = *nLength; /* save DFS visit order */
1705
nVisitOrd2[cur2] = *nLength;
1707
/* new version allows all inverted parities */
1708
if ( PARITY_WELL_DEF(at[cur1].stereo_atom_parity) &&
1709
PARITY_WELL_DEF(at[cur2].stereo_atom_parity) ) {
1710
if ( *bParitiesInverted < 0 ) {
1711
*bParitiesInverted = (at[cur1].stereo_atom_parity + at[cur2].stereo_atom_parity) % 2;
1713
if ( *bParitiesInverted != (at[cur1].stereo_atom_parity + at[cur2].stereo_atom_parity) % 2 ) {
1714
return 0; /* Different known in advance parities have wrong "inverted" relation */
1717
if ( PARITY_KNOWN(at[cur1].stereo_atom_parity) &&
1718
PARITY_KNOWN(at[cur2].stereo_atom_parity) &&
1719
at[cur1].stereo_atom_parity != at[cur2].stereo_atom_parity ) {
1720
return 0; /* Different known in advance parities */
1723
if ( cur1 != cur2 &&
1724
!at[cur1].stereo_bond_neighbor[0] && !at[cur2].stereo_bond_neighbor[0] &&
1725
PARITY_KNOWN(at[cur1].parity) != PARITY_KNOWN(at[cur2].parity) ) {
1726
return 0; /* one atom is stereogenic, another (presumably equivalent) is not. 9-11-2002 */
1728
#if ( PROPAGATE_ILL_DEF_STEREO != 1 )
1729
if ( cur1 != cur2 &&
1730
(PARITY_ILL_DEF(at[cur1].stereo_atom_parity) ||
1731
PARITY_ILL_DEF(at[cur2].stereo_atom_parity))
1733
return 0; /* Cannot detect whether the paths are same or different */
1737
if ( at[cur1].valence != at[cur2].valence ) {
1738
return CT_REMOVE_STEREO_ERR; /* program error */ /* <BRKPT> */
1740
if ( at[cur1].valence == 1 ) {
1741
return 1; /* so far success */
1744
if ( nl1[(int)cur1][0] != nl2[(int)cur2][0] || nl1[(int)cur1][0] != at[cur1].valence ) {
1745
return CT_REMOVE_STEREO_ERR; /* error: different valences */ /* <BRKPT> */
1749
for ( k = 1, k1 = 1, k2 = 1; k < at[cur1].valence; k ++, k1 ++, k2 ++ ) {
1750
if ( (n1 = nl1[(int)cur1][k1]) == prev1 ) {
1751
n1 = nl1[(int)cur1][++k1]; /* don't go back */
1753
if ( (n2 = nl2[(int)cur2][k2]) == prev2 ) {
1754
n2 = nl2[(int)cur2][++k2]; /* don't go back */
1757
if ( 0 >= (ret = CheckNextSymmNeighborsAndBonds( at, cur1, cur2, n1, n2, nAvoidCheckAtom,
1758
nVisited1, nVisited2, nVisitOrd1, nVisitOrd2, nRank1, nRank2 ) ) ) {
1759
return ret; /* different neighbors or bonds */
1762
if ( !nVisited1[n1] ) { /* recursion */
1763
/* allow all inverted parities only inside a single ring system containing the starting point */
1764
pbParitiesInverted = (at[cur1].nRingSystem == at[n1].nRingSystem)? bParitiesInverted:&bParitiesInvertedZero;
1765
if ( 0 >= (ret = CreateCheckSymmPaths( at, cur1, n1, cur2, n2, nAvoidCheckAtom,
1766
nVisited1, nVisited2, nVisitOrd1, nVisitOrd2,
1767
nl1, nl2, nRank1, nRank2, nCanonRank, nLength, pbParitiesInverted, mode ) ) ) {
1772
return 1; /* Success */
1775
/**************************************************************************************/
1776
/* Compare parities */
1777
#define MAX_OTHER_NEIGH 2
1779
#define NEIGH_MODE_RING 1
1780
#define NEIGH_MODE_CHAIN 2
1782
#define CHECKING_STEREOCENTER 1
1783
#define CHECKING_STEREOBOND 2
1785
#define COMP_STEREO_SUCCESS 1
1786
#define NOT_WELL_DEF_UNKN 2
1787
#define NOT_WELL_DEF_UNDF 4
1789
#define PARITY_IMPOSSIBLE 999
1790
/**************************************************************************************
1791
Note: the following C2v/S4 stereo center symmetry recognition
1792
is not included in the final InChI version released in April 2005
1793
It is disabled in the mode.h (CHECK_C2v_S4_SYMM = 0)
1794
As the result, the only central atom in S4 or atoms on C2v axis
1795
may have pasrity (-) even though these atoms are not stereogenic.
1797
Reason: Not finished/tested yet
1798
**************************************************************************************
1800
In case of stereocenter with 2 pairs of constitutionally identical neighbors :
1802
G(n) > H(m) means group G has n elements; group H has m elements and
1803
group H is a subgroup of G
1805
Td(24) > D2d(8> > D2(4)
1806
> S4(4) > C2(2) -- Test for S4
1807
> C2v(4) > C2(2) -- Test for C2v
1810
Td(24) > C3v(6) > C3(3) -- does not have 2 pairs of constitutionally identical neighbors
1813
The pair of atoms to check for the existence of a steregenic atom: X, Y
1821
Conditions to check:
1823
(a) Old #0: Map canonical numbers X1 <--> Y2
1824
Traverse DFS from X and Y
1825
If all parities vs. canon. numbers unchanged except that of C
1826
then C is not stereogenic
1828
(b) C2v #1: discover ACB symmetry plain Cv
1829
o Map canonical numbers X1 <--> Y2, Fix(Ai), Fix(Bi)
1830
o Make sure that after mapping X1 <--> Y2 the atoms Ai and
1831
Bi still have equal mapping ranks
1832
Traverse DFS from X and Y
1833
In this case canonical numbers will be reflected in plane ACB if it exists.
1834
o Criterion of the presence of the symmetry plain is:
1835
--> all stereogenic atoms and allenes parities are inverted
1836
(c) C2v #2: discover vertical axis C2
1837
o Map canonical numbers X1 <--> Y2 and A1 <--> B2
1838
o Make sure that after mapping X1 <--> Y2 the atoms Ai and
1839
Bi still have equal mapping ranks
1840
o Traverse DFS from X1 and Y2
1841
In this case canonical numbers will be rotated by
1842
180 degrees around the vertical axis
1843
(this may be considered as a superposition of two Cv
1844
reflections in perpendicular vertical planes)
1845
o Criterion of the presence of the C2 axis is:
1846
--> all stereogenic atoms and allenes parities are not changed
1847
(d) S4 #3: discover axis horizontal S4 axis
1848
o Map canonical numbers X1 <--> Y2, Y1 <--> A2, A1 <--> B2, B1 <--> X2
1849
o Traverse DFS from X1 and Y2
1850
In this case the canonical numbers will be rotated by
1851
90 degrees and reflected in a horizontal plane.
1852
3 attempts corrresponding to transpositions 0132, 0213, 0321
1853
are sufficient (XY=01,02,03)
1854
o Criterion of the presence of the S4 symmetry axis is:
1855
--> all stereogenic atoms and allenes parities are inverted
1857
***************************************************************************************/
1859
/**************************************************************************************/
1860
int CalculatedPathsParitiesAreIdentical( sp_ATOM *at, int num_atoms, const AT_RANK *nSymmRank,
1861
AT_RANK *nCanonRank, AT_RANK *nAtomNumberCanon,
1862
AT_RANK *nAtomNumberCanon1, AT_RANK *nAtomNumberCanon2,
1863
AT_RANK *nVisited1, AT_RANK *nVisited2,
1864
AT_RANK prev_sb_neigh, AT_RANK cur, AT_RANK next1, AT_RANK next2, int nNeighMode,
1865
int bParitiesInverted, int mode, CANON_STAT *pCS,
1866
int vABParityUnknown)
1868
int i, i01, i02, i11, i12, i21, i22, k, parity, parity1, parity2, parity12, num_other_neigh;
1869
int nNumEqStereogenic, nCheckingMode, not_well_def_parities;
1870
AT_RANK other_neigh[MAX_NUM_STEREO_ATOM_NEIGH], neigh, r1, r2;
1871
int nNumComparedCenters = 0, nNumComparedBonds = 0, bCurParityInv1=0 /*, bCurParityInv2=0*/;
1872
int bCurRotated=0, nNumDiff=0, nNumInv=0;
1875
nCheckingMode = ( prev_sb_neigh < num_atoms )? CHECKING_STEREOBOND : CHECKING_STEREOCENTER;
1876
not_well_def_parities = 0;
1877
nNumEqStereogenic = 0;
1879
if ( nNeighMode != NEIGH_MODE_RING &&
1880
bParitiesInverted != 0 || abs(bParitiesInverted) != 1 ) {
1881
bParitiesInverted = 0;
1884
if ( bParitiesInverted ) {
1885
for ( i = 0, i11 = i22 = 0; i < num_atoms; i ++ ) {
1886
/* count number of atoms that have not been visited */
1887
i11 += !nVisited1[i];
1888
i22 += !nVisited2[i];
1889
nAtomNumberCanon1[i] = MAX_ATOMS+1; /* mark unchanged */
1890
nAtomNumberCanon2[i] = MAX_ATOMS+1; /* mark unchanged */
1893
if ( bParitiesInverted == 1 )
1894
return 0; /* only a part of the structure has been inverted */
1896
bParitiesInverted = 0;
1899
for ( i = 0; i < num_atoms; i ++ ) {
1900
nAtomNumberCanon1[i] = MAX_ATOMS+1; /* mark unchanged */
1901
nAtomNumberCanon2[i] = MAX_ATOMS+1; /* mark unchanged */
1904
if ( bParitiesInverted > 0 && !(mode == MAP_MODE_C2v || mode == MAP_MODE_S4) ||
1905
bParitiesInverted == 0 && !(mode == MAP_MODE_C2 || mode == MAP_MODE_STD)) {
1908
/**************************************************************************************
1909
* The following discussion assumes that the canonical numbers are
1910
* switched for some pairs of constitutionally identical atoms
1911
* in such a way that the new numbering is an equivalent to the
1912
* nCanonRank[] canonical numbering (the transposition belongs to the
1913
* automorphism group of the chemical structure having no stereo).
1914
* At this point non-zero elements of nVisited1[] and nVisited2[]
1915
* together contain transposition P of the atom numbers.
1916
* and P2 respectively of the ordering atom numbers: nVisitedi[k] = Pi(k)+1;
1917
* In this implementation:
1919
* P2(cur)=cur, P2(next1)=next2, P2(next2)=next1
1921
* Below we call one of the numberings "old", another "new".
1923
* *IF* the old and the new canonical numberings produce same parities for stereogenic
1924
* elements for the same canonical number(s)
1925
* (that is, old_parity(canon_number) == new_parity(canon_number)
1926
* *except* the currently being tested stereocenter at[cur] or stereobond/cumulene
1927
* at[cur]=at[prev_sb_neigh], whose parity MUST be inverted
1929
* *THEN* the stereocenter or stereobond/cumulene is not stereogenic with one
1931
* *EXCEPTION* If the currently tested stereogenic element is constitutionally
1932
* equivalent to two or more other stereogenic elements that have been
1933
* permuted then the currently tested one is still stereogenic.
1934
**************************************************************************************/
1937
* 1. replace the assigned in each of the parallel traversals atom numbers
1938
* with the canon. ranks corresponding to the atom numbers in the
1939
* currently numbered atoms at[].
1940
* One of obtained this way canonical numberings (probably nVisited1[])
1941
* is same as the nCanonRank[] because usually nVisited1[i] = i+1 or 0
1943
for ( i = 0; i < num_atoms; i ++ ) {
1945
if ( nVisited1[i] ) {
1946
/* canonical number of the atom mapped on atom #i in 'left' path */
1947
nVisited1[i] = nCanonRank[ (int)nVisited1[i] - 1 ];
1948
/* reverse: atom # from the mapped canonical rank in 'left' path */
1949
nAtomNumberCanon1[nVisited1[i] - 1] = i;
1951
if ( nVisited2[i] ) {
1952
/* canonical number of the atom mapped on atom #i in 'right' path */
1953
nVisited2[i] = nCanonRank[ (int)nVisited2[i] - 1 ];
1954
/* reverse: atom # from the mapped canonical rank in 'right' path */
1955
nAtomNumberCanon2[nVisited2[i] - 1] = i;
1957
/* if 'left' and 'right' path do not have atoms in common except the
1958
starting atom (and in case of stereobond, the end atom) some of
1959
nVisitedi[i] elements may be zero.
1964
* if started with a stereobond then check whether its parity has changed.
1965
* If yes then continue, otherwise parities are different
1967
* if started with a stereo center then prev_sb_neigh = MAX_ATOMS+1
1969
* If the transposition of next1 and next2 changes only the parity of the starting stereo atom or stereo bond
1970
* then the stereo bond or stereo atom is not stereogenic
1972
* The exception: the stereogenic elememt in question is equivalent
1973
* to two or more traversed other stereogenic elememts
1974
* (see nNumEqStereogenic below, case similar to trimethylcyclopropane:
1975
* 3 or more constitutionally equivalent stereogenic elements)
1977
if ( nCheckingMode == CHECKING_STEREOBOND ) {
1978
/******************************************************************************
1980
* Possibly stereogenic starting bond or cumulene at[cur]-at[prev_sb_neigh]
1982
*******************************************************************************/
1983
/* checking the starting stereo bond */
1984
if ( nVisited1[prev_sb_neigh] || nVisited2[prev_sb_neigh] ) {
1985
/* the bond or cumulene is in the ring and the opposite atom has been visited */
1986
if ( nVisited1[prev_sb_neigh] != nVisited2[prev_sb_neigh] ||
1987
nCanonRank[prev_sb_neigh] != nVisited2[prev_sb_neigh] ) {
1988
return 0; /* error: we came back to the same bond/cumulene and */ /* <BRKPT> */
1989
/* assigned different canon. ranks to the opposite atom. */
1991
if ( at[prev_sb_neigh].valence + at[prev_sb_neigh].num_H > 3 )
1992
return 0; /* at[prev_sb_neigh] atom can not be adjacent to a stereo bond/cumulene */
1993
/* or does not have 3 attachments (hydrogens are not considered here) */
1994
for ( i = 0, k = 0; i < MAX_NUM_STEREO_BONDS &&
1995
(neigh=at[prev_sb_neigh].stereo_bond_neighbor[i]) && !(k=(neigh-1 == cur)); i ++ )
1998
return -1; /* program error: could not locate stereogenic bond mark on the opposite atom */
2000
k = (int)at[prev_sb_neigh].stereo_bond_ord[i]; /* seq. number of the double or cumulene bond on at[prev_sb_neigh] */
2002
for ( i = 0, num_other_neigh = 0; i < at[prev_sb_neigh].valence && num_other_neigh <= MAX_OTHER_NEIGH; i ++ ) {
2003
if ( i != k ) { /* do not include the double or cumulene bond */
2004
other_neigh[num_other_neigh ++] = at[prev_sb_neigh].neighbor[i];
2007
if ( num_other_neigh + at[prev_sb_neigh].num_H > MAX_OTHER_NEIGH ) {
2008
return CT_STEREOCOUNT_ERR; /* <BRKPT> */
2010
for ( i = 0; i < num_other_neigh; i ++ ) {
2011
k = (int)other_neigh[i];
2012
if ( nVisited1[k] && nVisited1[k] != nCanonRank[k] ) {
2013
return 0; /* parity of the statring stereo bond/cumulene has not changed. */
2015
if ( nVisited2[k] && nVisited2[k] != nCanonRank[k] ) {
2016
return 0; /* parity of the statring stereo bond/cumulene has not changed. */
2021
if ( nCheckingMode == CHECKING_STEREOCENTER ) {
2022
/**************************************************
2024
* Possibly stereogenic starting atom at[cur]
2026
**************************************************/
2027
/* checking the starting stereo center */
2028
for ( i = 0, num_other_neigh = 0; i < at[cur].valence && num_other_neigh <= MAX_OTHER_NEIGH; i ++ ) {
2029
neigh = at[cur].neighbor[i];
2030
if ( neigh != next1 && neigh != next2 ) {
2031
other_neigh[num_other_neigh ++] = neigh;
2034
if ( num_other_neigh + at[cur].num_H > MAX_OTHER_NEIGH ) {
2035
return CT_STEREOCOUNT_ERR; /* <BRKPT> */
2038
if ( bParitiesInverted && at[cur].valence == MAX_NUM_STEREO_ATOM_NEIGH ) {
2039
if ( nVisited1[other_neigh[0]] == nCanonRank[other_neigh[0]] ||
2040
nVisited2[other_neigh[0]] == nCanonRank[other_neigh[0]] ||
2041
nVisited1[other_neigh[1]] == nCanonRank[other_neigh[1]] ||
2042
nVisited2[other_neigh[1]] == nCanonRank[other_neigh[1]] ) {
2043
bParitiesInverted = 0;
2048
/* bParitiesInverted = -1 means no predefined stereocenter has been checked */
2049
if ( bParitiesInverted && at[cur].valence == MAX_NUM_STEREO_ATOM_NEIGH ) {
2050
/* special case: 4 canonically eq. neighbors */
2051
int canon_parity, parity_vis_1, parity_vis_2;
2052
canon_parity = GetPermutationParity( at+cur, MAX_ATOMS+1, nCanonRank );
2053
parity_vis_1 = GetPermutationParity( at+cur, MAX_ATOMS+1, nVisited1 );
2054
parity_vis_2 = GetPermutationParity( at+cur, MAX_ATOMS+1, nVisited2 );
2055
if ( parity_vis_1 != parity_vis_2 ) {
2058
if ( bParitiesInverted == 1 && parity_vis_1 == canon_parity ) {
2059
return 0; /* not a typical case of inversion during the mapping of D4h stereocenter */
2061
if ( bParitiesInverted == -1 ) {
2062
if ( parity_vis_1 == canon_parity ) {
2063
bParitiesInverted = 0;
2065
bParitiesInverted = 1;
2069
/* at this point bParitiesInverted >= 0 */
2070
if ( !bParitiesInverted && !bCurRotated ) {
2071
for ( i = 0; i < num_other_neigh; i ++ ) {
2072
k = (int)other_neigh[i];
2073
if ( nVisited1[k] && nVisited1[k] != nCanonRank[k] ) {
2074
return 0; /* parity of the statring stereo center has not changed. */
2076
if ( nVisited2[k] && nVisited2[k] != nCanonRank[k] ) {
2077
return 0; /* parity of the statring stereo center has not changed. */
2083
/*****************************************************
2084
* Check other (non-starting) stereo centers
2085
******************************************************/
2086
for ( i = 0; i < pCS->nLenLinearCTStereoCarb; i ++, nNumComparedCenters += (k > 0) ) {
2087
r1 = pCS->LinearCTStereoCarb[i].at_num;
2088
i01 = nAtomNumberCanon[r1-1]; /* ord. number of the atom that has canon rank r1 */
2090
i11 = nAtomNumberCanon1[r1-1]; /* = (MAX_ATOMS+1) > num_atoms if the atom has not been traversed */
2091
i12 = nAtomNumberCanon2[r1-1]; /* = otherwise < num_atoms */
2093
s1 = (i11 < num_atoms); /* 1 => the center was traversed on path #1 */
2094
s2 = (i12 < num_atoms); /* 1 => the center was traversed on path #2 */
2096
bCurParityInv1 = (bParitiesInverted &&
2097
at[cur].nRingSystem == at[i11].nRingSystem &&
2098
at[cur].nRingSystem == at[i12].nRingSystem );
2103
/* check whether the two stereo centers (they can be one and the same atom) have been traversed */
2105
continue; /* Both stereo centers have not been traversed; check the next pair. */
2108
if ( nCheckingMode == CHECKING_STEREOCENTER ) {
2109
/* check whether the stereocenters are the starting stereocenter */
2110
switch( (cur == i11) + (cur == i12) ) {
2112
continue; /* do not recheck the starting atom */
2114
return -1; /* possibly program error */ /* <BRKPT> */
2116
/* break; */ /* the stereo centers are not the sarting stereo center */
2119
return -1; /* program error: in this case at least one of the i11, i12 must be == cur */ /* <BRKPT> */
2123
if ( nNeighMode == NEIGH_MODE_RING ) {
2124
if ( i11 != i12 && !bCurParityInv1 ) {
2125
return -1; /* failed: the two stereo atoms have not been traversed synchronously */
2127
if ( !at[i11].parity || !at[i12].parity ) {
2128
return 0; /* another atom does not have parity (it might have been removed) 9-11-2002 */
2131
if ( nNeighMode == NEIGH_MODE_CHAIN ) {
2133
return -1; /* program error: only one out of s1 and s2 must be 1, another must be 0. */
2135
if ( s1 && !at[i11].parity || s2 && !at[i12].parity ) {
2136
return 0; /* another atom does not have parity (it might have been removed) 9-11-2002 */
2140
parity = pCS->LinearCTStereoCarb[i].parity;
2141
if ( nNeighMode == NEIGH_MODE_RING && (i11 != i01) && (i12 != i01) ||
2142
/* in NEIGH_MODE_RING case we know that i11 == i12 except bCurParityInv1 == 1 */
2143
nNeighMode == NEIGH_MODE_CHAIN
2144
/* in NEIGH_MODE_CHAIN case here we always have 2 different atoms */
2146
/****************************************************************
2147
* Case of two transposed atoms or a circular permutation in D4h
2149
parity1 = s1? GetStereoCenterParity( at, i11, nVisited1 ) : PARITY_IMPOSSIBLE;
2150
parity2 = s2? GetStereoCenterParity( at, i12, nVisited2 ) : PARITY_IMPOSSIBLE;
2151
if ( !ATOM_PARITY_KNOWN(parity1) && !ATOM_PARITY_KNOWN(parity2) ) {
2152
return -1; /* should not happen: must have been detected at the time of the traversal */
2155
if ( bCurParityInv1 ) {
2156
int parity1orig = GetStereoCenterParity( at, i11, nCanonRank );
2157
int parity2orig = GetStereoCenterParity( at, i12, nCanonRank );
2159
(parity1 == parity1orig || parity2 == parity2orig || parity1 != parity2) &&
2160
ATOM_PARITY_WELL_DEF(parity1) ||
2161
parity1 != parity2 && (!ATOM_PARITY_WELL_DEF(parity1) ||
2162
!ATOM_PARITY_WELL_DEF(parity2)) )
2163
/*return -1; */ /* should be different atoms with inverted parities */
2166
if ( i11 != i12 || parity1 != parity2 )
2167
return -1; /* program error: must be the same atom */
2170
parity12 = s1? parity1 : parity2;
2172
if ( ATOM_PARITY_WELL_DEF(parity) && parity == parity12 ) {
2173
/* symmetrical neighbors have well-defined equal parities */
2175
if ( nCheckingMode == CHECKING_STEREOCENTER && nNeighMode == NEIGH_MODE_RING ) {
2176
/* all 3: cur, i01, i11 are different atoms (here i11==i12) */
2177
/* here nSymmRank[i01]==nSymmRank[i11] due to the parallel traversal */
2178
if ( nSymmRank[cur] == nSymmRank[i01] ) {
2179
nNumEqStereogenic ++; /* all 3 are equ */
2183
if ( ATOM_PARITY_WELL_DEF(parity) && ATOM_PARITY_WELL_DEF(parity12) ) {
2184
/* apparently different well-defined parities */
2185
if ( !bCurParityInv1 ) {
2190
#if ( PROPAGATE_ILL_DEF_STEREO == 1 )
2191
/* at least one parity is ill-defined. Use parity1 and parity2 to temporarily save bitmaps */
2192
parity1 = (parity ==vABParityUnknown /*AB_PARITY_UNKN*/)? NOT_WELL_DEF_UNKN :
2193
(parity ==AB_PARITY_UNDF)? NOT_WELL_DEF_UNDF : 0;
2194
parity2 = (parity12==vABParityUnknown /*AB_PARITY_UNKN*/)? NOT_WELL_DEF_UNKN :
2195
(parity12==AB_PARITY_UNDF)? NOT_WELL_DEF_UNDF : 0;
2196
if ( parity1 | parity2 ) {
2197
not_well_def_parities |= ( parity1 | parity2 );
2200
return -1; /* program error */ /* <BRKPT> */
2207
if ( i11 == i01 && i12 == i01 ) {
2208
/********************************************************************/
2209
/* i11 == i12 are same atom as i01, nNeighMode == NEIGH_MODE_RING */
2213
/* the parity of the new neighbors permutation must be same as the old one */
2214
/* this must work for well-defined and ill-defined parities. */
2215
/* actual parity (that includes the geometry) is not important here. */
2216
/* old permutation */
2217
parity = GetPermutationParity( at+i01, MAX_ATOMS+1, nCanonRank );
2218
/* new parmutation */
2219
parity1 = GetPermutationParity( at+i01, MAX_ATOMS+1, nVisited1 );
2220
parity2 = GetPermutationParity( at+i01, MAX_ATOMS+1, nVisited2 );
2221
if ( parity != parity1 || parity != parity2 ) {
2226
/* nNeighMode == NEIGH_MODE_RING and only one out of the two (i11 == i01) (i12 == i01) is true */
2229
/* nNumComparedCenters += (k > 0); */
2231
if ( bCurRotated || nNumDiff || nNumInv ) {
2235
/* !!!! Add here bParitiesInverted == 1 case !!!! */
2236
/******************************************************/
2237
/* Check other (non-starting) stereo bonds/cumulenes */
2238
/******************************************************/
2239
for ( i = 0; i < pCS->nLenLinearCTStereoDble; i ++, nNumComparedBonds += (k > 0) ) {
2240
r1 = pCS->LinearCTStereoDble[i].at_num1;
2241
r2 = pCS->LinearCTStereoDble[i].at_num2;
2242
i01 = nAtomNumberCanon[r1-1]; /* ord. number of the atom that originally has canon rank r1 */
2243
i02 = nAtomNumberCanon[r2-1]; /* ord. number of the atom that originally has canon rank r2 */
2245
i11 = nAtomNumberCanon1[r1-1]; /* ord. number of the atom that got canon rank r1 during the parallel traversal */
2246
i12 = nAtomNumberCanon1[r2-1]; /* ord. number of the atom that got canon rank r2 during the parallel traversal */
2248
i21 = nAtomNumberCanon2[r1-1];
2249
i22 = nAtomNumberCanon2[r2-1];
2252
s1 = (i11 < num_atoms && i12 < num_atoms);
2253
s2 = (i21 < num_atoms && i22 < num_atoms);
2257
/* check whether the two stereo bonds/allenes (they can be one and the same) have been traversed */
2259
continue; /* Both stereo bonds/cumulenes have not been traversed; check the next pair. */
2262
if ( nCheckingMode == CHECKING_STEREOBOND ) {
2263
switch ( (i11 == cur && i12 == prev_sb_neigh || i12 == cur && i11 == prev_sb_neigh) +
2264
(i21 == cur && i22 == prev_sb_neigh || i22 == cur && i21 == prev_sb_neigh) ) {
2266
continue; /* do not recheck the starting bond/cumulene */
2268
return -1; /* possibly program error */ /* <BRKPT> */
2270
/* break; */ /* the stereo centers are not the sarting stereo center */
2272
if ( (i01 == cur && i02 == prev_sb_neigh) || (i02 == cur && i01 == prev_sb_neigh) ) {
2273
return -1; /* program error: in this case at least one of the i1x, i2x must be == cur */ /* <BRKPT> */
2277
if ( nNeighMode == NEIGH_MODE_RING ) {
2278
if ( (i11 != i21 || i12 != i22) && (i11 != i22 || i12 != i21) ) {
2279
return -1; /* failed: the two bonds/cumulenes have not been traversed synchronously */
2281
if ( 0 > GetStereoNeighborPos( at, i11, i12 ) ) {
2282
return 0; /* another bond is not stereo (the stereo might have been removed) 9-11-2002 */
2286
if ( nNeighMode == NEIGH_MODE_CHAIN ) {
2288
return -1; /* program error: only one out of s1 and s2 must be 1, another must be 0. */
2290
if ( s1 && 0 > GetStereoNeighborPos( at, i11, i12 ) ||
2291
s2 && 0 > GetStereoNeighborPos( at, i21, i22 ) ) {
2292
return 0; /* another bond is not stereo (the stereo might have been removed) 9-11-2002 */
2296
parity = pCS->LinearCTStereoDble[i].parity;
2297
/* bMustBeIdentical = ATOM_PARITY_ILL_DEF(parity); */
2298
/* nNumEqStereogenic = 0; */
2300
if ( nNeighMode == NEIGH_MODE_RING && (i11 != i01 || i12 != i02) && (i11 != i02 || i12 != i01) ||
2301
nNeighMode == NEIGH_MODE_CHAIN /* in NEIGH_MODE_CHAIN case here we always have 2 different atoms */
2303
/*******************************************/
2304
/* case of two transposed bonds/cumulenes */
2305
parity1 = s1? GetStereoBondParity( at, i11, i12, nVisited1 ) : PARITY_IMPOSSIBLE;
2306
parity2 = s2? GetStereoBondParity( at, i21, i22, nVisited2 ) : PARITY_IMPOSSIBLE;
2307
if ( !ATOM_PARITY_KNOWN(parity1) && !ATOM_PARITY_KNOWN(parity2) ) {
2308
return -1; /* should not happen: must have been detected at the time of traversal */
2310
if ( s1 && s2 && ((i11 != i21 || i12 != i22) && (i11 != i22 || i12 != i21) || parity1 != parity2 ) ) {
2311
return -1; /* program error: must be the same bond/cumulene */
2313
parity12 = s1? parity1 : parity2;
2314
if ( ATOM_PARITY_WELL_DEF(parity) && parity == parity12 ) {
2315
/* symmetrical neighbors have well-defined equal parities */
2317
if ( nCheckingMode == CHECKING_STEREOBOND && nNeighMode == NEIGH_MODE_RING ) {
2318
/* all 3 bonds: cur-prev_sb_neigh, i01-i02, i11-i12 are different */
2319
/* (here <i11,i12>==<i21,i22> compared as unordered pairs) */
2320
if ( nSymmRank[cur] == nSymmRank[i01] && nSymmRank[prev_sb_neigh] == nSymmRank[i02] ||
2321
nSymmRank[cur] == nSymmRank[i02] && nSymmRank[prev_sb_neigh] == nSymmRank[i01] ) {
2322
nNumEqStereogenic ++;
2326
if ( ATOM_PARITY_WELL_DEF(parity) && ATOM_PARITY_WELL_DEF(parity12) ) {
2327
/* apparently different well-defined parities */
2330
/* at least one parity is ill-defined. Use parity1 and parity2 to temporarily save bitmaps */
2331
#if ( PROPAGATE_ILL_DEF_STEREO == 1 )
2332
parity1 = (parity ==vABParityUnknown /*AB_PARITY_UNKN*/)? NOT_WELL_DEF_UNKN :
2333
(parity ==AB_PARITY_UNDF)? NOT_WELL_DEF_UNDF : 0;
2334
parity2 = (parity12==vABParityUnknown /*AB_PARITY_UNKN*/)? NOT_WELL_DEF_UNKN :
2335
(parity12==AB_PARITY_UNDF)? NOT_WELL_DEF_UNDF : 0;
2336
if ( parity1 | parity2 ) {
2337
not_well_def_parities |= ( parity1 | parity2 );
2340
return -1; /* program error */
2347
/*****************************************************************************************/
2348
/* i11-i12 and i21-i22 are same as i01-i02 bond/cumulene, nNeighMode == NEIGH_MODE_RING */
2354
/* find neighbors along the stereo bond/cumulene */
2355
for ( j = 0, n1 = MAX_ATOMS+1; j < MAX_NUM_STEREO_BOND_NEIGH && at[i01].stereo_bond_neighbor[j]; j ++ ) {
2356
if ( (int)at[i01].stereo_bond_neighbor[j] == i02+1 ) {
2357
n1 = at[i01].neighbor[ (int)at[i01].stereo_bond_ord[j] ];
2361
for ( j = 0, n2 = MAX_ATOMS+1; j < MAX_NUM_STEREO_BOND_NEIGH && at[i02].stereo_bond_neighbor[j]; j ++ ) {
2362
if ( (int)at[i02].stereo_bond_neighbor[j] == i01+1 ) {
2363
n2 = at[i02].neighbor[ (int)at[i02].stereo_bond_ord[j] ];
2367
if ( n1 > MAX_ATOMS || n2 > MAX_ATOMS ) {
2368
return CT_REMOVE_STEREO_ERR;
2370
/* the parity of the new neighbors permutation must be same as the old one */
2371
/* this must work for well-defined and ill-defined parities. */
2372
/* actual parity (that includes the geometry) is not important here. */
2373
/* old permutation */
2374
parity = GetPermutationParity( at+i01, n1, nCanonRank) + GetPermutationParity( at+i02, n2, nCanonRank);
2375
/* new parmutation */
2376
parity1 = GetPermutationParity( at+i01, n1, nVisited1 ) + GetPermutationParity( at+i02, n2, nVisited1 );
2377
parity2 = GetPermutationParity( at+i01, n1, nVisited2 ) + GetPermutationParity( at+i02, n2, nVisited2 );
2378
if ( parity %2 != parity1 % 2 || parity1 % 2 != parity2 % 2 ) {
2384
/* nNumComparedBonds += ( k > 0 ); */
2387
if ( nNumEqStereogenic > 0 ) {
2388
/* case similar to trimethylcyclopropane: 3 constitutionally equivalent stereogenic elements */
2389
/* the transposition does not change the parities */
2390
#if ( bRELEASE_VERSION == 0 )
2391
pCS->bExtract |= EXTR_2EQL2CENTER_TO_REMOVE_PARITY;
2395
/* =========================================================================================
2398
At this point the comparison is complete and no difference sufficient to establish
2399
absence of stereo parity has been found.
2400
However, non-zero not_well_def_parities means that an ill-defined parity was
2401
compared to an ill-defined or well-defined parity. This means that the parity
2402
of the atom or bond being checked cannot be well-defined anymore.
2403
========================================================================================*/
2406
not_well_def_parities |= COMP_STEREO_SUCCESS;
2408
return not_well_def_parities;
2410
/* Add 1 to indicate success. The stereogenic elements might have been */
2411
/* removed while checking existence of the previous atom/bond stereo */
2412
/* return (nNumComparedCenters + nNumComparedBonds + 1); */
2414
/********************************************************************************/
2415
/* Remove stereo marks from the bonds that are calculated to be non-stereo */
2416
/* Such bonds must have 2 constitutionally equivalent attachments */
2417
/* (can find two canonical numberings that change only one stereo bond parity) */
2418
int RemoveCalculatedNonStereoBondParities( sp_ATOM *at, int num_atoms, int num_at_tg,
2419
AT_RANK **pRankStack1, AT_RANK **pRankStack2, AT_RANK *nTempRank, NEIGH_LIST *NeighList,
2420
AT_RANK *nCanonRank, const AT_RANK *nSymmRank,
2421
AT_RANK *nAtomNumberCanon, AT_RANK *nAtomNumberCanon1, AT_RANK *nAtomNumberCanon2,
2422
NEIGH_LIST *nl, NEIGH_LIST *nl1, NEIGH_LIST *nl2,
2423
AT_RANK *nVisited1, AT_RANK *nVisited2,
2425
int vABParityUnknown)
2427
int j, n, m, ret, ret1, ret2, ret_failed=0;
2429
int i1, n1, s2; /* n1 must be SIGNED integer */
2430
AT_RANK nAtomRank1, nAtomRank2, neigh[3], nAvoidCheckAtom[2], opposite_atom, nLength;
2431
int nNeighMode = NEIGH_MODE_CHAIN;
2432
int nNumEqRingNeigh = 0, bRingNeigh, bSymmNeigh, bParitiesInverted;
2433
NEIGH_LIST *nl01, *nl02;
2434
const AT_RANK *nSymmRank1, *nSymmRank2;
2440
for ( i1 = 0; i1 < num_atoms && !RETURNED_ERROR(ret_failed); i1 ++ ) {
2441
if ( at[i1].valence != 3 || !at[i1].stereo_bond_neighbor[0] ) {
2444
for ( n1 = 0; n1 < MAX_NUM_STEREO_BONDS && !RETURNED_ERROR(ret_failed) && (s2=at[i1].stereo_bond_neighbor[n1]); n1++ ) {
2445
if ( !PARITY_CALCULATE(at[i1].stereo_bond_parity[n1]) && PARITY_WELL_DEF(at[i1].stereo_bond_parity[n1]) ) {
2448
opposite_atom = (AT_RANK)(s2-1);
2449
s2 = at[i1].neighbor[(int)at[i1].stereo_bond_ord[n1]]; /* different from opposite_atom in case of a cumulene */
2450
for ( j = 1, n = 0; j <= (int)at[i1].valence; j ++ ) {
2451
if ( nl[i1][j] != s2 ) {
2452
neigh[n++] = nl[i1][j]; /* sorting guarantees that canon. rank of neigh[0] is greater or equal */
2456
ret = CT_STEREOBOND_ERROR; /* <BRKPT> */
2459
if ( nSymmRank[(int)neigh[0]] != nSymmRank[(int)neigh[1]] ) {
2460
continue; /* may happen if another half-bond has not a defined parity */
2463
bRingNeigh = (at[(int)neigh[0]].nRingSystem == at[(int)neigh[1]].nRingSystem);
2464
switch ( nNeighMode ) {
2465
case NEIGH_MODE_CHAIN:
2472
nSymmRank1 = nSymmRank;
2473
nSymmRank2 = nSymmRank;
2476
case NEIGH_MODE_RING:
2479
/* break a tie between the two contitutionally equivalent neighbors, */
2480
/* refine the two partitions, sort neighbors lists nl1, nl2 */
2481
bSymmNeigh = BreakNeighborsTie( at, num_atoms, num_at_tg, opposite_atom, i1,
2483
pRankStack1, pRankStack2, nTempRank, NeighList, nSymmRank, nCanonRank,
2484
nl1, nl2, &pCS->lNumNeighListIter );
2485
if ( bSymmNeigh <= 0 ) {
2486
if ( ret_failed > bSymmNeigh )
2487
ret_failed = bSymmNeigh;
2492
nSymmRank1 = pRankStack1[0];
2493
nSymmRank2 = pRankStack2[0];
2496
return CT_STEREOCOUNT_ERR; /* <BRKPT> */
2499
/* initialize arrays */
2500
memset( nVisited1, 0, sizeof(nVisited1[0])*num_atoms );
2501
memset( nVisited2, 0, sizeof(nVisited2[0])*num_atoms );
2502
memset( nAtomNumberCanon1, 0, sizeof(nAtomNumberCanon1[0])*num_atoms );
2503
memset( nAtomNumberCanon2, 0, sizeof(nAtomNumberCanon2[0])*num_atoms );
2505
nVisited1[i1] = i1+1; /* start atoms are the same */
2506
nVisited2[i1] = i1+1;
2507
nAtomNumberCanon1[i1] = nLength;
2508
nAtomNumberCanon2[i1] = nLength;
2509
nAvoidCheckAtom[0] = i1;
2510
nAvoidCheckAtom[1] = opposite_atom;
2511
bParitiesInverted = (nNeighMode == NEIGH_MODE_RING &&
2512
IS_ALLENE_CHAIN(at[i1].stereo_bond_parity[n1]) &&
2513
PARITY_CALCULATE(at[i1].stereo_bond_parity[n1]) &&
2514
at[i1].nRingSystem == at[opposite_atom].nRingSystem &&
2515
at[opposite_atom].valence==MAX_NUM_STEREO_BONDS)? -1 : 0;
2517
if ( 0 < (ret1=CreateCheckSymmPaths( at, (AT_RANK)i1, neigh[0], (AT_RANK)i1, neigh[1], nAvoidCheckAtom,
2518
nVisited1, nVisited2, nAtomNumberCanon1, nAtomNumberCanon2,
2519
nl01, nl02, nSymmRank1, nSymmRank2, nCanonRank, &nLength, &bParitiesInverted, 0 ) ) &&
2520
0 < (ret2=CalculatedPathsParitiesAreIdentical( at, num_atoms, nSymmRank,
2521
nCanonRank, nAtomNumberCanon, nAtomNumberCanon1, nAtomNumberCanon2,
2522
nVisited1, nVisited2, opposite_atom, (AT_RANK)i1,
2523
neigh[0], neigh[1], nNeighMode, bParitiesInverted, 0,
2524
pCS, vABParityUnknown ) ) ) {
2525
if ( ret2 & ( NOT_WELL_DEF_UNKN | NOT_WELL_DEF_UNDF ) ) {
2526
/* possibly change the parity to unknown or undefined */
2527
int new_parity = (ret2 & NOT_WELL_DEF_UNKN)? vABParityUnknown /*AB_PARITY_UNKN*/: AB_PARITY_UNDF;
2528
if ( PARITY_ILL_DEF(at[i1].stereo_bond_parity[n1]) && PARITY_VAL(at[i1].stereo_bond_parity[n1]) > new_parity ||
2529
PARITY_CALCULATE(at[i1].stereo_bond_parity[n1]) ) {
2530
/* set new unknown or undefined parity */
2531
SetOneStereoBondIllDefParity( at, i1, /* atom number*/ n1 /* stereo bond ord. number*/, new_parity );
2533
nAtomRank1 = inchi_max( nCanonRank[i1], nCanonRank[opposite_atom]);
2534
nAtomRank2 = inchi_min( nCanonRank[i1], nCanonRank[opposite_atom]);
2535
for ( n = 0, m = pCS->nLenLinearCTStereoDble-1; n <= m; n ++ ) {
2536
if ( pCS->LinearCTStereoDble[n].at_num1 == nAtomRank1 &&
2537
pCS->LinearCTStereoDble[n].at_num2 == nAtomRank2 ) {
2538
pCS->LinearCTStereoDble[n].parity = new_parity;
2539
#if ( bRELEASE_VERSION == 0 )
2540
pCS->bExtract |= EXTR_CALC_USED_TO_REMOVE_PARITY;
2547
ret = CT_STEREOCOUNT_ERR; /* <BRKPT> */
2553
/* remove the parity */
2554
if ( !RemoveOneStereoBond( at, i1, /* atom number*/ n1 /* stereo bond ord. number*/ ) ) {
2555
ret = CT_STEREOBOND_ERROR; /* <BRKPT> */
2558
n1 --; /* cycle counter may temporarily become negative */
2559
/* Remove from the pCS */
2560
nAtomRank1 = inchi_max( nCanonRank[i1], nCanonRank[opposite_atom]);
2561
nAtomRank2 = inchi_min( nCanonRank[i1], nCanonRank[opposite_atom]);
2562
for ( n = 0, m = pCS->nLenLinearCTStereoDble-1; n <= m; n ++ ) {
2563
if ( pCS->LinearCTStereoDble[n].at_num1 == nAtomRank1 &&
2564
pCS->LinearCTStereoDble[n].at_num2 == nAtomRank2 ) {
2565
if ( n < m ) { /* remove pCS->LinearCTStereoDble[n] */
2566
memmove( pCS->LinearCTStereoDble + n,
2567
pCS->LinearCTStereoDble + n + 1,
2568
(m-n)*sizeof(pCS->LinearCTStereoDble[0]) );
2570
pCS->nLenLinearCTStereoDble --;
2571
#if ( bRELEASE_VERSION == 0 )
2572
pCS->bExtract |= EXTR_CALC_USED_TO_REMOVE_PARITY;
2579
ret = CT_STEREOCOUNT_ERR; /* <BRKPT> */
2585
if ( !ret_failed ) {
2586
ret_failed = (ret1<0)? ret1 : (ret2<0)? ret2 : 0;
2588
if ( !RETURNED_ERROR(ret_failed) ) {
2589
if ( RETURNED_ERROR( ret1 ) )
2592
if ( RETURNED_ERROR( ret2 ) )
2598
if ( nNeighMode == NEIGH_MODE_CHAIN && nNumEqRingNeigh && !RETURNED_ERROR(ret_failed) ) {
2599
nNeighMode = NEIGH_MODE_RING;
2605
return RETURNED_ERROR(ret_failed)? ret_failed : ret_failed? -(ret_failed+1) : ret;
2607
/****************************************************************************/
2608
/* Remove stereo marks from the atoms that are calculated to be non-stereo */
2609
/* (can find two numberings that change only one stereo center parity) */
2610
int RemoveCalculatedNonStereoCenterParities( sp_ATOM *at, int num_atoms, int num_at_tg,
2611
AT_RANK **pRankStack1, AT_RANK **pRankStack2, AT_RANK *nTempRank, NEIGH_LIST *NeighList,
2612
AT_RANK *nCanonRank, const AT_RANK *nSymmRank,
2613
AT_RANK *nAtomNumberCanon, AT_RANK *nAtomNumberCanon1, AT_RANK *nAtomNumberCanon2,
2614
NEIGH_LIST *nl, NEIGH_LIST *nl1, NEIGH_LIST *nl2,
2615
AT_RANK *nVisited1, AT_RANK *nVisited2,
2617
int vABParityUnknown)
2621
int i, k, ret1, ret2, ret_failed=0, mode, max_mode;
2622
AT_RANK nAtomRank1, neigh[MAX_NUM_STEREO_ATOM_NEIGH], nAvoidCheckAtom[2], nLength;
2623
int nNeighMode = NEIGH_MODE_CHAIN;
2624
int nNumEqRingNeigh = 0, bRingNeigh, bSymmNeigh, bParitiesInverted;
2625
NEIGH_LIST *nl01, *nl02;
2626
const AT_RANK *nSymmRank1, *nSymmRank2;
2631
for ( i = 0; i < num_atoms && !RETURNED_ERROR(ret_failed); i ++ ) {
2632
if ( !at[i].parity || at[i].stereo_bond_neighbor[0] ) {
2635
if ( at[i].valence > MAX_NUM_STEREO_ATOM_NEIGH ) {
2636
continue; /* error: stereo center cannot have more than 4 neighbors */ /* <BRKPT> */
2638
/* at[i1] is a stereo center */
2639
if ( !PARITY_CALCULATE(at[i].stereo_atom_parity) && !PARITY_ILL_DEF(at[i].stereo_atom_parity) ) {
2642
/* neighbors sorted according to symm. ranks (primary key) and canon. ranks (secondary key), in descending order */
2643
/* sorting guarantees that for two constit. equ. neighbors canon. ranks of the first is greater */
2644
/* !!! previously (but not anymore) the canon. rank of neigh[0] was greater than the others !!! */
2645
for ( j = 0; j < at[i].valence; j ++ ) {
2646
neigh[j] = nl[i][j+1]; /* sorting does NOT guarantee that canon. rank of neigh[0] is greater than others */
2649
* mode = 0 => Standard approach: switch 2 neighbors
2650
* 1 => Check for C2v reflection leading to parity inversion
2651
* 2 => Check for C2 rotation preserving parities
2652
* 3 => Check for S4 rotation/reflection leading to parity inversion
2654
#if ( CHECK_C2v_S4_SYMM == 1 )
2655
if ( nNeighMode = NEIGH_MODE_RING && at[i].valence == 4 &&
2656
nSymmRank[(int)neigh[0]] == nSymmRank[(int)neigh[1]] &&
2657
nSymmRank[(int)neigh[2]] == nSymmRank[(int)neigh[3]] &&
2660
if ( nSymmRank[(int)neigh[1]] == nSymmRank[(int)neigh[2]] ) {
2661
max_mode = MAP_MODE_S4;
2663
max_mode = inchi_max(MAP_MODE_C2v, MAP_MODE_C2);
2666
max_mode = MAP_MODE_STD;
2669
max_mode = MAP_MODE_STD;
2671
for ( j = 0; j < at[i].valence && at[i].parity && !RETURNED_ERROR(ret_failed); j ++ ) {
2672
for ( k = j+1; k < at[i].valence && at[i].parity && !RETURNED_ERROR(ret_failed); k ++ ) {
2673
for ( mode = 0; mode <= max_mode && at[i].parity && !RETURNED_ERROR(ret_failed); mode ++ ) {
2674
if ( nSymmRank[(int)neigh[j]] != nSymmRank[(int)neigh[k]] ) {
2675
continue; /* the two neighbors are not constitutionally identical */
2677
bRingNeigh = (at[(int)neigh[j]].nRingSystem == at[(int)neigh[k]].nRingSystem);
2678
switch ( nNeighMode ) {
2679
case NEIGH_MODE_CHAIN:
2686
nSymmRank1 = nSymmRank;
2687
nSymmRank2 = nSymmRank;
2689
case NEIGH_MODE_RING:
2692
/* break a tie between the two contitutionally equivalent neighbors, */
2693
/* refine the two partitions, sort neighbors lists nl1, nl2 */
2694
bSymmNeigh = BreakNeighborsTie( at, num_atoms, num_at_tg, MAX_ATOMS+1, i,
2696
pRankStack1, pRankStack2, nTempRank, NeighList, nSymmRank, nCanonRank,
2697
nl1, nl2, &pCS->lNumNeighListIter );
2698
if ( bSymmNeigh <= 0 ) {
2699
if ( ret_failed > bSymmNeigh )
2700
ret_failed = bSymmNeigh;
2705
nSymmRank1 = pRankStack1[0];
2706
nSymmRank2 = pRankStack2[0];
2709
return CT_STEREOCOUNT_ERR; /* <BRKPT> */
2712
/* initialize arrays */
2713
memset( nVisited1, 0, sizeof(nVisited1[0])*num_atoms );
2714
memset( nVisited2, 0, sizeof(nVisited2[0])*num_atoms );
2715
memset( nAtomNumberCanon1, 0, sizeof(nAtomNumberCanon1[0])*num_atoms );
2716
memset( nAtomNumberCanon2, 0, sizeof(nAtomNumberCanon2[0])*num_atoms );
2718
nVisited1[i] = i+1; /* start atom is same */
2720
nAtomNumberCanon1[i] = nLength;
2721
nAtomNumberCanon2[i] = nLength;
2722
nAvoidCheckAtom[0] = i;
2723
nAvoidCheckAtom[1] = MAX_ATOMS+1;
2725
bParitiesInverted = (mode==MAP_MODE_C2v || mode==MAP_MODE_S4)? -1 : 0;
2727
if (nNeighMode==NEIGH_MODE_RING && at[i].valence==MAX_NUM_STEREO_ATOM_NEIGH) {
2728
AT_RANK other_neigh[2];
2730
for ( m = n = 0; m < MAX_NUM_STEREO_ATOM_NEIGH; m ++ ) {
2731
if ( at[i].neighbor[m] != neigh[j] && at[i].neighbor[m] != neigh[k] )
2732
other_neigh[n++] = at[i].neighbor[m];
2734
if ( nSymmRank[(int)other_neigh[0]] == nSymmRank[(int)other_neigh[1]] )
2735
bParitiesInverted = -1;
2738
/* allow matching inverted centers only in case all equivalent neighbors in same ring system */
2740
ret2 = 0; /* initilize. 1/8/2002 */
2742
if ( 0 < (ret1 = CreateCheckSymmPaths( at, (AT_RANK)i, neigh[j], (AT_RANK)i, neigh[k],
2744
nVisited1, nVisited2, nAtomNumberCanon1, nAtomNumberCanon2,
2745
nl01, nl02, nSymmRank1, nSymmRank2, nCanonRank, &nLength,
2746
&bParitiesInverted, mode ) ) &&
2747
0 < (ret2 = CalculatedPathsParitiesAreIdentical( at, num_atoms, nSymmRank,
2748
nCanonRank, nAtomNumberCanon, nAtomNumberCanon1, nAtomNumberCanon2,
2749
nVisited1, nVisited2, (AT_RANK)MAX_ATOMS, (AT_RANK)i,
2750
neigh[j], neigh[k], nNeighMode,
2751
bParitiesInverted, mode, pCS,
2752
vABParityUnknown) ) ) {
2753
if ( ret2 & ( NOT_WELL_DEF_UNKN | NOT_WELL_DEF_UNDF ) ) {
2754
/* possibly change the parity to unknown or undefined */
2755
int new_parity = (ret2 & NOT_WELL_DEF_UNKN)? vABParityUnknown /*AB_PARITY_UNKN*/: AB_PARITY_UNDF;
2756
if ( PARITY_ILL_DEF(at[i].stereo_atom_parity) &&
2757
PARITY_VAL(at[i].stereo_atom_parity) > new_parity ||
2758
PARITY_CALCULATE(at[i].stereo_atom_parity) ) {
2759
/* set new unknown or undefined parity */
2760
at[i].stereo_atom_parity = (at[i].stereo_atom_parity ^ PARITY_VAL(at[i].stereo_atom_parity)) | PARITY_VAL(new_parity);
2761
at[i].parity = PARITY_VAL(new_parity);
2762
/* Remove from pCS */
2763
nAtomRank1 = nCanonRank[i];
2764
for ( n = 0, m = pCS->nLenLinearCTStereoCarb-1; n <= m; n ++ ) {
2765
if ( pCS->LinearCTStereoCarb[n].at_num == nAtomRank1 ) {
2766
pCS->LinearCTStereoCarb[n].parity = PARITY_VAL(new_parity);
2767
#if ( bRELEASE_VERSION == 0 )
2768
pCS->bExtract |= EXTR_CALC_USED_TO_REMOVE_PARITY;
2775
ret = CT_STEREOCOUNT_ERR; /* <BRKPT> */
2778
ret ++; /* number of removed or set unknown/undefined parities */
2781
RemoveOneStereoCenter( at, i /* atom number*/ );
2782
/* Remove from pCS */
2783
nAtomRank1 = nCanonRank[i];
2784
for ( n = 0, m = pCS->nLenLinearCTStereoCarb-1; n <= m; n ++ ) {
2785
if ( pCS->LinearCTStereoCarb[n].at_num == nAtomRank1 ) {
2786
if ( n < m ) { /* remove pCS->LinearCTStereoDble[n] */
2787
memmove( pCS->LinearCTStereoCarb + n,
2788
pCS->LinearCTStereoCarb + n + 1,
2789
(m-n)*sizeof(pCS->LinearCTStereoCarb[0]) );
2791
pCS->nLenLinearCTStereoCarb --;
2792
#if ( bRELEASE_VERSION == 0 )
2793
pCS->bExtract |= EXTR_CALC_USED_TO_REMOVE_PARITY;
2800
ret = CT_STEREOCOUNT_ERR; /* <BRKPT> */
2803
ret ++; /* number of removed or set unknown/undefined parities */
2806
if ( !ret_failed ) {
2814
if ( !RETURNED_ERROR(ret_failed) ) {
2815
if ( RETURNED_ERROR( ret1 ) )
2818
if ( RETURNED_ERROR( ret2 ) )
2826
if ( nNeighMode == NEIGH_MODE_CHAIN && nNumEqRingNeigh && !RETURNED_ERROR(ret_failed) ) {
2827
nNeighMode = NEIGH_MODE_RING;
2833
return RETURNED_ERROR(ret_failed)? ret_failed : ret_failed? -(ret+1) : ret;
2836
/**************************************************************************************/
2837
int RemoveCalculatedNonStereo( sp_ATOM *at, int num_atoms, int num_at_tg,
2838
AT_RANK **pRankStack1, AT_RANK **pRankStack2, AT_RANK *nTempRank, NEIGH_LIST *NeighList,
2839
const AT_RANK *nSymmRank, AT_RANK *nCanonRank,
2840
AT_RANK *nAtomNumberCanon, CANON_STAT *pCS,
2841
int vABParityUnknown)
2843
NEIGH_LIST *nl = NULL, *nl1 = NULL, *nl2 = NULL;
2844
AT_RANK *nVisited1 = NULL, *nVisited2 = NULL, *nAtomNumberCanon1 = NULL, *nAtomNumberCanon2 = NULL;
2845
int nNumRemoved = 0, nTotRemoved = 0, ret = 0, ret1 = 0, ret2 = 0;
2847
if ( !AllocateForNonStereoRemoval( at, num_atoms, nSymmRank, nCanonRank,
2848
&nAtomNumberCanon1, &nAtomNumberCanon2,
2849
&nl, &nl1, &nl2, &nVisited1, &nVisited2 ) ) {
2850
return CT_OUT_OF_RAM; /* <BRKPT> */
2856
ret = RemoveCalculatedNonStereoBondParities( at, num_atoms, num_at_tg,
2857
pRankStack1, pRankStack2, nTempRank, NeighList,
2858
nCanonRank, nSymmRank,
2859
nAtomNumberCanon, nAtomNumberCanon1, nAtomNumberCanon2,
2860
nl, nl1, nl2, nVisited1, nVisited2, pCS,
2862
if ( RETURNED_ERROR( ret ) ) {
2866
if ( ret < ret1 ) { /* <BRKPT> */
2869
ret = - ( ret + 1 ); /* number of removed */
2874
ret = RemoveCalculatedNonStereoCenterParities( at, num_atoms, num_at_tg,
2875
pRankStack1, pRankStack2, nTempRank, NeighList,
2876
nCanonRank, nSymmRank,
2877
nAtomNumberCanon, nAtomNumberCanon1, nAtomNumberCanon2,
2878
nl, nl1, nl2, nVisited1, nVisited2, pCS,
2880
if ( RETURNED_ERROR( ret ) ) {
2884
if ( ret < ret2 ) { /* <BRKPT> */
2887
ret = - ( ret + 1 ); /* number of removed */
2891
nTotRemoved += nNumRemoved;
2893
} while ( nNumRemoved );
2895
if ( !RETURNED_ERROR( ret1 ) && !RETURNED_ERROR( ret2 ) ) {
2896
ret = inchi_min( ret1, ret2 );
2897
ret = (ret >= 0)? nTotRemoved : -(1+nTotRemoved);
2902
DeAllocateForNonStereoRemoval( &nAtomNumberCanon1, &nAtomNumberCanon2, &nl, &nl1, &nl2, &nVisited1, &nVisited2 );
2906
#endif /* } REMOVE_CALC_NONSTEREO */