2
* International Chemical Identifier (InChI)
4
* Software version 1.02
8
* The InChI library and programs are free software developed under the
9
* auspices of the International Union of Pure and Applied Chemistry (IUPAC);
10
* you can redistribute this software and/or modify it under the terms of
11
* the GNU Lesser General Public License as published by the Free Software
13
* http://www.opensource.org/licenses/lgpl-license.php
24
/* #define CHECK_WIN32_VC_HEAP */
27
#if( READ_INCHI_STRING == 1 )
49
/******************************************************************************************************/
50
int InChI2Atom( ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd, const char *szCurHdr, long num_inp,
51
StrFromINChI *pStruct, int iComponent, int iAtNoOffset, int bI2A_Flag, int bHasSomeFixedH, InpInChI *OneInput)
53
int iINChI = (bI2A_Flag & I2A_FLAG_RECMET)? INCHI_REC : INCHI_BAS;
54
int bMobileH = (bI2A_Flag & I2A_FLAG_FIXEDH)? TAUT_NON : TAUT_YES;
55
INChI *pInChI[TAUT_NUM];
58
memset( pInChI, 0, sizeof(pInChI) );
59
/* disconnected or reconnected */
60
if ( iINChI == INCHI_REC ) {
61
if ( !OneInput->nNumComponents[iINChI][TAUT_YES] ) {
65
if ( iComponent >= OneInput->nNumComponents[iINChI][TAUT_YES] ) {
66
return 0; /* component does not exist */
68
/* mobile or fixed H */
69
pStruct->bFixedHExists = 0;
70
if ( bMobileH == TAUT_NON ) {
71
if ( !OneInput->nNumComponents[iINChI][bMobileH] ) {
72
/* only one InChI exists (no mobile H) */
77
if ( iComponent >= OneInput->nNumComponents[iINChI][bMobileH] ) {
78
return 0; /* component does not exist */
80
/* pointer to the InChI that is going to be reversed */
81
pInChI[0] = &OneInput->pInpInChI[iINChI][bMobileH][iComponent];
82
pStruct->bMobileH = bMobileH;
83
pStruct->iINCHI = iINChI;
84
/* deleted component only in case Mobile-H and compound contains only protons */
85
if ( pInChI[0]->bDeleted ) {
86
return 0; /* deleted component, presumably H(+) */
89
if ( bMobileH == TAUT_NON && OneInput->nNumProtons[iINChI][TAUT_YES].pNumProtons ) {
90
pStruct->nNumRemovedProtonsMobHInChI =
91
OneInput->nNumProtons[iINChI][TAUT_YES].pNumProtons[iComponent].nNumRemovedProtons;
94
if ( bMobileH == TAUT_NON || bMobileH == TAUT_YES && OneInput->pInpInChI[iINChI][TAUT_NON] &&
95
OneInput->pInpInChI[iINChI][TAUT_NON][iComponent].nNumberOfAtoms > 0 &&
96
!OneInput->pInpInChI[iINChI][TAUT_NON][iComponent].bDeleted ) {
97
pStruct->bFixedHExists = 1;
99
if ( bMobileH == TAUT_NON && iComponent < OneInput->nNumComponents[iINChI][TAUT_YES] &&
100
OneInput->pInpInChI[iINChI][TAUT_YES] &&
101
OneInput->pInpInChI[iINChI][TAUT_YES][iComponent].nNumberOfAtoms > 0 &&
102
!OneInput->pInpInChI[iINChI][TAUT_YES][iComponent].bDeleted ) {
103
/* pointer to the Mobile-H InChI if we are reversing Fixed-H InChI */
104
pInChI[1] = &OneInput->pInpInChI[iINChI][TAUT_YES][iComponent];
106
pStruct->num_inp_actual = OneInput->num_inp;
107
ret = OneInChI2Atom( ip, sd, szCurHdr, num_inp, pStruct, iComponent, iAtNoOffset, bHasSomeFixedH, pInChI);
108
return ret; /* same interpretation as in ProcessOneStructure ??? */
111
/*******************************************************************/
112
void RemoveFixHInChIIdentical2MobH( InpInChI *pOneInput )
114
int iInchiRec, cur_num_comp, k;
115
/* eliminate Fixed-H InChI that are exactly came as the corresponding Mobile-H structures */
116
for ( iInchiRec = 0; iInchiRec < INCHI_NUM; iInchiRec ++ ) {
117
cur_num_comp = inchi_min(pOneInput->nNumComponents[iInchiRec][TAUT_YES],
118
pOneInput->nNumComponents[iInchiRec][TAUT_NON]);
119
for ( k = 0; k < cur_num_comp; k ++ ) {
120
if ( !CompareReversedINChI( pOneInput->pInpInChI[iInchiRec][TAUT_YES]+k,
121
pOneInput->pInpInChI[iInchiRec][TAUT_NON]+k, NULL, NULL ) ) {
122
Free_INChI_Members( pOneInput->pInpInChI[iInchiRec][TAUT_NON]+k );
123
memset( pOneInput->pInpInChI[iInchiRec][TAUT_NON]+k, 0, sizeof(pOneInput->pInpInChI[0][0][0]) );
128
/*******************************************************************/
129
int MarkDisconectedIdenticalToReconnected ( InpInChI *pOneInput )
131
/* mark Disconnected InChI components that are exactly came as Reconnected ones */
132
/* Disconnected will have a negative number of the reconnected component */
133
/* Reconnected will have a positive number of the disconnected component */
134
int k1, k2, num_marked = 0;
135
for ( k1 = 0; k1 < inchi_max(pOneInput->nNumComponents[INCHI_BAS][TAUT_YES],
136
pOneInput->nNumComponents[INCHI_BAS][TAUT_NON]); k1 ++ ) {
137
for ( k2 = 0; k2 < inchi_max(pOneInput->nNumComponents[INCHI_REC][TAUT_YES],
138
pOneInput->nNumComponents[INCHI_REC][TAUT_NON]); k2 ++ ) {
139
int eqM = ( k1 < pOneInput->nNumComponents[INCHI_BAS][TAUT_YES] &&
140
k2 < pOneInput->nNumComponents[INCHI_REC][TAUT_YES] &&
141
!pOneInput->pInpInChI[INCHI_REC][TAUT_YES][k2].nLink && /* already linked */
142
!pOneInput->pInpInChI[INCHI_BAS][TAUT_YES][k1].bDeleted &&
143
pOneInput->pInpInChI[INCHI_BAS][TAUT_YES][k1].nNumberOfAtoms &&
144
pOneInput->pInpInChI[INCHI_BAS][TAUT_YES][k1].nNumberOfAtoms ==
145
pOneInput->pInpInChI[INCHI_REC][TAUT_YES][k2].nNumberOfAtoms &&
146
!pOneInput->pInpInChI[INCHI_REC][TAUT_YES][k2].bDeleted &&
147
!CompareReversedINChI( pOneInput->pInpInChI[INCHI_REC][TAUT_YES]+k2,
148
pOneInput->pInpInChI[INCHI_BAS][TAUT_YES]+k1,
150
int isF1 = (k1 < pOneInput->nNumComponents[INCHI_BAS][TAUT_NON] &&
151
0 == pOneInput->pInpInChI[INCHI_BAS][TAUT_NON][k1].bDeleted &&
152
0 < pOneInput->pInpInChI[INCHI_BAS][TAUT_NON][k1].nNumberOfAtoms );
153
int isF2 = (k2 < pOneInput->nNumComponents[INCHI_REC][TAUT_NON] &&
154
0 == pOneInput->pInpInChI[INCHI_REC][TAUT_NON][k2].bDeleted &&
155
0 < pOneInput->pInpInChI[INCHI_REC][TAUT_NON][k2].nNumberOfAtoms );
156
int eqF = isF1 && isF2 &&
157
!pOneInput->pInpInChI[INCHI_REC][TAUT_NON][k2].nLink &&
158
pOneInput->pInpInChI[INCHI_BAS][TAUT_NON][k1].nNumberOfAtoms ==
159
pOneInput->pInpInChI[INCHI_REC][TAUT_NON][k2].nNumberOfAtoms &&
160
!CompareReversedINChI( pOneInput->pInpInChI[INCHI_REC][TAUT_NON]+k2,
161
pOneInput->pInpInChI[INCHI_BAS][TAUT_NON]+k1,
163
if ( eqM && (!isF1 && !isF2 || eqF ) ) {
164
pOneInput->pInpInChI[INCHI_BAS][TAUT_YES][k1].nLink = -(k2+1);
165
pOneInput->pInpInChI[INCHI_REC][TAUT_YES][k2].nLink = (k1+1);
167
pOneInput->pInpInChI[INCHI_BAS][TAUT_NON][k1].nLink = -(k2+1);
168
pOneInput->pInpInChI[INCHI_REC][TAUT_NON][k2].nLink = (k1+1);
171
break; /* equal InChI has been deleted from the disconnected layer, get next k1 */
178
/**************************************************************/
179
void SetUpSrm( SRM *pSrm )
181
/* structure restore parms !!!!! */
182
memset( pSrm, 0, sizeof(pSrm[0]) );
183
pSrm->bFixStereoBonds = FIX_STEREO_BOND_ORDER;
184
pSrm->nMetal2EndpointMinBondOrder = 1;
185
pSrm->nMetal2EndpointInitEdgeFlow = 0;
186
if ( METAL_FREE_CHARGE_VAL == 1 ) {
187
pSrm->bMetalAddFlower = 1;
188
/* the next 3 parameters: */
189
/* 0, 0, 0 => all bonds 0, no init radical on metal */
190
/* 0, 0, 1 => all bonds 0, init radical on metal */
191
/* 0, 1, 0 => wrong */
192
/* 0, 1, 1 => all bonds 1, no init radical on metal */
193
/* 1, 0, 1 => min bond order 1, all bonds to metal have order 1 */
194
/* 1, 1, 0 => wrong */
195
/* 1, 1, 1 => wrong */
196
pSrm->nMetalMinBondOrder = 0;
197
pSrm->nMetalInitEdgeFlow = 1;
198
pSrm->nMetalInitBondOrder = 1;
199
pSrm->bStereoRemovesMetalFlag = pSrm->bFixStereoBonds;
200
pSrm->nMetalFlowerParam_D = 16;
201
pSrm->nMetalMaxCharge_D = 16;
203
pSrm->bMetalAddFlower = 0;
204
pSrm->nMetalMinBondOrder = 1;
205
pSrm->nMetalInitEdgeFlow = 0;
206
pSrm->nMetalInitBondOrder = 1;
207
pSrm->bStereoRemovesMetalFlag = pSrm->bFixStereoBonds;
208
pSrm->nMetalFlowerParam_D = 16;
209
pSrm->nMetalMaxCharge_D = 0;
212
pSrm->nMetalInitBondOrder = pSrm->nMetalMinBondOrder
213
+ pSrm->nMetalInitEdgeFlow;
215
pSrm->nMetal2EndpointInitBondOrder = pSrm->nMetal2EndpointMinBondOrder
216
+ pSrm->nMetal2EndpointInitEdgeFlow;
219
/**************************************************************************************/
220
int MergeStructureComponents( ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd, long num_inp, char *szCurHdr,
221
ICHICONST SRM *pSrm, int bReqNonTaut, StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM],
222
InpInChI *pOneInput )
224
int iInchiRec, iMobileH, iAlternH, num_components, tot_just_atoms, tot_removed_H, tot_atoms, cur_nA, cur_nH;
225
int k, i, j, ret, iCurAtomOffs, iNxtAtomOffs, iCurDelHOffs, iNxtDelHOffs, len, len2, iShiftH, icomp;
226
int *nAtomOffs=NULL, *nDelHOffs=NULL;
227
StrFromINChI *pStruct1;
228
inp_ATOM *at=NULL, *a;
231
pOneInput->num_atoms = 0;
232
/* select highest detail level */
233
if ( num_components = pOneInput->nNumComponents[INCHI_REC][TAUT_NON] ) {
234
iInchiRec = INCHI_REC;
237
if ( num_components = pOneInput->nNumComponents[INCHI_REC][TAUT_YES] ) {
238
iInchiRec = INCHI_REC;
241
if ( num_components = pOneInput->nNumComponents[INCHI_BAS][TAUT_NON] ) {
242
iInchiRec = INCHI_BAS;
245
if ( num_components = pOneInput->nNumComponents[INCHI_BAS][TAUT_YES] ) {
246
iInchiRec = INCHI_BAS;
249
return 0; /* no components available */
252
nAtomOffs = (int*)inchi_malloc((num_components+1) * sizeof(nAtomOffs[0]));
253
nDelHOffs = (int*)inchi_malloc((num_components+1) * sizeof(nDelHOffs[0]));
254
if ( !nAtomOffs || !nDelHOffs ) {
258
/* count number of atoms and removed H */
259
tot_just_atoms = tot_removed_H = tot_atoms = 0;
260
iAlternH = (iMobileH==TAUT_NON && pOneInput->nNumComponents[iInchiRec][TAUT_YES])? TAUT_YES : -1;
261
nAtomOffs[0] = nDelHOffs[0] = 0;
262
for ( k = 0; k < num_components; k ++ ) {
263
pStruct1 = pStruct[iInchiRec][iMobileH][k].num_atoms? pStruct[iInchiRec][iMobileH]+k :
265
pStruct[iInchiRec][iAlternH][k].num_atoms? pStruct[iInchiRec][iAlternH]+k : NULL;
266
if ( !pStruct1 || !pStruct1->at2 || !pStruct1->num_atoms || pStruct1->bDeleted ) {
269
cur_nA = pStruct1->num_atoms;
270
cur_nH = pStruct1->num_deleted_H;
272
nAtomOffs[k+1] = nAtomOffs[k] + cur_nA;
273
nDelHOffs[k+1] = nDelHOffs[k] + cur_nH;
275
tot_just_atoms = nAtomOffs[num_components];
276
/* shift all H to the end */
277
for ( k = 0; k <= num_components; k ++ ) {
278
nDelHOffs[k] += tot_just_atoms;
280
tot_atoms = nDelHOffs[num_components];
282
/* merge atoms together: 1. Allocate */
283
if ( NULL == (at = (inp_ATOM *)inchi_malloc( (tot_atoms+1) * sizeof(at[0]) ) ) ) {
289
goto exit_function; /* empty structure */
291
/* merge atoms together: 2. Copy */
292
for ( k = 0; k < num_components; k ++ ) {
293
pStruct1 = pStruct[iInchiRec][iMobileH][k].num_atoms? pStruct[iInchiRec][iMobileH]+k :
295
pStruct[iInchiRec][iAlternH][k].num_atoms? pStruct[iInchiRec][iAlternH]+k : NULL;
296
if ( len = nAtomOffs[k+1] - nAtomOffs[k] ) {
297
memcpy( at + nAtomOffs[k], pStruct1->at2, len * sizeof(at[0]) );
298
if ( len2 = nDelHOffs[k+1] - nDelHOffs[k] ) {
299
memcpy( at + nDelHOffs[k], pStruct1->at2+len, len2 * sizeof(at[0]) );
303
/* merge atoms together: 3. Update atom numbers */
305
for ( k = 0; k < num_components; k ++ ) {
306
iCurAtomOffs = nAtomOffs[k];
307
iNxtAtomOffs = nAtomOffs[k+1];
308
iCurDelHOffs = nDelHOffs[k];
309
iNxtDelHOffs = nDelHOffs[k+1];
310
len = nAtomOffs[k+1] - nAtomOffs[k]; /* number of atoms in a component excluding explicit H */
311
iShiftH = iCurDelHOffs - len;
315
icomp ++; /* current component number */
317
for ( i = iCurAtomOffs; i < iNxtAtomOffs; i ++ ) {
322
a->bAmbiguousStereo = 0;
325
a->bUsed0DParity = 0;
328
a->nNumAtInRingSystem = 0;
331
for ( j = 0; j < a->valence; j ++ ) {
332
if ( a->neighbor[j] < len ) {
333
a->neighbor[j] += iCurAtomOffs; /* atom */
335
a->neighbor[j] += iShiftH; /* explicit H */
338
a->orig_at_number += iCurAtomOffs;
339
a->component = icomp;
341
for ( j = 0; j < MAX_NUM_STEREO_ATOM_NEIGH; j ++ ) {
342
if ( a->p_orig_at_num[j] <= len ) {
343
/* originally, orig_at_num = atom_index+1, therefore <= instead of < */
344
a->p_orig_at_num[j] += iCurAtomOffs;
346
a->p_orig_at_num[j] += iShiftH;
350
for ( j = 0; j < MAX_NUM_STEREO_BONDS && a->sb_parity[j]; j ++ ) {
351
if ( a->sn_orig_at_num[j] <= len ) {
352
/* originally, orig_at_num = atom_index+1, therefore <= instead of < */
353
a->sn_orig_at_num[j] += iCurAtomOffs;
355
a->sn_orig_at_num[j] += iShiftH;
360
for ( i = iCurDelHOffs; i < iNxtDelHOffs; i ++ ) {
362
a->neighbor[0] += iCurAtomOffs;
363
a->orig_at_number += iShiftH;
367
/* save the results */
368
pOneInput->atom = at;
369
pOneInput->num_atoms = tot_atoms;
373
if ( at ) inchi_free( at ); /* in case of failure */
374
if ( nAtomOffs ) inchi_free( nAtomOffs );
375
if ( nDelHOffs ) inchi_free( nDelHOffs );
378
#ifndef INCHI_ANSI_ONLY
379
static PER_DRAW_PARMS pdp;
380
/******************************************************************************************************/
381
int DisplayAllRestoredComponents( inp_ATOM *at, int num_at, const char *szCurHdr )
390
memset( &dp, 0, sizeof(dp));
391
memset( &tdp, 0, sizeof(tdp) );
392
//memset( &pdp, 0, sizeof(pdp) );
395
dp.sdp.nFontSize = -9;
396
sprintf( szTitle, "All Components of Restored %s Structure", szCurHdr? szCurHdr : "(No structure name)");
397
ret = DisplayStructure( at, num_at, 0 /* nNumDeletedH*/, 0 /*bAdd_DT_to_num_H*/,
398
0 /*nNumRemovedProtons*/, NULL /*NUM_H *nNumRemovedProtonsIsotopic*/,
399
1 /*int bIsotopic*/, 0 /*bTautomeric*/,
400
NULL /* pINChI */, NULL /* INChI_Aux **cur_INChI_Aux*/,
401
0 /*bAbcNumbers*/, &dp, 0 /*INCHI_MODE nMode*/, szTitle );
404
/******************************************************************************************************/
405
int DisplayOneRestoredComponent( StrFromINChI *pStruct, inp_ATOM *at,
406
int iComponent, int nNumComponents, int bMobileH,
407
const char *szCurHdr )
410
int num_at = pStruct->num_atoms;
411
XYZ_COORD *pxyz = pStruct->pXYZ;
415
int iInchiRec = pStruct->iInchiRec;
416
int iMobileH = pStruct->iMobileH;
417
INChI **pInChI = NULL;
418
INChI_Aux **pAux = NULL;
419
int nNumRemovedProtons = pAux? pAux[iMobileH]->nNumRemovedProtons : 0;
420
NUM_H *nNumRemovedProtonsIsotopic = pAux? pAux[iMobileH]->nNumRemovedIsotopicH : NULL;
423
if ( num_at <= 0 || !pxyz ) {
426
if ( iInchiRec && !pStruct->RevInChI.pINChI_Aux[iInchiRec][0] ) {
430
if ( !bRevInchiComponentExists( pStruct, iInchiRec, k, 0 ) ) {
433
pInChI = pStruct->RevInChI.pINChI[iInchiRec][0];
434
pAux = pStruct->RevInChI.pINChI_Aux[iInchiRec][0];
437
memset( &dp, 0, sizeof(dp));
438
memset( &tdp, 0, sizeof(tdp) );
439
//memset( &pdp, 0, sizeof(pdp) );
442
dp.sdp.nFontSize = -9;
443
sprintf( szTitle, "Restored %s Component %d of %d %c%c",
444
szCurHdr? szCurHdr : "(No structure name)", iComponent+1, nNumComponents,
445
pStruct->iInchiRec? 'R':'D', pStruct->iMobileH?'M':'F' );
446
ret = DisplayStructure( at, num_at, 0 /* nNumDeletedH*/, 0 /*bAdd_DT_to_num_H*/,
447
nNumRemovedProtons, /*NULL*/ nNumRemovedProtonsIsotopic,
448
1 /*int bIsotopic*/, k,
450
0 /*bAbcNumbers*/, &dp, 0 /*INCHI_MODE nMode*/, szTitle );
453
/******************************************************************************************************/
454
int DisplayRestoredComponent( StrFromINChI *pStruct, int iComponent, int iAtNoOffset, INChI *pInChI, const char *szCurHdr )
457
int num_at = pStruct->num_atoms;
458
int num_deleted_H = pStruct->num_deleted_H;
459
inp_ATOM *atom = pStruct->at2;
460
XYZ_COORD *pxyz = pStruct->pXYZ;
465
if ( !atom || num_at <= 0 || !pxyz ) {
468
at = (inp_ATOM *)inchi_calloc( num_at + num_deleted_H, sizeof(at[0]) );
472
memcpy( at, atom, (num_at + num_deleted_H) * sizeof(at[0]) );
473
for ( i = 0; i < num_at; i ++ ) {
474
at[i].x = pxyz[i].xyz[0];
475
at[i].y = pxyz[i].xyz[1];
476
at[i].z = pxyz[i].xyz[2];
478
memset( &dp, 0, sizeof(dp));
479
memset( &tdp, 0, sizeof(tdp) );
480
//memset( &pdp, 0, sizeof(pdp) );
483
dp.sdp.nFontSize = -9;
484
sprintf( szTitle, "DBG Restored %s Component %d %c%c", szCurHdr? szCurHdr : "(No structure name)", iComponent+1, pStruct->iInchiRec? 'R':'D', pStruct->iMobileH?'M':'F' );
485
ret = DisplayStructure( at, num_at, 0 /* nNumDeletedH*/, 0 /*bAdd_DT_to_num_H*/,
486
0 /*nNumRemovedProtons*/, NULL /*NUM_H *nNumRemovedProtonsIsotopic*/,
487
1 /*int bIsotopic*/, 0 /*bTautomeric*/,
488
&pInChI, NULL /* INChI_Aux **cur_INChI_Aux*/,
489
0 /*bAbcNumbers*/, &dp, 0 /*INCHI_MODE nMode*/, szTitle );
493
/**************************************************************************************/
494
int DisplayStructureComponents( ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd, long num_inp, char *szCurHdr,
495
ICHICONST SRM *pSrm, int bReqNonTaut, StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM],
496
InpInChI *pOneInput )
498
int iInchiRec, iMobileH, iCurMobH, iAlternH, num_components, tot_just_atoms, tot_removed_H, tot_atoms, cur_nA, cur_nH;
499
int k, i, j, ret, iCurAtomOffs, iNxtAtomOffs, iCurDelHOffs, iNxtDelHOffs, len, len2, iShiftH, icomp;
500
int *nAtomOffs=NULL, *nDelHOffs=NULL, bNoCoord=0, iNewCoord=0, nNewCoord=0;
501
double x_max=-1.0e16, x_min = 1.0e16, y_max=-1.0e16, y_min=1.0e16, delta = 0.0;
502
StrFromINChI *pStruct1;
503
inp_ATOM *at=NULL, *a;
505
if (!ip->bDisplayCompositeResults && !ip->bDisplay ) {
510
pOneInput->num_atoms = 0;
511
/* select highest detail level */
512
if ( num_components = pOneInput->nNumComponents[INCHI_REC][TAUT_NON] ) {
513
iInchiRec = INCHI_REC;
516
if ( num_components = pOneInput->nNumComponents[INCHI_REC][TAUT_YES] ) {
517
iInchiRec = INCHI_REC;
520
if ( num_components = pOneInput->nNumComponents[INCHI_BAS][TAUT_NON] ) {
521
iInchiRec = INCHI_BAS;
524
if ( num_components = pOneInput->nNumComponents[INCHI_BAS][TAUT_YES] ) {
525
iInchiRec = INCHI_BAS;
528
return 0; /* no components available */
530
for ( k = 0; k < num_components; k ++ ) {
531
if ( pStruct[iInchiRec][iMobileH][k].bDeleted )
536
nAtomOffs = (int*)inchi_malloc((num_components+1) * sizeof(nAtomOffs[0]));
537
nDelHOffs = (int*)inchi_malloc((num_components+1) * sizeof(nDelHOffs[0]));
538
if ( !nAtomOffs || !nDelHOffs ) {
542
/* count number of atoms and removed H */
543
tot_just_atoms = tot_removed_H = tot_atoms = 0;
544
iAlternH = (iMobileH==TAUT_NON && pOneInput->nNumComponents[iInchiRec][TAUT_YES])? TAUT_YES : -1;
545
nAtomOffs[0] = nDelHOffs[0] = 0;
546
for ( k = 0; k < num_components; k ++ ) {
547
pStruct1 = pStruct[iInchiRec][iMobileH][k].num_atoms? pStruct[iInchiRec][iMobileH]+k :
549
pStruct[iInchiRec][iAlternH][k].num_atoms? pStruct[iInchiRec][iAlternH]+k : NULL;
550
if ( !pStruct1 || !pStruct1->at2 || !pStruct1->num_atoms ) {
553
cur_nA = pStruct1->num_atoms;
554
cur_nH = pStruct1->num_deleted_H;
555
if ( cur_nA && !pStruct1->pXYZ ) {
557
ret = 0; /* no coordinates available */
564
nAtomOffs[k+1] = nAtomOffs[k] + cur_nA;
565
nDelHOffs[k+1] = nDelHOffs[k] + cur_nH;
567
tot_just_atoms = nAtomOffs[num_components];
568
/* shift all H to the end */
569
for ( k = 0; k <= num_components; k ++ ) {
570
nDelHOffs[k] += tot_just_atoms;
572
tot_atoms = nDelHOffs[num_components];
574
/* merge atoms together: 1. Allocate */
575
if ( NULL == (at = (inp_ATOM *)inchi_malloc( (tot_atoms+1) * sizeof(at[0]) ) ) ) {
581
goto exit_function; /* empty structure */
583
/* merge atoms together: 2. Copy */
584
for ( k = 0; k < num_components; k ++ ) {
585
pStruct1 = pStruct[iInchiRec][iMobileH][k].num_atoms? pStruct[iInchiRec][iCurMobH=iMobileH]+k :
587
pStruct[iInchiRec][iAlternH][k].num_atoms? pStruct[iInchiRec][iCurMobH=iAlternH]+k : NULL;
588
if ( len = nAtomOffs[k+1] - nAtomOffs[k] ) {
589
XYZ_COORD *pxyz = pStruct1->pXYZ;
590
len2 = nDelHOffs[k+1] - nDelHOffs[k]; /* do not separate H from the atom: we will not need them */
591
iCurAtomOffs = nAtomOffs[k];
592
a = at + iCurAtomOffs;
593
memcpy( a, pStruct1->at2, (len+len2) * sizeof(at[0]) );
594
DisconnectedConnectedH( a, len, len2 );
596
for ( i = 0; i < len; i ++ ) {
597
a[i].x = pxyz[i].xyz[0];
598
x_max = inchi_max( x_max, pxyz[i].xyz[0] );
599
x_min = inchi_min( x_min, pxyz[i].xyz[0] );
600
a[i].y = pxyz[i].xyz[1];
601
y_max = inchi_max( y_max, pxyz[i].xyz[1] );
602
y_min = inchi_min( y_min, pxyz[i].xyz[1] );
603
a[i].z = pxyz[i].xyz[2];
610
goto exit_function; /* empty structure */
612
delta = inchi_max(x_max - x_min, y_max - y_min);
613
if ( delta == 0.0 ) {
614
delta = 0.5 * (x_max+x_min);
618
delta /= sqrt( (double)(nNewCoord+1) );
621
for ( i = 0; i < len; i ++ ) {
622
a[i].x = x_max + delta;
623
a[i].y = y_max - iNewCoord * delta;
627
if ( pStruct1->pXYZ = (XYZ_COORD *)inchi_calloc(len, sizeof(pStruct1->pXYZ[0]) ) ) {
629
for ( i = 0; i < len; i ++ ) {
630
pStruct1->pXYZ[i].xyz[0] = a[i].x;
631
pStruct1->pXYZ[i].xyz[1] = a[i].y;
632
pStruct1->pXYZ[i].xyz[2] = 0.0;
636
if ( ip->bDisplay || ip->bDisplayCompositeResults && 1 == num_components ) {
637
DisplayOneRestoredComponent( pStruct1, a, k, num_components, iCurMobH, szCurHdr );
639
if ( !pxyz && pStruct1->pXYZ ) {
640
inchi_free( pStruct1->pXYZ );
641
pStruct1->pXYZ = NULL;
645
/* merge atoms together: 3. Update atom numbers */
647
if ( ip->bDisplayCompositeResults && num_components > 1 ) {
648
for ( k = 0; k < num_components; k ++ ) {
649
/* display each restored component if requested */
650
iCurAtomOffs = nAtomOffs[k];
651
iNxtAtomOffs = nAtomOffs[k+1];
652
iCurDelHOffs = nDelHOffs[k];
653
iNxtDelHOffs = nDelHOffs[k+1];
654
len = nAtomOffs[k+1] - nAtomOffs[k]; /* number of atoms in a component excluding explicit H */
655
iShiftH = iCurDelHOffs - len;
659
icomp ++; /* current component number */
661
for ( i = iCurAtomOffs; i < iNxtAtomOffs; i ++ ) {
663
for ( j = 0; j < a->valence; j ++ ) {
664
if ( a->neighbor[j] < len ) {
665
a->neighbor[j] += iCurAtomOffs; /* atom */
667
ret = RI_ERR_PROGR; /* explicit H */
671
a->orig_at_number += iCurAtomOffs;
674
tot_atoms = nAtomOffs[num_components];
675
DisplayAllRestoredComponents( at, tot_atoms, szCurHdr );
680
if ( at ) inchi_free( at ); /* in case of failure */
681
if ( nAtomOffs ) inchi_free( nAtomOffs );
682
if ( nDelHOffs ) inchi_free( nDelHOffs );
686
/**************************************************************************************/
687
int AllInchiToStructure( ICHICONST INPUT_PARMS *ip_inp, STRUCT_DATA *sd_inp, long num_inp, char *szCurHdr,
688
ICHICONST SRM *pSrm, int bHasSomeFixedH, StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM],
689
InpInChI *pOneInput )
691
int iInchiRec, iMobileH, cur_num_comp, bCurI2A_Flag, k, ret, num_err;
692
INPUT_PARMS *ip, ip_loc;
693
STRUCT_DATA *sd, sd_loc;
694
long ulProcessingTime = 0;
697
InchiTimeGet( &ulTStart );
701
memset( sd, 0, sizeof(*sd));
702
sd->ulStructTime = sd_inp->ulStructTime;
705
for ( iInchiRec = 0; iInchiRec < INCHI_NUM; iInchiRec ++ ) { /* Disconnected/Connected */
706
for ( iMobileH = 0; iMobileH < TAUT_NUM; iMobileH ++ ) { /* Mobile/Fixed H */
707
cur_num_comp = pOneInput->nNumComponents[iInchiRec][iMobileH];
708
if ( !cur_num_comp ) {
711
/* allocate memory for all existing components */
712
pStruct[iInchiRec][iMobileH] = (StrFromINChI *)inchi_calloc( cur_num_comp, sizeof(pStruct[0][0][0]));
713
if ( !pStruct[iInchiRec][iMobileH] ) {
717
/* set conversion mode */
718
bCurI2A_Flag = (iMobileH? 0: I2A_FLAG_FIXEDH) | (iInchiRec? I2A_FLAG_RECMET : 0);
720
ip->nMode &= ~REQ_MODE_BASIC;
722
ip->nMode |= REQ_MODE_BASIC;
724
/* InChI --> structure conversion for all components except duplicated */
725
for ( k = 0; k < cur_num_comp; k ++ ) { /* components */
726
if ( !iMobileH && !pOneInput->pInpInChI[iInchiRec][iMobileH][k].nNumberOfAtoms ||
727
pOneInput->pInpInChI[iInchiRec][iMobileH][k].bDeleted ||
728
pOneInput->pInpInChI[iInchiRec][iMobileH][k].nLink < 0 ) {
730
pStruct[iInchiRec][iMobileH][k].nLink = pOneInput->pInpInChI[iInchiRec][iMobileH][k].nLink;
731
pStruct[iInchiRec][iMobileH][k].bDeleted = pOneInput->pInpInChI[iInchiRec][iMobileH][k].bDeleted;
732
continue; /* do not create a structure out of an unavailable
733
Fixed-H InChI or out of the one present in Reconnected layer */
734
#ifdef NEVER /* a wrong attempt to process deleted components here */
735
if ( pStruct[iInchiRec][iMobileH][k].nLink = pOneInput->pInpInChI[iInchiRec][iMobileH][k].nLink ) {
736
continue; /* do not create a structure out of an unavailable
737
Fixed-H InChI or out of the one present in Reconnected layer */
739
if ( iMobileH && pOneInput->pInpInChI[iInchiRec][iMobileH][k].nNumberOfAtoms &&
740
pOneInput->pInpInChI[iInchiRec][iMobileH][k].bDeleted &&
741
pOneInput->pInpInChI[iInchiRec][iMobileH][0].bDeleted ) {
742
/* all components are protons */
749
if ( bHasSomeFixedH && iMobileH && k < pOneInput->nNumComponents[iInchiRec][TAUT_NON] &&
750
pOneInput->pInpInChI[iInchiRec][TAUT_NON][k].nNumberOfAtoms ) {
751
continue; /* do not process Mobile-H if Fixed-H is requested and exists */
753
pStruct[iInchiRec][iMobileH][k].pSrm = pSrm;
754
pStruct[iInchiRec][iMobileH][k].iInchiRec = iInchiRec;
755
pStruct[iInchiRec][iMobileH][k].iMobileH = iMobileH;
757
/****************************************************/
759
/* Convert InChI of one component into a Structure */
761
/****************************************************/
763
ret = InChI2Atom( ip, sd, szCurHdr, num_inp, pStruct[iInchiRec][iMobileH]+k, k,
764
0 /* AtNoOffset*/, bCurI2A_Flag, bHasSomeFixedH, pOneInput );
765
pStruct[iInchiRec][iMobileH][k].nLink = pOneInput->pInpInChI[iInchiRec][iMobileH][k].nLink;
767
#if( bRELEASE_VERSION != 1 )
768
#ifndef INCHI_LIBRARY
769
/* !!! Conversion Error -- Ignore for now !!! */
770
fprintf( stdout, "%ld %s Conversion failed: %d, %c%c comp %d\n",
771
num_inp, szCurHdr? szCurHdr : "Struct", ret, iInchiRec? 'R':'D', iMobileH? 'M':'F', k+1);
774
if ( ret == CT_USER_QUIT_ERR ) {
777
pStruct[iInchiRec][iMobileH][k].nError = ret;
778
ret = 0; /* force to ignore the errors for now !!!! */
785
ulProcessingTime += InchiTimeElapsed( &ulTStart );
786
sd->ulStructTime += ulProcessingTime;
787
return ret<0? ret : num_err;
789
/**************************************************************************************/
790
int AddProtonAndIsoHBalanceToMobHStruct( ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd,
791
long num_inp, int bHasSomeFixedH, char *szCurHdr,
792
StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM], InpInChI *pOneInput)
794
COMPONENT_REM_PROTONS nToBeRemovedByNormFromRevrs[INCHI_NUM];
795
int nRemovedByNormFromRevrs[INCHI_NUM];
796
int nRemovedByRevrs[INCHI_NUM];
798
int nDeltaFromDisconnected = 0, nRemovedProtonsByNormFromRevrs, nRemovedProtonsByRevrs, num_changes = 0;
799
NUM_H nIsoDeltaFromDisconnected[NUM_H_ISOTOPES];
800
int iInchiRec, i, k, k1, ret = 0;
801
int nChargeInChI, nChargeRevrs;
803
if ( bHasSomeFixedH ) {
804
return 0; /* 2005-03-01 */
807
/* num protons removed by InChI Normalization from the original structure */
808
for ( i = 0; i < INCHI_NUM; i ++ ) {
809
nToBeRemovedByNormFromRevrs[i].nNumRemovedProtons = pOneInput->nNumProtons[i][TAUT_YES].nNumRemovedProtons;
810
for ( k = 0; k < NUM_H_ISOTOPES; k ++ ) {
811
nToBeRemovedByNormFromRevrs[i].nNumRemovedIsotopicH[k] = pOneInput->nNumProtons[i][TAUT_YES].nNumRemovedIsotopicH[k];
814
/* accumulate here num. protons removed by the normalization from the reversed structure */
815
nRemovedByNormFromRevrs[INCHI_BAS] =
816
nRemovedByNormFromRevrs[INCHI_REC] = 0;
817
nRemovedByRevrs[INCHI_REC] =
818
nRemovedByRevrs[INCHI_BAS] = 0;
819
/* protons added/removed by InChI Normalization to/from Restored Structure might have been added by StructureRestore */
820
for ( iInchiRec = 0; iInchiRec < INCHI_NUM; iInchiRec ++ ) {
821
for ( k = 0; k < pOneInput->nNumComponents[iInchiRec][TAUT_YES]; k ++ ) {
822
if ( !bInpInchiComponentExists( pOneInput, iInchiRec, TAUT_YES, k ) ) {
825
nRemovedProtonsByNormFromRevrs = 0; /* Num protons removed from the Restored Structure by InChI Normalization */
826
nRemovedProtonsByRevrs = 0; /* Num protons removed by the Reconstruction from the Restored Structure */
827
if ( iInchiRec == INCHI_REC || iInchiRec == INCHI_BAS && (k1=pStruct[iInchiRec][TAUT_YES][k].nLink) >= 0 ) {
829
REV_INCHI *pRevInChI = &pStruct[iInchiRec][TAUT_YES][k].RevInChI;
830
INChI_Aux **pINChI_Aux2 = pRevInChI->pINChI_Aux[iInchiRec][0]; /* component 0*/
831
INChI **pINChI_Revr = pRevInChI->pINChI[iInchiRec][0];
832
INChI *pINChI_Orig = pOneInput->pInpInChI[iInchiRec][TAUT_YES]+k;
833
nChargeRevrs = pINChI_Revr? pINChI_Revr[TAUT_YES]->nTotalCharge : NO_VALUE_INT;
834
nChargeInChI = pINChI_Orig->nTotalCharge;
836
nRemovedProtonsByNormFromRevrs = pINChI_Aux2[TAUT_YES]->nNumRemovedProtons;
838
nRemovedProtonsByRevrs = pStruct[iInchiRec][TAUT_YES][k].nNumRemovedProtonsByRevrs;
839
pStruct[iInchiRec][TAUT_YES][k].nChargeRevrs = nChargeRevrs;
840
pStruct[iInchiRec][TAUT_YES][k].nChargeInChI = nChargeInChI;
842
if ( 0 <= ( k1 = -(1+pStruct[iInchiRec][TAUT_YES][k].nLink) ) ) {
843
REV_INCHI *pRevInChI = &pStruct[INCHI_REC][TAUT_YES][k1].RevInChI;
844
INChI_Aux **pINChI_Aux2 = pRevInChI->pINChI_Aux[INCHI_BAS][0]; /* component 0 */
845
INChI **pINChI_Revr = pRevInChI->pINChI[INCHI_BAS][0];
846
INChI *pINChI_Orig = pOneInput->pInpInChI[INCHI_REC][TAUT_YES]+k1;
847
nChargeRevrs = pINChI_Revr? pINChI_Revr[TAUT_YES]->nTotalCharge : NO_VALUE_INT;
848
nChargeInChI = pINChI_Orig->nTotalCharge;
850
nRemovedProtonsByNormFromRevrs = pINChI_Aux2[TAUT_YES]->nNumRemovedProtons;
852
/* this component cannot be disconnected because it is same as in reconnected layer */
853
nRemovedProtonsByRevrs = pStruct[INCHI_REC][TAUT_YES][k1].nNumRemovedProtonsByRevrs;
854
pStruct[iInchiRec][TAUT_YES][k1].nChargeRevrs = nChargeRevrs;
855
pStruct[iInchiRec][TAUT_YES][k1].nChargeInChI = nChargeInChI;
857
/* how many protons (to be removed by InChI Normalization) to add =
858
(proton balance in InChI} -
859
{number of protons known to be removed by InChI Normalization from Reconstructed structure} */
860
nToBeRemovedByNormFromRevrs[iInchiRec].nNumRemovedProtons -= nRemovedProtonsByNormFromRevrs;
861
nRemovedByNormFromRevrs[iInchiRec] += nRemovedProtonsByNormFromRevrs;
862
nRemovedByRevrs[iInchiRec] += nRemovedProtonsByRevrs;
863
pStruct[iInchiRec][TAUT_YES][k].nRemovedProtonsByNormFromRevrs = nRemovedProtonsByNormFromRevrs;
867
/* Since fixed-H layer is missing we need to add proton balance to the components */
868
memset( nIsoDeltaFromDisconnected, 0, sizeof(nIsoDeltaFromDisconnected) );
869
for ( iInchiRec = INCHI_REC; INCHI_BAS <= iInchiRec; iInchiRec -- ) {
871
if ( !pOneInput->nNumComponents[iInchiRec][TAUT_NON] &&
872
pOneInput->nNumComponents[iInchiRec][TAUT_YES] ) {
874
int bHasRecMobH = (iInchiRec==INCHI_BAS && pOneInput->nNumComponents[INCHI_REC][TAUT_YES]);
875
/* bHasRecMobH means all components that could not be disconnected are in reconnected part */
876
if ( iInchiRec==INCHI_BAS ) {
877
/* second pass: common structures have been changed */
878
nToBeRemovedByNormFromRevrs[INCHI_BAS].nNumRemovedProtons += nDeltaFromDisconnected;
880
/* after proton removal InChI is recalculated */
882
ret = AddRemProtonsInRestrStruct( ip, sd, num_inp, bHasSomeFixedH, pStruct[iInchiRec][TAUT_YES],
883
pOneInput->nNumComponents[iInchiRec][TAUT_YES],
884
bHasRecMobH? pStruct[INCHI_REC][TAUT_YES] : NULL,
885
bHasRecMobH? pOneInput->nNumComponents[INCHI_REC][TAUT_YES]:0,
886
&nToBeRemovedByNormFromRevrs[iInchiRec].nNumRemovedProtons,
887
(iInchiRec==INCHI_REC)?&nDeltaFromDisconnected : NULL);
896
/* if fixed-H layer is missing then we need to add isotopic exchangeable proton balance to the components */
897
for ( iInchiRec = INCHI_REC; INCHI_BAS <= iInchiRec; iInchiRec -- ) {
899
if ( !pOneInput->nNumComponents[iInchiRec][TAUT_NON] &&
900
pOneInput->nNumComponents[iInchiRec][TAUT_YES] ) {
902
int bHasRecMobH = (iInchiRec==INCHI_BAS && pOneInput->nNumComponents[INCHI_REC][TAUT_YES]);
903
/* bHasRecMobH means all components that could not be disconnected are in reconnected part */
904
if ( iInchiRec==INCHI_BAS ) {
905
/* second pass: common structures have been changed */
906
for ( k = 0; k < NUM_H_ISOTOPES; k ++ ) {
907
nToBeRemovedByNormFromRevrs[INCHI_BAS].nNumRemovedIsotopicH[k] += nIsoDeltaFromDisconnected[k];
910
/* after proton removal InChI is recalculated */
911
ret = AddRemIsoProtonsInRestrStruct( ip, sd, num_inp, bHasSomeFixedH, pStruct[iInchiRec][TAUT_YES],
912
pOneInput->nNumComponents[iInchiRec][TAUT_YES],
913
bHasRecMobH? pStruct[INCHI_REC][TAUT_YES] : NULL,
914
bHasRecMobH? pOneInput->nNumComponents[INCHI_REC][TAUT_YES]:0,
915
nToBeRemovedByNormFromRevrs[iInchiRec].nNumRemovedIsotopicH,
916
(iInchiRec==INCHI_REC)?nIsoDeltaFromDisconnected : NULL);
930
/*************************************************************/
931
void FreeStrFromINChI( StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM], int nNumComponents[INCHI_NUM][TAUT_NUM] )
933
int iInchiRec, iMobileH, cur_num_comp, k, j;
934
StrFromINChI *pStruct1;
935
for ( iInchiRec = 0; iInchiRec < INCHI_NUM; iInchiRec ++ ) {
936
for ( iMobileH = 0; iMobileH < TAUT_NUM; iMobileH ++ ) {
937
cur_num_comp = nNumComponents[iInchiRec][iMobileH];
938
if ( !cur_num_comp || !(pStruct1=pStruct[iInchiRec][iMobileH]) ) {
941
for ( k = 0; k < cur_num_comp; k ++ ) {
942
if ( pStruct1[k].at ) {
943
inchi_free(pStruct1[k].at);
945
if ( pStruct1[k].at2 ) {
946
inchi_free(pStruct1[k].at2);
948
if ( pStruct1[k].st ) {
949
inchi_free(pStruct1[k].st);
951
if ( pStruct1[k].pVA ) {
952
inchi_free(pStruct1[k].pVA);
955
if ( pStruct1[k].ti.t_group ) {
956
inchi_free( pStruct1[k].ti.t_group );
959
if ( pStruct1[k].pXYZ ) {
960
inchi_free(pStruct1[k].pXYZ);
963
free_t_group_info( &pStruct1[k].ti );
964
if ( pStruct1[k].endpoint ) {
965
inchi_free(pStruct1[k].endpoint);
967
if ( pStruct1[k].fixed_H ) {
968
inchi_free(pStruct1[k].fixed_H);
970
for ( j = 0; j < TAUT_NUM; j ++ ) {
971
if ( pStruct1[k].nAtno2Canon[j] )
972
inchi_free( pStruct1[k].nAtno2Canon[j] );
973
if ( pStruct1[k].nCanon2Atno[j] )
974
inchi_free( pStruct1[k].nCanon2Atno[j] );
977
/* free INChI memory */
978
FreeAllINChIArrays( pStruct1[k].RevInChI.pINChI,
979
pStruct1[k].RevInChI.pINChI_Aux,
980
pStruct1[k].RevInChI.num_components );
982
/* don't do that: these are just pointers to OneInput structure members */
983
Free_INChI( &pStruct1[k].pINChI );
984
Free_INChI_Aux( &pStruct1[k].pINChI_Aux );
985
if ( pStruct1[k].inp_norm_data ) {
986
FreeInpAtomData( pStruct1[k].inp_norm_data );
987
inchi_free( pStruct1[k].inp_norm_data );
991
inchi_free(pStruct[iInchiRec][iMobileH]);
992
pStruct[iInchiRec][iMobileH] = NULL;
996
/********************************************************************/
997
void FreeInpInChI( InpInChI *pOneInput )
1000
for ( iINChI = 0; iINChI < INCHI_NUM; iINChI ++ ) {
1001
for ( j = 0; j < TAUT_NUM; j ++ ) {
1002
if ( pOneInput->pInpInChI[iINChI][j] ) {
1003
for ( k = 0; k < pOneInput->nNumComponents[iINChI][j]; k ++ ) {
1004
Free_INChI_Members( &pOneInput->pInpInChI[iINChI][j][k] );
1006
inchi_free(pOneInput->pInpInChI[iINChI][j]);
1007
pOneInput->pInpInChI[iINChI][j] = NULL;
1009
if ( pOneInput->nNumProtons[iINChI][j].pNumProtons ) {
1010
inchi_free( pOneInput->nNumProtons[iINChI][j].pNumProtons );
1011
pOneInput->nNumProtons[iINChI][j].pNumProtons = NULL;
1015
if ( pOneInput->atom ) inchi_free(pOneInput->atom);
1016
memset( pOneInput, 0, sizeof(*pOneInput) );
1019
/***********************************************************************************************/
1020
int CompareAllOrigInchiToRevInChI(StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM], InpInChI *pOneInput, int bReqNonTaut,
1021
long num_inp, char *szCurHdr)
1023
int i, iInchiRec, iMobileH, iMobileHpStruct, num_components, iComponent, ret=0;
1024
COMPONENT_REM_PROTONS nCurRemovedProtons, nNumRemovedProtons;
1025
INChI *pInChI[TAUT_NUM];
1026
INCHI_MODE CompareInchiFlags[TAUT_NUM];
1027
memset( pOneInput->CompareInchiFlags[0], 0, sizeof(pOneInput->CompareInchiFlags[0]) );
1028
memset( &nNumRemovedProtons, 0, sizeof(nNumRemovedProtons) );
1030
/* do we have reconnected InChI ?*/
1031
iInchiRec = INCHI_REC;
1032
iMobileH = TAUT_NON;
1033
if ( !pOneInput->nNumComponents[iInchiRec][TAUT_YES] && !pOneInput->nNumComponents[iInchiRec][TAUT_NON] ) {
1034
iInchiRec = INCHI_BAS;
1036
/* do we have Mobile or Fixed-H ? */
1037
if ( !pOneInput->nNumComponents[iInchiRec][TAUT_NON] || !bReqNonTaut ) {
1038
iMobileH = TAUT_YES; /* index for pOneInput */
1040
/* if a restored structure has Fixed-H InChI then its mobile-H restored InChI is in Fixed-H pStruct */
1041
num_components = pOneInput->nNumComponents[iInchiRec][iMobileH];
1042
for ( iComponent = 0; iComponent < num_components; iComponent ++ ) {
1043
int bMobileH = iMobileH;
1044
pInChI[0] = pInChI[1] = NULL;
1045
if ( pOneInput->pInpInChI[iInchiRec][bMobileH][iComponent].nNumberOfAtoms &&
1046
!pOneInput->pInpInChI[iInchiRec][bMobileH][iComponent].bDeleted ) {
1047
/* the requested InChI layer exists */
1048
pInChI[0] = &pOneInput->pInpInChI[iInchiRec][bMobileH][iComponent];
1049
if ( bMobileH == TAUT_NON ) {
1050
pInChI[1] = &pOneInput->pInpInChI[iInchiRec][TAUT_YES][iComponent];
1053
if ( bMobileH == TAUT_NON &&
1054
pOneInput->pInpInChI[iInchiRec][TAUT_YES][iComponent].nNumberOfAtoms &&
1055
!pOneInput->pInpInChI[iInchiRec][TAUT_YES][iComponent].bDeleted ) {
1056
/* the requested Fixed-H InChI layer does not exist; however, the Mobile-H does exist */
1057
bMobileH = TAUT_YES; /* only Mobile-H is available */
1058
pInChI[0] = &pOneInput->pInpInChI[iInchiRec][bMobileH][iComponent];
1060
memset( CompareInchiFlags, 0, sizeof(CompareInchiFlags) );
1061
memset( &nCurRemovedProtons, 0, sizeof(nCurRemovedProtons) );
1063
#if( bRELEASE_VERSION == 0 )
1064
#ifndef INCHI_LIBRARY
1065
/* legacy: reproduce old output */
1066
OldPrintCompareOneOrigInchiToRevInChI(pStruct[iInchiRec][bMobileH]+iComponent, pInChI, bMobileH,
1067
iComponent, num_inp, szCurHdr);
1070
/* one component comparison result bits */
1071
ret = CompareOneOrigInchiToRevInChI( pStruct[iInchiRec][bMobileH]+iComponent, pInChI, bMobileH, iComponent,
1072
num_inp, szCurHdr, &nCurRemovedProtons, CompareInchiFlags);
1074
/* no errors encountered -> accumulate removed protons from individual Mobile-H layers of components */
1075
nNumRemovedProtons.nNumRemovedProtons += nCurRemovedProtons.nNumRemovedProtons;
1076
for ( i = 0; i < NUM_H_ISOTOPES; i ++ ) {
1077
nNumRemovedProtons.nNumRemovedIsotopicH[i] += nCurRemovedProtons.nNumRemovedIsotopicH[i];
1079
/* accumulate compare bits */
1080
for ( i = 0; i < TAUT_NUM; i ++ ) {
1081
pOneInput->CompareInchiFlags[0][i] |= CompareInchiFlags[i];
1087
if ( iMobileH == TAUT_YES ) {
1088
if ( pOneInput->nNumProtons[iInchiRec][iMobileH].pNumProtons ) {
1089
ret = RI_ERR_PROGR; /* in Mobile-H case proton balances are split between compoments */
1091
/* num removed protons in orig. InChI num removed protons in restored InChi */
1092
if ( nNumRemovedProtons.nNumRemovedProtons != pOneInput->nNumProtons[iInchiRec][iMobileH].nNumRemovedProtons ) {
1093
/* restored structure InChI has less or more removed protons */
1094
pOneInput->CompareInchiFlags[0][TAUT_YES] |= INCHIDIFF_MOBH_PROTONS;
1095
#if( bRELEASE_VERSION == 0 )
1096
/* debug output only */
1098
int num_H_AddedByRevrs = pOneInput->nNumProtons[iInchiRec][iMobileH].nNumRemovedProtons
1099
- nNumRemovedProtons.nNumRemovedProtons;
1100
fprintf( stdout, "COMPARE_INCHI: %ld: %s %cM: Proton balance (Diff: %d, RevrsRem=%d)\n",
1101
num_inp, szCurHdr? szCurHdr : "Struct", iInchiRec? 'R':'D',
1102
pOneInput->nNumProtons[iInchiRec][iMobileH].nNumRemovedProtons,num_H_AddedByRevrs);
1106
for ( i = 0; i < NUM_H_ISOTOPES; i ++ ) {
1107
if ( nNumRemovedProtons.nNumRemovedIsotopicH[i] != pOneInput->nNumProtons[iInchiRec][TAUT_YES].nNumRemovedIsotopicH[i] ) {
1108
pOneInput->CompareInchiFlags[0][TAUT_YES] |= INCHIDIFF_MOB_ISO_H;
1109
#if( bRELEASE_VERSION == 0 )
1110
/* debug output only */
1112
int num_H_AddedByRevrs = pOneInput->nNumProtons[iInchiRec][TAUT_YES].nNumRemovedIsotopicH[i]
1113
- nNumRemovedProtons.nNumRemovedIsotopicH[i];
1114
fprintf( stdout, "COMPARE_INCHI: %ld: %s %cM: Iso Xchg %dH balance (Diff: %d, RevrsRem=%d)\n",
1115
num_inp, szCurHdr? szCurHdr : "Struct", iInchiRec? 'R':'D', i+1,
1116
pOneInput->nNumProtons[iInchiRec][TAUT_YES].nNumRemovedIsotopicH[i],num_H_AddedByRevrs);
1127
/***********************************************************************************************/
1128
int CompareAllDisconnectedOrigInchiToRevInChI(StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM],
1129
InpInChI *pOneInput, int bHasSomeFixedH,
1130
long num_inp, char *szCurHdr)
1132
int i, k, m, n, iInChI, iMobileH, bMobileH, ifk;
1133
int num_components_D, num_components_R;
1134
int nNumCompHaveSeparateProtons_D, nNumCompHaveSeparateProtons_R;
1135
int num_fragments_D, num_fragments_R, num_fragments_DR, num_fragments, iComponent, ret;
1136
int ifInChI, ifMobileH, bfMobileH, nLink;
1137
COMPONENT_REM_PROTONS nNumRemovedProtons_D; /* removed from the disconnected layer of the Input InChI */
1138
COMPONENT_REM_PROTONS nNumRemovedProtons_D_all; /* if only totals are avalable */
1139
COMPONENT_REM_PROTONS nNumRemovedProtons_R; /* removed from disconnected layer of the reconstructed struct */
1140
COMPONENT_REM_PROTONS nNumRemovedProtons_R_all;
1141
INCHI_MODE CompareInchiFlags[TAUT_NUM];
1142
StrFromINChI *pStruct1;
1143
INChI_Aux *pINChI_Aux;
1144
INCHI_SORT *pINChISort1 = NULL; /* from reversed structure */
1145
INCHI_SORT *pINChISort2 = NULL; /* original input InChI */
1146
int nNumNonTaut1=0, nNumNonTaut2=0;
1149
memset( pOneInput->CompareInchiFlags[1], 0, sizeof(pOneInput->CompareInchiFlags[1]) );
1151
/* count components that are not subject to disconnection */
1152
if ( !pOneInput->nNumComponents[INCHI_REC][TAUT_YES] &&
1153
!pOneInput->nNumComponents[INCHI_REC][TAUT_NON] ) {
1154
return 0; /* nothing to do */
1157
memset( &nNumRemovedProtons_D, 0, sizeof(nNumRemovedProtons_D) );
1158
memset( &nNumRemovedProtons_R, 0, sizeof(nNumRemovedProtons_R) );
1159
memset( &nNumRemovedProtons_D_all, 0, sizeof(nNumRemovedProtons_D_all) );
1160
memset( &nNumRemovedProtons_R_all, 0, sizeof(nNumRemovedProtons_R_all) );
1161
memset( CompareInchiFlags, 0, sizeof(CompareInchiFlags) );
1163
num_components_D = inchi_max( pOneInput->nNumComponents[INCHI_BAS][TAUT_YES],
1164
pOneInput->nNumComponents[INCHI_BAS][TAUT_NON] );
1165
num_components_R = inchi_max( pOneInput->nNumComponents[INCHI_REC][TAUT_YES],
1166
pOneInput->nNumComponents[INCHI_REC][TAUT_NON] );
1167
/***********************************************************************************************/
1168
/* InpInChI: count fragments -- disconnected components that do not match reconnected */
1169
/* Accumulate removed H and isotopic H from ALL Fixed-H disconnected components except deleted */
1170
/* This segment collects info from the original InChI */
1171
/***********************************************************************************************/
1172
/*---- Original InChI ----*/
1173
num_fragments_D = 0;
1175
iMobileH = bHasSomeFixedH? !pOneInput->nNumComponents[iInChI][TAUT_NON] : TAUT_YES;
1176
nNumCompHaveSeparateProtons_D = 0;
1178
/* in case of Mobile-H components here are the proton totals from the original InChI disconn. layer */
1179
nNumRemovedProtons_D.nNumRemovedProtons = pOneInput->nNumProtons[iInChI][TAUT_YES].nNumRemovedProtons;
1180
memcpy( nNumRemovedProtons_D.nNumRemovedIsotopicH,
1181
pOneInput->nNumProtons[iInChI][TAUT_YES].nNumRemovedIsotopicH,
1182
sizeof(nNumRemovedProtons_D.nNumRemovedIsotopicH) ); /* total for the disconnected layer */
1184
for ( k = 0; k < num_components_D; k ++ ) {
1185
bMobileH = iMobileH;
1186
if ( !bInpInchiComponentExists( pOneInput, iInChI, bMobileH, k ) ) {
1187
if ( bInpInchiComponentExists( pOneInput, iInChI, TAUT_YES, k ) ) {
1188
bMobileH = TAUT_YES;
1190
continue; /* component is missing ??? */
1193
if ( 0 > (nLink = pOneInput->pInpInChI[iInChI][bMobileH][k].nLink) ) {
1194
/* component in Disconnected layer is linked to the identical one in the Reconnected layer */
1195
if ( pOneInput->nNumProtons[INCHI_REC][TAUT_YES].pNumProtons ) {
1196
nNumCompHaveSeparateProtons_D ++;
1198
nNumRemovedProtons_D.nNumRemovedProtons += pOneInput->nNumProtons[INCHI_REC][TAUT_YES].pNumProtons[nLink].nNumRemovedProtons;
1199
for ( m = 0; m < NUM_H_ISOTOPES; m ++ ) {
1200
nNumRemovedProtons_D.nNumRemovedIsotopicH[m] += pOneInput->nNumProtons[INCHI_REC][TAUT_YES].pNumProtons[nLink].nNumRemovedIsotopicH[m];
1203
continue; /* same as reconnected */
1205
/* component in the reconnected layer that was disconnected */
1206
nNumNonTaut2 += (bMobileH == TAUT_NON);
1207
if ( pOneInput->nNumProtons[iInChI][TAUT_YES].pNumProtons ) {
1208
nNumCompHaveSeparateProtons_D ++;
1209
nNumRemovedProtons_D.nNumRemovedProtons += pOneInput->nNumProtons[iInChI][TAUT_YES].pNumProtons[k].nNumRemovedProtons;
1210
for ( m = 0; m < NUM_H_ISOTOPES; m ++ ) {
1211
nNumRemovedProtons_D.nNumRemovedIsotopicH[m] += pOneInput->nNumProtons[iInChI][TAUT_YES].pNumProtons[k].nNumRemovedIsotopicH[m];
1214
num_fragments_D ++; /* number of disconnected fragments from original reconnected structure */
1216
/* in case of Mobile-H components here are the proton totals from the original InChI */
1218
nNumRemovedProtons_D_all.nNumRemovedProtons = pOneInput->nNumProtons[iInChI][TAUT_YES].nNumRemovedProtons;
1219
memcpy( nNumRemovedProtons_D_all.nNumRemovedIsotopicH,
1220
pOneInput->nNumProtons[iInChI][TAUT_YES].nNumRemovedIsotopicH,
1221
sizeof(nNumRemovedProtons_D_all.nNumRemovedIsotopicH) );
1224
/****************************************************************************************************/
1225
/* count fragments in reconstructed reconnected structure */
1226
/* accumulate removed H and isotopic H from ALL reconstructed reconnected components except deleted */
1227
/* This segment collects info from the reconstructed structure InChI */
1228
/****************************************************************************************************/
1229
/*---- InChI from the reconstructed reconnected structure ----*/
1230
num_fragments_R = 0;
1232
iMobileH = bHasSomeFixedH? !pOneInput->nNumComponents[iInChI][TAUT_NON] : TAUT_YES;
1233
nNumCompHaveSeparateProtons_R = 0;
1234
for ( k = 0; k < num_components_R; k ++ ) {
1235
bMobileH = iMobileH;
1236
if ( !bInpInchiComponentExists( pOneInput, iInChI, bMobileH, k ) ) {
1237
if ( bInpInchiComponentExists( pOneInput, iInChI, TAUT_YES, k ) ) {
1238
bMobileH = TAUT_YES;
1240
continue; /* component is missing ??? (Deleted proton in Mobile-H layer) */
1243
if ( 0 < pOneInput->pInpInChI[iInChI][bMobileH][k].nLink ) {
1244
/* this reconstructed reconnected component was NOT DISCONNECTED */
1245
/* same component is in the disconnected layer, it has no metal atoms or is an isolated metal atom */
1246
pStruct1 = pStruct[iInChI][bMobileH]+k;
1247
ifMobileH = TAUT_YES; /* Mobile-H Aux_Info contains number removed protons */
1248
ifInChI = INCHI_BAS; /* this component cannot be reconnected */
1249
ifk = 0; /* 0th component since it is InChI of a single component */
1250
/* The statement in the following line is *WRONG*, component number mixed with bMobileH: */
1251
/* in RevInchi, when only Mobile-H is present then its only non-NULL InChI has index 0==TAUT_NON */
1252
if ( bRevInchiComponentExists( pStruct1, ifInChI, ifMobileH, ifk ) ) {
1254
pINChI_Aux = pStruct1->RevInChI.pINChI_Aux[ifInChI][ifk][ifMobileH];
1256
nNumRemovedProtons_R.nNumRemovedProtons += pINChI_Aux->nNumRemovedProtons;
1257
for ( m = 0; m < NUM_H_ISOTOPES; m ++ ) {
1258
nNumRemovedProtons_R.nNumRemovedIsotopicH[m] += pINChI_Aux->nNumRemovedIsotopicH[m];
1262
nNumCompHaveSeparateProtons_R += bRevInchiComponentExists( pStruct1, ifInChI, ALT_TAUT(ifMobileH), ifk );
1263
continue; /* same as disconnected, has no metal atoms */
1265
/* this reconstructed reconnected component WAS DISCONNECTED; check its fragments */
1266
/* it does not have same component in the disconnected layer */
1267
pStruct1 = pStruct[iInChI][bMobileH]+k;
1268
num_fragments = pStruct1->RevInChI.num_components[INCHI_BAS];
1269
ifInChI = INCHI_BAS; /* disconnected layer */
1270
ifMobileH = bHasSomeFixedH? TAUT_NON : TAUT_YES;
1271
for ( ifk = 0; ifk < num_fragments; ifk ++ ) {
1272
bfMobileH = ifMobileH;
1273
if ( !bRevInchiComponentExists( pStruct1, ifInChI, bfMobileH, ifk ) ) {
1274
if ( bRevInchiComponentExists( pStruct1, ifInChI, TAUT_YES, ifk ) ) {
1275
bfMobileH = TAUT_YES;
1277
continue; /* fragment does not exist ??? */
1280
nNumNonTaut1 += (bfMobileH == TAUT_NON);
1281
nNumCompHaveSeparateProtons_R += (bfMobileH == TAUT_NON);
1282
/* count protons from fragments made by metal disconnection */
1283
pINChI_Aux = pStruct1->RevInChI.pINChI_Aux[ifInChI][ifk][TAUT_YES];
1285
nNumRemovedProtons_R.nNumRemovedProtons += pINChI_Aux->nNumRemovedProtons;
1286
for ( m = 0; m < NUM_H_ISOTOPES; m ++ ) {
1287
nNumRemovedProtons_R.nNumRemovedIsotopicH[m] += pINChI_Aux->nNumRemovedIsotopicH[m];
1290
num_fragments_R ++; /* number of disconnected fragments from reconstructed reconnected structure */
1293
/*---------------- special treatment of the last reconstructed component -----------------*/
1294
/*---------------- this may contain separate protons added by the reconstruction ---------*/
1295
k = num_components_R - 1;
1296
pStruct1 = pStruct[iInChI][iMobileH]+k;
1297
if ( iMobileH == TAUT_YES && !bHasSomeFixedH &&
1298
bInpInchiComponentDeleted( pOneInput, iInChI, iMobileH, k ) &&
1299
(num_fragments = pStruct1->RevInChI.num_components[INCHI_BAS]) ) {
1301
ifInChI = INCHI_BAS; /* disconnected layer */
1302
ifMobileH = TAUT_YES;
1303
for ( ifk = 0; ifk < num_fragments; ifk ++ ) {
1304
bfMobileH = ifMobileH;
1305
if ( !bRevInchiComponentDeleted( pStruct1, ifInChI, bfMobileH, ifk ) ) {
1306
continue; /* fragment does exist ??? Should not happen */
1309
nNumNonTaut1 += (bfMobileH == TAUT_NON);
1310
nNumCompHaveSeparateProtons_R += (bfMobileH == TAUT_NON);
1312
/* count protons from fragments made by metal disconnection */
1313
pINChI_Aux = pStruct1->RevInChI.pINChI_Aux[ifInChI][ifk][TAUT_YES];
1315
nNumRemovedProtons_R.nNumRemovedProtons += pINChI_Aux->nNumRemovedProtons;
1316
for ( m = 0; m < NUM_H_ISOTOPES; m ++ ) {
1317
nNumRemovedProtons_R.nNumRemovedIsotopicH[m] += pINChI_Aux->nNumRemovedIsotopicH[m];
1320
/*num_fragments_R ++;*/ /* number of disconnected fragments from reconstructed reconnected structure */
1326
num_fragments_DR = inchi_max( num_fragments_D, num_fragments_R );
1327
/* in case of correct reconstruction, num_fragments_D, num_fragments_R */
1329
if ( !num_fragments_DR ) {
1330
return 0; /* no component was disconnected */
1332
if ( num_fragments_D != num_fragments_R ) {
1333
for ( i = 0; i < TAUT_NUM; i ++ ) {
1334
if ( pOneInput->nNumComponents[INCHI_BAS][i] ) {
1335
pOneInput->CompareInchiFlags[1][i] |= INCHIDIFF_PROBLEM;
1338
return 1; /* severe error */
1342
pINChISort1 = (INCHI_SORT *)inchi_calloc(num_fragments_DR, sizeof(pINChISort1[0]));
1343
pINChISort2 = (INCHI_SORT *)inchi_calloc(num_fragments_DR, sizeof(pINChISort2[0]));
1344
if ( !pINChISort1 || !pINChISort2 ) {
1349
/* accumulate original InChI of fragments -- disconnected components that do not match reconnected */
1351
iMobileH = bHasSomeFixedH? !pOneInput->nNumComponents[iInChI][TAUT_NON] : TAUT_YES;
1352
for ( k = n = 0; k < num_components_D; k ++ ) {
1353
bMobileH = iMobileH;
1354
if ( !bInpInchiComponentExists( pOneInput, iInChI, bMobileH, k ) ) {
1355
if ( bInpInchiComponentExists( pOneInput, iInChI, TAUT_YES, k ) ) {
1356
bMobileH = TAUT_YES;
1358
continue; /* component is missing ??? (Deleted proton in Mobile-H layer) */
1361
if ( 0 > pOneInput->pInpInChI[iInChI][bMobileH][k].nLink ) {
1362
continue; /* same as reconnected */
1364
/* the component exists in disconnected layer of the orig. InChI only: it is a fragment */
1365
pINChISort2[n].pINChI[bMobileH] = pOneInput->pInpInChI[iInChI][bMobileH] + k;
1366
if ( bMobileH == TAUT_NON &&
1367
(bInpInchiComponentExists( pOneInput, iInChI, TAUT_YES, k ) ||
1368
bInpInchiComponentDeleted( pOneInput, iInChI, TAUT_YES, k ) ) ) {
1369
pINChISort2[n].pINChI[TAUT_YES] = pOneInput->pInpInChI[iInChI][TAUT_YES] + k;
1371
/* the last sort key is a number of removed protons */
1372
pINChISort2[n].ord_number = pOneInput->nNumProtons[iInChI][TAUT_YES].pNumProtons?
1373
pOneInput->nNumProtons[iInChI][TAUT_YES].pNumProtons[k].nNumRemovedProtons : 0;
1374
pINChISort2[n].n1 = k; /* orig. InChI disconnected layer component number */
1375
pINChISort2[n].n2 = -1; /* no fragment index */
1379
/* accumulate fragments from the reconstructed structure */
1381
iMobileH = bHasSomeFixedH? !pOneInput->nNumComponents[iInChI][TAUT_NON] : TAUT_YES;
1382
for ( k = n = 0; k < num_components_R; k ++ ) {
1383
bMobileH = iMobileH;
1384
if ( !bInpInchiComponentExists( pOneInput, iInChI, bMobileH, k ) ) {
1385
if ( bInpInchiComponentExists( pOneInput, iInChI, TAUT_YES, k ) ) {
1386
bMobileH = TAUT_YES;
1388
continue; /* component is missing ??? (Deleted proton in Mobile-H layer) */
1391
/* the reconstructed structure */
1392
if ( 0 < pOneInput->pInpInChI[iInChI][bMobileH][k].nLink ) {
1393
continue; /* same as disconnected, has no metal atoms */
1395
/* this reconstructed structure was disconnected */
1396
pStruct1 = pStruct[iInChI][bMobileH]+k;
1397
num_fragments = pStruct1->RevInChI.num_components[INCHI_BAS];
1398
ifInChI = INCHI_BAS;
1399
ifMobileH = bHasSomeFixedH? TAUT_NON : TAUT_YES;
1400
for ( i = 0; i < num_fragments; i ++ ) {
1401
bfMobileH = ifMobileH;
1402
if ( !bRevInchiComponentExists( pStruct1, ifInChI, bfMobileH, i ) ) {
1403
if ( bRevInchiComponentExists( pStruct1, ifInChI, TAUT_YES, i ) ) {
1404
bfMobileH = TAUT_YES;
1406
continue; /* component is missing ??? */
1409
pINChISort1[n].pINChI[bfMobileH] = pStruct1->RevInChI.pINChI[ifInChI][i][bfMobileH];
1410
if ( bfMobileH == TAUT_NON /*&& bRevInchiComponentExists( pStruct1, ifInChI, TAUT_YES, i )*/ ) {
1411
pINChISort1[n].pINChI[TAUT_YES] = pStruct1->RevInChI.pINChI[ifInChI][i][TAUT_YES];
1412
/* remove Fixed-H InChI if is is identical to Mobile-H */
1413
/* do it exactly same way the identical components were removed from InpInChI */
1414
if ( !CompareReversedINChI( pINChISort1[n].pINChI[bfMobileH],
1415
pINChISort1[n].pINChI[TAUT_YES], NULL, NULL ) ) {
1416
pINChISort1[n].pINChI[bfMobileH] = NULL; /* remove Fixed-H layer */
1418
pINChISort1[n].ord_number = pStruct1->RevInChI.pINChI_Aux[ifInChI][i][TAUT_YES]->nNumRemovedProtons;
1422
pINChISort1[n].n1 = k; /* reconstructed reconnected structure component index */
1423
pINChISort1[n].n2 = i; /* index of a fragment made out of this component */
1428
/* sort fragment InChI before comparing them */
1429
qsort( pINChISort1, num_fragments_D, sizeof(pINChISort1[0]), CompINChITaut2 );
1430
qsort( pINChISort2, num_fragments_R, sizeof(pINChISort2[0]), CompINChITaut2 );
1432
/* compare fragments -- components present in disconnected layer only */
1433
for ( iComponent = 0; iComponent < num_fragments_DR; iComponent ++ ) {
1434
INChI *pInChI1[TAUT_NUM]; /* from reversed structure */
1435
INChI *pInChI2[TAUT_NUM]; /* original input InChI */
1436
for ( i = 0; i < TAUT_NUM; i ++ ) {
1437
pInChI1[i] = pINChISort1[iComponent].pINChI[i];
1438
pInChI2[i] = pINChISort2[iComponent].pINChI[i];
1440
CompareTwoPairsOfInChI( pInChI1, pInChI2, !bHasSomeFixedH, CompareInchiFlags );
1443
if ( /*nNumNonTaut1 && nNumNonTaut2 &&*/ bHasSomeFixedH ) {
1444
if ( nNumCompHaveSeparateProtons_D || nNumCompHaveSeparateProtons_R ) {
1445
/* for each component, compare number removed protons */
1446
/* comparison does not make sense if Disconnected Fixed-H layer is not present */
1447
for ( iComponent = 0; iComponent < num_fragments_DR; iComponent ++ ) {
1448
NUM_H nNumRemovedIsotopicH1[NUM_H_ISOTOPES];
1449
NUM_H nNumRemovedIsotopicH2[NUM_H_ISOTOPES];
1451
memset( nNumRemovedIsotopicH1, 0, sizeof(nNumRemovedIsotopicH1) );
1452
memset( nNumRemovedIsotopicH2, 0, sizeof(nNumRemovedIsotopicH2) );
1453
/* compare removed protons */
1454
if ( pINChISort1[iComponent].ord_number != pINChISort2[iComponent].ord_number ) {
1455
CompareInchiFlags[TAUT_YES] |= INCHIDIFF_MOBH_PROTONS; /* diff number of removed protons */
1457
/* also compare removed isotopic atoms H */
1458
k = pINChISort2[iComponent].n1; /* input InChI, OneInput */
1459
if ( pOneInput->nNumProtons[INCHI_BAS][TAUT_YES].pNumProtons ) {
1460
memcpy( nNumRemovedIsotopicH2,
1461
pOneInput->nNumProtons[INCHI_BAS][TAUT_YES].pNumProtons[k].nNumRemovedIsotopicH,
1462
sizeof( nNumRemovedIsotopicH2 ) );
1464
/* get fragments of reconstructed structure removed protons info */
1465
k = pINChISort1[iComponent].n1; /* restored component number */
1466
i = pINChISort1[iComponent].n2; /* subcomponent number */
1468
iMobileH = bHasSomeFixedH? !pOneInput->nNumComponents[iInChI][TAUT_NON] : TAUT_YES;
1469
bMobileH = iMobileH;
1470
if ( !bInpInchiComponentExists( pOneInput, iInChI, bMobileH, k ) ) {
1471
if ( bInpInchiComponentExists( pOneInput, iInChI, TAUT_YES, k ) ) {
1472
bMobileH = TAUT_YES;
1477
if ( pOneInput->pInpInChI[iInChI][bMobileH][k].nLink ) {
1484
pStruct1 = pStruct[iInChI][bMobileH]+k;
1485
num_fragments = pStruct1->RevInChI.num_components[INCHI_BAS];
1486
ifInChI = INCHI_BAS;
1487
ifMobileH = bHasSomeFixedH? TAUT_NON : TAUT_YES;
1488
if ( i < num_fragments ) {
1489
bfMobileH = ifMobileH;
1490
if ( !bRevInchiComponentExists( pStruct1, ifInChI, bfMobileH, i ) ) {
1491
if ( bRevInchiComponentExists( pStruct1, ifInChI, TAUT_YES, i ) ) {
1492
bfMobileH = TAUT_YES;
1497
memcpy( nNumRemovedIsotopicH1,
1498
pStruct1->RevInChI.pINChI_Aux[ifInChI][i][TAUT_YES]->nNumRemovedIsotopicH,
1499
sizeof( nNumRemovedIsotopicH1 ) );
1502
if ( memcmp( nNumRemovedIsotopicH1, nNumRemovedIsotopicH2, sizeof( nNumRemovedIsotopicH1 ) ) ) {
1503
CompareInchiFlags[TAUT_YES] |= INCHIDIFF_REM_ISO_H;
1508
/*if ( !nNumNonTaut1 && !nNumNonTaut2 || !bHasSomeFixedH )*/ {
1509
/* compare totals for removed protons and isotopic H */
1510
if ( pOneInput->nNumProtons[INCHI_BAS][TAUT_YES].nNumRemovedProtons !=
1511
nNumRemovedProtons_R.nNumRemovedProtons ) {
1512
CompareInchiFlags[TAUT_YES] |= INCHIDIFF_MOBH_PROTONS;
1514
if ( memcmp( pOneInput->nNumProtons[INCHI_BAS][TAUT_YES].nNumRemovedIsotopicH,
1515
nNumRemovedProtons_R.nNumRemovedIsotopicH,
1516
sizeof( nNumRemovedProtons_R.nNumRemovedIsotopicH ) ) ) {
1517
CompareInchiFlags[TAUT_YES] |= INCHIDIFF_REM_ISO_H;
1521
if ( !nNumNonTaut1 == !nNumNonTaut2 ) {
1522
; /* difference if(nNumNonTaut1 != nNumNonTaut2) will be caught in InChI comparison */
1524
if ( nNumNonTaut1 ) {
1525
/* reconstructed has Fixed-H while the original has not: extra Fixed-H layer */
1526
CompareInchiFlags[TAUT_YES] |= INCHIDIFF_WRONG_TAUT;
1528
/* the original InChI has Fixed-H while the reconstructed one has not: missing Fixed-H layer */
1529
CompareInchiFlags[TAUT_YES] |= INCHIDIFF_NO_TAUT;
1531
for ( i = 0; i < TAUT_NUM; i ++ ) {
1532
pOneInput->CompareInchiFlags[1][i] |= CompareInchiFlags[i];
1535
/* compare totals */
1536
if ( nNumRemovedProtons_R.nNumRemovedProtons != nNumRemovedProtons_D.nNumRemovedProtons ) {
1537
CompareInchiFlags[TAUT_YES] |= INCHIDIFF_MOBH_PROTONS; /* diff number of removed protons */
1539
if ( memcmp( nNumRemovedProtons_R.nNumRemovedIsotopicH,
1540
nNumRemovedProtons_D.nNumRemovedIsotopicH,
1541
sizeof( nNumRemovedProtons_D.nNumRemovedIsotopicH ) ) ) {
1542
CompareInchiFlags[TAUT_YES] |= INCHIDIFF_REM_ISO_H;
1547
if ( pINChISort1 ) inchi_free( pINChISort1 );
1548
if ( pINChISort2 ) inchi_free( pINChISort2 );
1552
/******************************************************************************************************/
1553
int CompareTwoPairsOfInChI( INChI *pInChI1[TAUT_NUM], INChI *pInChI2[TAUT_NUM],
1554
int bMobileH, INCHI_MODE CompareInchiFlags[] )
1556
int iMobileH, err=0;
1558
for ( iMobileH = 0; iMobileH < TAUT_NUM; iMobileH ++ ) {
1559
if ( !pInChI1[iMobileH] != !pInChI2[iMobileH] ) {
1560
if ( iMobileH == TAUT_NON &&
1561
pInChI1[TAUT_YES] && pInChI1[TAUT_YES] ) {
1562
CompareInchiFlags[iMobileH] |= INCHIDIFF_COMP_HLAYER;
1564
CompareInchiFlags[iMobileH] |= INCHIDIFF_COMP_NUMBER;
1568
if ( pInChI1[iMobileH] && pInChI2[iMobileH] ) {
1569
cmp = CompareReversedINChI3( pInChI1[iMobileH], pInChI2[iMobileH], NULL, NULL, &err );
1571
CompareInchiFlags[iMobileH] |= cmp;
1577
/******************************************************************************************************/
1578
int CompareOneOrigInchiToRevInChI(StrFromINChI *pStruct, INChI *pInChI[TAUT_NUM], int bMobileH, int iComponent,
1579
long num_inp, char *szCurHdr,
1580
COMPONENT_REM_PROTONS *nCurRemovedProtons, INCHI_MODE CompareInchiFlags[])
1582
int ret = pStruct->RevInChI.nRetVal, err=0;
1584
if ( ret == _IS_OKAY || ret == _IS_WARNING ) {
1585
/* ignore bMobileH for now */
1586
int i, i0, b /* created type */, b0 /* requested type*/, j, k;
1587
/* pINChI[iINCHI][iComponent][bTaut] */
1588
/* i0 = requested Rec/Disconnected: 1/0 */
1589
/* i = what InChI creaded out of the restored structure */
1590
/* b0 = requested Mobile/Fixed-H: 1/0 */
1591
/* b = what InChI creaded out of the restored structure */
1592
i = i0 = pStruct->iINCHI;
1593
b = b0 = pStruct->iMobileH;
1594
if ( i == INCHI_REC && !pStruct->RevInChI.num_components[i] ) {
1597
if ( b == TAUT_NON && (!pStruct->RevInChI.pINChI[i] ||
1598
!pStruct->RevInChI.pINChI[i][0][b] ||
1599
!pStruct->RevInChI.pINChI[i][0][b]->nNumberOfAtoms ) ) {
1602
if ( pStruct->bDeleted && (!pInChI[0] || pInChI[0]->bDeleted ) ) {
1606
if ( pStruct->RevInChI.num_components[i] > 1 &&
1607
!pStruct->RevInChI.pINChI[i][1][b]->bDeleted ||
1608
pStruct->RevInChI.num_components[i] < 1 ) {
1609
CompareInchiFlags[bMobileH] |= INCHIDIFF_COMP_NUMBER;
1611
if ( b != b0 || b != bMobileH || b0 != bMobileH || i > i0 ) {
1612
/* do not print messages about TAUT_YES instead of TAUT_NON */
1613
CompareInchiFlags[bMobileH] |= INCHIDIFF_COMP_HLAYER;
1616
if ( pStruct->RevInChI.num_components[i] ) {
1617
/* compare InChI from restored structure; '0' in [i][0][b] is the first component */
1618
if ( b == TAUT_YES && pStruct->RevInChI.pINChI[i][0][b]->bDeleted && (!pInChI[0] || pInChI[0]->bDeleted ) ) {
1619
/* the 1st component is made out of proton(s) and the input component is missing or also a proton */
1622
cmp = CompareReversedINChI3( pStruct->RevInChI.pINChI[i][0][b], pInChI[0], NULL, NULL, &err );
1624
CompareInchiFlags[bMobileH] |= cmp;
1627
if ( b == b0 && b == TAUT_NON ) {
1628
if ( pStruct->RevInChI.pINChI[i][0][TAUT_YES] &&
1629
!pStruct->RevInChI.pINChI[i][0][TAUT_YES]->bDeleted ||
1630
pInChI[1] && !pInChI[1]->bDeleted ) {
1632
/* in addition to fixed-H also compare mobile-H InChI */
1633
cmp = CompareReversedINChI3( pStruct->RevInChI.pINChI[i][0][TAUT_YES], pInChI[1], NULL, NULL, &err );
1635
CompareInchiFlags[TAUT_YES] |= cmp;
1638
/* compare removed H */
1639
if ( pStruct->nNumRemovedProtonsMobHInChI != pStruct->RevInChI.pINChI_Aux[i][0][TAUT_YES]->nNumRemovedProtons ) {
1640
CompareInchiFlags[TAUT_YES] |= INCHIDIFF_MOBH_PROTONS;
1643
memset( nCurRemovedProtons, 0, sizeof(*nCurRemovedProtons) );
1644
for ( k = 0; k < pStruct->RevInChI.num_components[i]; k ++ ) {
1645
if ( !k || pStruct->RevInChI.pINChI[i][k][TAUT_YES]->bDeleted ) {
1646
/* get removed protons from the 1st component; add othere only if they are deleted protons */
1647
nCurRemovedProtons->nNumRemovedProtons += pStruct->RevInChI.pINChI_Aux[i][k][TAUT_YES]->nNumRemovedProtons;
1648
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
1649
nCurRemovedProtons->nNumRemovedIsotopicH[j] += pStruct->RevInChI.pINChI_Aux[i][k][TAUT_YES]->nNumRemovedIsotopicH[j];
1655
CompareInchiFlags[bMobileH] |= INCHIDIFF_STR2INCHI_ERR;
1659
/*************************************************************************************/
1660
INCHI_MODE CompareReversedStereoINChI3( INChI_Stereo *s1/* InChI from reversed struct */, INChI_Stereo *s2 /* input InChI */, ICR *picr)
1663
int j1, j2, num_eq, num_dif, num_extra_undf, num_miss_undf, num_in1_only, num_in2_only;
1664
int bAddSb = !(picr->num_sb_undef_in1_only + picr->num_sb_in1_only + picr->num_sb_in2_only);
1665
int bAddSc = !(picr->num_sc_undef_in1_only + picr->num_sc_in1_only + picr->num_sc_in2_only);
1667
int nNumSc1 = s1? s1->nNumberOfStereoCenters : 0;
1668
int nNumSc2 = s2? s2->nNumberOfStereoCenters : 0;
1669
int nNumSb1 = s1? s1->nNumberOfStereoBonds : 0;
1670
int nNumSb2 = s2? s2->nNumberOfStereoBonds : 0;
1672
if ( (nNumSc1 || nNumSc1) &&
1673
( nNumSc1 != nNumSc2 ||
1674
memcmp( s1->nNumber, s2->nNumber, nNumSc1*sizeof(s1->nNumber[0] ) ) ||
1675
memcmp( s1->t_parity, s2->t_parity, nNumSc1*sizeof(s1->t_parity[0]) ) ) ) {
1677
num_eq = num_dif = num_extra_undf = num_miss_undf = num_in1_only = num_in2_only = 0;
1678
for ( j1 = j2 = 0; j1 < nNumSc1 && j2 < nNumSc2; ) {
1679
if ( s1->nNumber[j1] == s2->nNumber[j2] ) {
1680
if ( s1->t_parity[j1] == s2->t_parity[j2] ) {
1688
if ( s1->nNumber[j1] < s2->nNumber[j2] ) {
1690
if ( s1->t_parity[j1] == AB_PARITY_UNDF ) {
1694
if ( picr->num_sc_in1_only < ICR_MAX_SC_IN1_ONLY )
1695
picr->sc_in1_only[picr->num_sc_in1_only ++] = j1;
1696
if ( s1->t_parity[j1] == AB_PARITY_UNDF ) {
1697
if ( picr->num_sc_undef_in1_only < ICR_MAX_SC_UNDF )
1698
picr->sc_undef_in1_only[picr->num_sc_undef_in1_only ++] = j1;
1704
if ( s2->t_parity[j2] == AB_PARITY_UNDF ) {
1708
if ( picr->num_sc_in2_only < ICR_MAX_SC_IN2_ONLY )
1709
picr->sc_in2_only[picr->num_sc_in2_only ++] = j2;
1710
if ( s2->t_parity[j2] == AB_PARITY_UNDF ) {
1711
if ( picr->num_sc_undef_in2_only < ICR_MAX_SC_UNDF )
1712
picr->sc_undef_in2_only[picr->num_sc_undef_in2_only ++] = j1;
1718
while ( j1 < nNumSc1 ) {
1719
if ( s1->t_parity[j1] == AB_PARITY_UNDF ) {
1724
if ( picr->num_sc_in1_only < ICR_MAX_SC_IN1_ONLY )
1725
picr->sc_in1_only[picr->num_sc_in1_only ++] = j1;
1726
if ( s1->t_parity[j1] == AB_PARITY_UNDF ) {
1727
if ( picr->num_sc_undef_in1_only < ICR_MAX_SC_UNDF )
1728
picr->sc_undef_in1_only[picr->num_sc_undef_in1_only ++] = j1;
1733
while ( j2 < nNumSc2 ) {
1734
if ( s2->t_parity[j2] == AB_PARITY_UNDF ) {
1739
if ( picr->num_sc_in2_only < ICR_MAX_SC_IN2_ONLY )
1740
picr->sc_in2_only[picr->num_sc_in2_only ++] = j2;
1745
ret |= INCHIDIFF_SC_PARITY;
1747
if ( num_in1_only ) {
1748
if ( num_extra_undf ) {
1749
ret |= INCHIDIFF_SC_EXTRA_UNDF;
1751
if ( num_in1_only != num_extra_undf ) {
1752
ret |= INCHIDIFF_SC_EXTRA;
1755
if ( num_in2_only ) {
1756
if ( num_miss_undf ) {
1757
ret |= INCHIDIFF_SC_MISS_UNDF;
1759
if ( num_in2_only != num_miss_undf ) {
1760
ret |= INCHIDIFF_SC_MISS;
1764
if ( s1 && s2 && (s2->nCompInv2Abs != 2) && s1->nCompInv2Abs != s2->nCompInv2Abs && s1->nCompInv2Abs && s2->nCompInv2Abs ) {
1765
ret |= INCHIDIFF_SC_INV; /* 2007-07-13 DT: added (s2->nCompInv2Abs != 2) to fix bug reoprted by Yerin on 2007/02/28 */
1766
/* Bug description: falsely reported "Stereo centers/allenes: Falsely inverted" for /S2 or /S3 */
1769
if ( (nNumSb1 || nNumSb2 ) &&
1770
(nNumSb1 != nNumSb2 ||
1771
memcmp( s1->nBondAtom1, s2->nBondAtom1, nNumSb1*sizeof(s1->nBondAtom1[0]) ) ||
1772
memcmp( s1->nBondAtom2, s2->nBondAtom2, nNumSb1*sizeof(s1->nBondAtom2[0]) ) ||
1773
memcmp( s1->b_parity, s2->b_parity, nNumSb1*sizeof(s1->b_parity[0]) ) ) ) {
1775
num_eq = num_dif = num_extra_undf = num_miss_undf = num_in1_only = num_in2_only = 0;
1776
for ( j1 = j2 = 0; j1 < nNumSb1 && j2 < nNumSb2; ) {
1777
if ( s1->nBondAtom1[j1] == s2->nBondAtom1[j2] &&
1778
s1->nBondAtom2[j1] == s2->nBondAtom2[j2] ) {
1779
if ( s1->b_parity[j1] == s2->b_parity[j2] ) {
1787
if ( s1->nBondAtom1[j1] < s2->nBondAtom1[j2] ||
1788
s1->nBondAtom1[j1] == s2->nBondAtom1[j2] && s1->nBondAtom2[j1] < s2->nBondAtom2[j2]) {
1790
if ( s1->b_parity[j1] == AB_PARITY_UNDF ) {
1794
if ( picr->num_sb_in1_only < ICR_MAX_SB_IN1_ONLY )
1795
picr->sb_in1_only[picr->num_sb_in1_only ++] = j1;
1796
if ( s1->b_parity[j1] == AB_PARITY_UNDF ) {
1797
if ( picr->num_sb_undef_in1_only < ICR_MAX_SB_UNDF )
1798
picr->sb_undef_in1_only[picr->num_sb_undef_in1_only ++] = j1;
1804
if ( s2->b_parity[j2] == AB_PARITY_UNDF ) {
1808
if ( picr->num_sb_in2_only < ICR_MAX_SB_IN2_ONLY )
1809
picr->sb_in2_only[picr->num_sb_in2_only ++] = j2;
1810
if ( s2->b_parity[j2] == AB_PARITY_UNDF ) {
1811
if ( picr->num_sb_undef_in2_only < ICR_MAX_SB_UNDF )
1812
picr->sb_undef_in2_only[picr->num_sb_undef_in2_only ++] = j1;
1818
while ( j1 < nNumSb1 ) {
1820
if ( s1->b_parity[j1] == AB_PARITY_UNDF ) {
1824
if ( picr->num_sb_in1_only < ICR_MAX_SB_IN1_ONLY )
1825
picr->sb_in1_only[picr->num_sb_in1_only ++] = j1;
1826
if ( s1->b_parity[j1] == AB_PARITY_UNDF ) {
1827
if ( picr->num_sb_undef_in1_only < ICR_MAX_SB_UNDF )
1828
picr->sb_undef_in1_only[picr->num_sb_undef_in1_only ++] = j1;
1833
while ( j2 < nNumSb2 ) {
1835
if ( s2->b_parity[j2] == AB_PARITY_UNDF ) {
1839
if ( picr->num_sb_in2_only < ICR_MAX_SB_IN2_ONLY )
1840
picr->sb_in2_only[picr->num_sb_in2_only ++] = j2;
1841
if ( s2->b_parity[j2] == AB_PARITY_UNDF ) {
1842
if ( picr->num_sb_undef_in2_only < ICR_MAX_SB_UNDF )
1843
picr->sb_undef_in2_only[picr->num_sb_undef_in2_only ++] = j1;
1849
ret |= INCHIDIFF_SB_PARITY;
1851
if ( num_in1_only ) {
1852
if ( num_extra_undf ) {
1853
ret |= INCHIDIFF_SB_EXTRA_UNDF;
1855
if ( num_in1_only != num_extra_undf ) {
1856
ret |= INCHIDIFF_SB_EXTRA;
1859
if ( num_in2_only ) {
1860
if ( num_miss_undf ) {
1861
ret |= INCHIDIFF_SB_MISS_UNDF;
1863
if ( num_in2_only != num_miss_undf ) {
1864
ret |= INCHIDIFF_SB_MISS;
1871
/*********************************************************************************************************/
1872
INCHI_MODE CompareReversedINChI3( INChI *i1 /* InChI from reversed struct */, INChI *i2 /* input InChI */,
1873
INChI_Aux *a1, INChI_Aux *a2, int *err )
1876
INChI_Stereo *Stereo1=NULL, *Stereo2=NULL;
1877
int n1, n2, m, j, j1, j2, ret2, num_H1, num_H2;
1883
memset( picr, 0, sizeof(*picr) );
1885
if ( i1 == NULL && i2 == NULL )
1887
if ( (i1 == NULL) ^ (i2 == NULL) ) {
1888
ret |= INCHIDIFF_PROBLEM; /* one InChI exists while another doesn't */
1892
if ( i1->nErrorCode == i2->nErrorCode ) {
1893
if ( i1->nErrorCode ) {
1894
ret |= INCHIDIFF_PROBLEM; /* both InChI have same error codes */
1898
ret |= INCHIDIFF_PROBLEM; /* at least one InChI has an error code */
1902
if ( i1->nNumberOfAtoms != i2->nNumberOfAtoms ) {
1903
ret |= INCHIDIFF_NUM_AT;
1906
if ( i1->nNumberOfAtoms > 0 ) {
1907
if ( memcmp( i1->nAtom, i2->nAtom, i1->nNumberOfAtoms*sizeof(i1->nAtom[0]) ) ) {
1908
ret |= INCHIDIFF_ATOMS;
1911
/* INCHIDIFF_NON_TAUT_H, INCHIDIFF_MORE_FH, INCHIDIFF_LESS_FH */
1912
if ( memcmp( i1->nNum_H, i2->nNum_H, i1->nNumberOfAtoms*sizeof(i1->nNum_H[0]) ) ) {
1913
ret |= INCHIDIFF_POSITION_H;
1914
for ( j1 = 0; j1 < i1->nNumberOfAtoms; j1 ++ ) {
1915
if ( i1->nNum_H[j1] != i2->nNum_H[j1] && picr->num_diff_pos_H < ICR_MAX_DIFF_FIXED_H ) {
1916
picr->diff_pos_H_at[picr->num_diff_pos_H] = j1;
1917
picr->diff_pos_H_nH[picr->num_diff_pos_H] = i1->nNum_H[j1] - i2->nNum_H[j1];
1918
picr->num_diff_pos_H ++;
1923
if ( i1->nNum_H_fixed || i2->nNum_H_fixed ) {
1924
int bHasFixedH1 = 0, bHasFixedH2 = 0, i;
1925
if ( i1->nNum_H_fixed ) {
1926
for ( i = 0; i < i1->nNumberOfAtoms; i ++ ) {
1927
if ( i1->nNum_H_fixed[i] ) {
1932
if ( i2->nNum_H_fixed ) {
1933
for ( i = 0; i < i2->nNumberOfAtoms; i ++ ) {
1934
if ( i2->nNum_H_fixed[i] ) {
1939
if ( bHasFixedH1 && !bHasFixedH2 ) {
1940
for ( i = j = 0; i < i1->nNumberOfAtoms; i ++ ) {
1941
if ( i1->nNum_H_fixed[i] ) {
1942
if ( j < ICR_MAX_DIFF_FIXED_H ) {
1943
picr->fixed_H_at1_more[j] = i;
1944
picr->fixed_H_nH1_more[j] = i1->nNum_H_fixed[i];
1949
picr->num_fixed_H1_more = j;
1950
ret |= INCHIDIFF_MORE_FH; /* Extra Fixed-H */
1952
if ( !bHasFixedH1 && bHasFixedH2 ) {
1953
for ( i = j = 0; i < i2->nNumberOfAtoms; i ++ ) {
1954
if ( i2->nNum_H_fixed[i] ) {
1955
if ( j < ICR_MAX_DIFF_FIXED_H ) {
1956
picr->fixed_H_at2_more[j] = i;
1957
picr->fixed_H_nH2_more[j] = i2->nNum_H_fixed[i];
1962
picr->num_fixed_H2_more = j;
1963
ret |= INCHIDIFF_LESS_FH; /* Missed Fixed-H */
1965
if ( bHasFixedH1 && bHasFixedH2 &&
1966
memcmp( i1->nNum_H_fixed, i2->nNum_H_fixed, i1->nNumberOfAtoms*sizeof(i1->nNum_H_fixed[0]) ) ) {
1967
for ( i = j1 = j2 = 0; i < i1->nNumberOfAtoms; i ++ ) {
1968
if ( i1->nNum_H_fixed[i] > i2->nNum_H_fixed[i] ) {
1969
if ( j1 < ICR_MAX_DIFF_FIXED_H ) {
1970
picr->fixed_H_at1_more[j1] = i;
1971
picr->fixed_H_nH1_more[j1] = i1->nNum_H_fixed[i] - i2->nNum_H_fixed[i];
1975
if ( i1->nNum_H_fixed[i] < i2->nNum_H_fixed[i] ) {
1976
if ( j2 < ICR_MAX_DIFF_FIXED_H ) {
1977
picr->fixed_H_at2_more[j2] = i;
1978
picr->fixed_H_nH2_more[j2] = i2->nNum_H_fixed[i] - i1->nNum_H_fixed[i];
1983
ret |= (j1? INCHIDIFF_MORE_FH:0) | (j2? INCHIDIFF_LESS_FH:0);
1984
picr->num_fixed_H1_more = j1;
1985
picr->num_fixed_H2_more = j2;
1989
/* compare formulas and H */
1992
ret2 = CompareHillFormulasNoH( i1->szHillFormula, i2->szHillFormula, &num_H1, &num_H2 );
1993
picr->tot_num_H1 = num_H1;
1994
picr->tot_num_H2 = num_H2;
1996
ret |= INCHIDIFF_NUM_EL;
1999
if ( num_H1 > num_H2 ) {
2000
ret |= INCHIDIFF_MORE_H;
2002
if ( num_H1 < num_H2 ) {
2003
ret |= INCHIDIFF_LESS_H;
2006
if ( i1->lenConnTable != i2->lenConnTable ) {
2007
ret |= INCHIDIFF_CON_LEN;
2010
if ( i1->lenConnTable > 0 && memcmp( i1->nConnTable, i2->nConnTable, i1->lenConnTable*sizeof(i1->nConnTable[0]) ) ) {
2011
ret |= INCHIDIFF_CON_TBL;
2014
/* output special cases: different number of t-groups, different sizes of t-groups, different endpoints */
2015
/* in isotopic or deprotonated cases i1->lenTautomer == 1 && i1->nTautomer[0] = 0 */
2017
if ( i1->lenTautomer != i2->lenTautomer && (i1->lenTautomer > 1 || i2->lenTautomer > 1) ) {
2018
ret |= INCHIDIFF_TAUT_LEN;
2021
/* compare number of t-groups */
2022
n1 = i1->lenTautomer? i1->nTautomer[0] : 0;
2023
n2 = i2->lenTautomer? i2->nTautomer[0] : 0;
2025
ret |= INCHIDIFF_NO_TAUT;
2028
ret |= INCHIDIFF_WRONG_TAUT;
2030
if ( n1 == 1 && n2 > 1 ) {
2031
ret |= INCHIDIFF_SINGLE_TG;
2033
if ( n1 > 1 && n2 == 1 ) {
2034
ret |= INCHIDIFF_MULTIPLE_TG;
2037
ret |= INCHIDIFF_NUM_TG;
2040
/* number of endpoints */
2041
int num1 = 0, num2 = 0, num_M1=0, num_M2=0;
2042
int len, num_eq, num_in1_only, num_in2_only;
2043
AT_NUMB *pe1 = (AT_NUMB *)inchi_malloc( (i1->lenTautomer+1) * sizeof(pe1[0]) );
2044
AT_NUMB *pe2 = (AT_NUMB *)inchi_malloc( (i2->lenTautomer+1) * sizeof(pe2[0]) );
2046
/* collect endpoints, H, (-) */
2047
if ( !pe1 || !pe2 ) {
2048
if ( pe1 ) inchi_free( pe1 );
2049
if ( pe2 ) inchi_free( pe2 );
2050
*err = RI_ERR_ALLOC; /* allocation error */
2053
for ( m = 1; m < i1->lenTautomer; m += len ) {
2054
len = i1->nTautomer[m ++];
2055
num_H1 += i1->nTautomer[m];
2056
num_M1 += i1->nTautomer[m+1];
2057
for ( j = 2; j < len; j ++ ) {
2058
pe1[num1 ++] = i1->nTautomer[m + j];
2061
for ( m = 1; m < i2->lenTautomer; m += len ) {
2062
len = i2->nTautomer[m ++];
2063
num_H2 += i2->nTautomer[m];
2064
num_M2 += i2->nTautomer[m+1];
2065
for ( j = 2; j < len; j ++ ) {
2066
pe2[num2 ++] = i2->nTautomer[m + j];
2069
picr->num_taut_H1 = num_H1;
2070
picr->num_taut_H2 = num_H2;
2071
picr->num_taut_M1 = num_M1;
2072
picr->num_taut_M2 = num_M2;
2073
/* sort endpoints */
2074
insertions_sort_AT_NUMB( pe1, num1 );
2075
insertions_sort_AT_NUMB( pe2, num2 );
2078
if ( num1 < num2 ) {
2079
ret |= INCHIDIFF_LESS_TG_ENDP;
2081
if ( num1 > num2 ) {
2082
ret |= INCHIDIFF_MORE_TG_ENDP;
2086
num_eq = num_in1_only = num_in2_only = 0;
2087
for ( j1 = j2 = 0; j1 < num1 && j2 < num2; ) {
2088
if( pe1[j1] == pe2[j2] ) {
2093
if ( pe1[j1] < pe2[j1] ) {
2094
if ( picr->num_endp_in1_only < ICR_MAX_ENDP_IN1_ONLY ) {
2095
picr->endp_in1_only[picr->num_endp_in1_only ++] = pe1[j1];
2100
if ( picr->num_endp_in2_only < ICR_MAX_ENDP_IN2_ONLY ) {
2101
picr->endp_in2_only[picr->num_endp_in2_only ++] = pe2[j2];
2107
while ( j1 < num1 ) {
2108
if ( picr->num_endp_in1_only < ICR_MAX_ENDP_IN1_ONLY ) {
2109
picr->endp_in1_only[picr->num_endp_in1_only ++] = pe1[j1];
2114
while ( j2 < num2 ) {
2115
if ( picr->num_endp_in2_only < ICR_MAX_ENDP_IN2_ONLY ) {
2116
picr->endp_in2_only[picr->num_endp_in2_only ++] = pe2[j2];
2121
if ( num_in1_only ) {
2122
ret |= INCHIDIFF_EXTRA_TG_ENDP;
2124
if ( num_in2_only ) {
2125
ret |= INCHIDIFF_MISS_TG_ENDP;
2127
if ( !num_in1_only && !num_in2_only && num_eq ) {
2128
; /* same t-groups endpoints */
2130
ret |= INCHIDIFF_DIFF_TG_ENDP;
2137
if ( (i1->lenTautomer > 1 && i2->lenTautomer > 1) &&
2138
( i1->lenTautomer != i2->lenTautomer ||
2139
memcmp( i1->nTautomer, i2->nTautomer, i1->lenTautomer*sizeof(i1->nTautomer[0]) ) ) )
2140
ret |= INCHIDIFF_TG;
2142
if ( i1->nNumberOfIsotopicAtoms != i2->nNumberOfIsotopicAtoms ) {
2143
ret |= INCHIDIFF_NUM_ISO_AT;
2145
if ( i1->nNumberOfIsotopicAtoms > 0 && memcmp( i1->IsotopicAtom, i2->IsotopicAtom, i1->nNumberOfIsotopicAtoms*sizeof(i1->IsotopicAtom[0]) ) )
2146
ret |= INCHIDIFF_ISO_AT;
2147
if ( i1->nTotalCharge != i2->nTotalCharge )
2148
ret |= INCHIDIFF_CHARGE;
2149
if ( a1 && a1->nNumRemovedProtons && (!a2 || a2->nNumRemovedProtons != a1->nNumRemovedProtons) ) {
2150
ret |= INCHIDIFF_REM_PROT;
2153
a2->nNumRemovedIsotopicH[0] != a1->nNumRemovedIsotopicH[0] ||
2154
a2->nNumRemovedIsotopicH[1] != a1->nNumRemovedIsotopicH[1] ||
2155
a2->nNumRemovedIsotopicH[2] != a1->nNumRemovedIsotopicH[2]) ) {
2156
ret |= INCHIDIFF_REM_ISO_H;
2160
if ( i1->nPossibleLocationsOfIsotopicH && i2->nPossibleLocationsOfIsotopicH ) {
2161
if ( i1->nPossibleLocationsOfIsotopicH[0] != i2->nPossibleLocationsOfIsotopicH[0] ||
2162
memcmp(i1->nPossibleLocationsOfIsotopicH, i2->nPossibleLocationsOfIsotopicH,
2163
sizeof(i1->nPossibleLocationsOfIsotopicH[0])*i1->nPossibleLocationsOfIsotopicH[0]) )
2166
if ( !i1->nPossibleLocationsOfIsotopicH != !i2->nPossibleLocationsOfIsotopicH ) {
2170
if ( i1->StereoIsotopic &&
2171
i1->StereoIsotopic->nNumberOfStereoBonds + i1->StereoIsotopic->nNumberOfStereoCenters ) {
2172
Stereo1 = i1->StereoIsotopic;
2174
Stereo1 = i1->Stereo;
2176
if ( i2->StereoIsotopic &&
2177
i2->StereoIsotopic->nNumberOfStereoBonds + i2->StereoIsotopic->nNumberOfStereoCenters ) {
2178
Stereo2 = i2->StereoIsotopic;
2180
Stereo2 = i2->Stereo;
2182
ret |= CompareReversedStereoINChI3( Stereo1, Stereo2, picr );
2190
/* message group names */
2191
CMP_INCHI_MSG_GROUP CompareInchiMsgsGroup[] = {
2192
{IDGRP_ERR, " Error:"},
2193
{IDGRP_H, " Hydrogens:"},
2194
{IDGRP_MOB_GRP, " Mobile-H groups:"},
2195
{IDGRP_ISO_AT, " Isotopic:"},
2196
{IDGRP_CHARGE, " Charge(s):"},
2197
{IDGRP_PROTONS, " Proton balance:"},
2198
{IDGRP_ISO_H, " Exchangeable isotopic H:"},
2199
{IDGRP_SC, " Stereo centers/allenes:"},
2200
{IDGRP_SB, " Stereobonds/cumulenes:"},
2201
{IDGRP_HLAYER, " Fixed-H layer:"},
2202
{IDGRP_COMP, " Number of components:"},
2203
{IDGRP_CONV_ERR," Conversion encountered:"},
2207
CMP_INCHI_MSG CompareInchiMsgs[] = {
2208
{INCHIDIFF_PROBLEM ,IDGRP_ERR, " Wrong result" }, /*0x00000001, severe: at least one InChI does not exist */
2209
{INCHIDIFF_POSITION_H ,IDGRP_H, " Locations or number" }, /*0x00000002, difference in non-taut {Mobile-H} or all H {Fixed-H} location/number */
2210
{INCHIDIFF_MORE_FH ,IDGRP_H, " Fixed-H" }, /*0x00000004, extra fixed H */
2211
{INCHIDIFF_LESS_FH ,IDGRP_H, " Fixed-H" }, /*0x00000004, missing fixed H */
2212
{INCHIDIFF_MORE_H ,IDGRP_H, " Number" }, /*0x00000008, formulas differ in number of H */
2213
{INCHIDIFF_LESS_H ,IDGRP_H, " Number" }, /*0x00000008, formulas differ in number of H */
2214
{INCHIDIFF_NO_TAUT ,IDGRP_MOB_GRP, " Missing" }, /*0x00000010, restored structure has no taut groups while the original InChI has some */
2215
{INCHIDIFF_WRONG_TAUT ,IDGRP_MOB_GRP, " Falsely present" }, /*0x00000020, restored has tautomerism while the original does not have it */
2216
{INCHIDIFF_SINGLE_TG ,IDGRP_MOB_GRP, " One instead of multiple" }, /*0x00000040, restored has 1 taut. group while the original InChI has multiple tg */
2217
{INCHIDIFF_MULTIPLE_TG ,IDGRP_MOB_GRP, " Multiple instead of one" }, /*0x00000080, restored has multiple tg while the original InChI has only one tg */
2218
{INCHIDIFF_EXTRA_TG_ENDP,IDGRP_MOB_GRP, " Attachment points" }, /*0x00000100, extra tautomeric endpoint{s} in restored structure */
2219
{INCHIDIFF_MISS_TG_ENDP ,IDGRP_MOB_GRP, " Attachment points" }, /*0x00000100, one or more tg endpoint is not in the restored structure */
2220
{INCHIDIFF_DIFF_TG_ENDP ,IDGRP_MOB_GRP, " Attachment points" }, /*0x00000100, lists of tg endpoints are different */
2221
{INCHIDIFF_NUM_TG ,IDGRP_MOB_GRP, " Number" }, /*0x00000200, different number of tautomeric groups */
2222
{INCHIDIFF_TG ,IDGRP_MOB_GRP, " Do not match" }, /*0x00000200, different tautomeric groups */
2223
{INCHIDIFF_NUM_ISO_AT ,IDGRP_ISO_AT, " Atoms do not match" }, /*0x00000400, ?severe: restored struct. has different number of isotopic atoms */
2224
{INCHIDIFF_ISO_AT ,IDGRP_ISO_AT, " Atoms do not match" }, /*0x00000400, ?severe: restored struct. has different locations/isotopes of isotopic atoms */
2225
{INCHIDIFF_REM_ISO_H ,IDGRP_ISO_H, " Does not match for a component" }, /*0x00000800, isotopic H removed */
2226
{INCHIDIFF_MOB_ISO_H ,IDGRP_ISO_H, " Do not match" }, /*0x00001000, different number of mobile exchangeable isotopic H */
2227
{INCHIDIFF_CHARGE ,IDGRP_CHARGE, " Do not match" }, /*0x00002000, restored structure has different charge */
2228
{INCHIDIFF_REM_PROT ,IDGRP_PROTONS, " Does not match for a component" }, /*0x00004000, proton{s} removed/added from the restored structure */
2229
{INCHIDIFF_MOBH_PROTONS ,IDGRP_PROTONS, " Does not match" }, /*0x00008000, different proton balance */
2230
{INCHIDIFF_SC_INV ,IDGRP_SC, " Falsely inverted" }, /*0x00010000, restores structure has different inversion stereocenter mark */
2231
{INCHIDIFF_SC_PARITY ,IDGRP_SC, " Wrong parity" }, /*0x00020000, restored structure has stereoatoms or allenes with different parity */
2232
{INCHIDIFF_SC_EXTRA_UNDF,IDGRP_SC, " Extra undefined" }, /*0x00040000, restored structure has extra undefined stereocenter{s} */
2233
{INCHIDIFF_SC_EXTRA ,IDGRP_SC, " Extra known" }, /*0x00080000, restored structure has extra stereocenter{s} */
2234
{INCHIDIFF_SC_MISS_UNDF ,IDGRP_SC, " Missing undefined" }, /*0x00100000, restored structure has not some undefined stereocenter{s} */
2235
{INCHIDIFF_SC_MISS ,IDGRP_SC, " Missing known" }, /*0x00200000, restored structure has not some stereocenters that are not undefined */
2236
{INCHIDIFF_SB_PARITY ,IDGRP_SB, " Wrong parity" }, /*0x00400000, restored structure has stereobonds or cumulenes with different parity */
2237
{INCHIDIFF_SB_EXTRA_UNDF,IDGRP_SB, " Extra undefined" }, /*0x00800000, restored structure has extra undefined stereobond{s} */
2238
{INCHIDIFF_SB_EXTRA ,IDGRP_SB, " Missing known" }, /*0x01000000, restored structure has extra stereobond{s} */
2239
{INCHIDIFF_SB_MISS_UNDF ,IDGRP_SB, " Missing undefined" }, /*0x02000000, restored structure has not some undefined stereocenters */
2240
{INCHIDIFF_SB_MISS ,IDGRP_SB, " Missing known" }, /*0x04000000, restored structure has not some stereobonds that are not undefined */
2241
{INCHIDIFF_COMP_HLAYER ,IDGRP_HLAYER, " Missing or extra" }, /*0x08000000, Restored component has Mobile-H layer instead of both Mobile-H & Fixed-H or both instead of one */
2242
{INCHIDIFF_COMP_NUMBER ,IDGRP_COMP, " Does not match" }, /*0x10000000, wrong number of components */
2243
{INCHIDIFF_STR2INCHI_ERR,IDGRP_CONV_ERR," Error" }, /*0x20000000 Restored structure to InChI conversion error */
2244
{INCHIDIFF_ZERO ,IDGRP_ZERO, "" }
2247
/*************************************************************************/
2248
int AddOneMsg( char *szMsg, int used_len, int tot_len, const char *szAddMsg, const char *szDelim )
2250
const char ellip[] = "...";
2251
int len = strlen( szAddMsg );
2252
int len_delim = (used_len && szDelim)? strlen(szDelim) : 0;
2254
if ( len + len_delim + used_len < tot_len ) {
2256
strcpy( szMsg+used_len, szDelim );
2257
used_len += len_delim;
2259
strcpy( szMsg+used_len, szAddMsg );
2262
if ( (len_to_copy = (tot_len - used_len - len_delim - (int)sizeof(ellip))) > 10 ) {
2264
strcpy( szMsg+used_len, szDelim );
2265
used_len += len_delim;
2267
strncpy( szMsg+used_len, szAddMsg, len_to_copy );
2268
used_len += len_to_copy;
2269
strcpy( szMsg+used_len, ellip );
2270
used_len += sizeof( ellip ) - 1;
2274
/*************************************************************************/
2275
int FillOutCompareMessage( char *szMsg, int nLenMsg, INCHI_MODE bits[] )
2277
int bMobileH, k, n, len = strlen( szMsg );
2278
int iPrevGrpIdx, iCurGrpIdx, bFound;
2280
static const char *hdr = " Problems/mismatches:";
2282
if ( bits[TAUT_YES] || bits[TAUT_NON] ) {
2283
if ( !strstr( szMsg, hdr ) ) {
2284
len = AddOneMsg( szMsg, len, nLenMsg, hdr, NULL );
2286
for ( bMobileH = TAUT_YES; 0 <= bMobileH; bMobileH -- ) {
2287
if ( bits[bMobileH] ) {
2288
strcpy( szOneMsg, bMobileH==TAUT_YES? " Mobile-H(" : " Fixed-H(" );
2289
len = AddOneMsg( szMsg, len, nLenMsg, szOneMsg, NULL );
2294
if ( bit & bits[bMobileH] ) {
2295
/* search for the message */
2297
for ( k = 0; CompareInchiMsgs[k].nBit != INCHIDIFF_ZERO && !bFound; k ++ ) {
2298
if ( bit & (INCHI_MODE)CompareInchiMsgs[k].nBit ) {
2300
for ( n = 0; CompareInchiMsgsGroup[n].nGroupID != IDGRP_ZERO; n ++ ) {
2301
if ( CompareInchiMsgsGroup[n].nGroupID == CompareInchiMsgs[k].nGroupID ) {
2303
if ( iCurGrpIdx != iPrevGrpIdx ) {
2304
if ( iPrevGrpIdx >= 0 ) {
2305
len = AddOneMsg( szMsg, len, nLenMsg, ";", NULL );
2307
len = AddOneMsg( szMsg, len, nLenMsg, CompareInchiMsgsGroup[iCurGrpIdx].szGroupName, NULL );
2309
len = AddOneMsg( szMsg, len, nLenMsg, CompareInchiMsgs[k].szMsg, iCurGrpIdx == iPrevGrpIdx? ",":NULL );
2310
iPrevGrpIdx = iCurGrpIdx;
2320
if ( bits[bMobileH] ) {
2321
len = AddOneMsg( szMsg, len, nLenMsg, ")", NULL );