2
* International Chemical Identifier (InChI)
4
* Software version 1.03
7
* Originally developed at NIST
8
* Modifications and additions by IUPAC and the InChI Trust
10
* The InChI library and programs are free software developed under the
11
* auspices of the International Union of Pure and Applied Chemistry (IUPAC);
12
* you can redistribute this software and/or modify it under the terms of
13
* the GNU Lesser General Public License as published by the Free Software
15
* http://www.opensource.org/licenses/lgpl-2.1.php
27
#if( TEST_RENUMB_ATOMS == 1 )
47
int inp2spATOM( inp_ATOM *inp_at, int num_inp_at, sp_ATOM *at );
48
int GetElementAndCount( const char **f, char *szEl, int *count );
49
int CompareHillFormulas( const char *f1, const char *f2 );
50
int CompareInchiStereo( INChI_Stereo *Stereo1, INCHI_MODE nFlags1, INChI_Stereo *Stereo2, INCHI_MODE nFlags2 );
51
int CompareReversedStereoINChI( INChI_Stereo *s1/* InChI from reversed struct */, INChI_Stereo *s2 /* input InChI */);
52
int GetAtomOrdNbrInCanonOrd( inp_ATOM *norm_at, AT_NUMB *nAtomOrdNbr,
53
AT_NUMB *nOrigAtNosInCanonOrd, int num_at );
54
int FillOutCanonInfAtom(inp_ATOM *norm_at, INF_ATOM_DATA *inf_norm_at_data, int init_num_at, int bIsotopic,
55
INChI *pINChI, INChI_Aux *pINChI_Aux, int bAbcNumbers, INCHI_MODE nMode);
56
int FillOutOneCanonInfAtom(inp_ATOM *inp_norm_at, INF_ATOM_DATA *inf_norm_at_data,
57
AT_NUMB *pStereoFlags, int init_num_at, int offset, int offset_H, int bIsotopic,
58
INChI *pINChI, INChI_Aux *pINChI_Aux, int bAbcNumbers, INCHI_MODE nMode);
59
int FillOutInputInfAtom(inp_ATOM *inp_at, INF_ATOM_DATA *inf_at_data, int init_num_at, int num_removed_H,
60
int bAdd_DT_to_num_H, int nNumRemovedProtons, NUM_H *nNumRemovedProtonsIsotopic, int bIsotopic, int bAbcNumbers);
62
int CheckCanonNumberingCorrectness(
63
int num_atoms, int num_at_tg,
64
sp_ATOM *at, CANON_STAT *pCS, int bTautomeric,
65
char *pStrErrStruct );
67
static int CompareDfsDescendants4CT( const void *a1, const void *a2 );
68
int GetSp3RelRacAbs( const INChI *pINChI, INChI_Stereo *Stereo );
71
#if( TEST_RENUMB_ATOMS == 1 || READ_INCHI_STRING == 1 ) /* { */
72
int CompareStereoINChI( INChI_Stereo *s1, INChI_Stereo *s2 );
75
#if( READ_INCHI_STRING == 1 ) /* { */
76
/*************************************************************************************/
78
int CompareReversedStereoINChI2( INChI_Stereo *s1, INChI_Stereo *s2, ICR *picr);
81
/**********************************************************************************************/
82
int inp2spATOM( inp_ATOM *inp_at, int num_inp_at, sp_ATOM *at )
85
memset( at, 0, sizeof(at[0])*num_inp_at );
86
for ( i = 0; i < num_inp_at; i ++ ) {
87
strncpy( at[i].elname, inp_at[i].elname, sizeof(at[0].elname) );
88
at[i].el_number = (U_CHAR)get_periodic_table_number( at[i].elname );
89
val = at[i].valence = inp_at[i].valence;
90
for ( j = 0; j < val; j ++ ) {
91
at[i].neighbor[j] = inp_at[i].neighbor[j];
92
at[i].bond_type[j] = inp_at[i].bond_type[j];
94
at[i].chem_bonds_valence = inp_at[i].chem_bonds_valence;
95
at[i].orig_at_number = inp_at[i].orig_at_number;
96
at[i].orig_compt_at_numb= inp_at[i].orig_compt_at_numb;
97
at[i].endpoint = inp_at[i].endpoint;
98
at[i].iso_atw_diff = inp_at[i].iso_atw_diff;
99
at[i].num_H = inp_at[i].num_H;
100
at[i].cFlags = inp_at[i].cFlags;
101
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
102
at[i].num_iso_H[j] = inp_at[i].num_iso_H[j];
104
at[i].charge = inp_at[i].charge;
105
at[i].radical = inp_at[i].radical;
107
#if( FIND_RING_SYSTEMS == 1 )
108
at[i].nBlockSystem = inp_at[i].nBlockSystem;
109
at[i].bCutVertex = inp_at[i].bCutVertex;
110
at[i].nRingSystem = inp_at[i].nRingSystem;
111
at[i].nNumAtInRingSystem = inp_at[i].nNumAtInRingSystem;
112
#if( FIND_RINS_SYSTEMS_DISTANCES == 1 )
113
at[i].nDistanceFromTerminal = inp_at[i].nDistanceFromTerminal;
118
at[i].x = inp_at[i].x;
119
at[i].y = inp_at[i].y;
120
at[i].z = inp_at[i].z;
125
/**********************************************************************************************/
126
int GetElementAndCount( const char **f, char *szEl, int *count )
132
if ( isupper( UCINT *p ) ) {
134
if ( *p && islower( UCINT *p ) ) {
138
if ( 1 == i && szEl[0] == 'C' ) {
139
szEl[0] = 'A'; /* less than any element: */
140
/* carbon-containing compounds should be first */
142
if ( *p && isdigit( UCINT *p ) ) {
143
*count = strtol( p, &q, 10 );
148
*f = p; /* next element; */
151
return -1; /* not a chemical formula */
153
strcpy( szEl, "Zz" ); /* zero termination 'element' is larger than any other element */
154
*count = 9999; /* zero termination 'element count' is larger than any other count */
157
/**********************************************************************************************
159
E1 < E2 if strcmp( E1, E2) < 0 OR E2 is empty and E1 is not
160
n1 < n2 if value n1 > n2
176
**********************************************************************************************/
177
int CompareHillFormulas( const char *f1, const char *f2 )
179
char szEl1[4], szEl2[4];
180
int count1, count2, ret1, ret2, ret;
183
ret1 = GetElementAndCount( &f1, szEl1, &count1 );
184
ret2 = GetElementAndCount( &f2, szEl2, &count2 );
185
if ( 0 <= ret1 && 0 <= ret2 ) {
186
if ( ret = strcmp( szEl1, szEl2 ) ) {
187
return ret; /* lexicographic order, string termination > any character */
189
if ( ret = count2 - count1 ) {
190
return ret; /* inverse atom count order */
193
return 0; /* program error <BRKPT> */
196
} while ( 0 < ret1 && 0 < ret2 );
200
/**********************************************************************************************/
201
int CompareHillFormulasNoH( const char *f1, const char *f2, int *num_H1, int *num_H2 )
203
char szEl1[4], szEl2[4];
204
int count1, count2, ret1, ret2, ret;
207
ret1 = GetElementAndCount( &f1, szEl1, &count1 );
208
if ( 0 < ret1 && szEl1[0] == 'H' && !szEl1[1] ) {
210
ret1 = GetElementAndCount( &f1, szEl1, &count1 );
212
ret2 = GetElementAndCount( &f2, szEl2, &count2 );
213
if ( 0 < ret2 && szEl2[0] == 'H' && !szEl2[1] ) {
215
ret2 = GetElementAndCount( &f2, szEl2, &count2 );
217
if ( 0 <= ret1 && 0 <= ret2 ) {
218
if ( ret = strcmp( szEl1, szEl2 ) ) {
219
return ret; /* lexicographic order, string termination > any character */
221
if ( ret = count2 - count1 ) {
222
return ret; /* inverse atom count order */
225
return 0; /* program error <BRKPT> */
228
} while ( 0 < ret1 && 0 < ret2 );
233
/**************************************************************/
234
int CompareTautNonIsoPartOfINChI( const INChI *i1, const INChI *i2 )
236
int len1, len2, ret, i;
238
len1 = i1->lenTautomer > 0 && i1->nTautomer[0]? i1->lenTautomer:0;
239
len2 = i2->lenTautomer > 0 && i2->nTautomer[0]? i2->lenTautomer:0;
240
if ( ret = len2 - len1 ) {
243
for ( i = 0; i < len1; i ++ ) {
244
if ( ret = (int)i2->nTautomer[i] - (int)i1->nTautomer[i] )
250
/**********************************************************************************************/
251
/* sorting in descending order: return -1 if *p1 > *p2, return +1 if *p1 < *p2 */
252
/**********************************************************************************************/
253
int CompINChITautVsNonTaut(const INCHI_SORT *p1, const INCHI_SORT *p2, int bCompareIsotopic)
255
int ret, num, i, num_H1, num_H2;
257
const INChI *i1 = NULL; /* Mobile-H layers in Mobile-H sorting order */
258
const INChI *i2 = NULL; /* Fixed-H layers in Fixed-H sorting order */
260
int n1; /* TAUT_YES if tautomeric i1 exists, otherwise TAUT_NON */
262
/* INChI_Stereo *Stereo1, *Stereo2; */
264
n1 = ( p1->pINChI[TAUT_YES] && p1->pINChI[TAUT_YES]->nNumberOfAtoms )? TAUT_YES : TAUT_NON;
267
i2 = (n1 == TAUT_YES && p2->pINChI[TAUT_NON] &&
268
p2->pINChI[TAUT_NON]->nNumberOfAtoms)? p2->pINChI[TAUT_NON] : (const INChI *)NULL;
271
/* non-deleted-non-empty < deleted < empty */
273
return 0; /* non-empty is the smallest (first) */
279
return 1; /* deleted is the largest (last) among non-empty */
283
if ( i1->nNumberOfAtoms > 0 && !i2->nNumberOfAtoms )
290
/* do not compare terminal H */
291
if ( ret = CompareHillFormulasNoH( i1->szHillFormula, i2->szHillFormula, &num_H1, &num_H2 ) ) {
292
return ret; /* lexicographic order except the shorter one is greater (last): CH2O < CH2; C3XX < C2XX */
295
/*********************************************************
296
compare non-isotopic non-tautomeric part
297
*********************************************************/
299
/* compare number of atoms (excluding terminal H) */
300
if ( ret = i2->nNumberOfAtoms - i1->nNumberOfAtoms )
301
return ret; /* more atoms first */
303
/* compare elements (excluding terminal H) */
304
num = i1->nNumberOfAtoms;
305
for ( i = 0; i < num; i ++ ) { /* should always be equal if Hill formulas are same */
306
if ( ret = (int)i2->nAtom[i] - (int)i1->nAtom[i] )
307
return ret; /* greater periodic number first */
309
/**********************************************************
310
compare connection tables
311
***********************************************************/
312
if ( ret = i2->lenConnTable - i1->lenConnTable )
313
return ret; /* longer connection table first */
314
num = i2->lenConnTable;
315
for ( i = 0; i < num; i ++ ) {
316
if ( ret = (int)i2->nConnTable[i] - (int)i1->nConnTable[i] )
317
return ret; /* greater connection table first */
319
/*********************************************************
320
compare compare total number of H (inverse: H3 < H2 )
321
**********************************************************/
322
if ( ret = num_H2 - num_H1 )
324
/*********************************************************
325
compare non-tautomeric num_H: N < NH3 < NH2 < NH
326
**********************************************************/
327
num = i1->nNumberOfAtoms;
328
for ( i = 0; i < num; i ++ ) {
329
if ( i2->nNum_H[i] != i1->nNum_H[i] ) {
330
return !i2->nNum_H[i]? 1 : /* no H first */
332
(int)i2->nNum_H[i] - (int)i1->nNum_H[i];
335
/*********************************************************
336
compare non-isotopic tautomeric part
337
*********************************************************/
338
if ( ret = CompareTautNonIsoPartOfINChI( i1, i2) ) {
342
if ( ret = i2->lenTautomer - i1->lenTautomer )
344
num = inchi_min( i2->lenTautomer, i1->lenTautomer );
345
for ( i = 0; i < num; i ++ ) {
346
if ( ret = (int)i2->nTautomer[i] - (int)i1->nTautomer[i] )
350
/*********************************************************
352
* at this point both components are either tautomeric *
353
* or non-tautomeric *
355
*********************************************************/
357
/*********************************************************
358
non-tautomeric "fixed H" specific
359
*********************************************************/
360
if ( /*TAUT_NON == bTaut &&*/ (i2 && i2->nNum_H_fixed ) ) {
361
/* first, compare non-tautomeric chem. formulas -- they may be different */
362
/* secondly, compare fixed-H distribution */
363
if ( i2->nNum_H_fixed ) {
364
num = i2->nNumberOfAtoms;
365
for ( i = 0; i < num; i ++ ) {
366
if ( i2->nNum_H_fixed[i] != 0 ) {
372
/*********************************************************
373
compare non-isotopic stereo
374
*********************************************************/
375
ret = CompareInchiStereo( i1->Stereo, i1->nFlags, i2->Stereo, i2->nFlags );
379
/*******************************************************
380
do not switch back to tautomeric i1, i2
381
*******************************************************/
382
/* -- how to switch back --
392
/******************************************************
393
compare isotopic non-tautomeric part
394
******************************************************/
395
if ( bCompareIsotopic ) {
396
if ( ret = i2->nNumberOfIsotopicAtoms - i1->nNumberOfIsotopicAtoms )
398
num = i1->nNumberOfIsotopicAtoms;
399
/* compare isotopic atoms */
400
for ( i = 0; i < num; i ++ ) {
401
if ( ret = (int)i2->IsotopicAtom[i].nAtomNumber - (int)i1->IsotopicAtom[i].nAtomNumber )
403
if ( ret = (int)i2->IsotopicAtom[i].nIsoDifference - (int)i1->IsotopicAtom[i].nIsoDifference )
406
/* compare isotopic H */
407
/* if tautomeric comparison mode then here are compared only non-tautomeric H */
408
for ( i = 0; i < num; i ++ ) {
409
if ( ret = (int)i2->IsotopicAtom[i].nNum_T - (int)i1->IsotopicAtom[i].nNum_T )
411
if ( ret = (int)i2->IsotopicAtom[i].nNum_D - (int)i1->IsotopicAtom[i].nNum_D )
413
if ( ret = (int)i2->IsotopicAtom[i].nNum_H - (int)i1->IsotopicAtom[i].nNum_H )
416
/*****************************************************
417
compare isotopic tautomeric part
418
*****************************************************/
419
if ( ret = i2->nNumberOfIsotopicTGroups || i1->nNumberOfIsotopicTGroups )
422
num = i1->nNumberOfIsotopicTGroups;
423
for ( i = 0; i < num; i ++ ) {
424
if ( ret = (int)i2->IsotopicTGroup[i].nTGroupNumber - (int)i1->IsotopicTGroup[i].nTGroupNumber )
426
if ( ret = (int)i2->IsotopicTGroup[i].nNum_T - (int)i1->IsotopicTGroup[i].nNum_T )
428
if ( ret = (int)i2->IsotopicTGroup[i].nNum_D - (int)i1->IsotopicTGroup[i].nNum_D )
430
if ( ret = (int)i2->IsotopicTGroup[i].nNum_H - (int)i1->IsotopicTGroup[i].nNum_H )
434
/****************************************************
435
compare isotopic stereo
436
****************************************************/
437
ret = CompareInchiStereo( i1->StereoIsotopic, i1->nFlags, i2->StereoIsotopic, i2->nFlags );
445
/**********************************************************
446
compare charges: non-charged first, then in order of
447
ascending charges (negative first)
448
***********************************************************/
449
if ( i2->nTotalCharge && i1->nTotalCharge ) {
450
/* both are charged; smaller charges first */
451
ret = (int)i1->nTotalCharge - (int)i2->nTotalCharge;
454
if ( ret = (i1->nTotalCharge? 1:0) - (i2->nTotalCharge? 1:0) ) {
455
/* only one is charged; uncharged first */
459
/*ret = p1->ord_number - p2->ord_number;*/
464
/*************************** stereo ***********************************************************/
465
typedef enum tagSp3StereoTypeTmp {
466
SP3_NONE = 0, /* no sp3 stereo: no /t, /m, /s segments */
468
SP3_ONLY = 1, /* no /s or /m segment: inversion leaves the structure unchanged */
469
SP3_ABS = 2, /* abs stereo: both /m and /s are present */
470
SP3_REL = 4, /* rel stereo: /s is present, /m is not */
471
SP3_RAC = 8, /* racemic stereo: /s is presen, /m is nott */
472
SP3_TYPE = (SP3_ABS|SP3_REL|SP3_RAC), /* bitmap for checking the presence of /m */
473
SP3_ANY = (SP3_ABS|SP3_REL|SP3_RAC|SP3_ONLY) /* bitmap for checking the presence of /t */
476
/**********************************************************************************************/
477
int GetSp3RelRacAbs( const INChI *pINChI, INChI_Stereo *Stereo )
480
if ( pINChI && !pINChI->bDeleted && Stereo && 0 < Stereo->nNumberOfStereoCenters ) {
481
if ( 0 != Stereo->nCompInv2Abs ) {
482
if ( pINChI->nFlags & INCHI_FLAG_REL_STEREO ) {
483
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
484
if ( 1 < Stereo->nNumberOfStereoCenters ) {
491
if ( pINChI->nFlags & INCHI_FLAG_RAC_STEREO ) {
492
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
493
if ( 1 < Stereo->nNumberOfStereoCenters ) {
503
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
504
if ( !(( pINChI->nFlags & (INCHI_FLAG_REL_STEREO|INCHI_FLAG_RAC_STEREO) ) && 1 == Stereo->nNumberOfStereoCenters) )
507
nRet = SP3_ONLY; /* SP3_NONE if relative stereo and 1 stereocenter */
513
/* char sDifSegs[DIFL_LENGTH][DIFS_LENGTH]; */
515
/**********************************************************************************************/
516
/* sorting in descending order: return -1 if *p1 > *p2, return +1 if *p1 < *p2 */
517
/**********************************************************************************************/
518
int CompINChILayers(const INCHI_SORT *p1, const INCHI_SORT *p2,
519
char sDifSegs[][DIFS_LENGTH], int bFixTranspChargeBug )
521
int ret = 0, num, i, num_H1, num_H2;
523
const INChI *i1 = NULL; /* Mobile-H layers in Mobile-H sorting order */
524
const INChI *i2 = NULL; /* Fixed-H layers in Fixed-H sorting order */
526
int n1; /* TAUT_YES if tautomeric i1 exists, otherwise TAUT_NON */
528
INChI_Stereo *Stereo1, *Stereo2;
529
INChI_Stereo *IsoStereo1, *IsoStereo2;
530
int bRelRac[DIFL_LENGTH];
533
n1 = ( p1->pINChI[TAUT_YES] && p1->pINChI[TAUT_YES]->nNumberOfAtoms )? TAUT_YES : TAUT_NON;
536
i2 = (n1 == TAUT_YES && p2->pINChI[TAUT_NON] &&
537
p2->pINChI[TAUT_NON]->nNumberOfAtoms)? p2->pINChI[TAUT_NON] : (const INChI *)NULL;
540
memset( bRelRac, DIFV_BOTH_EMPTY, sizeof(bRelRac) );
541
/*=====================*/
543
/*=====================*/
544
if ( i1 && !i1->bDeleted && i1->szHillFormula && i1->szHillFormula[0] ) {
545
sDifSegs[DIFL_M][DIFS_f_FORMULA] |= DIFV_NEQ2PRECED;
546
if ( i2 && !i2->bDeleted && i2->szHillFormula && i2->szHillFormula[0] ) {
547
if ( !CompareHillFormulasNoH( i1->szHillFormula, i2->szHillFormula, &num_H1, &num_H2 ) &&
549
sDifSegs[DIFL_F][DIFS_f_FORMULA] |= DIFV_EQL2PRECED;
551
sDifSegs[DIFL_F][DIFS_f_FORMULA] |= DIFV_NEQ2PRECED;
554
sDifSegs[DIFL_F][DIFS_f_FORMULA] |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
557
sDifSegs[DIFL_M][DIFS_f_FORMULA] |= DIFV_BOTH_EMPTY;
558
if ( i2 && !i2->bDeleted && i2->szHillFormula && i2->szHillFormula[0] ) {
559
sDifSegs[DIFL_F][DIFS_f_FORMULA] |= DIFV_NEQ2PRECED;
561
sDifSegs[DIFL_F][DIFS_f_FORMULA] |= DIFV_BOTH_EMPTY;
564
/*=====================*/
566
/*=====================*/
567
if ( i1 && !i1->bDeleted && i1->lenConnTable > 1 ) {
568
sDifSegs[DIFL_M][DIFS_f_FORMULA] |= DIFV_NEQ2PRECED;
570
sDifSegs[DIFL_M][DIFS_f_FORMULA] |= DIFV_BOTH_EMPTY;
572
/*=====================*/
574
/*=====================*/
576
if ( i1 && !i1->bDeleted ) {
577
num_H1 = (i1->lenTautomer > 0 && i1->nTautomer && i1->nTautomer[0])? 1 : 0; /* number of t-groups */
578
if ( !num_H1 && i1->nNum_H ) {
579
for ( i = 0; i < i1->nNumberOfAtoms; i ++ ) { /* immobile H */
580
if ( i1->nNum_H[i] ) {
586
sDifSegs[DIFL_M][DIFS_h_H_ATOMS] |= num_H1? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
588
sDifSegs[DIFL_M][DIFS_h_H_ATOMS] |= DIFV_BOTH_EMPTY;
590
/* F: fixed mobile H */
591
if ( i2 && !i2->bDeleted && i2->nNum_H_fixed ) {
593
if ( i1 && !i1->bDeleted ) {
594
for ( i = 0; i < i1->nNumberOfAtoms; i ++ ) {
595
if ( i2->nNum_H_fixed[i] ) {
601
sDifSegs[DIFL_F][DIFS_h_H_ATOMS] |= num_H2? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
603
sDifSegs[DIFL_F][DIFS_h_H_ATOMS] |= DIFV_BOTH_EMPTY;
605
/* MI: exchangable isotopic H: see OutputINChI1(), num_iso_H[] */
607
/*=====================*/
609
/*=====================*/
610
psDifSegs = &sDifSegs[DIFL_F][DIFS_q_CHARGE];
611
if ( i1 && !i1->bDeleted ) {
612
if ( i1->nTotalCharge ) {
613
sDifSegs[DIFL_M][DIFS_q_CHARGE] |= DIFV_NEQ2PRECED;
615
sDifSegs[DIFL_M][DIFS_q_CHARGE] |= DIFV_BOTH_EMPTY;
617
if ( i2 && !i2->bDeleted ) {
618
if ( i1->nTotalCharge ) {
619
if ( i1->nTotalCharge == i2->nTotalCharge ) {
620
*psDifSegs |= DIFV_EQL2PRECED;
622
if ( i2->nTotalCharge ) {
623
*psDifSegs |= DIFV_NEQ2PRECED;
625
*psDifSegs |= DIFV_IS_EMPTY;
628
if ( i2->nTotalCharge ) {
629
*psDifSegs |= DIFV_NEQ2PRECED;
631
*psDifSegs |= DIFV_BOTH_EMPTY;
636
if (bFixTranspChargeBug==1)
640
component #1 is tautomeric, component #2 is not
641
Mobile-H(#2) > Mobile-H(#1)
642
Fixed-H(#2) = Mobile-H(#2) < Fixed-H(#1)
644
Layer first_charge second_charge
646
Mobile-H 0 (comp#1) -1 (comp#2)
647
Fixed-H none (comp#2) -1 (comp#1)
649
v1.01 charge compared decided that charge layers are same and omitted Fixed-H /q layer
651
Solution: when component permutation is detected AND fixed-H component does not exist,
652
compare Mobile-H charge [0 (comp#1) in the example] to the charge of Mobile-H [-1 (comp#2)]
653
of the component that has none Fixed-H charge
656
/* Fixed-H i2 is empty because Fixed-H struct is same as Mobile-H */
657
if ( p1->ord_number != p2->ord_number && /* component order in Fixed-H is different from Mobile-H */
658
n1 == TAUT_YES && p2->pINChI[TAUT_YES] && !p2->pINChI[TAUT_YES]->bDeleted &&
659
p2->pINChI[TAUT_YES]->nNumberOfAtoms ) {
660
int i2_nTotalCharge = p2->pINChI[TAUT_YES]->nTotalCharge;
662
if ( i1->nTotalCharge ) {
663
if ( i1->nTotalCharge == i2_nTotalCharge ) {
664
*psDifSegs |= DIFV_EQL2PRECED;
666
if ( i2_nTotalCharge ) {
667
*psDifSegs |= DIFV_NEQ2PRECED;
669
*psDifSegs |= DIFV_IS_EMPTY;
672
if ( i2_nTotalCharge ) {
673
*psDifSegs |= DIFV_NEQ2PRECED;
675
*psDifSegs |= DIFV_BOTH_EMPTY;
679
*psDifSegs |= i1->nTotalCharge? DIFV_EQL2PRECED : DIFV_BOTH_EMPTY;
682
else /* if (bFixTranspChargeBug==1) */
684
*psDifSegs |= i1->nTotalCharge? DIFV_EQL2PRECED : DIFV_BOTH_EMPTY;
688
else /* if ( !i2 ) { */
690
/* i2 && i2->bDeleted */
691
*psDifSegs |= i1->nTotalCharge? DIFV_IS_EMPTY : DIFV_BOTH_EMPTY;
695
sDifSegs[DIFL_M][DIFS_q_CHARGE] |= DIFV_BOTH_EMPTY;
696
if ( i2 && !i2->bDeleted ) {
697
if ( i2->nTotalCharge ) {
698
sDifSegs[DIFL_F][DIFS_q_CHARGE] |= DIFV_NEQ2PRECED;
700
sDifSegs[DIFL_F][DIFS_q_CHARGE] |= DIFV_BOTH_EMPTY;
704
/*************** stereo *****************/
705
if ( i1 && !i1->bDeleted ) {
706
Stereo1 = i1->Stereo;
707
IsoStereo1 = i1->StereoIsotopic;
712
if ( i2 && !i2->bDeleted ) {
713
Stereo2 = i2->Stereo;
714
IsoStereo2 = i2->StereoIsotopic;
719
/*=====================*/
721
/*=====================*/
722
/* M double bond stereo */
723
psDifSegs = &sDifSegs[DIFL_M][DIFS_b_SBONDS];
724
if ( Stereo1 && Stereo1->nNumberOfStereoBonds ) {
725
*psDifSegs |= DIFV_NEQ2PRECED;
727
*psDifSegs |= DIFV_BOTH_EMPTY;
729
/* F double bond stereo */
730
psDifSegs = &sDifSegs[DIFL_F][DIFS_b_SBONDS];
731
if ( Stereo2 && Stereo2->nNumberOfStereoBonds ) {
732
if ( Stereo1 && Stereo1->nNumberOfStereoBonds ) {
733
if ( Eql_INChI_Stereo( Stereo1, EQL_SP2, Stereo2, EQL_SP2, 0 ) ) {
734
*psDifSegs |= DIFV_EQL2PRECED;
736
*psDifSegs |= DIFV_NEQ2PRECED;
739
*psDifSegs |= DIFV_NEQ2PRECED;
742
if ( Stereo1 && Stereo1->nNumberOfStereoBonds ) {
743
*psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
745
*psDifSegs |= DIFV_BOTH_EMPTY;
748
/* MI double bond stereo */
749
psDifSegs = &sDifSegs[DIFL_MI][DIFS_b_SBONDS];
750
if ( IsoStereo1 && IsoStereo1->nNumberOfStereoBonds ) {
751
if ( Eql_INChI_Stereo( IsoStereo1, EQL_SP2, Stereo1, EQL_SP2, 0 ) ) {
752
*psDifSegs |= DIFV_EQL2PRECED;
754
*psDifSegs |= DIFV_NEQ2PRECED;
757
if ( Stereo1 && Stereo1->nNumberOfStereoBonds ) {
758
*psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
760
*psDifSegs |= DIFV_BOTH_EMPTY;
763
/* FI double bond stereo */
764
psDifSegs = &sDifSegs[DIFL_FI][DIFS_b_SBONDS];
765
if ( IsoStereo2 && IsoStereo2->nNumberOfStereoBonds ) {
766
if ( Eql_INChI_Stereo( IsoStereo2, EQL_SP2, Stereo2, EQL_SP2, 0 ) ) {
767
*psDifSegs |= DIFV_EQL2PRECED;
769
if ( !(Stereo1 && Stereo1->nNumberOfStereoBonds) &&
770
!(Stereo2 && Stereo2->nNumberOfStereoBonds) &&
771
Eql_INChI_Stereo( IsoStereo2, EQL_SP2, IsoStereo1, EQL_SP2, 0 ) ) {
772
*psDifSegs |= DIFV_FI_EQ_MI;
774
*psDifSegs |= DIFV_NEQ2PRECED;
778
/* the solution table for FI stereo,
779
in case of FI stereo is empty
780
E = segment is empty, NE = not empty
781
+==============================+
782
| M | MI | F | result |
783
+=====+=====+=====+============+
784
| E | E | E | both empty |
785
+-----+-----+-----+------------+
786
| NE | E | E | both empty |
787
+-----+-----+-----+------------+
788
| E | NE | E | is empty |
789
+-----+-----+-----+------------+
790
| NE | NE | E | both empty |
791
+-----+-----+-----+------------+
792
| E | E | NE | is empty |
793
+-----+-----+-----+------------+
794
| NE | E | NE | is empty |
795
+-----+-----+-----+------------+
796
| E | NE | NE | is empty |
797
+-----+-----+-----+------------+
798
| NE | NE | ME | is empty |
799
+==============================+
801
if ( Stereo2 && Stereo2->nNumberOfStereoBonds ) {
802
*psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
804
if ( IsoStereo1 && IsoStereo1->nNumberOfStereoBonds &&
805
!(Stereo1 && Stereo1->nNumberOfStereoBonds)
807
*psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
809
*psDifSegs |= DIFV_BOTH_EMPTY;
812
/*==================================*/
813
/*==== /t, /m, /s for M ======*/
814
/*==================================*/
818
bRelRac[DIFL_M ] = GetSp3RelRacAbs( i1, Stereo1 ); /* Mobile-H */
819
bRelRac[DIFL_MI] = GetSp3RelRacAbs( i1, IsoStereo1 );
820
bRelRac[DIFL_F ] = GetSp3RelRacAbs( i2, Stereo2 ); /* Fixed-H */
821
bRelRac[DIFL_FI] = GetSp3RelRacAbs( i2, IsoStereo2 );
822
if ( SP3_NONE != bRelRac[DIFL_M] ) {
823
sDifSegs[DIFL_M][DIFS_t_SATOMS] |= (bRelRac[DIFL_M] & SP3_ANY)? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
824
sDifSegs[DIFL_M][DIFS_m_SP3INV] |= (bRelRac[DIFL_M] & SP3_ABS)? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
825
sDifSegs[DIFL_M][DIFS_s_STYPE] |= (bRelRac[DIFL_M] & SP3_TYPE)? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
827
sDifSegs[DIFL_M][DIFS_t_SATOMS] |= DIFV_BOTH_EMPTY;
828
sDifSegs[DIFL_M][DIFS_m_SP3INV] |= DIFV_BOTH_EMPTY;
829
sDifSegs[DIFL_M][DIFS_s_STYPE] |= DIFV_BOTH_EMPTY;
831
/*=====================*/
833
/*=====================*/
835
psDifSegs = &sDifSegs[DIFL_F][DIFS_t_SATOMS];
836
if ( SP3_ANY & bRelRac[DIFL_F] ) {
837
if ( Eql_INChI_Stereo( Stereo2, EQL_SP3, Stereo1, EQL_SP3, 0 ) ) {
838
*psDifSegs |= DIFV_EQL2PRECED;
840
*psDifSegs |= DIFV_NEQ2PRECED;
843
if ( SP3_ANY & bRelRac[DIFL_M] ) {
844
*psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
846
*psDifSegs |= DIFV_BOTH_EMPTY;
849
psDifSegs = &sDifSegs[DIFL_MI][DIFS_t_SATOMS];
850
if ( SP3_ANY & bRelRac[DIFL_MI] ) {
851
if ( Eql_INChI_Stereo( IsoStereo1, EQL_SP3, Stereo1, EQL_SP3, 0 ) ) {
852
*psDifSegs |= DIFV_EQL2PRECED;
854
*psDifSegs |= DIFV_NEQ2PRECED;
857
if ( SP3_ANY & bRelRac[DIFL_M] ) {
858
*psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
860
*psDifSegs |= DIFV_BOTH_EMPTY;
863
psDifSegs = &sDifSegs[DIFL_FI][DIFS_t_SATOMS];
864
if ( SP3_ANY & bRelRac[DIFL_FI] ) {
865
if ( Eql_INChI_Stereo( IsoStereo2, EQL_SP3, Stereo2, EQL_SP3, 0 ) ) {
866
*psDifSegs |= DIFV_EQL2PRECED;
868
if ( !(SP3_ANY & bRelRac[DIFL_M]) &&
869
!(SP3_ANY & bRelRac[DIFL_F]) &&
870
Eql_INChI_Stereo( IsoStereo2, EQL_SP3, IsoStereo1, EQL_SP3, 0 ) ) {
871
*psDifSegs |= DIFV_FI_EQ_MI;
873
*psDifSegs |= DIFV_NEQ2PRECED;
875
} else /* similar to /b */
876
if ( (SP3_ANY & bRelRac[DIFL_F]) ) {
877
*psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
879
if ( (SP3_ANY & bRelRac[DIFL_MI]) && !(SP3_ANY & bRelRac[DIFL_M]) ) {
880
*psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
882
*psDifSegs |= DIFV_BOTH_EMPTY;
884
/*=====================*/
886
/*=====================*/
887
/* F sp3 abs stereo inversion */
888
psDifSegs = &sDifSegs[DIFL_F][DIFS_m_SP3INV];
889
if ( bRelRac[DIFL_F] & SP3_ABS ) {
890
/* the order of || operands below is critically important: || is not a commutative operation */
891
if ( !(bRelRac[DIFL_M] & SP3_ABS) || Stereo2->nCompInv2Abs != Stereo1->nCompInv2Abs ) {
892
*psDifSegs |= DIFV_NEQ2PRECED;
894
*psDifSegs |= DIFV_EQL2PRECED;
897
if ( bRelRac[DIFL_M] & SP3_ABS ) {
898
*psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
900
*psDifSegs |= DIFV_BOTH_EMPTY;
902
/* MI sp3 abs stereo inversion */
903
psDifSegs = &sDifSegs[DIFL_MI][DIFS_m_SP3INV];
904
if ( SP3_ABS & bRelRac[DIFL_MI] ) {
905
if ( (SP3_ABS & bRelRac[DIFL_M]) && IsoStereo1->nCompInv2Abs == Stereo1->nCompInv2Abs ) {
906
*psDifSegs |= DIFV_EQL2PRECED;
908
*psDifSegs |= DIFV_NEQ2PRECED;
911
if ( SP3_ABS & bRelRac[DIFL_M] ) {
912
*psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
914
*psDifSegs |= DIFV_BOTH_EMPTY;
916
/* FI sp3 abs stereo inversion */
917
psDifSegs = &sDifSegs[DIFL_FI][DIFS_m_SP3INV];
918
if ( SP3_ABS & bRelRac[DIFL_FI] ) {
919
if ( (SP3_ABS & bRelRac[DIFL_F]) && IsoStereo2->nCompInv2Abs == Stereo2->nCompInv2Abs ) {
920
*psDifSegs |= DIFV_EQL2PRECED;
922
if ( !(SP3_ABS & bRelRac[DIFL_M]) &&
923
!(SP3_ABS & bRelRac[DIFL_F]) &&
924
(SP3_ABS & bRelRac[DIFL_MI]) && /* make sure IsoStereo1 != NULL */
925
IsoStereo2->nCompInv2Abs == IsoStereo1->nCompInv2Abs ) {
926
*psDifSegs |= DIFV_FI_EQ_MI;
928
*psDifSegs |= DIFV_NEQ2PRECED;
930
} else /* similar to /b */
931
/* the order of || operands below is critically important: || is no a commutative operation */
932
if ( (SP3_ABS & bRelRac[DIFL_F]) ) {
933
*psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
935
if ( (SP3_ABS & bRelRac[DIFL_MI]) && !(SP3_ABS & bRelRac[DIFL_M]) ) {
936
*psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
938
*psDifSegs |= DIFV_BOTH_EMPTY;
940
/*=====================*/
942
/*=====================*/
943
/* F sp3 stereo type */
944
psDifSegs = &sDifSegs[DIFL_F][DIFS_s_STYPE];
945
if ( bRelRac[DIFL_F] & SP3_TYPE ) {
946
if ( (bRelRac[DIFL_F] & SP3_TYPE) == (bRelRac[DIFL_M] & SP3_TYPE) ) {
947
*psDifSegs |= DIFV_EQL2PRECED;
949
*psDifSegs |= DIFV_NEQ2PRECED;
952
if ( bRelRac[DIFL_M] & SP3_TYPE ) {
953
*psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
955
*psDifSegs |= DIFV_BOTH_EMPTY;
957
/* MI sp3 stereo type */
958
psDifSegs = &sDifSegs[DIFL_MI][DIFS_s_STYPE];
959
if ( SP3_TYPE & bRelRac[DIFL_MI] ) {
960
if ( (SP3_TYPE & bRelRac[DIFL_MI]) == (SP3_TYPE & bRelRac[DIFL_M]) ) {
961
*psDifSegs |= DIFV_EQL2PRECED;
963
*psDifSegs |= DIFV_NEQ2PRECED;
966
if ( SP3_TYPE & bRelRac[DIFL_M] ) {
967
*psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
969
*psDifSegs |= DIFV_BOTH_EMPTY;
971
/* FI sp3 stereo type */
972
psDifSegs = &sDifSegs[DIFL_FI][DIFS_s_STYPE];
973
if ( SP3_TYPE & bRelRac[DIFL_FI] ) {
974
if ( (SP3_TYPE & bRelRac[DIFL_FI]) == (SP3_TYPE & bRelRac[DIFL_F]) ) {
975
*psDifSegs |= DIFV_EQL2PRECED;
977
if ( !(SP3_TYPE & bRelRac[DIFL_M]) &&
978
!(SP3_TYPE & bRelRac[DIFL_F]) &&
979
(SP3_TYPE & bRelRac[DIFL_MI]) ) {
980
*psDifSegs |= DIFV_FI_EQ_MI;
982
*psDifSegs |= DIFV_NEQ2PRECED;
984
} else /* similar to /b */
985
/* the order of || operands below is critically important: || is not a commutative operation */
986
if ( (SP3_TYPE & bRelRac[DIFL_F]) ) {
987
*psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
989
if ( (SP3_TYPE & bRelRac[DIFL_MI]) && !(SP3_TYPE & bRelRac[DIFL_M]) ) {
990
*psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
992
*psDifSegs |= DIFV_BOTH_EMPTY;
994
/*=====================*/
996
/*=====================*/
997
if ( p1 && p2 && p1->ord_number != p2->ord_number ) {
998
sDifSegs[DIFL_F][DIFS_o_TRANSP] |= DIFV_NEQ2PRECED;
1000
/*=====================*/
1002
/*=====================*/
1003
/* M isotopic atoms */
1004
psDifSegs = &sDifSegs[DIFL_MI][DIFS_i_IATOMS];
1005
if ( i1 && !i1->bDeleted && (i1->nNumberOfIsotopicAtoms || i1->nNumberOfIsotopicTGroups) ) {
1006
*psDifSegs |= DIFV_NEQ2PRECED;
1008
*psDifSegs |= DIFV_BOTH_EMPTY;
1010
/* F isotopic atoms */
1011
psDifSegs = &sDifSegs[DIFL_FI][DIFS_i_IATOMS];
1012
if ( i2 && !i2->bDeleted ) {
1013
if ( i2->nNumberOfIsotopicAtoms || i2->nNumberOfIsotopicTGroups ) {
1014
if ( !i1 || i1->bDeleted ||
1015
i2->nNumberOfIsotopicAtoms != i1->nNumberOfIsotopicAtoms ||
1016
i2->nNumberOfIsotopicTGroups != i1->nNumberOfIsotopicTGroups ) {
1017
*psDifSegs |= DIFV_NEQ2PRECED;
1020
num = i1->nNumberOfIsotopicAtoms;
1022
for ( i = 0; i < num; i ++ ) {
1023
/* compare isotopic atoms */
1024
if ( diff = (int)i2->IsotopicAtom[i].nAtomNumber - (int)i1->IsotopicAtom[i].nAtomNumber )
1026
if ( diff = (int)i2->IsotopicAtom[i].nIsoDifference - (int)i1->IsotopicAtom[i].nIsoDifference )
1028
/* compare isotopic H */
1029
if ( diff = (int)i2->IsotopicAtom[i].nNum_T - (int)i1->IsotopicAtom[i].nNum_T )
1031
if ( diff = (int)i2->IsotopicAtom[i].nNum_D - (int)i1->IsotopicAtom[i].nNum_D )
1033
if ( diff = (int)i2->IsotopicAtom[i].nNum_H - (int)i1->IsotopicAtom[i].nNum_H )
1037
num = i1->nNumberOfIsotopicTGroups;
1038
for ( i = 0; i < num; i ++ ) {
1039
if ( diff = (int)i2->IsotopicTGroup[i].nTGroupNumber - (int)i1->IsotopicTGroup[i].nTGroupNumber )
1041
if ( diff = (int)i2->IsotopicTGroup[i].nNum_T - (int)i1->IsotopicTGroup[i].nNum_T )
1043
if ( diff = (int)i2->IsotopicTGroup[i].nNum_D - (int)i1->IsotopicTGroup[i].nNum_D )
1045
if ( diff = (int)i2->IsotopicTGroup[i].nNum_H - (int)i1->IsotopicTGroup[i].nNum_H )
1049
*psDifSegs |= diff? DIFV_NEQ2PRECED : DIFV_FI_EQ_MI;
1053
if ( i1 && !i1->bDeleted && (i1->nNumberOfIsotopicAtoms || i1->nNumberOfIsotopicTGroups) ) {
1054
*psDifSegs |= DIFV_IS_EMPTY;
1058
if ( i1 && !i1->bDeleted && (i1->nNumberOfIsotopicAtoms || i1->nNumberOfIsotopicTGroups) ) {
1059
*psDifSegs |= DIFV_EQL2PRECED;
1061
*psDifSegs |= DIFV_BOTH_EMPTY;
1067
/**********************************************************************************************/
1068
int INChI_SegmentAction( char cDifSegs )
1070
if ( !(cDifSegs & DIFV_OUTPUT_OMIT_F) ) {
1071
return INCHI_SEGM_OMIT;
1073
if ( (cDifSegs & DIFV_OUTPUT_EMPTY_T) && !(cDifSegs & DIFV_OUTPUT_EMPTY_F) ) {
1074
return INCHI_SEGM_EMPTY;
1076
if ( (cDifSegs & DIFV_OUTPUT_FILL_T) ) {
1077
return INCHI_SEGM_FILL;
1079
return INCHI_SEGM_OMIT; /* the control flow shoul never reach this point */
1081
/**********************************************************************************************/
1082
int MarkUnusedAndEmptyLayers( char sDifSegs[][DIFS_LENGTH] )
1084
/****************************************************
1085
1. If all elements of a layer are DIFV_IS_EMPTY and/or DIFV_BOTH_EMPTY
1086
and/or DIFV_EQL2PRECED and/or DIFV_FI_EQ_MI
1087
and there is NO succeeding non-empty layer then mark the 1st element
1088
of the layer DIFV_BOTH_EMPTY; this layerr will be omitted.
1090
2. If all elements of a layer are DIFV_IS_EMPTY and/or DIFV_BOTH_EMPTY
1091
and/or DIFV_EQL2PRECED and/or DIFV_FI_EQ_MI
1092
and there IS a succeeding non-empty layer then mark the 1st element
1093
of the layer DIFV_IS_EMPTY and all other elements DIFV_BOTH_EMPTY;
1094
only the first empty segment of this layerr will be output.
1096
3. If NOT all elements of a layer are DIFV_IS_EMPTY and/or DIFV_BOTH_EMPTY
1097
and/or DIFV_EQL2PRECED and/or DIFV_FI_EQ_MI
1098
and the 1st element of the layer is DIFV_BOTH_EMPTY then mark it
1099
DIFV_IS_EMPTY; it will be output as empty (except M layer).
1102
int i, nLayer, sBits, nFirstSegm;
1103
#define nFirstFmlSegm DIFS_f_FORMULA
1104
#define nFirstIsoSegm DIFS_i_IATOMS
1107
nFirstSegm = nFirstIsoSegm;
1109
for ( i = 0; i < DIFS_idf_LENGTH; i ++ ) {
1110
sBits |= sDifSegs[nLayer][i];
1112
if ( !(sBits & DIFV_OUTPUT_OMIT_F) ) {
1113
/* Omit the FI layer */
1114
memset( sDifSegs[nLayer], DIFV_BOTH_EMPTY, DIFS_idf_LENGTH);
1116
if ( sDifSegs[nLayer][nFirstSegm] == DIFV_BOTH_EMPTY ||
1117
!(sDifSegs[nLayer][nFirstSegm] & DIFV_OUTPUT_OMIT_F) ) {
1118
sDifSegs[nLayer][nFirstSegm] = DIFV_IS_EMPTY;
1123
nFirstSegm = nFirstIsoSegm;
1125
for ( i = 0; i < DIFS_idf_LENGTH; i ++ ) {
1126
sBits |= sDifSegs[nLayer][i];
1128
if ( !(sBits & DIFV_OUTPUT_OMIT_F) ) {
1129
/* Omit the MI layer */
1130
memset( sDifSegs[nLayer], DIFV_BOTH_EMPTY, DIFS_idf_LENGTH);
1132
if ( sDifSegs[nLayer][nFirstSegm] == DIFV_BOTH_EMPTY ||
1133
!(sDifSegs[nLayer][nFirstSegm] & DIFV_OUTPUT_OMIT_F) ) {
1134
sDifSegs[nLayer][nFirstSegm] = DIFV_IS_EMPTY;
1139
nFirstSegm = nFirstFmlSegm;
1141
for ( i = 0; i < DIFS_idf_LENGTH; i ++ ) {
1142
sBits |= sDifSegs[nLayer][i];
1144
if ( !(sBits & DIFV_OUTPUT_OMIT_F) &&
1145
sDifSegs[DIFL_FI][nFirstIsoSegm] == DIFV_BOTH_EMPTY ) {
1146
/* Omit the F layer: no non-iotopic and no isotopic segments */
1147
memset( sDifSegs[nLayer], DIFV_BOTH_EMPTY, DIFS_idf_LENGTH);
1149
/* do not omit fixed-H layer */
1150
if ( sDifSegs[nLayer][nFirstSegm] == DIFV_BOTH_EMPTY ||
1151
!(sDifSegs[nLayer][nFirstSegm] & DIFV_OUTPUT_OMIT_F) ) {
1152
sDifSegs[nLayer][nFirstSegm] = DIFV_IS_EMPTY;
1155
/* M -- leave as it is */
1157
#undef nFirstFmlSegm
1158
#undef nFirstIsoSegm
1160
/*********************************************************************************************/
1161
int CompareInchiStereo( INChI_Stereo *Stereo1, INCHI_MODE nFlags1, INChI_Stereo *Stereo2, INCHI_MODE nFlags2 )
1164
if ( Stereo2 && Stereo1 ) {
1165
/* compare stereogenic bonds */
1166
num = inchi_min( Stereo2->nNumberOfStereoBonds, Stereo1->nNumberOfStereoBonds );
1167
for ( i = 0; i < num; i ++ ) {
1168
if ( ret = (int)Stereo2->nBondAtom1[i] - (int)Stereo1->nBondAtom1[i] )
1170
if ( ret = (int)Stereo2->nBondAtom2[i] - (int)Stereo1->nBondAtom2[i] )
1172
if ( ret = (int)Stereo2->b_parity[i] - (int)Stereo1->b_parity[i] )
1175
if ( ret = (int)Stereo2->nNumberOfStereoBonds - (int)Stereo1->nNumberOfStereoBonds )
1177
/* compare stereogenic atoms */
1178
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
1179
if ( ((nFlags1 | nFlags2) & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO) ) &&
1180
1 == Stereo2->nNumberOfStereoCenters &&
1181
1 == Stereo1->nNumberOfStereoCenters ) {
1182
; /* do not compare single stereocenters in case of relative stereo */
1186
num = inchi_min( Stereo2->nNumberOfStereoCenters, Stereo1->nNumberOfStereoCenters );
1187
for ( i = 0; i < num; i ++ ) {
1188
if ( ret = (int)Stereo2->nNumber[i] - (int)Stereo1->nNumber[i] )
1190
if ( ret = (int)Stereo2->t_parity[i] - (int)Stereo1->t_parity[i] )
1193
if ( ret = (int)Stereo2->nNumberOfStereoCenters - (int)Stereo1->nNumberOfStereoCenters )
1195
/* compare stereo-abs-is-inverted flags for non-relative, non-racemic */
1196
if ( !((nFlags1 | nFlags2) & (INCHI_FLAG_RAC_STEREO | INCHI_FLAG_REL_STEREO)) ) {
1197
if ( ret = (Stereo2->nCompInv2Abs < 0) - (Stereo1->nCompInv2Abs < 0) ) {
1203
if ( Stereo2 && ( Stereo2->nNumberOfStereoBonds > 0 ||
1204
Stereo2->nNumberOfStereoCenters > 0
1205
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
1206
&& /* do not compare single stereocenters in case of relative stereo */
1207
!((nFlags2 & (INCHI_FLAG_REL_STEREO|INCHI_FLAG_RAC_STEREO)) &&
1208
1 == Stereo2->nNumberOfStereoCenters
1214
if ( Stereo1 && ( Stereo1->nNumberOfStereoBonds > 0 ||
1215
Stereo1->nNumberOfStereoCenters > 0
1216
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
1217
&& /* do not compare single stereocenters in case of relative stereo */
1218
!((nFlags1 & (INCHI_FLAG_REL_STEREO|INCHI_FLAG_RAC_STEREO)) &&
1219
1 == Stereo1->nNumberOfStereoCenters
1227
/**********************************************************************************************/
1228
/* sorting in descending order: return -1 if *p1 > *p2, return +1 if *p1 < *p2 */
1229
/**********************************************************************************************/
1230
int CompINChI2(const INCHI_SORT *p1, const INCHI_SORT *p2, int bTaut, int bCompareIsotopic)
1232
int ret, num, i, num_H1, num_H2;
1234
const INChI *i1 = NULL; /* tautomeric if exists, otherwise non-tautomeric */
1235
const INChI *i2 = NULL; /* tautomeric if exists, otherwise non-tautomeric */
1237
int n1; /* TAUT_YES if tautomeric i1 exists, otherwise TAUT_NON */
1238
int n2; /* TAUT_YES if tautomeric i2 exists, otherwise TAUT_NON */
1240
const INChI *i1n = NULL; /* non-tautomeric if both tautomeric AND non-tautomeric exist */
1241
const INChI *i2n = NULL; /* non-tautomeric if both tautomeric AND non-tautomeric exist */
1243
/*const INChI *i1t = NULL;*/ /* temp for i1 if both tautomeric AND non-tautomeric exist */
1244
/*const INChI *i2t = NULL;*/ /* temp for i2 if both tautomeric AND non-tautomeric exist */
1247
/* INChI_Stereo *Stereo1, *Stereo2; */
1249
n1 = ( p1->pINChI[TAUT_YES] && p1->pINChI[TAUT_YES]->nNumberOfAtoms )? TAUT_YES : TAUT_NON;
1250
n2 = ( p2->pINChI[TAUT_YES] && p2->pINChI[TAUT_YES]->nNumberOfAtoms )? TAUT_YES : TAUT_NON;
1252
i1 = p1->pINChI[n1];
1253
i1n = (n1 == TAUT_YES && p1->pINChI[TAUT_NON] &&
1254
p1->pINChI[TAUT_NON]->nNumberOfAtoms)? p1->pINChI[TAUT_NON] : (const INChI *)NULL;
1256
i2 = p2->pINChI[n2];
1257
i2n = (n2 == TAUT_YES && p2->pINChI[TAUT_NON] &&
1258
p2->pINChI[TAUT_NON]->nNumberOfAtoms)? p2->pINChI[TAUT_NON] : (const INChI *)NULL;
1260
/* non-deleted-non-empty < deleted < empty */
1262
return -1; /* non-empty is the smallest (first) */
1267
if ( i1->bDeleted && !i2->bDeleted )
1268
return 1; /* deleted is the largest (last) among non-empty */
1269
if ( !i1->bDeleted && i2->bDeleted )
1272
num_H1 = num_H2 = 0;
1274
/* do not compare terminal H */
1275
if ( ret = CompareHillFormulasNoH( i1->szHillFormula, i2->szHillFormula, &num_H1, &num_H2 ) ) {
1276
return ret; /* lexicographic order except the shorter one is greater (last): CH2O < CH2; C3XX < C2XX */
1279
/*********************************************************
1280
compare non-isotopic non-tautomeric part
1281
*********************************************************/
1283
/* compare number of atoms (excluding terminal H) */
1284
if ( ret = i2->nNumberOfAtoms - i1->nNumberOfAtoms )
1285
return ret; /* more atoms first */
1287
/* compare elements (excluding terminal H) */
1288
num = i1->nNumberOfAtoms;
1289
for ( i = 0; i < num; i ++ ) { /* should always be equal if Hill formulas are same */
1290
if ( ret = (int)i2->nAtom[i] - (int)i1->nAtom[i] )
1291
return ret; /* greater periodic number first */
1293
/**********************************************************
1294
compare connection tables
1295
***********************************************************/
1296
if ( ret = i2->lenConnTable - i1->lenConnTable )
1297
return ret; /* longer connection table first */
1298
num = i2->lenConnTable;
1299
for ( i = 0; i < num; i ++ ) {
1300
if ( ret = (int)i2->nConnTable[i] - (int)i1->nConnTable[i] )
1301
return ret; /* greater connection table first */
1303
/*********************************************************
1304
compare compare total number of H (inverse: H3 < H2 )
1305
**********************************************************/
1306
if ( ret = num_H2 - num_H1 )
1308
/*********************************************************
1309
compare non-tautomeric num_H: N < NH3 < NH2 < NH
1310
**********************************************************/
1311
num = i1->nNumberOfAtoms;
1312
for ( i = 0; i < num; i ++ ) {
1313
if ( i2->nNum_H[i] != i1->nNum_H[i] ) {
1314
return !i2->nNum_H[i]? 1 : /* no H first */
1315
!i1->nNum_H[i]? -1 :
1316
(int)i2->nNum_H[i] - (int)i1->nNum_H[i];
1319
/*********************************************************
1320
compare non-isotopic tautomeric part
1321
*********************************************************/
1322
if ( ret = CompareTautNonIsoPartOfINChI( i1, i2) ) {
1326
if ( ret = i2->lenTautomer - i1->lenTautomer )
1328
num = inchi_min( i2->lenTautomer, i1->lenTautomer );
1329
for ( i = 0; i < num; i ++ ) {
1330
if ( ret = (int)i2->nTautomer[i] - (int)i1->nTautomer[i] )
1334
/*********************************************************
1336
* at this point both components are either tautomeric *
1337
* or non-tautomeric *
1339
*********************************************************/
1341
/*********************************************************
1342
non-tautomeric "fixed H" specific
1343
*********************************************************/
1344
if ( TAUT_NON == bTaut && (i1n && i1n->nNum_H_fixed || i2n && i2n->nNum_H_fixed) ) {
1345
/* first, compare non-tautomeric chem. formulas -- they may be different */
1346
const char *f1 = (i1n /*&& i1n->nNum_H_fixed*/)? i1n->szHillFormula : i1->szHillFormula;
1347
const char *f2 = (i2n /*&& i2n->nNum_H_fixed*/)? i2n->szHillFormula : i2->szHillFormula;
1348
if ( f1 && f2 &&(ret = CompareHillFormulas( f1, f2 ))) {
1351
/* secondly, compare fixed-H distribution */
1352
if ( i1n && i1n->nNum_H_fixed && i2n && i2n->nNum_H_fixed ) {
1353
num = inchi_min( i1n->nNumberOfAtoms, i2n->nNumberOfAtoms);
1354
for ( i = 0; i < num; i ++ ) {
1355
if ( i2n->nNum_H_fixed[i] != i1n->nNum_H_fixed[i] ) {
1356
return !i2n->nNum_H_fixed[i]? 1 : /* no fixed H first */
1357
!i1n->nNum_H_fixed[i]? -1 :
1358
(int)i2n->nNum_H_fixed[i] - (int)i1n->nNum_H_fixed[i];
1361
if ( ret = (int)i2n->nNumberOfAtoms - (int)i1n->nNumberOfAtoms ) {
1362
return ret; /* should not happen <BRKPT> */
1365
if ( i1n && i1n->nNum_H_fixed ) {
1366
num = i1n->nNumberOfAtoms;
1367
for ( i = 0; i < num; i ++ ) { /* added 2004-05-04 */
1368
if ( i1n->nNum_H_fixed[i] ) {
1369
return -1; /* i1n->nNum_H_fixed[i] > 0? -1:1;*/
1372
/* p1 is tautomeric, p2 is not tautomeric; this must have been detected earlier */
1373
/*return -1;*/ /* has fixed H first *//* <BRKPT> */ /* removed 2004-05-04 */
1375
num = i2n->nNumberOfAtoms;
1376
for ( i = 0; i < num; i ++ ) { /* added 2004-05-04 */
1377
if ( i2n->nNum_H_fixed[i] ) {
1378
return 1; /* i2n->nNum_H_fixed[i] > 0? 1:-1;*/
1381
/* p2 is tautomeric, p1 is not tautomeric; this must have been detected earlier */
1382
/*return 1; */ /* has fixed H first *//* <BRKPT> */ /* removed 2004-05-04 */
1386
/*************************************************************************
1387
if requested non-tautomeric comparison then
1388
prepare to compare non-taut non-isotopic stereo, etc.
1389
*************************************************************************/
1390
if ( TAUT_NON == bTaut ) {
1401
/*********************************************************
1402
compare non-isotopic stereo
1403
*********************************************************/
1404
ret = CompareInchiStereo( i1->Stereo, i1->nFlags, i2->Stereo, i2->nFlags );
1408
/*******************************************************
1409
do not switch back to tautomeric i1, i2
1410
*******************************************************/
1411
/* -- how to switch back --
1421
/******************************************************
1422
compare isotopic non-tautomeric part
1423
******************************************************/
1424
if ( bCompareIsotopic ) {
1425
if ( ret = i2->nNumberOfIsotopicAtoms - i1->nNumberOfIsotopicAtoms )
1427
num = i1->nNumberOfIsotopicAtoms;
1428
/* compare isotopic atoms */
1429
for ( i = 0; i < num; i ++ ) {
1430
if ( ret = (int)i2->IsotopicAtom[i].nAtomNumber - (int)i1->IsotopicAtom[i].nAtomNumber )
1432
if ( ret = (int)i2->IsotopicAtom[i].nIsoDifference - (int)i1->IsotopicAtom[i].nIsoDifference )
1435
/* compare isotopic H */
1436
/* if tautomeric comparison mode then here are compared only non-tautomeric H */
1437
for ( i = 0; i < num; i ++ ) {
1438
if ( ret = (int)i2->IsotopicAtom[i].nNum_T - (int)i1->IsotopicAtom[i].nNum_T )
1440
if ( ret = (int)i2->IsotopicAtom[i].nNum_D - (int)i1->IsotopicAtom[i].nNum_D )
1442
if ( ret = (int)i2->IsotopicAtom[i].nNum_H - (int)i1->IsotopicAtom[i].nNum_H )
1445
/*****************************************************
1446
compare isotopic tautomeric part
1447
*****************************************************/
1448
if ( ret = i2->nNumberOfIsotopicTGroups - i1->nNumberOfIsotopicTGroups )
1450
num = i1->nNumberOfIsotopicTGroups;
1451
for ( i = 0; i < num; i ++ ) {
1452
if ( ret = (int)i2->IsotopicTGroup[i].nTGroupNumber - (int)i1->IsotopicTGroup[i].nTGroupNumber )
1454
if ( ret = (int)i2->IsotopicTGroup[i].nNum_T - (int)i1->IsotopicTGroup[i].nNum_T )
1456
if ( ret = (int)i2->IsotopicTGroup[i].nNum_D - (int)i1->IsotopicTGroup[i].nNum_D )
1458
if ( ret = (int)i2->IsotopicTGroup[i].nNum_H - (int)i1->IsotopicTGroup[i].nNum_H )
1462
/****************************************************
1463
compare isotopic stereo
1464
****************************************************/
1465
ret = CompareInchiStereo( i1->StereoIsotopic, i1->nFlags, i2->StereoIsotopic, i2->nFlags );
1471
/**********************************************************
1472
compare charges: non-charged first, then in order of
1473
ascending charges (negative first)
1474
***********************************************************/
1475
if ( i2->nTotalCharge && i1->nTotalCharge ) {
1476
/* both are charged; smaller charges first */
1477
ret = (int)i1->nTotalCharge - (int)i2->nTotalCharge;
1480
if ( ret = (i1->nTotalCharge? 1:0) - (i2->nTotalCharge? 1:0) ) {
1481
/* only one is charged; uncharged first */
1485
/*ret = p1->ord_number - p2->ord_number;*/
1489
/***********************************************************************/
1490
int CompINChINonTaut2(const void *p1, const void *p2)
1493
ret = CompINChI2( (const INCHI_SORT *)p1, (const INCHI_SORT *)p2, TAUT_NON, 1 );
1494
#if( CANON_FIXH_TRANS == 1 )
1496
/* to obtain canonical transposition 2004-05-10 */
1497
ret = CompINChI2( (const INCHI_SORT *)p1, (const INCHI_SORT *)p2, TAUT_YES, 1 );
1502
ret = ((const INCHI_SORT *)p1)->ord_number - ((const INCHI_SORT *)p2)->ord_number;
1506
/***********************************************************************/
1507
int CompINChITaut2(const void *p1, const void *p2)
1510
ret = CompINChI2( (const INCHI_SORT *)p1, (const INCHI_SORT *)p2, TAUT_YES, 1 );
1511
#if( CANON_FIXH_TRANS == 1 )
1513
/* to obtain canonical transposition 2004-05-10 */
1514
ret = CompINChI2( (const INCHI_SORT *)p1, (const INCHI_SORT *)p2, TAUT_NON, 1 );
1519
ret = ((const INCHI_SORT *)p1)->ord_number - ((const INCHI_SORT *)p2)->ord_number;
1523
/**********************************************************************************************/
1524
/* strrev from K&R is not in ANSI-compatible C library */
1525
void mystrrev( char *p )
1530
q -= 2; /* pointer to the last character */
1537
/*****************************************************************************************/
1538
/* Find DFS order for CT(canon. numbers and Hs) output */
1539
/*****************************************************************************************/
1541
static AT_NUMB *gDfs4CT_nDfsNumber;
1542
static AT_NUMB *gDfs4CT_nNumDescendants;
1543
static int gDfs4CT_nCurrentAtom;
1545
/**********************************************************************************************/
1546
static int CompareDfsDescendants4CT( const void *a1, const void *a2 )
1548
int neigh1 = (int)*(const AT_RANK*)a1;
1549
int neigh2 = (int)*(const AT_RANK*)a2;
1550
if ( neigh1 > MAX_ATOMS ) {
1551
if ( neigh2 > MAX_ATOMS ) {
1556
if ( neigh2 > MAX_ATOMS ) {
1559
AT_RANK nCurDfsNumber = gDfs4CT_nDfsNumber[gDfs4CT_nCurrentAtom];
1560
int nDesc1 = nCurDfsNumber > gDfs4CT_nDfsNumber[neigh1]?
1561
0 : (int)gDfs4CT_nNumDescendants[neigh1];
1562
int nDesc2 = nCurDfsNumber > gDfs4CT_nDfsNumber[neigh2]?
1563
0 : (int)gDfs4CT_nNumDescendants[neigh2];
1565
if ( ret = nDesc1 - nDesc2 ) {
1568
return (int)neigh1 - (int)neigh2; /* canon. numbers difference */
1571
/**********************************************************************************************/
1572
/* sp_ATOM *at, AT_RANK *nRank, int num_atoms */
1573
AT_NUMB *GetDfsOrder4CT( AT_NUMB *LinearCT, int nLenCT, S_CHAR *nNum_H, int num_atoms, int nCtMode )
1575
AT_NUMB *nStackAtom = NULL;
1576
int nTopStackAtom=-1;
1577
AT_NUMB *nNumDescendants = NULL; /* number of descendants incl. closures and the atom itself */
1578
AT_NUMB *nDfsNumber = NULL;
1579
S_CHAR *cNeighNumb = NULL;
1580
NEIGH_LIST *nl = NULL;
1582
int i, j, u, k, start, num_rings, nTotOutputStringLen;
1583
AT_NUMB *nOutputString = NULL, cDelim;
1584
int bCtPredecessors = (nCtMode & CT_MODE_PREDECESSORS);
1586
/* int nNumStartChildren; */
1589
/* allocate arrays */
1590
nStackAtom = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nStackAtom[0]));
1591
nNumDescendants = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nNumDescendants[0]));
1592
nDfsNumber = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nDfsNumber[0]));
1593
cNeighNumb = (S_CHAR *)inchi_malloc(num_atoms*sizeof(cNeighNumb[0]));
1594
nl = CreateNeighListFromLinearCT( LinearCT, nLenCT, num_atoms );
1595
/* check allocation */
1596
if ( !nStackAtom || !nNumDescendants || !nDfsNumber || !cNeighNumb || !nl ) {
1597
/* ret = CT_OUT_OF_RAM; */ /* program error */ /* <BRKPT> */
1600
if ( bCtPredecessors ) {
1603
/* find DFS start vertex (atom) */
1604
for ( i = 1, start = 0; i < num_atoms; i ++ ) {
1605
if ( nl[i][0] < nl[start][0] ) { /* index = nRank-1 */
1612
1. Number of (forward edges) + (back edges, first visit -- ring closures): nl[i][0]
1613
2. Number of vertices traversed from this vertex, including the vertex: nNumDescendants[i]
1614
3. Each edge information:
1615
a. forward edge (0) or back edge (1) indicator: nDfsNumber[i] > nDfsNumber[neigh]
1616
b. neighbor at another end of the edge neigh = nl[i][k+1], k < i
1618
Total per edge: 2 + 2*(number of edges)
1621
/* DFS initiation */
1622
u = start; /* start atom */
1625
memset( nDfsNumber, 0, num_atoms*sizeof(nDfsNumber[0]));
1626
memset( nNumDescendants, 0, num_atoms*sizeof(nNumDescendants[0]));
1627
memset( cNeighNumb, 0, num_atoms*sizeof(cNeighNumb[0]));
1628
/* push the start atom on the stack */
1629
nDfsNumber[u] = ++nDfs;
1630
if ( bCtPredecessors ) {
1631
nNumDescendants[u] = 0; /* atom #1 has no predecessor */
1633
nNumDescendants[u] = 1; /* count itself as a descendant */
1635
nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
1636
/* nNumStartChildren = 0; */
1643
while ( i=(int)nStackAtom[nTopStackAtom], j = (int)cNeighNumb[i]+1, (int)nl[i][0] >= j )
1644
/*while ( (int)nl[i=nStackAtom[nTopStackAtom]][0] >= (j = (int)cNeighNumb[i]+1) )*/
1645
/* replaced due to missing sequence point; undefined behavior, pointed by Geoffrey Hutchison */
1648
u = (int)nl[i][j]; /* jth neighbor of the vertex i */
1649
if ( !nDfsNumber[u] ) {
1650
/* tree edge, 1st visit -- advance */
1651
/* put unexplored vertex u on the stack for further examination */
1652
nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
1653
nDfsNumber[u] = ++nDfs;
1654
if ( bCtPredecessors ) {
1655
nNumDescendants[u] = i+1; /* predecessor's rank */
1657
nNumDescendants[u] ++; /* count atom u as its descendant */
1660
if ( nTopStackAtom && u != (int)nStackAtom[nTopStackAtom-1] &&
1661
/* back edge: u is not a predecessor of i */
1662
nDfsNumber[u] < nDfsNumber[i] ) {
1663
/* Back edge, 1st visit: u is an ancestor of i (ring closure) */
1664
if ( !bCtPredecessors ) {
1665
nNumDescendants[i] ++; /* count closures as descendants */
1667
num_rings ++; /* count ring closures */
1669
nl[i][j] = MAX_ATOMS+1; /* back edge, 2nd visit: mark as deleted */
1672
cNeighNumb[i] = 0; /* all neighbors of the ith atom have been
1673
traversed; resore the neighbor counter */
1675
if ( !bCtPredecessors && nTopStackAtom /* that is, i != start */) {
1676
u = (int)nStackAtom[nTopStackAtom-1]; /* predecessor of i */
1677
nNumDescendants[u] += nNumDescendants[i]; /* add descendants */
1679
} while ( --nTopStackAtom >= 0 );
1681
/* Sort the neighbors in ascending order so that:
1682
primary key = number of descendants in the DFS tree; closure neighbor is 0
1683
secondary key = canonical number (here vertex number = canonical number - 1)
1686
/* set static globals for the sorting: */
1687
gDfs4CT_nDfsNumber = nDfsNumber;
1688
gDfs4CT_nNumDescendants = nNumDescendants;
1689
gDfs4CT_nCurrentAtom = -1;
1691
/* sorting; deleted will be the last neighbors */
1692
for ( i = 0; i < num_atoms; i ++ ) {
1693
if ( nl[i][0] > 1 ) {
1694
gDfs4CT_nCurrentAtom = i;
1695
insertions_sort( &nl[i][1], nl[i][0], sizeof(nl[i][1]), CompareDfsDescendants4CT );
1697
/* reduce number of neighbors to exclude deleted */
1698
for ( k = 0; k < nl[i][0] && nl[i][k+1] <= MAX_ATOMS; k ++ )
1703
nTotOutputStringLen = 3*(num_atoms+num_rings+1); /* last 3 elements are a 'zero termination' */
1705
if ( bCtPredecessors ) {
1706
if ( nOutputString = (AT_RANK *)inchi_calloc( nTotOutputStringLen, sizeof(nOutputString[0]) ) ) {
1708
for ( u = 0, k = -3 ; u < num_atoms; u ++ ) {
1710
if ( k+6 > nTotOutputStringLen ) {
1711
goto exit_error; /* program error */
1713
nOutputString[k] = nNumDescendants[u]? nNumDescendants[u] : MAX_ATOMS+1;
1714
nOutputString[k+1] = nNum_H? 16+nNum_H[u]:0;
1715
nOutputString[k+2] = k? ',' : '\0';
1716
for ( j = 1; j <= nl[u][0] && nDfsNumber[u] > nDfsNumber[i=nl[u][j]]; j ++ ) {
1719
if ( k+6 > nTotOutputStringLen ) {
1720
goto exit_error; /* program error */
1722
nOutputString[k] = i+1; /* closure */
1723
nOutputString[k+1] = 0;
1724
nOutputString[k+2] = cDelim;
1729
if ( nNumDescendants ) { /* do not need anymore */
1730
inchi_free( nNumDescendants );
1731
nNumDescendants = NULL;
1734
the output string contains:
1735
(num_atoms) atoms for the DFS (spanning) tree
1736
(num_atoms-1) delimiters for the DFS (spanning) tree
1737
1 character for each atom that has 1 terminal hydrogen atoms
1738
2 characters for each atom that has 2-9 terminal hydrogen atoms
1739
3 characters for each atom that has 10-99 terminal hydrogen atoms, etc.
1740
(num_rings) atoms for the ring closures
1741
(num_rings) delimiters for the ring closures
1744
if ( nOutputString = (AT_RANK *)inchi_calloc( nTotOutputStringLen, sizeof(nOutputString[0]) ) ) {
1745
u = start; /* start atom */
1747
memset( cNeighNumb, 0, num_atoms*sizeof(cNeighNumb[0]));
1748
/* push the start atom on the stack */
1749
nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
1750
/* output the starting atom */
1752
nOutputString[k] = u+1;
1753
nOutputString[k+1] = nNum_H? 16+nNum_H[u]:0;
1754
nOutputString[k+2] = '\0';
1758
while ( i=(int)nStackAtom[nTopStackAtom], j = (int)cNeighNumb[i]+1, (int)nl[i][0] >= j )
1759
/*while ( (int)nl[i=nStackAtom[nTopStackAtom]][0] >= (j = (int)cNeighNumb[i]+1) )*/
1760
/* replaced due to missing sequence point; undefined behavior, reported by Geoffrey Hutchison */
1763
if ( k+6 > nTotOutputStringLen ) {
1764
goto exit_error; /* program error */
1767
u = (int)nl[i][j]; /* neighbor */
1769
/* output neighbor's canonical number */
1770
nOutputString[k] = u+1;
1772
if ( nDfsNumber[u] > nDfsNumber[i] ) {
1773
/* tree edge, 1st visit -- advance */
1774
/* put 'unexplored' vertex u on the stack */
1775
nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
1777
/* output neighbor's number of H */
1778
nOutputString[k+1] = nNum_H? 16+nNum_H[u]:0;
1780
nOutputString[k+1] = 0;
1782
/* output a delimiter preceding the neighbor */
1783
if ( 1 < nl[i][0] ) {
1787
if ( j == nl[i][0] ) {
1795
nOutputString[k+2] = cDelim;
1799
/* back up: nothing else to do */
1800
} while ( --nTopStackAtom >= 0 );
1806
if ( nOutputString ) {
1807
inchi_free( nOutputString );
1808
nOutputString = NULL;
1813
inchi_free( nStackAtom );
1814
if ( nNumDescendants )
1815
inchi_free( nNumDescendants );
1817
inchi_free( nDfsNumber );
1819
inchi_free( cNeighNumb );
1821
FreeNeighList( nl );
1822
return nOutputString;
1824
/**********************************************************************************************/
1825
int GetInpStructErrorType( INPUT_PARMS *ip, int err, char *pStrErrStruct, int num_inp_atoms )
1827
if ( err && err == 9 )
1828
return _IS_ERROR; /* sdfile bypassed to $$$$ */
1829
if ( err && err < 30 )
1831
if ( num_inp_atoms <= 0 || err ) {
1832
if ( 98 == err && 0 == num_inp_atoms && ip->bAllowEmptyStructure )
1836
if ( pStrErrStruct[0] )
1840
/**********************************************************************************************/
1841
int ProcessStructError( INCHI_IOSTREAM *output_file, INCHI_IOSTREAM *log_file, /*int err,*/
1842
char *pStrErrStruct, int nErrorType,
1843
int *bXmlStructStarted, long num_inp, INPUT_PARMS *ip, char *pStr, int nStrLen )
1847
int bPlainText = (ip->bINChIOutputOptions & INCHI_OUT_PLAIN_TEXT) &&
1848
(ip->bINChIOutputOptions & INCHI_OUT_WINCHI_WINDOW ) &&
1849
!(ip->bINChIOutputOptions & INCHI_OUT_XML);
1853
if ( !bPlainText && *bXmlStructStarted <= 0 ) {
1856
/* Fatal error, Error, Warning */
1859
if ( !(b_ok=OutputINChIPlainError( output_file, pStr, nStrLen, pStrErrStruct, nErrorType ) ) ) {
1860
inchi_ios_eprint( log_file, "Cannot create message for error (structure #%ld.%s%s%s%s) Terminating.\n",
1861
num_inp, SDF_LBL_VAL(ip->pSdfLabel,ip->pSdfValue) );
1863
inchi_ios_print( output_file, "\n" ); /* add a blank line after the WINCHI Window message */
1866
if ( !(b_ok=OutputINChIXmlError( output_file, pStr, nStrLen, 2, /*err,*/ pStrErrStruct, nErrorType ) ) ) {
1867
inchi_ios_eprint( log_file, "Cannot create xml tag for error (structure #%ld.%s%s%s%s) Terminating.\n",
1868
num_inp, SDF_LBL_VAL(ip->pSdfLabel,ip->pSdfValue) );
1870
if ( !b_ok || nErrorType == _IS_FATAL || nErrorType == _IS_ERROR ) {
1871
/* close current structure output */
1872
if ( !OutputINChIXmlStructEndTag( output_file, pStr, nStrLen, 1 ) ) {
1873
inchi_ios_eprint( log_file, "Cannot create end xml tag for structure #%ld.%s%s%s%s Terminating.\n", num_inp, SDF_LBL_VAL(ip->pSdfLabel,ip->pSdfValue) );
1874
*bXmlStructStarted = -1;
1877
*bXmlStructStarted = 0;
1881
return b_ok? nErrorType : _IS_FATAL;
1887
#if( TEST_RENUMB_ATOMS == 1 ) /* { */
1888
/***************************************************************************************/
1889
int CompareStereoINChI( INChI_Stereo *s1, INChI_Stereo *s2 )
1891
if ( s1 == NULL && s2 == NULL )
1893
if ( (s1 == NULL) ^ (s2 == NULL) )
1896
if ( s1->nNumberOfStereoCenters != s2->nNumberOfStereoCenters )
1898
if ( s1->nNumberOfStereoCenters > 0 ) {
1899
if ( memcmp( s1->nNumber, s2->nNumber, s1->nNumberOfStereoCenters*sizeof(s1->nNumber[0]) ) )
1901
if ( memcmp( s1->t_parity, s2->t_parity, s1->nNumberOfStereoCenters*sizeof(s1->t_parity[0]) ) )
1903
if ( s1->nNumberInv && s2->nNumberInv ) {
1904
if ( memcmp( s1->nNumberInv, s2->nNumberInv, s1->nNumberOfStereoCenters*sizeof(s1->nNumber[0]) ) )
1906
if ( memcmp( s1->t_parityInv, s2->t_parityInv, s1->nNumberOfStereoCenters*sizeof(s1->t_parity[0]) ) )
1908
if ( s1->nCompInv2Abs != s2->nCompInv2Abs ||
1909
s1->bTrivialInv != s2->bTrivialInv ) {
1913
if ( s1->nNumberInv || s2->nNumberInv ) {
1917
if ( s1->nNumberOfStereoBonds != s2->nNumberOfStereoBonds )
1919
if ( s1->nNumberOfStereoBonds > 0 ) {
1920
if ( memcmp( s1->nBondAtom1, s2->nBondAtom1, s1->nNumberOfStereoBonds*sizeof(s1->nBondAtom1[0]) ) )
1922
if ( memcmp( s1->nBondAtom2, s2->nBondAtom2, s1->nNumberOfStereoBonds*sizeof(s1->nBondAtom2[0]) ) )
1924
if ( memcmp( s1->b_parity, s2->b_parity, s1->nNumberOfStereoBonds*sizeof(s1->b_parity[0]) ) )
1929
/***************************************************************************************/
1930
int CompareINChI( INChI *i1, INChI *i2, INChI_Aux *a1, INChI_Aux *a2 )
1933
if ( i1 == NULL && i2 == NULL )
1935
if ( (i1 == NULL) ^ (i2 == NULL) )
1938
if ( i1->nErrorCode == i2->nErrorCode ) {
1939
if ( i1->nErrorCode )
1945
if ( i1->nNumberOfAtoms != i2->nNumberOfAtoms )
1947
if ( i1->nNumberOfAtoms > 0 ) {
1948
if ( memcmp( i1->nAtom, i2->nAtom, i1->nNumberOfAtoms*sizeof(i1->nAtom[0]) ) )
1950
if ( memcmp( i1->nNum_H, i2->nNum_H, i1->nNumberOfAtoms*sizeof(i1->nNum_H[0]) ) )
1952
if ( i1->nNum_H_fixed && i2->nNum_H_fixed &&
1953
memcmp( i1->nNum_H_fixed, i2->nNum_H_fixed, i1->nNumberOfAtoms*sizeof(i1->nNum_H_fixed[0]) ) ) {
1956
if ( strcmp( i1->szHillFormula, i2->szHillFormula ) )
1960
if ( i1->lenConnTable != i2->lenConnTable )
1962
if ( i1->lenConnTable > 0 && memcmp( i1->nConnTable, i2->nConnTable, i1->lenConnTable*sizeof(i1->nConnTable[0]) ) )
1965
if ( i1->lenTautomer != i2->lenTautomer )
1967
if ( i1->lenTautomer > 0 && memcmp( i1->nTautomer, i2->nTautomer, i1->lenTautomer*sizeof(i1->nTautomer[0]) ) )
1970
if ( i1->nNumberOfIsotopicAtoms != i2->nNumberOfIsotopicAtoms )
1972
if ( i1->nNumberOfIsotopicAtoms > 0 && memcmp( i1->IsotopicAtom, i2->IsotopicAtom, i1->nNumberOfIsotopicAtoms*sizeof(i1->IsotopicAtom[0]) ) )
1975
if ( i1->nNumberOfIsotopicTGroups != i2->nNumberOfIsotopicTGroups )
1977
if ( i1->nNumberOfIsotopicTGroups > 0 && memcmp( i1->IsotopicTGroup, i2->IsotopicTGroup, i1->nNumberOfIsotopicTGroups*sizeof(i1->IsotopicTGroup[0]) ) )
1979
if ( a1->nNumRemovedProtons != a2->nNumRemovedProtons )
1981
if ( memcmp( a1->nNumRemovedIsotopicH, a2->nNumRemovedIsotopicH, sizeof(a1->nNumRemovedIsotopicH) ) )
1983
if ( i1->nPossibleLocationsOfIsotopicH && i2->nPossibleLocationsOfIsotopicH ) {
1984
if ( i1->nPossibleLocationsOfIsotopicH[0] != i2->nPossibleLocationsOfIsotopicH[0] ||
1985
memcmp(i1->nPossibleLocationsOfIsotopicH, i2->nPossibleLocationsOfIsotopicH,
1986
sizeof(i1->nPossibleLocationsOfIsotopicH[0])*i1->nPossibleLocationsOfIsotopicH[0]) )
1989
if ( !i1->nPossibleLocationsOfIsotopicH != !i2->nPossibleLocationsOfIsotopicH ) {
1993
if ( ret = CompareStereoINChI( i1->Stereo, i2->Stereo ) )
1996
if ( ret = CompareStereoINChI( i1->StereoIsotopic, i2->StereoIsotopic ) )
2001
#endif /* } TEST_RENUMB_ATOMS == 1 */
2002
#if( READ_INCHI_STRING == 1 ) /* { */
2003
/*************************************************************************************/
2004
int CompareReversedStereoINChI( INChI_Stereo *s1/* InChI from reversed struct */, INChI_Stereo *s2 /* input InChI */)
2006
if ( s1 == NULL && s2 == NULL )
2008
if ( (s1 == NULL) ^ (s2 == NULL) ) {
2009
INChI_Stereo *s = s1? s1 : s2;
2010
if ( s->nNumberOfStereoCenters || s->nNumberOfStereoBonds ) {
2011
return 20; /* Diff: Missing Stereo */
2017
if ( s1->nNumberOfStereoCenters != s2->nNumberOfStereoCenters )
2018
return 21; /* Diff: Number of sp3 stereocenters */
2019
if ( s1->nNumberOfStereoCenters > 0 ) {
2020
if ( memcmp( s1->nNumber, s2->nNumber, s1->nNumberOfStereoCenters*sizeof(s1->nNumber[0]) ) )
2021
return 22; /* Diff: sp3 stereocenter locations */
2022
if ( memcmp( s1->t_parity, s2->t_parity, s1->nNumberOfStereoCenters*sizeof(s1->t_parity[0]) ) )
2023
return 23; /* Diff: sp3 stereocenter parities */
2024
if ( s1->nCompInv2Abs != s2->nCompInv2Abs && s1->nCompInv2Abs && s2->nCompInv2Abs )
2025
return 24; /* Diff: sp3 inversion */
2027
if ( s1->nNumberInv && s2->nNumberInv ) {
2028
if ( memcmp( s1->nNumberInv, s2->nNumberInv, s1->nNumberOfStereoCenters*sizeof(s1->nNumber[0]) ) )
2030
if ( memcmp( s1->t_parityInv, s2->t_parityInv, s1->nNumberOfStereoCenters*sizeof(s1->t_parity[0]) ) )
2032
if ( s1->nCompInv2Abs != s2->nCompInv2Abs ||
2033
s1->bTrivialInv != s2->bTrivialInv ) {
2037
if ( s1->nNumberInv || s2->nNumberInv ) {
2042
if ( s1->nNumberOfStereoBonds != s2->nNumberOfStereoBonds )
2043
return 25; /* Diff: Number of stereobonds */
2044
if ( s1->nNumberOfStereoBonds > 0 ) {
2045
if ( memcmp( s1->nBondAtom1, s2->nBondAtom1, s1->nNumberOfStereoBonds*sizeof(s1->nBondAtom1[0]) ) )
2046
return 26; /* Diff: Stereobond 1st atom locations */
2047
if ( memcmp( s1->nBondAtom2, s2->nBondAtom2, s1->nNumberOfStereoBonds*sizeof(s1->nBondAtom2[0]) ) )
2048
return 27; /* Diff: Stereobond 2nd atom locations */
2049
if ( memcmp( s1->b_parity, s2->b_parity, s1->nNumberOfStereoBonds*sizeof(s1->b_parity[0]) ) )
2050
return 28; /* Diff: Stereobond parities */
2054
/*************************************************************************************/
2055
int CompareReversedStereoINChI2( INChI_Stereo *s1/* InChI from reversed struct */, INChI_Stereo *s2 /* input InChI */, ICR *picr)
2058
int j1, j2, num_eq, num_dif, num_extra_undf, num_miss_undf, num_in1_only, num_in2_only;
2059
int bAddSb = !(picr->num_sb_undef_in1_only + picr->num_sb_in1_only + picr->num_sb_in2_only);
2060
int bAddSc = !(picr->num_sc_undef_in1_only + picr->num_sc_in1_only + picr->num_sc_in2_only);
2062
int nNumSc1 = s1? s1->nNumberOfStereoCenters : 0;
2063
int nNumSc2 = s2? s2->nNumberOfStereoCenters : 0;
2064
int nNumSb1 = s1? s1->nNumberOfStereoBonds : 0;
2065
int nNumSb2 = s2? s2->nNumberOfStereoBonds : 0;
2067
if ( (nNumSc1 || nNumSc1) &&
2068
( nNumSc1 != nNumSc2 ||
2069
memcmp( s1->nNumber, s2->nNumber, nNumSc1*sizeof(s1->nNumber[0] ) ) ||
2070
memcmp( s1->t_parity, s2->t_parity, nNumSc1*sizeof(s1->t_parity[0]) ) ) ) {
2072
num_eq = num_dif = num_extra_undf = num_miss_undf = num_in1_only = num_in2_only = 0;
2073
for ( j1 = j2 = 0; j1 < nNumSc1 && j2 < nNumSc2; ) {
2074
if ( s1->nNumber[j1] == s2->nNumber[j2] ) {
2075
if ( s1->t_parity[j1] == s2->t_parity[j2] ) {
2083
if ( s1->nNumber[j1] < s2->nNumber[j2] ) {
2085
if ( s1->t_parity[j1] == AB_PARITY_UNDF ) {
2089
if ( picr->num_sc_in1_only < ICR_MAX_SC_IN1_ONLY )
2090
picr->sc_in1_only[picr->num_sc_in1_only ++] = j1;
2091
if ( s1->t_parity[j1] == AB_PARITY_UNDF ) {
2092
if ( picr->num_sc_undef_in1_only < ICR_MAX_SC_UNDF )
2093
picr->sc_undef_in1_only[picr->num_sc_undef_in1_only ++] = j1;
2099
if ( s2->t_parity[j2] == AB_PARITY_UNDF ) {
2103
if ( picr->num_sc_in2_only < ICR_MAX_SC_IN2_ONLY )
2104
picr->sc_in2_only[picr->num_sc_in2_only ++] = j2;
2105
if ( s2->t_parity[j2] == AB_PARITY_UNDF ) {
2106
if ( picr->num_sc_undef_in2_only < ICR_MAX_SC_UNDF )
2107
picr->sc_undef_in2_only[picr->num_sc_undef_in2_only ++] = j1;
2113
while ( j1 < nNumSc1 ) {
2114
if ( s1->t_parity[j1] == AB_PARITY_UNDF ) {
2119
if ( picr->num_sc_in1_only < ICR_MAX_SC_IN1_ONLY )
2120
picr->sc_in1_only[picr->num_sc_in1_only ++] = j1;
2121
if ( s1->t_parity[j1] == AB_PARITY_UNDF ) {
2122
if ( picr->num_sc_undef_in1_only < ICR_MAX_SC_UNDF )
2123
picr->sc_undef_in1_only[picr->num_sc_undef_in1_only ++] = j1;
2128
while ( j2 < nNumSc2 ) {
2129
if ( s2->t_parity[j2] == AB_PARITY_UNDF ) {
2134
if ( picr->num_sc_in2_only < ICR_MAX_SC_IN2_ONLY )
2135
picr->sc_in2_only[picr->num_sc_in2_only ++] = j2;
2140
ret |= IDIF_SC_PARITY;
2142
if ( num_in1_only ) {
2143
if ( num_extra_undf ) {
2144
ret |= IDIF_SC_EXTRA_UNDF;
2146
if ( num_in1_only != num_extra_undf ) {
2147
ret |= IDIF_SC_EXTRA;
2150
if ( num_in2_only ) {
2151
if ( num_miss_undf ) {
2152
ret |= IDIF_SC_MISS_UNDF;
2154
if ( num_in2_only != num_miss_undf ) {
2155
ret |= IDIF_SC_MISS;
2159
if ( s1 && s2 && s1->nCompInv2Abs != s2->nCompInv2Abs && s1->nCompInv2Abs && s2->nCompInv2Abs ) {
2163
if ( (nNumSb1 || nNumSb2 ) &&
2164
(nNumSb1 != nNumSb2 ||
2165
memcmp( s1->nBondAtom1, s2->nBondAtom1, nNumSb1*sizeof(s1->nBondAtom1[0]) ) ||
2166
memcmp( s1->nBondAtom2, s2->nBondAtom2, nNumSb1*sizeof(s1->nBondAtom2[0]) ) ||
2167
memcmp( s1->b_parity, s2->b_parity, nNumSb1*sizeof(s1->b_parity[0]) ) ) ) {
2169
num_eq = num_dif = num_extra_undf = num_miss_undf = num_in1_only = num_in2_only = 0;
2170
for ( j1 = j2 = 0; j1 < nNumSb1 && j2 < nNumSb2; ) {
2171
if ( s1->nBondAtom1[j1] == s2->nBondAtom1[j2] &&
2172
s1->nBondAtom2[j1] == s2->nBondAtom2[j2] ) {
2173
if ( s1->b_parity[j1] == s2->b_parity[j2] ) {
2181
if ( s1->nBondAtom1[j1] < s2->nBondAtom1[j2] ||
2182
s1->nBondAtom1[j1] == s2->nBondAtom1[j2] && s1->nBondAtom2[j1] < s2->nBondAtom2[j2]) {
2184
if ( s1->b_parity[j1] == AB_PARITY_UNDF ) {
2188
if ( picr->num_sb_in1_only < ICR_MAX_SB_IN1_ONLY )
2189
picr->sb_in1_only[picr->num_sb_in1_only ++] = j1;
2190
if ( s1->b_parity[j1] == AB_PARITY_UNDF ) {
2191
if ( picr->num_sb_undef_in1_only < ICR_MAX_SB_UNDF )
2192
picr->sb_undef_in1_only[picr->num_sb_undef_in1_only ++] = j1;
2198
if ( s2->b_parity[j2] == AB_PARITY_UNDF ) {
2202
if ( picr->num_sb_in2_only < ICR_MAX_SB_IN2_ONLY )
2203
picr->sb_in2_only[picr->num_sb_in2_only ++] = j2;
2204
if ( s2->b_parity[j2] == AB_PARITY_UNDF ) {
2205
if ( picr->num_sb_undef_in2_only < ICR_MAX_SB_UNDF )
2206
picr->sb_undef_in2_only[picr->num_sb_undef_in2_only ++] = j1;
2212
while ( j1 < nNumSb1 ) {
2214
if ( s1->b_parity[j1] == AB_PARITY_UNDF ) {
2218
if ( picr->num_sb_in1_only < ICR_MAX_SB_IN1_ONLY )
2219
picr->sb_in1_only[picr->num_sb_in1_only ++] = j1;
2220
if ( s1->b_parity[j1] == AB_PARITY_UNDF ) {
2221
if ( picr->num_sb_undef_in1_only < ICR_MAX_SB_UNDF )
2222
picr->sb_undef_in1_only[picr->num_sb_undef_in1_only ++] = j1;
2227
while ( j2 < nNumSb2 ) {
2229
if ( s2->b_parity[j2] == AB_PARITY_UNDF ) {
2233
if ( picr->num_sb_in2_only < ICR_MAX_SB_IN2_ONLY )
2234
picr->sb_in2_only[picr->num_sb_in2_only ++] = j2;
2235
if ( s2->b_parity[j2] == AB_PARITY_UNDF ) {
2236
if ( picr->num_sb_undef_in2_only < ICR_MAX_SB_UNDF )
2237
picr->sb_undef_in2_only[picr->num_sb_undef_in2_only ++] = j1;
2243
ret |= IDIF_SB_PARITY;
2245
if ( num_in1_only ) {
2246
if ( num_extra_undf ) {
2247
ret |= IDIF_SB_EXTRA_UNDF;
2249
if ( num_in1_only != num_extra_undf ) {
2250
ret |= IDIF_SB_EXTRA;
2253
if ( num_in2_only ) {
2254
if ( num_miss_undf ) {
2255
ret |= IDIF_SB_MISS_UNDF;
2257
if ( num_in2_only != num_miss_undf ) {
2258
ret |= IDIF_SB_MISS;
2265
/*************************************************************************************/
2266
int CompareReversedINChI( INChI *i1 /* InChI from reversed struct */, INChI *i2 /* input InChI */, INChI_Aux *a1, INChI_Aux *a2 )
2269
if ( i1 == NULL && i2 == NULL )
2271
if ( (i1 == NULL) ^ (i2 == NULL) )
2272
return 1; /* Diff: Missing InChI */
2274
if ( i1->nErrorCode == i2->nErrorCode ) {
2275
if ( i1->nErrorCode )
2278
return 2; /* Diff: Error codes */
2280
if ( i1->bDeleted != i2->bDeleted ) {
2281
return 1; /* Diff: Missing InChI */
2283
if ( i1->nNumberOfAtoms != i2->nNumberOfAtoms )
2284
return 3; /* Diff: Num. atoms */
2285
if ( i1->nNumberOfAtoms > 0 ) {
2286
if ( memcmp( i1->nAtom, i2->nAtom, i1->nNumberOfAtoms*sizeof(i1->nAtom[0]) ) )
2287
return 4; /* Diff: Elements */
2288
if ( strcmp( i1->szHillFormula, i2->szHillFormula ) )
2289
return 7; /* Diff: Hill Formulas */
2290
if ( memcmp( i1->nNum_H, i2->nNum_H, i1->nNumberOfAtoms*sizeof(i1->nNum_H[0]) ) ) {
2291
if ( i1->lenConnTable > 1 || i2->lenConnTable > 1 ) {
2292
return 5; /* Diff: H Locations (mobile H present) */
2294
return 6; /* Diff: H Locations (no mobile H) */
2298
if ( i1->nNum_H_fixed || i2->nNum_H_fixed ) {
2299
int bHasFixedH1 = 0, bHasFixedH2 = 0, i, j1, j2;
2300
if ( i1->nNum_H_fixed ) {
2301
for ( i = 0; i < i1->nNumberOfAtoms; i ++ ) {
2302
if ( i1->nNum_H_fixed[i] ) {
2307
if ( i2->nNum_H_fixed ) {
2308
for ( i = 0; i < i2->nNumberOfAtoms; i ++ ) {
2309
if ( i2->nNum_H_fixed[i] ) {
2314
/* count the differences */
2316
if ( bHasFixedH1 && !bHasFixedH2 ) {
2317
for ( i = 0; i < i1->nNumberOfAtoms; i ++ ) {
2318
if ( i1->nNum_H_fixed[i] > 0 ) {
2321
if ( i1->nNum_H_fixed[i] < 0 ) {
2326
return 18; /* Diff: Extra Fixed-H */
2328
if ( !bHasFixedH1 && bHasFixedH2 ) {
2329
for ( i = j1 = j2 = 0; i < i1->nNumberOfAtoms; i ++ ) {
2330
if ( 0 > i2->nNum_H_fixed[i] ) {
2333
if ( 0 < i2->nNum_H_fixed[i] ) {
2337
return 19; /* Diff: Missed Fixed-H */
2339
if ( bHasFixedH1 && bHasFixedH2 &&
2340
memcmp( i1->nNum_H_fixed, i2->nNum_H_fixed, i1->nNumberOfAtoms*sizeof(i1->nNum_H_fixed[0]) ) ) {
2341
for ( i = j1 = j2 = 0; i < i1->nNumberOfAtoms; i ++ ) {
2342
if ( i1->nNum_H_fixed[i] > i2->nNum_H_fixed[i] ) {
2345
if ( i1->nNum_H_fixed[i] < i2->nNum_H_fixed[i] ) {
2350
ret = (j1 && j2)? 20 : j1? 18 : j2? 19 : 0;
2352
return ret; /* 20 => Diff: NotEql Fixed-H */
2353
/* 19 => Diff: Missed Fixed-H (i1 has less) */
2354
/* 18 => Diff: Extra Fixed-H (i1 has more) */
2359
if ( i1->lenConnTable != i2->lenConnTable )
2360
return 8; /* Diff: Connections length */
2361
if ( i1->lenConnTable > 0 && memcmp( i1->nConnTable, i2->nConnTable, i1->lenConnTable*sizeof(i1->nConnTable[0]) ) )
2362
return 9; /* Diff: Connections */
2363
/* output special cases: different number of t-groups, different sizes of t-groups, different endpoints */
2364
if ( i1->lenTautomer != i2->lenTautomer && (i1->lenTautomer > 1 || i2->lenTautomer > 1) )
2365
return 10; /* Diff: Mobile groups length */ /* in isotopic or deprotonated cases i1->lenTautomer == 1 && i1->nTautomer[0] = 0 */
2366
if ( (i1->lenTautomer > 1 && i2->lenTautomer > 1) &&
2367
memcmp( i1->nTautomer, i2->nTautomer, i1->lenTautomer*sizeof(i1->nTautomer[0]) ) )
2368
return 11; /* Diff: Mobile groups */
2370
if ( i1->nNumberOfIsotopicAtoms != i2->nNumberOfIsotopicAtoms )
2371
return 12; /* Diff: Isotopic atoms number */
2372
if ( i1->nNumberOfIsotopicAtoms > 0 && memcmp( i1->IsotopicAtom, i2->IsotopicAtom, i1->nNumberOfIsotopicAtoms*sizeof(i1->IsotopicAtom[0]) ) )
2373
return 13; /* Diff: Isotopic atoms */
2374
if ( i1->nTotalCharge != i2->nTotalCharge )
2375
return 14; /* Diff: Charge */
2377
if ( i1->nNumberOfIsotopicTGroups != i2->nNumberOfIsotopicTGroups )
2379
if ( i1->nNumberOfIsotopicTGroups > 0 && memcmp( i1->IsotopicTGroup, i2->IsotopicTGroup, i1->nNumberOfIsotopicTGroups*sizeof(i1->IsotopicTGroup[0]) ) )
2383
if ( a1->nNumRemovedProtons != a2->nNumRemovedProtons )
2384
return 16; /* Diff: Number of removed protons */
2385
if ( memcmp( a1->nNumRemovedIsotopicH, a2->nNumRemovedIsotopicH, sizeof(a1->nNumRemovedIsotopicH) ) )
2386
return 17; /* Diff: Removed isotopic H */
2389
if ( i1->nPossibleLocationsOfIsotopicH && i2->nPossibleLocationsOfIsotopicH ) {
2390
if ( i1->nPossibleLocationsOfIsotopicH[0] != i2->nPossibleLocationsOfIsotopicH[0] ||
2391
memcmp(i1->nPossibleLocationsOfIsotopicH, i2->nPossibleLocationsOfIsotopicH,
2392
sizeof(i1->nPossibleLocationsOfIsotopicH[0])*i1->nPossibleLocationsOfIsotopicH[0]) )
2395
if ( !i1->nPossibleLocationsOfIsotopicH != !i2->nPossibleLocationsOfIsotopicH ) {
2399
/* ret = 20..31 => 40..51 */
2400
if ( ret = CompareReversedStereoINChI( i1->Stereo, i2->Stereo ) )
2402
/* ret = 40..51 => 60..71 */
2404
if ( !i2->StereoIsotopic && i2->Stereo && i1->StereoIsotopic &&
2405
0 < (i1->StereoIsotopic->nNumberOfStereoBonds + i1->StereoIsotopic->nNumberOfStereoCenters) &&
2406
0 == CompareReversedStereoINChI( i1->StereoIsotopic, i2->Stereo ) ) {
2407
/* InChI from reversed structure does not contain fully duplicated isotopic stereo */
2411
if ( ret = CompareReversedStereoINChI( i1->StereoIsotopic, i2->StereoIsotopic ) ) {
2418
/*******************************************************************************/
2419
int CompareIcr( ICR *picr1, ICR *picr2, INCHI_MODE *pin1, INCHI_MODE *pin2, INCHI_MODE mask )
2421
int nNumExtraBits1 = 0, nNumExtraBits2 = 0, bit1, bit2;
2422
INCHI_MODE Flg1=picr1->flags, Flg2 = picr2->flags, cur_bit = 1, in1, in2;
2427
for ( i = 0; Flg1 || Flg2; i ++, Flg1 >>= 1, Flg2 >>= 1, cur_bit <<= 1 ) {
2428
if ( !(mask & cur_bit) ) {
2433
if ( bit1 && !bit2 ) {
2437
if ( !bit1 && bit2 ) {
2442
if ( nNumExtraBits1 && !nNumExtraBits2 ) {
2445
if ( !nNumExtraBits1 && nNumExtraBits2 ) {
2448
if ( !in1 && !in2 ) {
2451
ret = 2; /* compare produced undefined results */
2453
if ( pin1 ) *pin1 = in1;
2454
if ( pin2 ) *pin2 = in2;
2455
/* more detailed compare not implemented */
2459
/*********************************************************************************************************/
2460
INCHI_MODE CompareReversedINChI2( INChI *i1 /* InChI from reversed struct */, INChI *i2 /* input InChI */,
2461
INChI_Aux *a1, INChI_Aux *a2, ICR *picr, int *err )
2464
INChI_Stereo *Stereo1=NULL, *Stereo2=NULL;
2465
int n1, n2, m, j, j1, j2, ret2, num_H1, num_H2;
2469
memset( picr, 0, sizeof(*picr) );
2471
if ( i1 == NULL && i2 == NULL )
2473
if ( (i1 == NULL) ^ (i2 == NULL) ) {
2474
ret |= IDIF_PROBLEM; /* one InChI exists while another doesn't */
2478
if ( i1->nErrorCode == i2->nErrorCode ) {
2479
if ( i1->nErrorCode ) {
2480
ret |= IDIF_PROBLEM; /* both InChI have same error codes */
2484
ret |= IDIF_PROBLEM; /* at least one InChI has an error code */
2488
if ( i1->nNumberOfAtoms != i2->nNumberOfAtoms ) {
2492
if ( i1->nNumberOfAtoms > 0 ) {
2493
if ( memcmp( i1->nAtom, i2->nAtom, i1->nNumberOfAtoms*sizeof(i1->nAtom[0]) ) ) {
2497
/* IDIF_NON_TAUT_H, IDIF_MORE_FH, IDIF_LESS_FH */
2498
if ( memcmp( i1->nNum_H, i2->nNum_H, i1->nNumberOfAtoms*sizeof(i1->nNum_H[0]) ) ) {
2499
ret |= IDIF_POSITION_H;
2500
for ( j1 = 0; j1 < i1->nNumberOfAtoms; j1 ++ ) {
2501
if ( i1->nNum_H[j1] != i2->nNum_H[j1] && picr->num_diff_pos_H < ICR_MAX_DIFF_FIXED_H ) {
2502
picr->diff_pos_H_at[picr->num_diff_pos_H] = j1;
2503
picr->diff_pos_H_nH[picr->num_diff_pos_H] = i1->nNum_H[j1] - i2->nNum_H[j1];
2504
picr->num_diff_pos_H ++;
2509
if ( i1->nNum_H_fixed || i2->nNum_H_fixed ) {
2510
int bHasFixedH1 = 0, bHasFixedH2 = 0, i;
2511
if ( i1->nNum_H_fixed ) {
2512
for ( i = 0; i < i1->nNumberOfAtoms; i ++ ) {
2513
if ( i1->nNum_H_fixed[i] ) {
2518
if ( i2->nNum_H_fixed ) {
2519
for ( i = 0; i < i2->nNumberOfAtoms; i ++ ) {
2520
if ( i2->nNum_H_fixed[i] ) {
2525
if ( bHasFixedH1 && !bHasFixedH2 ) {
2526
for ( i = j = 0; i < i1->nNumberOfAtoms; i ++ ) {
2527
if ( i1->nNum_H_fixed[i] ) {
2528
if ( j < ICR_MAX_DIFF_FIXED_H ) {
2529
picr->fixed_H_at1_more[j] = i;
2530
picr->fixed_H_nH1_more[j] = i1->nNum_H_fixed[i];
2535
picr->num_fixed_H1_more = j;
2536
ret |= IDIF_MORE_FH; /* Extra Fixed-H */
2538
if ( !bHasFixedH1 && bHasFixedH2 ) {
2539
for ( i = j = 0; i < i2->nNumberOfAtoms; i ++ ) {
2540
if ( i2->nNum_H_fixed[i] ) {
2541
if ( j < ICR_MAX_DIFF_FIXED_H ) {
2542
picr->fixed_H_at2_more[j] = i;
2543
picr->fixed_H_nH2_more[j] = i2->nNum_H_fixed[i];
2548
picr->num_fixed_H2_more = j;
2549
ret |= IDIF_LESS_FH; /* Missed Fixed-H */
2551
if ( bHasFixedH1 && bHasFixedH2 &&
2552
memcmp( i1->nNum_H_fixed, i2->nNum_H_fixed, i1->nNumberOfAtoms*sizeof(i1->nNum_H_fixed[0]) ) ) {
2553
for ( i = j1 = j2 = 0; i < i1->nNumberOfAtoms; i ++ ) {
2554
if ( i1->nNum_H_fixed[i] > i2->nNum_H_fixed[i] ) {
2555
if ( j1 < ICR_MAX_DIFF_FIXED_H ) {
2556
picr->fixed_H_at1_more[j1] = i;
2557
picr->fixed_H_nH1_more[j1] = i1->nNum_H_fixed[i] - i2->nNum_H_fixed[i];
2561
if ( i1->nNum_H_fixed[i] < i2->nNum_H_fixed[i] ) {
2562
if ( j2 < ICR_MAX_DIFF_FIXED_H ) {
2563
picr->fixed_H_at2_more[j2] = i;
2564
picr->fixed_H_nH2_more[j2] = i2->nNum_H_fixed[i] - i1->nNum_H_fixed[i];
2569
ret |= (j1? IDIF_MORE_FH:0) | (j2? IDIF_LESS_FH:0);
2570
picr->num_fixed_H1_more = j1;
2571
picr->num_fixed_H2_more = j2;
2575
/* compare formulas and H */
2578
ret2 = CompareHillFormulasNoH( i1->szHillFormula, i2->szHillFormula, &num_H1, &num_H2 );
2579
picr->tot_num_H1 = num_H1;
2580
picr->tot_num_H2 = num_H2;
2585
if ( num_H1 > num_H2 ) {
2588
if ( num_H1 < num_H2 ) {
2592
if ( i1->lenConnTable != i2->lenConnTable ) {
2593
ret |= IDIF_CON_LEN;
2596
if ( i1->lenConnTable > 0 && memcmp( i1->nConnTable, i2->nConnTable, i1->lenConnTable*sizeof(i1->nConnTable[0]) ) ) {
2597
ret |= IDIF_CON_TBL;
2600
/* output special cases: different number of t-groups, different sizes of t-groups, different endpoints */
2601
/* in isotopic or deprotonated cases i1->lenTautomer == 1 && i1->nTautomer[0] = 0 */
2603
if ( i1->lenTautomer != i2->lenTautomer && (i1->lenTautomer > 1 || i2->lenTautomer > 1) ) {
2604
ret |= IDIF_TAUT_LEN;
2607
/* compare number of t-groups */
2608
n1 = i1->lenTautomer? i1->nTautomer[0] : 0;
2609
n2 = i2->lenTautomer? i2->nTautomer[0] : 0;
2611
ret |= IDIF_NO_TAUT;
2614
ret |= IDIF_WRONG_TAUT;
2616
if ( n1 == 1 && n2 > 1 ) {
2617
ret |= IDIF_SINGLE_TG;
2619
if ( n1 > 1 && n2 == 1 ) {
2620
ret |= IDIF_MULTIPLE_TG;
2626
/* number of endpoints */
2627
int num1 = 0, num2 = 0, num_M1=0, num_M2=0;
2628
int len, num_eq, num_in1_only, num_in2_only;
2629
AT_NUMB *pe1 = (AT_NUMB *)inchi_malloc( (i1->lenTautomer+1) * sizeof(pe1[0]) );
2630
AT_NUMB *pe2 = (AT_NUMB *)inchi_malloc( (i2->lenTautomer+1) * sizeof(pe2[0]) );
2632
/* collect endpoints, H, (-) */
2633
if ( !pe1 || !pe2 ) {
2634
if ( pe1 ) inchi_free( pe1 );
2635
if ( pe2 ) inchi_free( pe2 );
2636
*err = -1; /* allocation error */
2639
for ( m = 1; m < i1->lenTautomer; m += len ) {
2640
len = i1->nTautomer[m ++];
2641
num_H1 += i1->nTautomer[m];
2642
num_M1 += i1->nTautomer[m+1];
2643
for ( j = 2; j < len; j ++ ) {
2644
pe1[num1 ++] = i1->nTautomer[m + j];
2647
for ( m = 1; m < i2->lenTautomer; m += len ) {
2648
len = i2->nTautomer[m ++];
2649
num_H2 += i2->nTautomer[m];
2650
num_M2 += i2->nTautomer[m+1];
2651
for ( j = 2; j < len; j ++ ) {
2652
pe2[num2 ++] = i2->nTautomer[m + j];
2655
picr->num_taut_H1 = num_H1;
2656
picr->num_taut_H2 = num_H2;
2657
picr->num_taut_M1 = num_M1;
2658
picr->num_taut_M2 = num_M2;
2659
/* sort endpoints */
2660
insertions_sort_AT_RANK( pe1, num1 );
2661
insertions_sort_AT_RANK( pe2, num2 );
2664
if ( num1 < num2 ) {
2665
ret |= IDIF_LESS_TG_ENDP;
2667
if ( num1 > num2 ) {
2668
ret |= IDIF_MORE_TG_ENDP;
2672
num_eq = num_in1_only = num_in2_only = 0;
2673
for ( j1 = j2 = 0; j1 < num1 && j2 < num2; ) {
2674
if( pe1[j1] == pe2[j2] ) {
2679
if ( pe1[j1] < pe2[j2] ) { /* BC: fixed, was pe2[j1] 2006-03-27 */
2680
if ( picr->num_endp_in1_only < ICR_MAX_ENDP_IN1_ONLY ) {
2681
picr->endp_in1_only[picr->num_endp_in1_only ++] = pe1[j1];
2686
if ( picr->num_endp_in2_only < ICR_MAX_ENDP_IN2_ONLY ) {
2687
picr->endp_in2_only[picr->num_endp_in2_only ++] = pe2[j2];
2693
while ( j1 < num1 ) {
2694
if ( picr->num_endp_in1_only < ICR_MAX_ENDP_IN1_ONLY ) {
2695
picr->endp_in1_only[picr->num_endp_in1_only ++] = pe1[j1];
2700
while ( j2 < num2 ) {
2701
if ( picr->num_endp_in2_only < ICR_MAX_ENDP_IN2_ONLY ) {
2702
picr->endp_in2_only[picr->num_endp_in2_only ++] = pe2[j2];
2707
if ( num_in1_only ) {
2708
ret |= IDIF_EXTRA_TG_ENDP;
2710
if ( num_in2_only ) {
2711
ret |= IDIF_MISS_TG_ENDP;
2713
if ( !num_in1_only && !num_in2_only && num_eq ) {
2714
; /* same t-groups endpoints */
2716
ret |= IDIF_DIFF_TG_ENDP;
2723
if ( (i1->lenTautomer > 1 && i2->lenTautomer > 1) &&
2724
( i1->lenTautomer != i2->lenTautomer ||
2725
memcmp( i1->nTautomer, i2->nTautomer, i1->lenTautomer*sizeof(i1->nTautomer[0]) ) ) )
2728
if ( i1->nNumberOfIsotopicAtoms != i2->nNumberOfIsotopicAtoms ) {
2729
ret |= IDIF_NUM_ISO_AT;
2731
if ( i1->nNumberOfIsotopicAtoms > 0 && memcmp( i1->IsotopicAtom, i2->IsotopicAtom, i1->nNumberOfIsotopicAtoms*sizeof(i1->IsotopicAtom[0]) ) )
2733
if ( i1->nTotalCharge != i2->nTotalCharge )
2735
if ( a1 && a1->nNumRemovedProtons && (!a2 || a2->nNumRemovedProtons != a1->nNumRemovedProtons) ) {
2736
ret |= IDIF_REM_PROT;
2739
a2->nNumRemovedIsotopicH[0] != a1->nNumRemovedIsotopicH[0] ||
2740
a2->nNumRemovedIsotopicH[1] != a1->nNumRemovedIsotopicH[1] ||
2741
a2->nNumRemovedIsotopicH[2] != a1->nNumRemovedIsotopicH[2]) ) {
2742
ret |= IDIF_REM_ISO_H;
2746
if ( i1->nPossibleLocationsOfIsotopicH && i2->nPossibleLocationsOfIsotopicH ) {
2747
if ( i1->nPossibleLocationsOfIsotopicH[0] != i2->nPossibleLocationsOfIsotopicH[0] ||
2748
memcmp(i1->nPossibleLocationsOfIsotopicH, i2->nPossibleLocationsOfIsotopicH,
2749
sizeof(i1->nPossibleLocationsOfIsotopicH[0])*i1->nPossibleLocationsOfIsotopicH[0]) )
2752
if ( !i1->nPossibleLocationsOfIsotopicH != !i2->nPossibleLocationsOfIsotopicH ) {
2756
if ( i1->StereoIsotopic &&
2757
i1->StereoIsotopic->nNumberOfStereoBonds + i1->StereoIsotopic->nNumberOfStereoCenters ) {
2758
Stereo1 = i1->StereoIsotopic;
2760
Stereo1 = i1->Stereo;
2762
if ( i2->StereoIsotopic &&
2763
i2->StereoIsotopic->nNumberOfStereoBonds + i2->StereoIsotopic->nNumberOfStereoCenters ) {
2764
Stereo2 = i2->StereoIsotopic;
2766
Stereo2 = i2->Stereo;
2768
ret |= CompareReversedStereoINChI2( Stereo1, Stereo2, picr );
2776
#endif /* } READ_INCHI_STRING */
2777
/***************************************************************************************/
2778
int Create_INChI( INChI **ppINChI, INChI_Aux **ppINChI_Aux, ORIG_ATOM_DATA *orig_inp_data, /* not used */
2779
inp_ATOM *inp_at, INP_ATOM_DATA *out_norm_data[2],
2780
int num_inp_at, INCHI_MODE nUserMode,
2781
INCHI_MODE *pbTautFlags, INCHI_MODE *pbTautFlagsDone,
2782
struct tagInchiTime *ulMaxTime, T_GROUP_INFO *ti_out, char *pStrErrStruct)
2788
sp_ATOM *at[TAUT_NUM]; /* at[0]=>non-tautomeric, at[1]=>tautomeric */
2789
/* inp_ATOM *out_norm_taut_at, *out_norm_nontaut_at; */
2790
int i, n1, n2, num_atoms, num_at_tg, num_removed_H, num_removed_H_taut=0, ret=0, ret2=0;
2792
T_GROUP_INFO vt_group_info;
2793
T_GROUP_INFO vt_group_info_orig;
2794
T_GROUP_INFO * /*const*/ t_group_info = &vt_group_info;
2795
T_GROUP_INFO * /*const*/ t_group_info_orig = &vt_group_info_orig;
2798
CANON_STAT *pCS = &CS;
2799
CANON_STAT *pCS2 = &CS2; /* save all allocations to avoid memory leaks in case Canon_INChI() removes the pointer */
2801
ATOM_SIZES s[TAUT_NUM];
2806
int bHasIsotopicAtoms = 0;
2807
int bMayHaveStereo = 0;
2808
int num_taut_at = 0;
2810
inp_ATOM *out_at = NULL; /*, *norm_at_fixed_bonds[TAUT_NUM]; */ /* = {out_norm_nontaut_at, out_norm_taut_at} ; */
2811
INChI *pINChI=NULL; /* added initialization 2006-03 */
2812
INChI_Aux *pINChI_Aux=NULL; /* added initialization 2006-03 */
2813
int bPointedEdgeStereo = ((TG_FLAG_POINTED_EDGE_STEREO & *pbTautFlags)? PES_BIT_POINT_EDGE_STEREO:0)
2814
| ((TG_FLAG_PHOSPHINE_STEREO & *pbTautFlags)? PES_BIT_PHOSPHINE_STEREO :0)
2815
| ((TG_FLAG_ARSINE_STEREO & *pbTautFlags)? PES_BIT_ARSINE_STEREO :0)
2816
| ((TG_FLAG_FIX_SP3_BUG & *pbTautFlags)? PES_BIT_FIX_SP3_BUG :0);
2817
INCHI_MODE bTautFlags = (*pbTautFlags & (~(INCHI_MODE)TG_FLAG_ALL_TAUTOMERIC) );
2818
INCHI_MODE bTautFlagsDone = (*pbTautFlagsDone /*& (~(INCHI_MODE)TG_FLAG_ALL_TAUTOMERIC) */);
2819
#if( bRELEASE_VERSION == 0 )
2820
int bExtract = 0; /* EXTR_HAS_ATOM_WITH_DEFINED_PARITY; */
2824
int bFixIsoFixedH = 0;
2825
int bFixTermHChrg = 0;
2827
#if( TEST_RENUMB_ATOMS == 1 )
2829
long ulCanonTime=0, ulCanonTime2=0;
2831
inchiTime ulNormTimeStart;
2832
inchiTime ulCanonTimeStart;
2834
InchiTimeGet( &ulNormTimeStart );
2837
/* vABParityUnknown holds actual value of an internal constant signifying */
2838
/* unknown parity: either the same as for undefined parity (default==standard) */
2839
/* or a specific one (non-std; requested by SLUUD switch). */
2840
int vABParityUnknown = AB_PARITY_UNDF;
2841
if ( 0 != ( nUserMode & REQ_MODE_DIFF_UU_STEREO) )
2843
/* Make labels for unknown and undefined stereo different */
2844
vABParityUnknown = AB_PARITY_UNKN;
2850
#if( FIX_ISO_FIXEDH_BUG == 1 )
2851
if (TG_FLAG_FIX_ISO_FIXEDH_BUG & *pbTautFlags)
2854
#if( FIX_TERM_H_CHRG_BUG == 1 )
2855
if (TG_FLAG_FIX_TERM_H_CHRG_BUG & *pbTautFlags)
2860
memset( s, 0, sizeof(s) );
2862
memset( pBCN, 0, sizeof( pBCN[0] ) );
2864
memset( t_group_info, 0, sizeof(*t_group_info) );
2865
memset( t_group_info_orig, 0, sizeof(*t_group_info_orig) );
2866
/*norm_at[TAUT_NON] = out_norm_data[TAUT_NON]->at; *//* output normalized non-tautomeric component */
2867
/*norm_at[TAUT_YES] = out_norm_data[TAUT_YES]->at; *//* output normalized tautomeric component */
2868
/*norm_at_fixed_bonds[TAUT_NON] = NULL;*/
2869
/*norm_at_fixed_bonds[TAUT_YES] = out_norm_data[TAUT_YES]->at_fixed_bonds;*/
2870
for ( i = 0; i < TAUT_NUM; i ++ ) {
2871
if ( out_norm_data[i]->at ) {
2872
if ( !(at[i] = (sp_ATOM *)inchi_malloc( num_inp_at * sizeof(*at[0]) ) ) ) {
2879
if ( !out_norm_data[TAUT_NON]->at && !out_norm_data[TAUT_YES]->at || !inp_at || ret ) {
2883
/* the first struct to process: tautomeric if exists else non-tautomeric */
2884
out_at = out_norm_data[TAUT_YES]->at? out_norm_data[TAUT_YES]->at : out_norm_data[TAUT_NON]->at;
2885
/* copy the input structure to be normalized to the buffer for the normalization data */
2886
memcpy( out_at, inp_at, num_inp_at*sizeof(out_at[0]) );
2888
/* tautomeric groups setting */
2889
t_group_info->bIgnoreIsotopic = 0; /* include tautomeric group isotopic info in MarkTautomerGroups() */
2890
t_group_info->bTautFlags = *pbTautFlags;
2891
t_group_info->bTautFlagsDone = *pbTautFlagsDone;
2893
/* Preprocess the structure; here THE NUMBER OF ATOMS MAY BE REDUCED */
2894
/* ??? Ambiguity: H-D may become HD or DH (that is, H+implicit D or D+implicit H) */
2895
if ( TG_FLAG_H_ALREADY_REMOVED & bTautFlags ) {
2896
INP_ATOM_DATA *out_norm_data1 = out_norm_data[TAUT_YES]->at? out_norm_data[TAUT_YES] :
2897
out_norm_data[TAUT_NON]->at? out_norm_data[TAUT_NON] : NULL;
2898
if ( out_norm_data1 ) {
2900
num_atoms = out_norm_data1->num_at - out_norm_data1->num_removed_H;
2901
num_removed_H = out_norm_data1->num_removed_H;
2902
t_group_info->tni.nNumRemovedExplicitH = num_removed_H;
2909
num_atoms = remove_terminal_HDT( num_inp_at, out_at, bFixTermHChrg );
2910
num_removed_H = num_inp_at - num_atoms;
2911
t_group_info->tni.nNumRemovedExplicitH = num_removed_H;
2912
add_DT_to_num_H( num_atoms, out_at );
2914
/*fix_odd_things( num_atoms, out_at );*/
2915
#if( FIND_RING_SYSTEMS == 1 )
2916
MarkRingSystemsInp( out_at, num_atoms, 0 );
2918
/* duplicate the preprocessed structure so that all supplied out_norm_data[]->at buffers are filled */
2919
if ( out_at != out_norm_data[TAUT_YES]->at && out_norm_data[TAUT_YES]->at ) {
2920
memcpy( out_norm_data[TAUT_YES]->at, out_at, num_inp_at*sizeof(out_at[0]) );
2922
if ( out_norm_data[TAUT_YES]->at_fixed_bonds && out_norm_data[TAUT_YES]->at ) {
2923
memcpy( out_norm_data[TAUT_YES]->at_fixed_bonds, out_at, num_inp_at*sizeof(out_at[0]) );
2925
if ( out_at != out_norm_data[TAUT_NON]->at && out_norm_data[TAUT_NON]->at ) {
2926
memcpy( out_norm_data[TAUT_NON]->at, out_at, num_inp_at*sizeof(out_at[0]) );
2929
/*******************************************************************************
2930
* ??? not true ??? duplicate inp_at and keep inp_at[] unchanged after terminal hydrogens removal
2931
* set stereo parities in taut_at[], non_taut_at[]
2932
* obtain max. lenghts of the name stereo parts
2933
* Ignore absence/presence of isotopic stereo for now
2934
* mark isotopic atoms
2935
*******************************************************************************/
2936
if ( out_norm_data[TAUT_YES]->at && at[TAUT_YES] ) {
2937
/* final normalization of possibly tautomeric structure */
2938
ret = mark_alt_bonds_and_taut_groups ( out_norm_data[TAUT_YES]->at, out_norm_data[TAUT_YES]->at_fixed_bonds, num_atoms,
2939
t_group_info, NULL, NULL );
2941
goto exit_function;/* out of RAM or other normalization problem */
2943
num_taut_at = ret; /* number of atoms without removed H? */
2944
num_removed_H_taut = t_group_info->tni.nNumRemovedExplicitH;
2945
out_norm_data[TAUT_YES]->num_at = num_atoms + num_removed_H_taut; /* protons might have been removed */
2946
out_norm_data[TAUT_YES]->num_removed_H = num_removed_H_taut;
2947
out_norm_data[TAUT_YES]->nNumRemovedProtons += t_group_info->tni.nNumRemovedProtons;
2948
for ( i = 0; i < NUM_H_ISOTOPES; i ++ ) {
2949
out_norm_data[TAUT_YES]->nNumRemovedProtonsIsotopic[i] += t_group_info->tni.nNumRemovedProtonsIsotopic[i] /*+ t_group_info->num_iso_H[i]*/;
2950
out_norm_data[TAUT_YES]->num_iso_H[i] += t_group_info->num_iso_H[i];
2952
/* mark deleted isolated tautomeric H(+) */
2953
if ( num_taut_at == 1 && out_norm_data[TAUT_YES]->at[0].at_type == ATT_PROTON &&
2954
t_group_info && t_group_info->tni.nNumRemovedProtons == 1 ) {
2955
out_norm_data[TAUT_YES]->bDeleted = 1;
2956
FreeInpAtom( &out_norm_data[TAUT_YES]->at_fixed_bonds );
2958
if ( (t_group_info->tni.bNormalizationFlags & FLAG_NORM_CONSIDER_TAUT) &&
2959
out_norm_data[TAUT_YES]->at_fixed_bonds) {
2960
out_norm_data[TAUT_YES]->bTautPreprocessed = 1;
2963
if ( !(t_group_info->tni.bNormalizationFlags & (FLAG_NORM_CONSIDER_TAUT & ~FLAG_PROTON_SINGLE_REMOVED)) &&
2964
out_norm_data[TAUT_YES]->at_fixed_bonds) {
2965
FreeInpAtom( &out_norm_data[TAUT_YES]->at_fixed_bonds );
2968
/*out_norm_data[TAUT_YES]->num_removed_H = num_removed_H_taut;*/
2969
out_norm_data[TAUT_YES]->bTautFlags = *pbTautFlags = t_group_info->bTautFlags;
2970
out_norm_data[TAUT_YES]->bTautFlagsDone = *pbTautFlagsDone = t_group_info->bTautFlagsDone;
2971
out_norm_data[TAUT_YES]->bNormalizationFlags = t_group_info->tni.bNormalizationFlags;
2972
/* create internal sp_ATOM at[] out of out_norm_data[]->at */
2973
inp2spATOM( out_norm_data[TAUT_YES]->at, num_inp_at, at[TAUT_YES] );
2974
/* set stereo parities to at[]; nUserMode: accept alt. stereo bonds, min ring size */
2975
ret = set_stereo_parity( out_norm_data[TAUT_YES]->at, at[TAUT_YES], num_taut_at, num_removed_H_taut,
2976
&s[TAUT_YES].nMaxNumStereoAtoms, &s[TAUT_YES].nMaxNumStereoBonds, nUserMode,
2977
bPointedEdgeStereo, vABParityUnknown );
2978
#if( bRELEASE_VERSION == 0 )
2980
bExtract |= EXTR_HAS_ATOM_WITH_DEFINED_PARITY;
2982
if ( t_group_info->tni.bNormalizationFlags & FLAG_NORM_CONSIDER_TAUT ) {
2983
bExtract |= EXTR_TAUT_TREATMENT_CHARGES;
2986
if ( RETURNED_ERROR( ret ) ) {
2987
goto exit_function; /* stereo bond error */
2989
s[TAUT_YES].bMayHaveStereo = (s[TAUT_YES].nMaxNumStereoAtoms || s[TAUT_YES].nMaxNumStereoBonds);
2991
* mark isotopic atoms and atoms that have non-tautomeric
2992
* isotopic terminal hydrogen atoms 1H, 2H(D), 3H(T)
2994
s[TAUT_YES].num_isotopic_atoms = set_atom_iso_sort_keys( num_taut_at, at[TAUT_YES], t_group_info,
2995
&s[TAUT_YES].bHasIsotopicTautGroups );
2996
/**************************************************************************
2997
* prepare tautomeric (if no tautomerism found then prepare non-tautomeric)
2998
* structure for canonicalizaton:
2999
**************************************************************************
3000
* remove t-groups that have no H,
3001
* remove charges from t-groups if requested
3002
* renumber t-groups and find final t_group_info->num_t_groups
3003
* add to t-groups lists of endpoints tgroup->nEndpointAtomNumber[]
3004
* calculate length of the t-group part of the connection table
3005
**************************************************************************/
3006
s[TAUT_YES].nLenLinearCTTautomer = CountTautomerGroups( at[TAUT_YES], num_taut_at, t_group_info );
3007
if ( RETURNED_ERROR(s[TAUT_YES].nLenLinearCTTautomer) ) { /* added error treatment 9-11-2003 */
3008
ret = s[TAUT_YES].nLenLinearCTTautomer;
3010
/* error has happened; no breakpoint here
3011
s[TAUT_YES].nLenLinearCTTautomer = 0;
3014
if ( s[TAUT_YES].nLenLinearCTTautomer > 0 ) {
3015
num_at_tg = num_taut_at+t_group_info->num_t_groups;
3016
/* ??? -not true- create t_group_info_orig for multiple calls with atom renumbering */
3017
make_a_copy_of_t_group_info( t_group_info_orig /* dest*/, t_group_info /* source*/ );
3018
/* mark isotopic tautomer groups: calculate t_group->iWeight */
3019
s[TAUT_YES].nLenLinearCTIsotopicTautomer=set_tautomer_iso_sort_keys( t_group_info );
3020
if ( s[TAUT_YES].nLenLinearCTIsotopicTautomer < 0 ) {
3021
/* ??? -error cannot happen- error has happened; no breakpoint here */
3022
s[TAUT_YES].nLenLinearCTIsotopicTautomer = 0;
3024
out_norm_data[TAUT_YES]->bTautomeric = s[TAUT_YES].nLenLinearCTTautomer;
3026
/* new variable: s[TAUT_YES].nLenCT introduced 7-22-2002 */
3027
GetCanonLengths( num_taut_at, at[TAUT_YES], &s[TAUT_YES], t_group_info );
3029
if ( out_norm_data[TAUT_NON]->at && out_norm_data[TAUT_YES]->at && at[TAUT_NON] && !s[TAUT_YES].nLenLinearCTTautomer ) {
3030
/* the structure is non-tautomeric: use tautomeric treatment results only for it */
3031
inchi_free( at[TAUT_NON] );
3032
at[TAUT_NON] = NULL;
3034
if ( !out_norm_data[TAUT_NON]->at && out_norm_data[TAUT_YES]->at &&
3035
!at[TAUT_NON] && at[TAUT_YES] && !s[TAUT_YES].nLenLinearCTTautomer ) {
3036
/* requested tautomeric; found non-tautomeric; it is located in out_norm_data[TAUT_YES]->at */
3037
out_norm_data[TAUT_YES]->bTautomeric = 0;
3039
if ( out_norm_data[TAUT_NON]->at && at[TAUT_NON] ) {
3040
/* the structure needs non-tautomeric treatment: final normalization of non-tautomeric structure */
3041
ret = mark_alt_bonds_and_taut_groups ( out_norm_data[TAUT_NON]->at, NULL, num_atoms, NULL, &bTautFlags, &bTautFlagsDone );
3043
goto exit_function; /* out of RAM or other normalization problem */
3045
out_norm_data[TAUT_NON]->num_at = num_atoms + num_removed_H;
3046
out_norm_data[TAUT_NON]->num_removed_H = num_removed_H;
3047
out_norm_data[TAUT_NON]->bTautFlags = *pbTautFlags;
3048
out_norm_data[TAUT_NON]->bTautFlagsDone = *pbTautFlagsDone;
3049
out_norm_data[TAUT_NON]->bNormalizationFlags = 0;
3050
/* create internal sp_ATOM at[] out of out_norm_data[]->at */
3051
inp2spATOM( out_norm_data[TAUT_NON]->at, num_inp_at, at[TAUT_NON] );
3052
/* set stereo parities to at[]; nUserMode: accept alt. stereo bonds, min ring size */
3053
ret = set_stereo_parity( out_norm_data[TAUT_NON]->at, at[TAUT_NON], num_atoms, num_removed_H,
3054
&s[TAUT_NON].nMaxNumStereoAtoms, &s[TAUT_NON].nMaxNumStereoBonds, nUserMode,
3055
bPointedEdgeStereo, vABParityUnknown );
3056
#if( bRELEASE_VERSION == 0 )
3058
bExtract |= EXTR_HAS_ATOM_WITH_DEFINED_PARITY;
3061
if ( RETURNED_ERROR( ret ) ) {
3062
goto exit_function; /* stereo bond error */
3064
s[TAUT_NON].bMayHaveStereo = (s[TAUT_NON].nMaxNumStereoAtoms || s[TAUT_NON].nMaxNumStereoBonds);
3066
* mark isotopic atoms and atoms that have non-tautomeric
3067
* isotopic terminal hydrogen atoms 1H, 2H(D), 3H(T)
3069
s[TAUT_NON].num_isotopic_atoms = set_atom_iso_sort_keys( num_atoms, at[TAUT_NON], NULL, NULL );
3070
GetCanonLengths( num_atoms, at[TAUT_NON], &s[TAUT_NON], NULL);
3071
out_norm_data[TAUT_NON]->bTautomeric = 0;
3074
/**********************************************************/
3076
bMayHaveStereo = s[TAUT_YES].bMayHaveStereo || s[TAUT_NON].bMayHaveStereo;
3077
bHasIsotopicAtoms = s[TAUT_NON].num_isotopic_atoms > 0 || s[TAUT_NON].bHasIsotopicTautGroups > 0 ||
3078
s[TAUT_YES].num_isotopic_atoms > 0 || s[TAUT_YES].bHasIsotopicTautGroups > 0 ;
3080
if (bFixIsoFixedH) /* 2008-03-21 DT */
3081
bHasIsotopicAtoms = bHasIsotopicAtoms ||
3082
s[TAUT_YES].nLenLinearCTTautomer > 0 && t_group_info &&
3083
(0 < NUM_H_ISOTOPES && t_group_info->tni.nNumRemovedProtonsIsotopic[0] ||
3084
1 < NUM_H_ISOTOPES && t_group_info->tni.nNumRemovedProtonsIsotopic[1] ||
3085
2 < NUM_H_ISOTOPES && t_group_info->tni.nNumRemovedProtonsIsotopic[2]) ;
3087
bHasIsotopicAtoms = bHasIsotopicAtoms ||
3088
s[TAUT_YES].nLenIsotopicEndpoints > 1 && t_group_info &&
3089
(t_group_info->bTautFlagsDone & (TG_FLAG_FOUND_ISOTOPIC_H_DONE|TG_FLAG_FOUND_ISOTOPIC_ATOM_DONE));
3092
if ( !(nUserMode & REQ_MODE_DEFAULT) ) {
3094
nUserMode |= REQ_MODE_DEFAULT;
3097
/* adjust the mode to the reality */
3098
if ( ( nUserMode & REQ_MODE_ISO ) && !bHasIsotopicAtoms ) {
3099
nUserMode ^= REQ_MODE_ISO;
3100
nUserMode |= REQ_MODE_NON_ISO; /* at least one is needed */
3102
if ( (nUserMode & REQ_MODE_STEREO) && ( nUserMode & REQ_MODE_ISO ) ) {
3103
nUserMode |= REQ_MODE_ISO_STEREO;
3105
if ( (nUserMode & REQ_MODE_STEREO) && !( nUserMode & REQ_MODE_NON_ISO ) ) {
3106
nUserMode ^= REQ_MODE_STEREO;
3108
if ( !bMayHaveStereo ) {
3109
if ( nUserMode & REQ_MODE_STEREO )
3110
nUserMode ^= REQ_MODE_STEREO;
3111
if ( nUserMode & REQ_MODE_ISO_STEREO )
3112
nUserMode ^= REQ_MODE_ISO_STEREO;
3115
if ( (nUserMode & REQ_MODE_BASIC) && (!out_norm_data[TAUT_NON]->at || !ppINChI[TAUT_NON] || !ppINChI_Aux[TAUT_NON] || !at[TAUT_NON]) ) {
3116
nUserMode ^= REQ_MODE_BASIC;
3118
if ( (nUserMode & REQ_MODE_TAUT) && (!out_norm_data[TAUT_YES]->at || !ppINChI[TAUT_YES] || !ppINChI_Aux[TAUT_YES] || !at[TAUT_YES]) ) {
3119
nUserMode ^= REQ_MODE_TAUT;
3123
switch ((int)nUserMode & (REQ_MODE_BASIC | REQ_MODE_TAUT)) {
3124
case REQ_MODE_BASIC:
3132
case (REQ_MODE_BASIC | REQ_MODE_TAUT):
3138
goto exit_function; /* program error: inconsistent nUserMode or missing taut/non-taut allocation */ /* <BRKPT> */
3140
#if( TEST_RENUMB_ATOMS == 1 )
3141
ulNormTime = InchiTimeElapsed( &ulNormTimeStart);
3143
/************************************************************
3145
* Obtain all non-stereo canonical numberings *
3147
************************************************************/
3148
#if( TEST_RENUMB_ATOMS == 1 )
3149
InchiTimeGet( &ulCanonTimeStart );
3151
if ( (nUserMode & REQ_MODE_NON_ISO) && !(nUserMode & REQ_MODE_ISO) ) {
3152
/* added for special non-isotopic test mode 2004-10-04 */
3153
if ( t_group_info ) {
3154
t_group_info->bIgnoreIsotopic = 1;
3155
if ( t_group_info->nIsotopicEndpointAtomNumber ) {
3156
t_group_info->nIsotopicEndpointAtomNumber[0] = inchi_min(1, t_group_info->nIsotopicEndpointAtomNumber[0]);
3158
memset( t_group_info->num_iso_H, 0, sizeof(t_group_info->num_iso_H) );
3159
memset ( t_group_info->tni.nNumRemovedProtonsIsotopic, 0, sizeof(t_group_info->tni.nNumRemovedProtonsIsotopic));
3160
t_group_info->bTautFlagsDone &= ~(TG_FLAG_FOUND_ISOTOPIC_H_DONE|TG_FLAG_FOUND_ISOTOPIC_ATOM_DONE);
3162
for ( i = 0; i < TAUT_NUM; i ++ ) {
3163
s[i].bHasIsotopicTautGroups = 0;
3164
s[i].bIgnoreIsotopic = 1;
3165
s[i].nLenIsotopic = 0;
3166
s[i].nLenIsotopicEndpoints = 0;
3167
s[i].nLenLinearCTIsotopicTautomer = 0;
3168
s[i].num_isotopic_atoms = 0;
3170
bHasIsotopicAtoms = 0;
3172
ret = GetBaseCanonRanking( num_atoms, num_at_tg, at, t_group_info, s, pBCN, ulMaxTime, bFixIsoFixedH );
3173
#if( TEST_RENUMB_ATOMS == 1 )
3174
ulCanonTime = InchiTimeElapsed( &ulCanonTimeStart );
3177
goto exit_function; /* program error */
3179
#if( bRELEASE_VERSION == 0 && FIND_CANON_NE_EQUITABLE == 1 )
3180
/* Debug only: find whether canonical equivalence is different from equitable partition */
3181
if ( bCanonIsFinerThanEquitablePartition( num_atoms, at[n1], pBCN->ftcn[TAUT_NON].nSymmRankCt ) ) {
3182
bExtract |= EXTR_CANON_NE_EQUITABLE;
3185
/* added for special non-isotopic test mode 2004-10-04 */
3186
if ( !pBCN->ftcn[n1].PartitionCt.Rank ) {
3189
if ( !pBCN->ftcn[n2].PartitionCt.Rank ) {
3193
ret = CT_TAUCOUNT_ERR;
3194
goto exit_function; /* program error */
3197
/************************************************************
3199
* Obtain stereo canonical numberings *
3201
************************************************************/
3203
for ( i = n2; i >= n1 && !RETURNED_ERROR( ret ); i -- ) {
3205
memset( pCS, 0, sizeof(*pCS) );
3208
case TAUT_NON: /* non-tautomeric */
3210
nMode = (s[i].nLenLinearCTTautomer == 0)? CANON_MODE_CT:CANON_MODE_TAUT;
3211
nMode |= (bHasIsotopicAtoms && (nUserMode & REQ_MODE_ISO))? CANON_MODE_ISO:0;
3212
nMode |= (s[TAUT_NON].bMayHaveStereo && (nUserMode & REQ_MODE_STEREO) )? CANON_MODE_STEREO:0;
3213
nMode |= (bHasIsotopicAtoms && s[TAUT_NON].bMayHaveStereo && (nUserMode & REQ_MODE_ISO_STEREO))? CANON_MODE_ISO_STEREO:0;
3214
nMode |= (nUserMode & REQ_MODE_NOEQ_STEREO )? CMODE_NOEQ_STEREO : 0;
3215
nMode |= (nUserMode & REQ_MODE_REDNDNT_STEREO)? CMODE_REDNDNT_STEREO : 0;
3216
nMode |= (nUserMode & REQ_MODE_NO_ALT_SBONDS )? CMODE_NO_ALT_SBONDS : 0;
3217
if ( (nMode & CANON_MODE_STEREO) == CANON_MODE_STEREO ||
3218
(nMode & CANON_MODE_ISO_STEREO) == CANON_MODE_ISO_STEREO ) {
3219
nMode |= (nUserMode & REQ_MODE_RELATIVE_STEREO)? CMODE_RELATIVE_STEREO: 0;
3220
nMode |= (nUserMode & REQ_MODE_RACEMIC_STEREO )? CMODE_RACEMIC_STEREO : 0;
3221
nMode |= (nUserMode & REQ_MODE_SC_IGN_ALL_UU )? CMODE_SC_IGN_ALL_UU : 0;
3222
nMode |= (nUserMode & REQ_MODE_SB_IGN_ALL_UU )? CMODE_SB_IGN_ALL_UU : 0;
3224
if ( ret= AllocateCS( pCS, num_atoms, num_atoms, s[TAUT_NON].nLenCT, s[TAUT_NON].nLenCTAtOnly,
3225
s[TAUT_NON].nLenLinearCTStereoDble, s[TAUT_NON].nMaxNumStereoBonds,
3226
s[TAUT_NON].nLenLinearCTStereoCarb, s[TAUT_NON].nMaxNumStereoAtoms,
3227
0, 0, s[TAUT_NON].nLenIsotopic, nMode, pBCN ) ) {
3232
case TAUT_YES: /* tautomeric */
3234
nMode = (s[i].nLenLinearCTTautomer == 0)? CANON_MODE_CT:CANON_MODE_TAUT;
3235
nMode |= (bHasIsotopicAtoms && (nUserMode & REQ_MODE_ISO) )? CANON_MODE_ISO:0;
3236
nMode |= (s[TAUT_YES].bMayHaveStereo && (nUserMode & REQ_MODE_STEREO) )? CANON_MODE_STEREO:0;
3237
nMode |= (bHasIsotopicAtoms && s[TAUT_YES].bMayHaveStereo && (nUserMode & REQ_MODE_ISO_STEREO))? CANON_MODE_ISO_STEREO:0;
3238
nMode |= (nUserMode & REQ_MODE_NOEQ_STEREO )? CMODE_NOEQ_STEREO : 0;
3239
nMode |= (nUserMode & REQ_MODE_REDNDNT_STEREO)? CMODE_REDNDNT_STEREO : 0;
3240
nMode |= (nUserMode & REQ_MODE_NO_ALT_SBONDS )? CMODE_NO_ALT_SBONDS : 0;
3241
if ( (nMode & CANON_MODE_STEREO) == CANON_MODE_STEREO ||
3242
(nMode & CANON_MODE_ISO_STEREO) == CANON_MODE_ISO_STEREO ) {
3243
nMode |= (nUserMode & REQ_MODE_RELATIVE_STEREO)? CMODE_RELATIVE_STEREO: 0;
3244
nMode |= (nUserMode & REQ_MODE_RACEMIC_STEREO )? CMODE_RACEMIC_STEREO : 0;
3245
nMode |= (nUserMode & REQ_MODE_SC_IGN_ALL_UU )? CMODE_SC_IGN_ALL_UU : 0;
3246
nMode |= (nUserMode & REQ_MODE_SB_IGN_ALL_UU )? CMODE_SB_IGN_ALL_UU : 0;
3248
if ( ret= AllocateCS( pCS, num_atoms, num_at_tg, s[TAUT_YES].nLenCT, s[TAUT_YES].nLenCTAtOnly,
3249
s[TAUT_YES].nLenLinearCTStereoDble, s[TAUT_YES].nMaxNumStereoBonds,
3250
s[TAUT_YES].nLenLinearCTStereoCarb, s[TAUT_YES].nMaxNumStereoAtoms,
3251
s[TAUT_YES].nLenLinearCTTautomer, s[TAUT_YES].nLenLinearCTIsotopicTautomer,
3252
s[TAUT_YES].nLenIsotopic, nMode, pBCN ) ) {
3261
nMode |= (nUserMode & REQ_MODE_DIFF_UU_STEREO)? REQ_MODE_DIFF_UU_STEREO : 0;
3266
pCS->lNumDecreasedCT = -1;
3267
pCS->bDoubleBondSquare = DOUBLE_BOND_NEIGH_LIST? 2:0; /* 2 => special mode */
3268
pCS->bIgnoreIsotopic = !((s[TAUT_NON].num_isotopic_atoms ||
3269
s[TAUT_YES].num_isotopic_atoms ||
3270
s[TAUT_YES].bHasIsotopicTautGroups) ||
3271
(nUserMode & REQ_MODE_NON_ISO) ||
3272
!(nUserMode & REQ_MODE_ISO));
3274
if ( (nUserMode & REQ_MODE_NON_ISO) && !(nUserMode & REQ_MODE_ISO) ) {
3275
pCS->bIgnoreIsotopic = 1; /* 10-04-2004 */
3278
if ( i == TAUT_YES ) { /* tautomeric */
3279
pCS->t_group_info = t_group_info; /* ??? make a copy or reuse ??? */
3280
pCS->t_group_info->bIgnoreIsotopic = !(s[TAUT_YES].bHasIsotopicTautGroups ||
3281
(nUserMode & REQ_MODE_NON_ISO) ||
3282
!(nUserMode & REQ_MODE_ISO));
3283
if ( (nUserMode & REQ_MODE_NON_ISO) && !(nUserMode & REQ_MODE_ISO) ) {
3284
pCS->t_group_info->bIgnoreIsotopic = 1; /* 10-04-2004 */
3287
pCS->ulTimeOutTime = pBCN->ulTimeOutTime;
3288
/*=========== Obsolete Mode Bits (bit 0 is Least Significant Bit) ===========
3290
* Mode Bits Description
3291
* '0' c 0 Only one connection table canonicalization
3292
* '1' C 1 Recalculate CT using fixed nSymmRank
3293
* '2' i 1|2 Isotopic canonicalization (internal)
3294
* '3' I 1|2|4 Isotopic canonicalization (output)
3295
* '4' s 1|8 Stereo canonicalization
3296
* '5' S 1|2|4|16 Stereo isotopic canonicalization
3297
* '6' A 1|2|4|8|16 Output All
3299
#if( TEST_RENUMB_ATOMS == 1 )
3300
InchiTimeGet( &ulCanonTimeStart );
3302
/***************************************
3303
The last canonicalization step
3304
***************************************/
3306
/* USE_CANON2 == 1 */
3307
pCS->NeighList = NULL;
3309
ret = Canon_INChI( num_atoms, i?num_at_tg:num_atoms, at[i], pCS, nMode, i);
3312
pCS->NeighList = CreateNeighList( num_atoms, i?num_at_tg:num_atoms, at[i], pCS->bDoubleBondSquare, pCS->t_group_info );
3314
ret = Canon_INChI( num_atoms, i?num_at_tg:num_atoms, at[i], pCS, nMode, i);
3317
pINChI = ppINChI[i]; /* pointers to already allocated still empty InChI */
3318
pINChI_Aux = ppINChI_Aux[i];
3320
/***************************************/
3321
/* failure in Canon_INChI() */
3322
/***************************************/
3323
pINChI->nErrorCode = ret;
3324
pINChI_Aux->nErrorCode = ret;
3326
/***************************************/
3327
/* success Canon_INChI() */
3328
/* save canonicalization results in */
3329
/* pINChI and pINChI_Aux */
3330
/***************************************/
3331
pINChI->nErrorCode = 0;
3332
pINChI_Aux->nErrorCode = 0;
3333
pINChI->bDeleted = pINChI_Aux->bDeleted = out_norm_data[i]->bDeleted;
3334
pINChI_Aux->nCanonFlags = pCS->nCanonFlags;
3335
pINChI_Aux->bTautFlags = out_norm_data[i]->bTautFlags;
3336
pINChI_Aux->bTautFlagsDone = out_norm_data[i]->bTautFlagsDone;
3337
pINChI_Aux->bNormalizationFlags = out_norm_data[i]->bNormalizationFlags;
3338
/* may return an error or a warning */
3339
ret = FillOutINChI( pINChI, pINChI_Aux,
3340
num_atoms, i?num_at_tg:num_atoms,
3341
i?num_removed_H_taut:num_removed_H, at[i],
3342
out_norm_data[i]->at, pCS, i, nUserMode,
3344
if ( RETURNED_ERROR( ret ) ) {
3345
/* failure in FillOutINChI() */
3346
pINChI->nErrorCode = ret;
3347
pINChI_Aux->nErrorCode = ret;
3349
/****************************/
3350
/* success in FillOutINChI() */
3351
/****************************/
3352
#if( bRELEASE_VERSION == 0 )
3353
if ( pINChI->Stereo &&
3354
(pINChI->Stereo->nCompInv2Abs && !pINChI->Stereo->bTrivialInv) ||
3355
pINChI->StereoIsotopic &&
3356
(pINChI->StereoIsotopic->nCompInv2Abs && !pINChI->StereoIsotopic->bTrivialInv) ) {
3357
bExtract |= EXTR_NON_TRIVIAL_STEREO;
3360
/* mark non-tautomeric representation as having another, tautomeric representation */
3361
if ( pINChI_Aux && s[TAUT_YES].nLenLinearCTTautomer ) {
3362
pINChI_Aux->bIsTautomeric = s[TAUT_YES].nLenLinearCTTautomer;
3364
#if( bRELEASE_VERSION == 0 )
3365
pCS->bExtract |= bExtract;
3366
pINChI->bExtract |= pCS->bExtract;
3368
ret2 = CheckCanonNumberingCorrectness(
3369
num_atoms, i?num_at_tg:num_atoms,
3370
at[i], pCS, i, pStrErrStruct );
3372
pINChI->nErrorCode = ret2;
3373
pINChI_Aux->nErrorCode = ret2;
3378
#if( TEST_RENUMB_ATOMS == 1 )
3379
ulCanonTime2 = InchiTimeElapsed( &ulCanonTimeStart );
3380
pINChI_Aux->ulCanonTime = ulCanonTime+ulCanonTime2;
3381
pINChI_Aux->ulNormTime = ulNormTime;
3383
FreeNeighList( pCS->NeighList );
3384
DeAllocateCS( pCS2 );
3386
pINChI = NULL; /* avoid dangling pointers */
3387
pINChI_Aux = NULL; /* avoid dangling pointers */
3392
/* treat the results later */
3397
inchi_free( at[TAUT_YES] );
3399
inchi_free( at[TAUT_NON] );
3401
*ti_out = *t_group_info;
3403
free_t_group_info( t_group_info );
3405
free_t_group_info( t_group_info_orig );
3408
#ifndef INCHI_ANSI_ONLY /* { */
3409
/***************************************************************************************/
3410
int GetAtomOrdNbrInCanonOrd( inp_ATOM *norm_at, AT_NUMB *nAtomOrdNbr,
3411
AT_NUMB *nOrigAtNosInCanonOrd, int num_at )
3413
AT_NUMB *nCanonNbr, *nOrigAtNos, *nOrigAtNosOrd;
3418
nCanonNbr = (AT_NUMB *)inchi_calloc( num_at, sizeof(nCanonNbr[0]) );
3419
nOrigAtNos = (AT_NUMB *)inchi_calloc( num_at, sizeof(nOrigAtNos[0]) );
3420
nOrigAtNosOrd = (AT_NUMB *)inchi_calloc( num_at, sizeof(nOrigAtNosOrd[0]) );
3422
if ( !nCanonNbr || !nOrigAtNos || !nAtomOrdNbr || !nOrigAtNosOrd ) {
3423
ret = CT_OUT_OF_RAM; /* <BRKPT> */
3426
for ( i = 0; i < num_at; i ++ ) {
3427
nCanonNbr[i] = nAtomOrdNbr[i] = nOrigAtNosOrd[i] = (AT_NUMB)i;
3428
nOrigAtNos[i] = norm_at[i].orig_at_number;
3430
/* get nCanonNbr[]: canon. numbers-1 in order of increasing original atom numbers */
3431
pn_RankForSort = nOrigAtNosInCanonOrd;
3432
qsort( nCanonNbr, num_at, sizeof(nCanonNbr[0]), CompRank );
3433
/* get nOrigAtNosOrd[]: norm_atom ord. numbers the same order of increasing original atom numbers */
3434
pn_RankForSort = nOrigAtNos;
3435
qsort( nOrigAtNosOrd, num_at, sizeof(nOrigAtNosOrd[0]), CompRank );
3436
/* check whether the 2 sets of origiginal atom numbers have identical elements */
3437
for ( i = 0; i < num_at; i ++ ) {
3438
if ( nOrigAtNosInCanonOrd[nCanonNbr[i]] != nOrigAtNos[nOrigAtNosOrd[i]] ) {
3439
ret = CT_RANKING_ERR; /* <BRKPT> */
3443
for ( i = 0; i < num_at; i ++ ) {
3444
nAtomOrdNbr[(int)nCanonNbr[i]] = nOrigAtNosOrd[i];
3448
pn_RankForSort = nCanonNbr;
3449
qsort( nAtomOrdNbr, num_at, sizeof(nCanonNbr[0]), CompRank );
3454
inchi_free( nCanonNbr );
3456
inchi_free( nOrigAtNos );
3457
if ( nOrigAtNosOrd )
3458
inchi_free( nOrigAtNosOrd );
3461
/***************************************************************************************/
3462
int FillOutCanonInfAtom(inp_ATOM *norm_at, INF_ATOM_DATA *inf_norm_at_data, int init_num_at, int bIsotopic,
3463
INChI *pINChI, INChI_Aux *pINChI_Aux, int bAbcNumbers, INCHI_MODE nMode)
3465
int i, j, m, n, num_stereo, k, c, ret, len_str, len, atw, num_err;
3466
int next_atom[MAX_CUMULENE_LEN+1], best_next_atom[MAX_CUMULENE_LEN+1], cur_atom;
3467
int next_neigh[MAX_CUMULENE_LEN+1], best_next_neigh[MAX_CUMULENE_LEN+1], best_len;
3468
int num_iso_H[NUM_H_ISOTOPES];
3471
int num_at = pINChI->nNumberOfAtoms;
3472
int nNumberOfTGroups = (pINChI->lenTautomer && pINChI->nTautomer && pINChI->nTautomer[0])? (int)pINChI->nTautomer[0] : 0;
3473
AT_NUMB *nOrigAtNosInCanonOrd;
3474
INChI_Stereo *Stereo;
3475
AT_NUMB *nConstitEquNumbers;
3476
AT_NUMB *nConstitEquTGroupNumbers;
3477
S_CHAR *t_parity = NULL;
3478
AT_NUMB *nNumber = NULL;
3479
int bIncludeIsotopicH;
3481
AT_NUMB *nNormAtNosInCanonOrd;
3482
int (*MakeNumber)(char*, int, const char*, int) = bAbcNumbers? MakeAbcNumber:MakeDecNumber;
3483
int bRel= (0 != (nMode & ( REQ_MODE_RELATIVE_STEREO)));
3484
int bRac= (0 != (nMode & ( REQ_MODE_RACEMIC_STEREO)));
3485
int bRelRac= bRel || bRac;
3486
int bDoDisplaySp3 = 1;
3488
inf_ATOM *inf_norm_at = inf_norm_at_data? inf_norm_at_data->at : NULL;
3495
/* prepare removeable protons and H info */
3496
inf_norm_at_data->nNumRemovedProtons = pINChI_Aux->nNumRemovedProtons;
3497
MakeRemovedProtonsString( pINChI_Aux->nNumRemovedProtons, pINChI_Aux->nNumRemovedIsotopicH, NULL, bIsotopic,
3498
inf_norm_at_data->szRemovedProtons, &inf_norm_at_data->num_removed_iso_H );
3499
/* fill out info atom */
3500
if ( bIsotopic && !(pINChI->nNumberOfIsotopicAtoms || pINChI->nNumberOfIsotopicTGroups ||
3501
pINChI->nPossibleLocationsOfIsotopicH && pINChI->nPossibleLocationsOfIsotopicH[0]>1) )
3504
Stereo = bIsotopic? pINChI->StereoIsotopic :
3506
bDoDisplaySp3 = (NULL != Stereo) && (Stereo->nNumberOfStereoCenters > 0);
3508
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
3509
if ( bDoDisplaySp3 && bRelRac && Stereo->nNumberOfStereoCenters < 2 &&
3510
(Stereo->nCompInv2Abs || ATOM_PARITY_ILL_DEF(Stereo->t_parity[0]) ) ) {
3512
if ( Stereo->nCompInv2Abs ) {
3513
inf_norm_at_data->StereoFlags |= bRel? INF_STEREO_REL : bRac? INF_STEREO_RAC : 0;
3517
/* flag has stereo */
3518
if ( (NULL != Stereo) && (bDoDisplaySp3 || Stereo->nNumberOfStereoBonds > 0) ) {
3519
inf_norm_at_data->StereoFlags |= INF_STEREO;
3523
if ( bDoDisplaySp3 && bRelRac && Stereo->nNumberOfStereoCenters < 2 &&
3524
(Stereo->nCompInv2Abs || ATOM_PARITY_ILL_DEF(Stereo->t_parity[0]) ) ) {
3528
if ( bDoDisplaySp3 && Stereo->nCompInv2Abs ) {
3529
/* inversion changes stereo */
3531
inf_norm_at_data->StereoFlags |= INF_STEREO_REL;
3534
inf_norm_at_data->StereoFlags |= INF_STEREO_RAC;
3536
inf_norm_at_data->StereoFlags |= INF_STEREO_ABS;
3539
inf_norm_at_data->StereoFlags |= (Stereo->nCompInv2Abs > 0)? INF_STEREO_NORM : INF_STEREO_INV;
3542
if ( bDoDisplaySp3 && Stereo->nCompInv2Abs < 0 && !bRelRac ) {
3543
/* display Inv stereo which is Absolute Stereo */
3544
nNumber = Stereo->nNumberInv;
3545
t_parity = Stereo->t_parityInv;
3546
nOrigAtNosInCanonOrd = bIsotopic? pINChI_Aux->nIsotopicOrigAtNosInCanonOrdInv :
3547
pINChI_Aux->nOrigAtNosInCanonOrdInv;
3549
/* display Inv stereo which is Absolute Stereo */
3550
if ( bDoDisplaySp3 ) {
3551
nNumber = Stereo->nNumber;
3552
t_parity = Stereo->t_parity;
3554
nOrigAtNosInCanonOrd = bIsotopic? pINChI_Aux->nIsotopicOrigAtNosInCanonOrd :
3555
pINChI_Aux->nOrigAtNosInCanonOrd;
3558
nConstitEquNumbers = bIsotopic? pINChI_Aux->nConstitEquIsotopicNumbers :
3559
pINChI_Aux->nConstitEquNumbers;
3560
nConstitEquTGroupNumbers = bIsotopic? pINChI_Aux->nConstitEquIsotopicTGroupNumbers :
3561
pINChI_Aux->nConstitEquTGroupNumbers;
3562
memset( inf_norm_at, 0, init_num_at*sizeof(inf_norm_at[0]) );
3564
/* obtain norm_at[] atom numbers (from zero) in order of canonical numbers */
3565
nNormAtNosInCanonOrd = (AT_NUMB *)inchi_calloc( num_at, sizeof(nNormAtNosInCanonOrd[0]) );
3566
if ( ret = GetAtomOrdNbrInCanonOrd( norm_at, nNormAtNosInCanonOrd, nOrigAtNosInCanonOrd, num_at ) ) {
3570
/* atom canonical and equivalence numbers > 0 */
3571
for ( i = 0; i < num_at; i ++ ) {
3572
j = (int)nNormAtNosInCanonOrd[i];
3573
if ( j < 0 || j >= num_at )
3575
inf_norm_at[j].nCanonNbr = (AT_NUMB)(i+1);
3576
inf_norm_at[j].nCanonEquNbr = nConstitEquNumbers[i];
3577
#ifdef DISPLAY_DEBUG_DATA
3578
inf_norm_at[j].nDebugData = 0;
3579
#if( DISPLAY_DEBUG_DATA == DISPLAY_DEBUG_DATA_C_POINT )
3580
inf_norm_at[j].nDebugData = norm_at[j].c_point;
3584
/* tautomeric groups */
3585
if ( nNumberOfTGroups ) {
3587
: start from 1: bypass number of t-groups
3588
: j is a counter within the current t-group
3589
: g is a tautomeric group canonical number
3590
: e is a tautomeric group equivalence
3592
for ( g = 1, i = 1; g <= nNumberOfTGroups; g ++ ) {
3593
n = (int)pINChI->nTautomer[i] - INCHI_T_NUM_MOVABLE; /* number of atoms in t-group */
3594
e = nConstitEquTGroupNumbers[(int)g - 1];
3595
/* bypass number of hydrogen atoms, negative charges, ... */
3596
for ( i += INCHI_T_NUM_MOVABLE+1, j = 0; j < n && i < pINChI->lenTautomer; j ++, i ++ ) {
3597
/* scan canonical numbers of atoms within the atom t-group */
3598
k = (int)nNormAtNosInCanonOrd[(int)pINChI->nTautomer[i]-1];
3599
inf_norm_at[k].nTautGroupCanonNbr = g;
3600
inf_norm_at[k].nTautGroupEquNbr = e;
3603
if ( i != pINChI->lenTautomer || g != nNumberOfTGroups+1 ) {
3604
ret = CT_TAUCOUNT_ERR; /* <BRKPT> */
3608
/* atoms that may exchange isotopic H */
3609
if ( bIsotopic && pINChI->nPossibleLocationsOfIsotopicH && (n = (int)pINChI->nPossibleLocationsOfIsotopicH[0]) ) {
3610
for ( i = 1; i < n; i ++ ) {
3611
j = (int)pINChI->nPossibleLocationsOfIsotopicH[i];
3612
k = (int)nNormAtNosInCanonOrd[j - 1];
3613
if ( !inf_norm_at[k].nTautGroupCanonNbr ) {
3614
inf_norm_at[k].cFlags |= AT_FLAG_ISO_H_POINT;
3619
#if( DISPLAY_RING_SYSTEMS == 1 )
3621
for ( j = 0; j < num_at; j ++ ) {
3622
inf_norm_at[j].nCanonNbr = norm_at[j].nBlockSystem;
3623
inf_norm_at[j].nCanonEquNbr = norm_at[j].nRingSystem;
3624
#if( USE_DISTANCES_FOR_RANKING == 1 )
3625
inf_norm_at[j].nTautGroupCanonNbr = norm_at[j].nDistanceFromTerminal;
3626
inf_norm_at[j].nTautGroupEquNbr = norm_at[j].bCutVertex;
3628
inf_norm_at[j].nTautGroupCanonNbr = norm_at[j].bCutVertex;
3629
inf_norm_at[j].nTautGroupEquNbr = 0;
3636
/* Write isotopic mass, chemical element symbols and hydrogens, charge, radical, canon. numbers */
3637
len_str = sizeof(inf_norm_at[0].at_string);
3638
for ( i = 0; i < init_num_at; i ++ ) {
3639
str = inf_norm_at[i].at_string;
3641
bIncludeIsotopicH = bIsotopic && !inf_norm_at[i].nTautGroupCanonNbr && !(inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT);
3644
if ( norm_at[i].iso_atw_diff && bIsotopic ) {
3645
if ( norm_at[i].at_type == ATT_PROTON ) {
3646
; /* do not set isotopic mass of a tautomeric proton */
3648
if ( norm_at[i].el_number == PERIODIC_NUMBER_H && norm_at[i].chem_bonds_valence == 1 &&
3649
!norm_at[i].charge && !norm_at[i].radical && !norm_at[i].num_H &&
3650
(inf_norm_at[j=(int)norm_at[i].neighbor[0]].nTautGroupCanonNbr || (inf_norm_at[j].cFlags & AT_FLAG_ISO_H_POINT) ) ) {
3651
; /* do not set isotopic mass of an exchangeable proton */
3653
atw = get_atw(norm_at[i].elname);
3654
atw += (norm_at[i].iso_atw_diff>0)? norm_at[i].iso_atw_diff-1:norm_at[i].iso_atw_diff;
3655
/*len += sprintf( str+len, "^%d", atw );*/
3659
if ( norm_at[i].el_number == PERIODIC_NUMBER_H && 2 <= atw && atw <= 3 ) {
3660
len += sprintf( str+len, "%s", atw==2? "D" : "T" );
3663
len += sprintf( str+len, "^%d", atw );
3665
len += sprintf( str+len, "%s", norm_at[i].elname );
3668
/* find number of previuosly removed terminal hydrogen atoms because these terminal H will be displayed */
3669
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
3670
num_iso_H[j] = norm_at[i].num_iso_H[j];
3672
/* n = number of implicit H to display */
3673
for ( j = num_at, n = (int)norm_at[i].num_H; j < init_num_at; j ++ ) {
3674
/* subtract number of removed terminal */
3675
/* H atoms from the total number of H atoms */
3676
if ( i == (int)norm_at[j].neighbor[0] ) {
3677
n -= 1; /* found explicit H => decrement number of implicit H */
3678
m = (int)norm_at[j].iso_atw_diff-1;
3679
if ( 0 <= m && m < NUM_H_ISOTOPES ) {
3680
/* subtract number of removed terminal isotopic H */
3681
/* atoms from the total number of isotopic H atoms */
3686
/* at this point n = number of implicit H to display,
3687
num_iso_H[] contains number of implicit isotopic H among n */
3688
if ( bIncludeIsotopicH ) {
3689
/* subtract number of isotopic H atoms from the total number of H atoms */
3690
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
3694
/* non-isotopic hydrogen atoms */
3696
len += sprintf( str+len, "H%d", n );
3699
len += sprintf( str+len, "H" );
3701
/* isotopic hydrogen atoms */
3702
if ( bIncludeIsotopicH ) {
3703
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
3704
if ( num_iso_H[j] ) {
3705
if ( j == 0 || j != 1 && j != 2 ) {
3706
len += sprintf( str+len, "^%dH", j+1 );
3708
len += sprintf( str+len, j == 1? "D" : "T" );
3710
if ( num_iso_H[j] != 1 ) {
3711
len += sprintf( str+len, "%d", (int)num_iso_H[j] );
3716
if ( norm_at[i].el_number == PERIODIC_NUMBER_H && str[0] == str[1] ) {
3719
str[1] = '2'; /* quick fix: replace HH with H2 */
3721
if ( isdigit( UCINT str[2] ) && (n = strtol( str+2, &q, 10 )) && !q[0] ) {
3722
len = 1 + sprintf( str+1, "%d", n+1 );
3726
if ( str[0] == 'H' && str[1] == 'H' && !str[2] ) {
3731
if ( abs(norm_at[i].charge) > 1 )
3732
len += sprintf( str+len, "%+d", norm_at[i].charge );
3734
if ( abs(norm_at[i].charge) == 1 )
3735
len += sprintf( str+len, "%s", norm_at[i].charge>0? "+" : "-" );
3737
if ( norm_at[i].radical )
3738
len += sprintf( str+len, "%s", norm_at[i].radical==RADICAL_SINGLET? ":" :
3739
norm_at[i].radical==RADICAL_DOUBLET? "." :
3740
norm_at[i].radical==RADICAL_TRIPLET? ".." : "?");
3743
/* stereogenic centers */
3744
if ( bDoDisplaySp3 && Stereo && 0 < (num_stereo = Stereo->nNumberOfStereoCenters) ) {
3745
for ( i = 0; i < num_stereo; i ++ ) {
3746
j = (int)nNormAtNosInCanonOrd[(int)nNumber[i]-1];
3748
c = c==1? '-' : c==2? '+' : c==3? 'u' : c== 4? '?' : '*';
3749
inf_norm_at[j].cStereoCenterParity = c;
3750
str=inf_norm_at[j].at_string;
3752
if ( len + 3 < (int)sizeof(inf_norm_at[0].at_string) ) {
3754
str[len++] = inf_norm_at[j].cStereoCenterParity;
3757
/* mark ambuguous stereo center */
3758
if ( norm_at[j].bAmbiguousStereo && (c=='+' || c=='-' || c=='?') && str[0] != '!' &&
3759
len+1 < (int)sizeof(inf_norm_at[0].at_string) ) {
3760
memmove( str+1, str, len+1 );
3761
str[0] = '!'; /* output the atom in red color */
3767
/* stereogenic bonds */
3768
/* (cumulenes with odd number of double bonds are stereocenters, */
3769
/* and atom parity should be set) */
3770
if ( Stereo && 0 < (num_stereo = Stereo->nNumberOfStereoBonds) ) {
3771
for ( i = 0; i < num_stereo; i ++ ) {
3772
int start_at, num_eql=0, bAmbiguousStereoBond = 0;
3773
j = (int)nNormAtNosInCanonOrd[(int)Stereo->nBondAtom1[i]-1];
3774
k = (int)nNormAtNosInCanonOrd[(int)Stereo->nBondAtom2[i]-1];
3776
c = Stereo->b_parity[i];
3778
c = c==1? '-' : c==2? '+' : c==3? 'u' : c== 4? '?' : '*';
3780
/* mark ambuguous stereo bond atom(s) */
3781
if ( norm_at[j].bAmbiguousStereo && (c=='+' || c=='-' ) &&
3782
(len=strlen(str=inf_norm_at[j].at_string)+1) < (int)sizeof(inf_norm_at[0].at_string) &&
3784
memmove( str+1, str, len );
3785
str[0] = '!'; /* output the atom in red color */
3786
bAmbiguousStereoBond ++;
3788
if ( norm_at[k].bAmbiguousStereo && (c=='+' || c=='-') &&
3789
(len=strlen(str=inf_norm_at[k].at_string)+1) < (int)sizeof(inf_norm_at[0].at_string) &&
3791
memmove( str+1, str, len );
3792
str[0] = '!'; /* output the atom in red color */
3793
bAmbiguousStereoBond ++;
3796
/* find the opposite atom k. */
3797
/* Note: since it may be a cumulene, find the shortest(best) path */
3798
/* to atom number k to avoid confusion in case of, for example, */
3799
/* 4-member aromatic rings. */
3800
best_len = MAX_CUMULENE_LEN+1; /* moved here from inside the cycle 1-8-2003 */
3801
for ( n = 0; n < norm_at[j].valence; n ++ ) {
3802
if ( norm_at[j].bond_type[n] == BOND_SINGLE ) {
3803
/* single bond cannot be stereogenic. */
3806
/* best_len = MAX_CUMULENE_LEN+1; */
3807
len = 0; /* number of bonds in cumulene - 1 */
3808
next_atom[len] = (int)norm_at[j].neighbor[n];
3809
next_neigh[len] = n;
3811
while ( next_atom[len] != k && len < MAX_CUMULENE_LEN && 2 == norm_at[next_atom[len]].valence ) {
3812
next_neigh[len+1] = ((int)norm_at[next_atom[len]].neighbor[0] == cur_atom);
3813
next_atom[len+1] = (int)norm_at[next_atom[len]].neighbor[next_neigh[len+1]];
3814
cur_atom = next_atom[len];
3817
if ( next_atom[len] == k ) {
3818
if ( len < best_len ) {
3819
memcpy( best_next_neigh, next_neigh, sizeof(best_next_neigh) );
3820
memcpy( best_next_atom, next_atom, sizeof(best_next_atom) );
3824
break; /* path length cannot be smaller than 1 */
3827
if ( len == best_len ) {
3832
if ( best_len <= MAX_CUMULENE_LEN && best_next_atom[best_len] == k ) {
3834
num_err ++; /* program error; no breakpoint here */
3836
if ( best_len % 2 ) {
3837
/* even number of bonds: chiral atom, draw parity on the cenrtal atom */
3838
j = best_next_atom[best_len/2];
3839
inf_norm_at[j].cStereoCenterParity = c;
3840
str=inf_norm_at[j].at_string;
3842
if ( len + 3 < (int)sizeof(inf_norm_at[0].at_string) ) {
3844
str[len++] = inf_norm_at[j].cStereoCenterParity;
3849
/* odd number of bonds: draw parity on the central bond */
3850
if ( best_len == 0 ) {
3853
k = best_next_neigh[0];
3856
best_len = best_len/2-1;
3857
j = best_next_atom[best_len];
3858
k = best_next_neigh[best_len+1]; /* added +1 to display cumulene parity on the middle bond (6-24-2002) */
3860
/* mark "forward" bond */
3861
for ( m = 0; m < MAX_STEREO_BONDS && inf_norm_at[j].cStereoBondParity[m]; m ++ )
3863
if ( m < MAX_STEREO_BONDS ) {
3864
inf_norm_at[j].cStereoBondParity[m] = c;
3865
inf_norm_at[j].cStereoBondNumber[m] = k;
3866
inf_norm_at[j].cStereoBondWarning[m] = bAmbiguousStereoBond;
3868
num_err ++; /* program error; no breakpoint here */
3870
/* mark "backward" bond */
3871
n = norm_at[j].neighbor[k];
3872
for ( k = 0; k < norm_at[n].valence && j != (int)norm_at[n].neighbor[k]; k ++ )
3874
if ( k < norm_at[n].valence ) {
3876
for ( m = 0; m < MAX_STEREO_BONDS && inf_norm_at[j].cStereoBondParity[m]; m ++ )
3878
if ( m < MAX_STEREO_BONDS ) {
3879
inf_norm_at[j].cStereoBondParity[m] = c;
3880
inf_norm_at[j].cStereoBondNumber[m] = k;
3881
inf_norm_at[j].cStereoBondWarning[m] = bAmbiguousStereoBond;
3883
num_err ++; /* program error; no breakpoint here */
3886
num_err ++; /* program error; no breakpoint here */
3890
num_err ++; /* program error; no breakpoint here */
3895
for ( i = 0; i < init_num_at; i ++ ) {
3896
/* canonical numbers */
3897
if ( inf_norm_at[i].nCanonNbr ) {
3898
str = inf_norm_at[i].at_string;
3900
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nCanonNbr );
3901
if ( inf_norm_at[i].nCanonEquNbr || inf_norm_at[i].nTautGroupCanonNbr || (inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT) ) {
3902
if ( inf_norm_at[i].nCanonEquNbr ) {
3903
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nCanonEquNbr );
3905
if ( len + 1 < len_str ) {
3910
/* tautomeric groups */
3911
if ( inf_norm_at[i].nTautGroupCanonNbr ) {
3912
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nTautGroupCanonNbr );
3913
if ( inf_norm_at[i].nTautGroupEquNbr ) {
3914
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nTautGroupEquNbr );
3917
if ( (inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT) && len+2 <= len_str ) {
3922
#ifdef DISPLAY_DEBUG_DATA
3923
if ( inf_norm_at[i].nDebugData ) {
3924
len += (*MakeNumber)( str+len, len_str-len, "`", (int)inf_norm_at[i].nDebugData );
3933
if ( nNormAtNosInCanonOrd )
3934
inchi_free( nNormAtNosInCanonOrd );
3939
/***************************************************************************************/
3940
int FillOutOneCanonInfAtom(inp_ATOM *inp_norm_at, INF_ATOM_DATA *inf_norm_at_data,
3941
AT_NUMB *pStereoFlags, int init_num_at, int offset, int offset_H, int bIsotopic,
3942
INChI *pINChI, INChI_Aux *pINChI_Aux, int bAbcNumbers, INCHI_MODE nMode)
3944
int i, j, m, n, num_stereo, k, c, ret, len_str, len, atw, num_err;
3945
int next_atom[MAX_CUMULENE_LEN+1], best_next_atom[MAX_CUMULENE_LEN+1], cur_atom;
3946
int next_neigh[MAX_CUMULENE_LEN+1], best_next_neigh[MAX_CUMULENE_LEN+1], best_len, bIncludeIsotopicH;
3947
int num_iso_H[NUM_H_ISOTOPES];
3950
int num_at = pINChI->nNumberOfAtoms;
3951
int num_H = init_num_at - num_at; /* number of removed H */
3952
int nNumberOfTGroups = (pINChI->lenTautomer && pINChI->nTautomer && pINChI->nTautomer[0])? (int)pINChI->nTautomer[0] : 0;
3953
AT_NUMB *nOrigAtNosInCanonOrd;
3954
INChI_Stereo *Stereo;
3955
AT_NUMB *nConstitEquNumbers;
3956
AT_NUMB *nConstitEquTGroupNumbers;
3957
S_CHAR *t_parity = NULL;
3958
AT_NUMB *nNumber = NULL;
3960
AT_NUMB *nNormAtNosInCanonOrd;
3961
int (*MakeNumber)(char*, int, const char*, int) = bAbcNumbers? MakeAbcNumber:MakeDecNumber;
3962
int bRel= (0 != (nMode & ( REQ_MODE_RELATIVE_STEREO)));
3963
int bRac= (0 != (nMode & ( REQ_MODE_RACEMIC_STEREO)));
3964
int bRelRac= bRel || bRac;
3965
int bDoDisplaySp3 = 1;
3967
inf_ATOM *inf_norm_at = (inf_norm_at_data && inf_norm_at_data->at)? inf_norm_at_data->at+offset : NULL;
3968
inp_ATOM *norm_at = inp_norm_at? inp_norm_at + offset : NULL;
3969
inf_ATOM *inf_norm_at_H = (inf_norm_at_data && inf_norm_at_data->at)? inf_norm_at_data->at+offset_H : NULL;
3970
inp_ATOM *norm_at_H = inp_norm_at? inp_norm_at + offset_H : NULL;
3977
/* -- already added in FillOutCompositeCanonInfAtom() --
3979
for ( i = 0, j = 0; i < NUM_H_ISOTOPES; i ++ ) {
3980
if ( pINChI_Aux->nNumRemovedIsotopicH[i] ) {
3981
inf_norm_at_data->num_iso_H[i] += pINChI_Aux->nNumRemovedIsotopicH[i];
3982
inf_norm_at_data->num_removed_iso_H ++;
3988
if ( bIsotopic && !(pINChI->nNumberOfIsotopicAtoms || pINChI->nNumberOfIsotopicTGroups ||
3989
pINChI->nPossibleLocationsOfIsotopicH && pINChI->nPossibleLocationsOfIsotopicH[0]>1) )
3992
Stereo = bIsotopic? pINChI->StereoIsotopic :
3994
bDoDisplaySp3 = (NULL != Stereo) && (Stereo->nNumberOfStereoCenters > 0);
3996
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
3997
if ( bDoDisplaySp3 && bRelRac && Stereo->nNumberOfStereoCenters < 2 &&
3998
(Stereo->nCompInv2Abs || ATOM_PARITY_ILL_DEF(Stereo->t_parity[0]) ) ) {
4000
if ( Stereo->nCompInv2Abs ) {
4001
inf_norm_at_data->StereoFlags |= bRel? INF_STEREO_REL : bRac? INF_STEREO_RAC : 0;
4005
/* flag has stereo */
4006
if ( (NULL != Stereo) && (bDoDisplaySp3 || Stereo->nNumberOfStereoBonds > 0) ) {
4007
(*pStereoFlags) |= INF_STEREO;
4011
if ( bDoDisplaySp3 && bRelRac && Stereo->nCompInv2Abs && Stereo->nNumberOfStereoCenters < 2 ) {
4015
if ( bDoDisplaySp3 && Stereo->nCompInv2Abs ) {
4016
/* inversion changes stereo */
4018
(*pStereoFlags) |= INF_STEREO_REL;
4021
(*pStereoFlags) |= INF_STEREO_RAC;
4023
(*pStereoFlags) |= INF_STEREO_ABS;
4026
(*pStereoFlags) |= (Stereo->nCompInv2Abs > 0)? INF_STEREO_NORM : INF_STEREO_INV;
4029
if ( bDoDisplaySp3 && Stereo->nCompInv2Abs < 0 && !bRelRac ) {
4030
/* display Inv stereo which is Absolute Stereo */
4031
nNumber = Stereo->nNumberInv;
4032
t_parity = Stereo->t_parityInv;
4033
nOrigAtNosInCanonOrd = bIsotopic? pINChI_Aux->nIsotopicOrigAtNosInCanonOrdInv :
4034
pINChI_Aux->nOrigAtNosInCanonOrdInv;
4036
/* display Output stereo which is Absolute Stereo */
4037
if ( bDoDisplaySp3 ) {
4038
nNumber = Stereo->nNumber;
4039
t_parity = Stereo->t_parity;
4041
nOrigAtNosInCanonOrd = bIsotopic? pINChI_Aux->nIsotopicOrigAtNosInCanonOrd :
4042
pINChI_Aux->nOrigAtNosInCanonOrd;
4045
nConstitEquNumbers = bIsotopic? pINChI_Aux->nConstitEquIsotopicNumbers :
4046
pINChI_Aux->nConstitEquNumbers;
4047
nConstitEquTGroupNumbers = bIsotopic? pINChI_Aux->nConstitEquIsotopicTGroupNumbers :
4048
pINChI_Aux->nConstitEquTGroupNumbers;
4049
memset( inf_norm_at, 0, num_at*sizeof(inf_norm_at[0]) );
4051
memset( inf_norm_at_H, 0, num_H*sizeof(inf_norm_at[0]) );
4054
/* obtain norm_at[] atom numbers (from zero) in order of canonical numbers */
4055
nNormAtNosInCanonOrd = (AT_NUMB *)inchi_calloc( num_at, sizeof(nNormAtNosInCanonOrd[0]) );
4056
if ( ret = GetAtomOrdNbrInCanonOrd( norm_at, nNormAtNosInCanonOrd, nOrigAtNosInCanonOrd, num_at ) ) {
4060
/* atom canonical and equivalence numbers > 0 */
4061
for ( i = 0; i < num_at; i ++ ) {
4062
j = (int)nNormAtNosInCanonOrd[i];
4063
if ( j < 0 || j >= num_at )
4065
inf_norm_at[j].nCanonNbr = (AT_NUMB)(i+1);
4066
inf_norm_at[j].nCanonEquNbr = nConstitEquNumbers[i];
4067
#ifdef DISPLAY_DEBUG_DATA
4068
inf_norm_at[j].nDebugData = 0;
4069
#if( DISPLAY_DEBUG_DATA == DISPLAY_DEBUG_DATA_C_POINT )
4070
inf_norm_at[j].nDebugData = norm_at[j].c_point;
4074
/* tautomeric groups */
4075
if ( nNumberOfTGroups ) {
4077
: start from 1: bypass number of t-groups
4078
: j is a counter within the current t-group
4079
: g is a tautomeric group canonical number
4080
: e is a tautomeric group equivalence
4082
for ( g = 1, i = 1; g <= nNumberOfTGroups; g ++ ) {
4083
n = (int)pINChI->nTautomer[i] - INCHI_T_NUM_MOVABLE; /* number of atoms in t-group */
4084
e = nConstitEquTGroupNumbers[(int)g - 1];
4085
/* bypass number of hydrogen atoms, negative charges, ... */
4086
for ( i += INCHI_T_NUM_MOVABLE+1, j = 0; j < n && i < pINChI->lenTautomer; j ++, i ++ ) {
4087
/* scan canonical numbers of atoms within the atom t-group */
4088
k = (int)nNormAtNosInCanonOrd[(int)pINChI->nTautomer[i]-1];
4089
inf_norm_at[k].nTautGroupCanonNbr = g;
4090
inf_norm_at[k].nTautGroupEquNbr = e;
4093
if ( i != pINChI->lenTautomer || g != nNumberOfTGroups+1 ) {
4094
ret = CT_TAUCOUNT_ERR; /* <BRKPT> */
4098
/* atoms that may exchange isotopic H */
4099
if ( bIsotopic && pINChI->nPossibleLocationsOfIsotopicH && (n = (int)pINChI->nPossibleLocationsOfIsotopicH[0]) ) {
4100
for ( i = 1; i < n; i ++ ) {
4101
j = (int)pINChI->nPossibleLocationsOfIsotopicH[i];
4102
k = (int)nNormAtNosInCanonOrd[j - 1];
4103
if ( !inf_norm_at[k].nTautGroupCanonNbr ) {
4104
inf_norm_at[k].cFlags |= AT_FLAG_ISO_H_POINT;
4108
#if( DISPLAY_RING_SYSTEMS == 1 )
4110
for ( j = 0; j < num_at; j ++ ) {
4111
inf_norm_at[j].nCanonNbr = norm_at[j].nBlockSystem;
4112
inf_norm_at[j].nCanonEquNbr = norm_at[j].nRingSystem;
4113
#if( USE_DISTANCES_FOR_RANKING == 1 )
4114
inf_norm_at[j].nTautGroupCanonNbr = norm_at[j].nDistanceFromTerminal;
4115
inf_norm_at[j].nTautGroupEquNbr = norm_at[j].bCutVertex;
4117
inf_norm_at[j].nTautGroupCanonNbr = norm_at[j].bCutVertex;
4118
inf_norm_at[j].nTautGroupEquNbr = 0;
4125
/* Write isotopic mass, chemical element symbols and hydrogens, charge, radical, canon. numbers */
4126
len_str = sizeof(inf_norm_at[0].at_string);
4127
for ( i = 0; i < init_num_at; i ++ ) {
4128
inf_ATOM *cur_inf_norm_at = (i < num_at)? inf_norm_at+i : inf_norm_at_H+i-num_at;
4129
inp_ATOM *cur_norm_at = (i < num_at)? norm_at +i : norm_at_H +i-num_at;
4130
str = cur_inf_norm_at->at_string;
4132
bIncludeIsotopicH = bIsotopic && (i >= num_at || !inf_norm_at[i].nTautGroupCanonNbr && !(inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT));
4135
if ( cur_norm_at->iso_atw_diff && bIsotopic ) {
4136
if ( cur_norm_at->at_type == ATT_PROTON ) {
4137
; /* do not set isotopic mass of a tautomeric proton */
4139
if ( num_at <= i && cur_norm_at->el_number == PERIODIC_NUMBER_H && cur_norm_at->chem_bonds_valence == 1 &&
4140
!cur_norm_at->charge && !cur_norm_at->radical && !cur_norm_at->num_H &&
4141
0 <= (j=(int)cur_norm_at->neighbor[0]-offset) && j < num_at &&
4142
(inf_norm_at[j].nTautGroupCanonNbr || (inf_norm_at[j].cFlags & AT_FLAG_ISO_H_POINT) ) ) {
4143
; /* do not set isotopic mass of an exchangeable proton */
4145
atw = get_atw(cur_norm_at->elname);
4146
atw += (cur_norm_at->iso_atw_diff>0)? cur_norm_at->iso_atw_diff-1:cur_norm_at->iso_atw_diff;
4147
/*len += sprintf( str+len, "^%d", atw );*/
4151
if ( cur_norm_at->el_number == PERIODIC_NUMBER_H && 2 <= atw && atw <= 3 ) {
4152
len += sprintf( str+len, "%s", atw==2? "D" : "T" );
4155
len += sprintf( str+len, "^%d", atw );
4157
len += sprintf( str+len, "%s", cur_norm_at->elname );
4160
/* find number of previuosly removed terminal hydrogen atoms */
4161
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
4162
num_iso_H[j] = cur_norm_at->num_iso_H[j];
4164
for ( j = 0, n = (int)cur_norm_at->num_H; j < num_H; j ++ ) {
4165
/* subtract number of removed terminal */
4166
/* H atoms from the total number of H atoms */
4167
if ( i == (int)norm_at_H[j].neighbor[0]-offset ) {
4169
m = (int)norm_at_H[j].iso_atw_diff-1;
4170
if ( 0 <= m && m < NUM_H_ISOTOPES ) {
4171
/* subtract number of removed terminal isotopic */
4172
/* H atoms from the total number of isotopic H atoms */
4177
if ( bIncludeIsotopicH ) {
4178
/* subtract number of isotopic H atoms from the total number of H atoms */
4179
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
4183
/* non-isotopic hydrogen atoms */
4185
len += sprintf( str+len, "H%d", n );
4188
len += sprintf( str+len, "H" );
4190
/* isotopic hydrogen atoms */
4191
if ( bIncludeIsotopicH ) {
4192
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
4193
if ( num_iso_H[j] ) {
4194
if ( j == 0 || j != 1 && j != 2 ) {
4195
len += sprintf( str+len, "^%dH", j+1 );
4197
len += sprintf( str+len, j == 1? "D" : "T" );
4199
if ( num_iso_H[j] != 1 ) {
4200
len += sprintf( str+len, "%d", (int)num_iso_H[j] );
4205
if ( cur_norm_at->el_number == PERIODIC_NUMBER_H && str[0] == str[1] ) {
4208
str[1] = '2'; /* quick fix: replace HH with H2 */
4210
if ( isdigit( UCINT str[2] ) && (n = strtol( str+2, &q, 10 )) && !q[0] ) {
4211
len = 1 + sprintf( str+1, "%d", n+1 );
4215
if ( abs(cur_norm_at->charge) > 1 )
4216
len += sprintf( str+len, "%+d", cur_norm_at->charge );
4218
if ( abs(cur_norm_at->charge) == 1 )
4219
len += sprintf( str+len, "%s", cur_norm_at->charge>0? "+" : "-" );
4221
if ( cur_norm_at->radical )
4222
len += sprintf( str+len, "%s", cur_norm_at->radical==RADICAL_SINGLET? ":" :
4223
cur_norm_at->radical==RADICAL_DOUBLET? "." :
4224
cur_norm_at->radical==RADICAL_TRIPLET? ".." : "?");
4227
/* stereogenic centers */
4228
if ( bDoDisplaySp3 && Stereo && 0 < (num_stereo = Stereo->nNumberOfStereoCenters) ) {
4229
for ( i = 0; i < num_stereo; i ++ ) {
4230
j = (int)nNormAtNosInCanonOrd[(int)nNumber[i]-1];
4232
c = c==1? '-' : c==2? '+' : c==3? 'u' : c== 4? '?' : '*';
4233
inf_norm_at[j].cStereoCenterParity = c;
4234
str=inf_norm_at[j].at_string;
4236
if ( len + 3 < (int)sizeof(inf_norm_at[0].at_string) ) {
4238
str[len++] = inf_norm_at[j].cStereoCenterParity;
4241
/* mark ambuguous stereo center */
4242
if ( norm_at[j].bAmbiguousStereo && (c=='+' || c=='-' || c=='?') && str[0] != '!' &&
4243
len+1 < (int)sizeof(inf_norm_at[0].at_string) ) {
4244
memmove( str+1, str, len+1 );
4245
str[0] = '!'; /* output the atom in red color */
4251
/* stereogenic bonds */
4252
/* (cumulenes with odd number of double bonds are stereocenters, */
4253
/* and atom parity should be set) */
4254
if ( Stereo && 0 < (num_stereo = Stereo->nNumberOfStereoBonds) ) {
4255
for ( i = 0; i < num_stereo; i ++ ) {
4256
int start_at, num_eql=0, bAmbiguousStereoBond = 0;
4257
j = (int)nNormAtNosInCanonOrd[(int)Stereo->nBondAtom1[i]-1];
4258
k = (int)nNormAtNosInCanonOrd[(int)Stereo->nBondAtom2[i]-1];
4260
c = Stereo->b_parity[i];
4262
c = c==1? '-' : c==2? '+' : c==3? 'u' : c== 4? '?' : '*';
4264
/* mark ambuguous stereo bond atom(s) */
4265
if ( norm_at[j].bAmbiguousStereo && (c=='+' || c=='-' ) &&
4266
(len=strlen(str=inf_norm_at[j].at_string)+1) < (int)sizeof(inf_norm_at[0].at_string) &&
4268
memmove( str+1, str, len );
4269
str[0] = '!'; /* output the atom in red color */
4270
bAmbiguousStereoBond ++;
4272
if ( norm_at[k].bAmbiguousStereo && (c=='+' || c=='-') &&
4273
(len=strlen(str=inf_norm_at[k].at_string)+1) < (int)sizeof(inf_norm_at[0].at_string) &&
4275
memmove( str+1, str, len );
4276
str[0] = '!'; /* output the atom in red color */
4277
bAmbiguousStereoBond ++;
4280
/* find the opposite atom k. */
4281
/* Note: since it may be a cumulene, find the shortest(best) path */
4282
/* to atom number k to avoid confusion in case of, for example, */
4283
/* 4-member aromatic rings. */
4284
best_len = MAX_CUMULENE_LEN+1; /* moved here from inside the cycle 1-8-2003 */
4285
for ( n = 0; n < norm_at[j].valence; n ++ ) {
4286
if ( norm_at[j].bond_type[n] == BOND_SINGLE ) {
4287
/* single bond cannot be stereogenic. */
4290
/* best_len = MAX_CUMULENE_LEN+1; */
4291
len = 0; /* number of bonds in cumulene - 1 */
4292
next_atom[len] = (int)norm_at[j].neighbor[n]-offset;
4293
next_neigh[len] = n;
4295
while ( next_atom[len] != k && len < MAX_CUMULENE_LEN && 2 == norm_at[next_atom[len]].valence ) {
4296
next_neigh[len+1] = ((int)norm_at[next_atom[len]].neighbor[0]-offset == cur_atom);
4297
next_atom[len+1] = (int)norm_at[next_atom[len]].neighbor[next_neigh[len+1]]-offset;
4298
cur_atom = next_atom[len];
4301
if ( next_atom[len] == k ) {
4302
if ( len < best_len ) {
4303
memcpy( best_next_neigh, next_neigh, sizeof(best_next_neigh) );
4304
memcpy( best_next_atom, next_atom, sizeof(best_next_atom) );
4308
break; /* path length cannot be smaller than 1 */
4311
if ( len == best_len ) {
4316
if ( best_len <= MAX_CUMULENE_LEN && best_next_atom[best_len] == k ) {
4318
num_err ++; /* program error; no breakpoint here */
4320
if ( best_len % 2 ) {
4321
/* even number of bonds: chiral atom, draw parity on the cenrtal atom */
4322
j = best_next_atom[best_len/2];
4323
inf_norm_at[j].cStereoCenterParity = c;
4324
str=inf_norm_at[j].at_string;
4326
if ( len + 3 < (int)sizeof(inf_norm_at[0].at_string) ) {
4328
str[len++] = inf_norm_at[j].cStereoCenterParity;
4333
/* odd number of bonds: draw parity on the central bond */
4334
if ( best_len == 0 ) {
4337
k = best_next_neigh[0];
4340
best_len = best_len/2-1;
4341
j = best_next_atom[best_len];
4342
k = best_next_neigh[best_len+1]; /* added +1 to display cumulene parity on the middle bond (6-24-2002) */
4344
/* mark "forward" bond */
4345
for ( m = 0; m < MAX_STEREO_BONDS && inf_norm_at[j].cStereoBondParity[m]; m ++ )
4347
if ( m < MAX_STEREO_BONDS ) {
4348
inf_norm_at[j].cStereoBondParity[m] = c;
4349
inf_norm_at[j].cStereoBondNumber[m] = k;
4350
inf_norm_at[j].cStereoBondWarning[m] = bAmbiguousStereoBond;
4352
num_err ++; /* program error; no breakpoint here */
4354
/* mark "backward" bond */
4355
n = norm_at[j].neighbor[k]-offset;
4356
for ( k = 0; k < norm_at[n].valence && j != (int)norm_at[n].neighbor[k]-offset; k ++ )
4358
if ( k < norm_at[n].valence ) {
4360
for ( m = 0; m < MAX_STEREO_BONDS && inf_norm_at[j].cStereoBondParity[m]; m ++ )
4362
if ( m < MAX_STEREO_BONDS ) {
4363
inf_norm_at[j].cStereoBondParity[m] = c;
4364
inf_norm_at[j].cStereoBondNumber[m] = k;
4365
inf_norm_at[j].cStereoBondWarning[m] = bAmbiguousStereoBond;
4367
num_err ++; /* program error; no breakpoint here */
4370
num_err ++; /* program error; no breakpoint here */
4374
num_err ++; /* program error; no breakpoint here */
4379
for ( i = 0; i < num_at; i ++ ) {
4380
/* canonical numbers */
4381
if ( inf_norm_at[i].nCanonNbr ) {
4382
str = inf_norm_at[i].at_string;
4384
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nCanonNbr );
4385
if ( inf_norm_at[i].nCanonEquNbr || inf_norm_at[i].nTautGroupCanonNbr || (inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT) ) {
4386
if ( inf_norm_at[i].nCanonEquNbr ) {
4387
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nCanonEquNbr );
4389
if ( len + 1 < len_str ) {
4394
/* tautomeric groups */
4395
if ( inf_norm_at[i].nTautGroupCanonNbr ) {
4396
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nTautGroupCanonNbr );
4397
if ( inf_norm_at[i].nTautGroupEquNbr ) {
4398
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nTautGroupEquNbr );
4401
if ( (inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT) && len+2 <= len_str ) {
4406
#ifdef DISPLAY_DEBUG_DATA
4407
if ( inf_norm_at[i].nDebugData ) {
4408
len += (*MakeNumber)( str+len, len_str-len, "`", (int)inf_norm_at[i].nDebugData );
4417
if ( nNormAtNosInCanonOrd )
4418
inchi_free( nNormAtNosInCanonOrd );
4423
/***************************************************************************************/
4424
int FillOutInputInfAtom(inp_ATOM *inp_at, INF_ATOM_DATA *inf_at_data, int init_num_at, int num_removed_H,
4425
int bAdd_DT_to_num_H, int nNumRemovedProtons, NUM_H *nNumRemovedProtonsIsotopic, int bIsotopic, int bAbcNumbers)
4427
int i, j, m, n, ret, len_str, len, atw;
4428
int num_iso_H[NUM_H_ISOTOPES];
4430
int num_at = init_num_at - num_removed_H;
4431
int (*MakeNumber)(char*, int, const char*, int) = MakeDecNumber;
4433
inf_ATOM *inf_at = inf_at_data? inf_at_data->at : NULL;
4442
memset( inf_at, 0, init_num_at*sizeof(inf_at[0]) );
4444
inf_at_data->nNumRemovedProtons = nNumRemovedProtons;
4445
MakeRemovedProtonsString( nNumRemovedProtons, nNumRemovedProtonsIsotopic, NULL, bIsotopic, inf_at_data->szRemovedProtons, NULL );
4446
/* atom canonical and equivalence numbers > 0 */
4447
for ( i = 0; i < num_at; i ++ ) {
4448
#if( DISPLAY_ORIG_AT_NUMBERS == 1 )
4449
inf_at[i].nCanonNbr = inp_at[i].orig_at_number;
4451
inf_at[i].nCanonNbr = (AT_NUMB)(i+1);
4454
/* Write isotopic mass, chemical element symbols and hydrogens, charge, radical, canon. numbers */
4455
len_str = sizeof(inf_at[0].at_string);
4456
for ( i = 0; i < init_num_at; i ++ ) {
4457
str = inf_at[i].at_string;
4461
if ( inp_at[i].iso_atw_diff && bIsotopic ) {
4462
atw = get_atw(inp_at[i].elname);
4463
atw += (inp_at[i].iso_atw_diff>0)? inp_at[i].iso_atw_diff-1:inp_at[i].iso_atw_diff;
4464
/*len += sprintf( str+len, "^%d", atw );*/
4467
if ( inp_at[i].el_number == PERIODIC_NUMBER_H && 2 <= atw && atw <= 3 ) {
4468
len += sprintf( str+len, "%s", atw==2? "D" : "T" );
4471
len += sprintf( str+len, "^%d", atw );
4473
len += sprintf( str+len, "%s", inp_at[i].elname );
4476
/* find number of previuosly removed terminal hydrogen atoms */
4477
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
4478
num_iso_H[j] = inp_at[i].num_iso_H[j];
4480
for ( j = num_at, n = (int)inp_at[i].num_H; j < init_num_at; j ++ ) {
4481
/* subtract number of removed terminal */
4482
/* H atoms from the total number of H atoms */
4483
if ( i == (int)inp_at[j].neighbor[0] ) {
4485
m = (int)inp_at[j].iso_atw_diff-1;
4486
if ( 0 <= m && m < NUM_H_ISOTOPES ) {
4487
/* subtract number of removed terminal isotopic */
4488
/* H atoms from the total number of isotopic H atoms */
4493
if ( bIsotopic && !bAdd_DT_to_num_H ) {
4494
/* subtract number of isotopic H atoms from the total number of H atoms */
4495
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
4499
/* non-isotopic hydrogen atoms */
4501
len += sprintf( str+len, "H%d", n );
4504
len += sprintf( str+len, "H" ); /* fixed 12-21-2002: removed 3rd argument */
4507
/* isotopic hydrogen atoms */
4508
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
4509
if ( num_iso_H[j] ) {
4510
if ( j == 0 || j != 1 && j != 2 ) {
4511
len += sprintf( str+len, "^%dH", j+1 );
4513
len += sprintf( str+len, j == 1? "D" : "T" );
4515
if ( num_iso_H[j] != 1 ) {
4516
len += sprintf( str+len, "%d", (int)num_iso_H[j] );
4521
if ( inp_at[i].el_number == PERIODIC_NUMBER_H && str[0] == str[1] ) {
4524
str[1] = '2'; /* quick fix: replace HH with H2 */
4526
if ( isdigit( UCINT str[2] ) && (n = strtol( str+2, &q, 10 )) && !q[0] ) {
4527
len = 1 + sprintf( str+1, "%d", n+1 );
4531
if ( str[0] == 'H' && str[1] == 'H' && !str[2] ) {
4536
if ( abs(inp_at[i].charge) > 1 )
4537
len += sprintf( str+len, "%+d", inp_at[i].charge );
4539
if ( abs(inp_at[i].charge) == 1 )
4540
len += sprintf( str+len, "%s", inp_at[i].charge>0? "+" : "-" );
4542
if ( inp_at[i].radical )
4543
len += sprintf( str+len, "%s", inp_at[i].radical==RADICAL_SINGLET? ":" :
4544
inp_at[i].radical==RADICAL_DOUBLET? "." :
4545
inp_at[i].radical==RADICAL_TRIPLET? ".." : "?");
4548
for ( i = 0; i < init_num_at; i ++ ) {
4549
/* canonical numbers */
4550
if ( inf_at[i].nCanonNbr ) {
4551
str = inf_at[i].at_string;
4553
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_at[i].nCanonNbr );
4554
if ( inf_at[i].nCanonEquNbr || inf_at[i].nTautGroupCanonNbr ) {
4555
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_at[i].nCanonEquNbr );
4557
/* tautomeric groups */
4558
if ( inf_at[i].nTautGroupCanonNbr ) {
4559
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_at[i].nTautGroupCanonNbr );
4560
if ( inf_at[i].nTautGroupEquNbr ) {
4561
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_at[i].nTautGroupEquNbr );
4570
/**********************************************************************************************/
4571
int FillOutInfAtom(inp_ATOM *norm_at, INF_ATOM_DATA *inf_norm_at_data, int init_num_at, int num_removed_H,
4572
int bAdd_DT_to_num_H, int nNumRemovedProtons, NUM_H *nNumRemovedProtonsIsotopic, int bIsotopic,
4573
INChI *pINChI, INChI_Aux *pINChI_Aux, int bAbcNumbers, INCHI_MODE nMode )
4575
if ( norm_at && inf_norm_at_data && inf_norm_at_data->at ) {
4576
if ( pINChI && pINChI_Aux ) {
4577
return FillOutCanonInfAtom( norm_at, inf_norm_at_data, init_num_at, bIsotopic, pINChI,
4578
pINChI_Aux, bAbcNumbers, nMode);
4580
return FillOutInputInfAtom( norm_at, inf_norm_at_data, init_num_at, num_removed_H, bAdd_DT_to_num_H,
4581
nNumRemovedProtons, nNumRemovedProtonsIsotopic, bIsotopic, bAbcNumbers);
4586
/***************************************************************************************/
4587
int FillOutCompositeCanonInfAtom(COMP_ATOM_DATA *composite_norm_data, INF_ATOM_DATA *inf_norm_at_data,
4588
int bIsotopic, int bTautomeric,
4589
PINChI2 *pINChI2, PINChI_Aux2 *pINChI_Aux2, int bAbcNumbers, INCHI_MODE nMode)
4591
int i, num_components, j, k, ret;
4592
inp_ATOM *inp_norm_at;
4594
INChI_Aux *pINChI_Aux;
4595
int num_inp_at, num_at, num_H, offset, offset_H, next_offset, next_offset_H;
4597
if ( composite_norm_data && inf_norm_at_data && (bTautomeric == TAUT_INI || pINChI2 && pINChI_Aux2) ) {
4598
composite_norm_data += bTautomeric;
4599
inp_norm_at = composite_norm_data->at;
4600
num_components = composite_norm_data->num_components;
4602
offset_H = composite_norm_data->num_at - composite_norm_data->num_removed_H;
4603
if ( bTautomeric == TAUT_INI ) {
4604
ret = FillOutInputInfAtom( composite_norm_data->at, inf_norm_at_data, composite_norm_data->num_at,
4605
composite_norm_data->num_removed_H, 0 /*bAdd_DT_to_num_H*/,
4606
composite_norm_data->nNumRemovedProtons,
4607
composite_norm_data->nNumRemovedProtonsIsotopic,
4608
bIsotopic, bAbcNumbers);
4611
for ( i = 0; i < num_components; i ++ ) {
4612
j = inchi_min(bTautomeric, TAUT_YES);
4613
/* count isotopic H on removed atoms -- isolated H(+) cations */
4614
inf_norm_at_data->nNumRemovedProtons += pINChI_Aux2[i][j]->nNumRemovedProtons;
4615
if ( bIsotopic && bTautomeric == TAUT_YES ) {
4616
for ( k = 0; k < NUM_H_ISOTOPES; k ++ ) {
4617
if ( pINChI_Aux2[i][j]->nNumRemovedIsotopicH[k] ) {
4618
inf_norm_at_data->num_iso_H[k] += pINChI_Aux2[i][j]->nNumRemovedIsotopicH[k];
4619
inf_norm_at_data->num_removed_iso_H += pINChI_Aux2[i][j]->nNumRemovedIsotopicH[k];
4623
/* ignore deleted components */
4624
if ( pINChI2[i][j] && pINChI2[i][j]->bDeleted ) {
4627
if ( !pINChI2[i][j] || !pINChI2[i][j]->nNumberOfAtoms ) {
4629
if ( !pINChI2[i][j] || !pINChI2[i][j]->nNumberOfAtoms ) {
4630
continue; /* error ??? */
4633
pINChI = pINChI2[i][j];
4634
pINChI_Aux = pINChI_Aux2[i][j];
4635
next_offset = composite_norm_data->nOffsetAtAndH[2*i];
4636
next_offset_H = composite_norm_data->nOffsetAtAndH[2*i+1];
4637
num_at = next_offset - offset;
4640
num_H = next_offset_H - offset_H;
4641
num_inp_at = num_at + num_H;
4642
if ( num_at != pINChI->nNumberOfAtoms || num_at != pINChI_Aux->nNumberOfAtoms ) {
4643
return 0; /* error */
4645
ret = FillOutOneCanonInfAtom(inp_norm_at, inf_norm_at_data,
4646
inf_norm_at_data->pStereoFlags+i+1, num_inp_at,
4647
offset, offset_H, bIsotopic, pINChI, pINChI_Aux, bAbcNumbers, nMode);
4649
return 0; /* error */
4651
inf_norm_at_data->StereoFlags |= inf_norm_at_data->pStereoFlags[i+1];
4652
offset = next_offset;
4653
offset_H = next_offset_H;
4656
MakeRemovedProtonsString( inf_norm_at_data->nNumRemovedProtons, inf_norm_at_data->num_iso_H, NULL, bIsotopic,
4657
inf_norm_at_data->szRemovedProtons, &inf_norm_at_data->num_removed_iso_H );
4661
#endif /* } ifndef INCHI_ANSI_ONLY */
4662
/**********************************************************************************************/
4663
int CheckCanonNumberingCorrectness(int num_atoms, int num_at_tg,
4664
sp_ATOM *at, CANON_STAT *pCS, int bTautomeric,
4665
char *pStrErrStruct )
4668
AT_NUMB *pCanonOrd=NULL;
4670
AT_NUMB *pCanonRank; /* canonical ranks of the atoms or tautomeric groups */
4671
AT_NUMB *pCanonRankAtoms=NULL;
4673
static int count=0; /* for debug only */
4676
pCanonRankAtoms = (AT_NUMB *)inchi_calloc( num_at_tg+1, sizeof(pCanonRankAtoms[0]) );
4678
/**********************************************************************************************
4682
pCanonOrd = pCS->nLenCanonOrdStereo > 0? pCS->nCanonOrdStereo :
4683
pCS->nLenCanonOrd > 0? pCS->nCanonOrd : NULL;
4684
pCanonRank = pCanonRankAtoms;
4685
if ( pCanonOrd && pCanonRank ) {
4686
for ( i = 0; i < num_at_tg; i ++ ) {
4687
pCanonRank[pCanonOrd[i]] = (AT_NUMB)(i+1);
4689
ret = UpdateFullLinearCT( num_atoms, num_at_tg, at, pCanonRank, pCanonOrd, pCS, 0 );
4690
if ( ret /*|| memcmp(pCS->LinearCT, pCS->LinearCT2, sizeof(AT_RANK) * pCS->nLenLinearCT )*/ ) {
4691
nErrorCode |= WARN_FAILED_STEREO;
4695
nErrorCode |= ERR_NO_CANON_RESULTS;
4698
/**********************************************************************************************
4702
pCanonOrd = pCS->nLenCanonOrdIsotopicStereo > 0? pCS->nCanonOrdIsotopicStereo :
4703
pCS->nLenCanonOrdIsotopic > 0? pCS->nCanonOrdIsotopic : NULL;
4704
pCanonRank = pCanonRankAtoms;
4706
if ( pCanonOrd && pCanonRank ) {
4707
for ( i = 0; i < num_at_tg; i ++ ) {
4708
pCanonRank[pCanonOrd[i]] = (AT_NUMB)(i+1);
4710
ret = UpdateFullLinearCT( num_atoms, num_at_tg, at, pCanonRank, pCanonOrd, pCS, 0 );
4711
if ( ret /*|| memcmp(pCS->LinearCT, pCS->LinearCT2, sizeof(AT_RANK) * pCS->nLenLinearCT )*/ ) {
4712
nErrorCode |= (pCS->nLenCanonOrdIsotopicStereo? WARN_FAILED_ISOTOPIC_STEREO : WARN_FAILED_ISOTOPIC);
4718
if ( pCanonRankAtoms )
4719
inchi_free( pCanonRankAtoms );
4722
return CT_CANON_ERR;