rino 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/ext/extconf.rb +1 -24
- data/ext/libinchi.so +0 -0
- data/ext/src/aux2atom.h +120 -39
- data/ext/src/comdef.h +3 -3
- data/ext/src/dispstru.c +2547 -0
- data/ext/src/dispstru.h +73 -0
- data/ext/src/extr_ct.h +5 -2
- data/ext/src/ichi.h +27 -11
- data/ext/src/ichi_bns.c +1800 -254
- data/ext/src/ichi_bns.h +205 -4
- data/ext/src/ichican2.c +197 -86
- data/ext/src/ichicano.c +8 -13
- data/ext/src/ichicano.h +2 -2
- data/ext/src/ichicans.c +11 -6
- data/ext/src/ichicant.h +2 -2
- data/ext/src/ichicomn.h +2 -2
- data/ext/src/ichicomp.h +19 -4
- data/ext/src/ichidrp.h +9 -5
- data/ext/src/ichierr.h +5 -3
- data/ext/src/ichiisot.c +2 -2
- data/ext/src/ichimain.c +461 -0
- data/ext/src/ichimain.h +23 -15
- data/ext/src/ichimak2.c +6 -6
- data/ext/src/ichimake.c +843 -42
- data/ext/src/ichimake.h +4 -2
- data/ext/src/ichimap1.c +5 -5
- data/ext/src/ichimap2.c +2 -2
- data/ext/src/ichimap4.c +34 -21
- data/ext/src/ichinorm.c +11 -5
- data/ext/src/ichinorm.h +3 -2
- data/ext/src/ichiparm.c +2 -2
- data/ext/src/ichiparm.h +232 -30
- data/ext/src/ichiprt1.c +35 -11
- data/ext/src/ichiprt2.c +78 -7
- data/ext/src/ichiprt3.c +300 -120
- data/ext/src/ichiqueu.c +17 -2
- data/ext/src/ichiread.c +6932 -0
- data/ext/src/ichiring.c +3 -2
- data/ext/src/ichiring.h +2 -2
- data/ext/src/ichirvr1.c +4891 -0
- data/ext/src/ichirvr2.c +6344 -0
- data/ext/src/ichirvr3.c +5499 -0
- data/ext/src/ichirvr4.c +3177 -0
- data/ext/src/ichirvr5.c +1166 -0
- data/ext/src/ichirvr6.c +1287 -0
- data/ext/src/ichirvr7.c +2319 -0
- data/ext/src/ichirvrs.h +882 -0
- data/ext/src/ichisize.h +2 -2
- data/ext/src/ichisort.c +5 -5
- data/ext/src/ichister.c +281 -86
- data/ext/src/ichister.h +9 -3
- data/ext/src/ichitaut.c +208 -9
- data/ext/src/ichitaut.h +13 -11
- data/ext/src/ichitime.h +16 -2
- data/ext/src/inchicmp.h +107 -0
- data/ext/src/inpdef.h +6 -3
- data/ext/src/libinchi_wrap.c +912 -0
- data/ext/src/lreadmol.h +34 -31
- data/ext/src/mode.h +244 -7
- data/ext/src/mol2atom.c +1060 -0
- data/ext/src/mol2atom.h +31 -0
- data/ext/src/readinch.c +239 -0
- data/ext/src/readmol.c +28 -0
- data/ext/src/{e_readmol.h → readmol.h} +7 -9
- data/ext/src/runichi.c +251 -177
- data/ext/src/strutil.c +444 -238
- data/ext/src/strutil.h +150 -11
- data/ext/src/util.c +176 -118
- data/ext/src/util.h +15 -3
- data/lib/rino.rb +71 -3
- data/test/test.rb +33 -4
- metadata +22 -34
- data/ext/ruby_inchi_main.so +0 -0
- data/ext/src/e_0dstereo.c +0 -3014
- data/ext/src/e_0dstereo.h +0 -31
- data/ext/src/e_comdef.h +0 -57
- data/ext/src/e_ctl_data.h +0 -147
- data/ext/src/e_ichi_io.c +0 -498
- data/ext/src/e_ichi_io.h +0 -40
- data/ext/src/e_ichi_parms.c +0 -37
- data/ext/src/e_ichi_parms.h +0 -41
- data/ext/src/e_ichicomp.h +0 -50
- data/ext/src/e_ichierr.h +0 -40
- data/ext/src/e_ichimain.c +0 -593
- data/ext/src/e_ichisize.h +0 -43
- data/ext/src/e_inchi_atom.c +0 -75
- data/ext/src/e_inchi_atom.h +0 -33
- data/ext/src/e_inpdef.h +0 -41
- data/ext/src/e_mode.h +0 -706
- data/ext/src/e_mol2atom.c +0 -649
- data/ext/src/e_readinch.c +0 -58
- data/ext/src/e_readmol.c +0 -54
- data/ext/src/e_readstru.c +0 -251
- data/ext/src/e_readstru.h +0 -33
- data/ext/src/e_util.c +0 -284
- data/ext/src/e_util.h +0 -61
- data/ext/src/ichilnct.c +0 -286
- data/ext/src/inchi_api.h +0 -670
- data/ext/src/inchi_dll.c +0 -1480
- data/ext/src/inchi_dll.h +0 -34
- data/ext/src/inchi_dll_main.c +0 -23
- data/ext/src/inchi_dll_main.h +0 -31
- data/ext/src/ruby_inchi_main.c +0 -558
data/ext/src/ichirvr7.c
ADDED
@@ -0,0 +1,2319 @@
|
|
1
|
+
/*
|
2
|
+
* International Union of Pure and Applied Chemistry (IUPAC)
|
3
|
+
* International Chemical Identifier (InChI)
|
4
|
+
* Version 1
|
5
|
+
* Software version 1.01
|
6
|
+
* July 21, 2006
|
7
|
+
* Developed at NIST
|
8
|
+
*/
|
9
|
+
|
10
|
+
#include <stdio.h>
|
11
|
+
#include <stdlib.h>
|
12
|
+
#include <string.h>
|
13
|
+
#include <ctype.h>
|
14
|
+
#include <math.h>
|
15
|
+
|
16
|
+
/* #define CHECK_WIN32_VC_HEAP */
|
17
|
+
#include "mode.h"
|
18
|
+
|
19
|
+
#if( READ_INCHI_STRING == 1 )
|
20
|
+
|
21
|
+
#include "ichicomp.h"
|
22
|
+
#include "ichi.h"
|
23
|
+
#include "ichitime.h"
|
24
|
+
#include "ichierr.h"
|
25
|
+
#include "util.h"
|
26
|
+
#include "strutil.h"
|
27
|
+
|
28
|
+
/* reverse InChI */
|
29
|
+
#include "ichimain.h"
|
30
|
+
#include "extr_ct.h"
|
31
|
+
#include "ichitaut.h"
|
32
|
+
#include "ichister.h"
|
33
|
+
#include "strutil.h"
|
34
|
+
#include "ichisize.h"
|
35
|
+
#include "ichiring.h"
|
36
|
+
#include "ichinorm.h"
|
37
|
+
|
38
|
+
#include "ichirvrs.h"
|
39
|
+
#include "inchicmp.h"
|
40
|
+
|
41
|
+
/******************************************************************************************************/
|
42
|
+
int InChI2Atom( ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd, const char *szCurHdr, long num_inp,
|
43
|
+
StrFromINChI *pStruct, int iComponent, int iAtNoOffset, int bI2A_Flag, int bHasSomeFixedH, InpInChI *OneInput)
|
44
|
+
{
|
45
|
+
int iINChI = (bI2A_Flag & I2A_FLAG_RECMET)? INCHI_REC : INCHI_BAS;
|
46
|
+
int bMobileH = (bI2A_Flag & I2A_FLAG_FIXEDH)? TAUT_NON : TAUT_YES;
|
47
|
+
INChI *pInChI[TAUT_NUM];
|
48
|
+
int ret = 0;
|
49
|
+
|
50
|
+
memset( pInChI, 0, sizeof(pInChI) );
|
51
|
+
/* disconnected or reconnected */
|
52
|
+
if ( iINChI == INCHI_REC ) {
|
53
|
+
if ( !OneInput->nNumComponents[iINChI][TAUT_YES] ) {
|
54
|
+
iINChI = INCHI_BAS;
|
55
|
+
}
|
56
|
+
}
|
57
|
+
if ( iComponent >= OneInput->nNumComponents[iINChI][TAUT_YES] ) {
|
58
|
+
return 0; /* component does not exist */
|
59
|
+
}
|
60
|
+
/* mobile or fixed H */
|
61
|
+
pStruct->bFixedHExists = 0;
|
62
|
+
if ( bMobileH == TAUT_NON ) {
|
63
|
+
if ( !OneInput->nNumComponents[iINChI][bMobileH] ) {
|
64
|
+
/* only one InChI exists (no mobile H) */
|
65
|
+
bMobileH = TAUT_YES;
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
if ( iComponent >= OneInput->nNumComponents[iINChI][bMobileH] ) {
|
70
|
+
return 0; /* component does not exist */
|
71
|
+
}
|
72
|
+
/* pointer to the InChI that is going to be reversed */
|
73
|
+
pInChI[0] = &OneInput->pInpInChI[iINChI][bMobileH][iComponent];
|
74
|
+
pStruct->bMobileH = bMobileH;
|
75
|
+
pStruct->iINCHI = iINChI;
|
76
|
+
/* deleted component only in case Mobile-H and compound contains only protons */
|
77
|
+
if ( pInChI[0]->bDeleted ) {
|
78
|
+
return 0; /* deleted component, presumably H(+) */
|
79
|
+
}
|
80
|
+
|
81
|
+
if ( bMobileH == TAUT_NON && OneInput->nNumProtons[iINChI][TAUT_YES].pNumProtons ) {
|
82
|
+
pStruct->nNumRemovedProtonsMobHInChI =
|
83
|
+
OneInput->nNumProtons[iINChI][TAUT_YES].pNumProtons[iComponent].nNumRemovedProtons;
|
84
|
+
}
|
85
|
+
|
86
|
+
if ( bMobileH == TAUT_NON || bMobileH == TAUT_YES && OneInput->pInpInChI[iINChI][TAUT_NON] &&
|
87
|
+
OneInput->pInpInChI[iINChI][TAUT_NON][iComponent].nNumberOfAtoms > 0 &&
|
88
|
+
!OneInput->pInpInChI[iINChI][TAUT_NON][iComponent].bDeleted ) {
|
89
|
+
pStruct->bFixedHExists = 1;
|
90
|
+
}
|
91
|
+
if ( bMobileH == TAUT_NON && iComponent < OneInput->nNumComponents[iINChI][TAUT_YES] &&
|
92
|
+
OneInput->pInpInChI[iINChI][TAUT_YES] &&
|
93
|
+
OneInput->pInpInChI[iINChI][TAUT_YES][iComponent].nNumberOfAtoms > 0 &&
|
94
|
+
!OneInput->pInpInChI[iINChI][TAUT_YES][iComponent].bDeleted ) {
|
95
|
+
/* pointer to the Mobile-H InChI if we are reversing Fixed-H InChI */
|
96
|
+
pInChI[1] = &OneInput->pInpInChI[iINChI][TAUT_YES][iComponent];
|
97
|
+
}
|
98
|
+
pStruct->num_inp_actual = OneInput->num_inp;
|
99
|
+
ret = OneInChI2Atom( ip, sd, szCurHdr, num_inp, pStruct, iComponent, iAtNoOffset, bHasSomeFixedH, pInChI);
|
100
|
+
return ret; /* same interpretation as in ProcessOneStructure ??? */
|
101
|
+
}
|
102
|
+
|
103
|
+
/*******************************************************************/
|
104
|
+
void RemoveFixHInChIIdentical2MobH( InpInChI *pOneInput )
|
105
|
+
{
|
106
|
+
int iInchiRec, cur_num_comp, k;
|
107
|
+
/* eliminate Fixed-H InChI that are exactly came as the corresponding Mobile-H structures */
|
108
|
+
for ( iInchiRec = 0; iInchiRec < INCHI_NUM; iInchiRec ++ ) {
|
109
|
+
cur_num_comp = inchi_min(pOneInput->nNumComponents[iInchiRec][TAUT_YES],
|
110
|
+
pOneInput->nNumComponents[iInchiRec][TAUT_NON]);
|
111
|
+
for ( k = 0; k < cur_num_comp; k ++ ) {
|
112
|
+
if ( !CompareReversedINChI( pOneInput->pInpInChI[iInchiRec][TAUT_YES]+k,
|
113
|
+
pOneInput->pInpInChI[iInchiRec][TAUT_NON]+k, NULL, NULL ) ) {
|
114
|
+
Free_INChI_Members( pOneInput->pInpInChI[iInchiRec][TAUT_NON]+k );
|
115
|
+
memset( pOneInput->pInpInChI[iInchiRec][TAUT_NON]+k, 0, sizeof(pOneInput->pInpInChI[0][0][0]) );
|
116
|
+
}
|
117
|
+
}
|
118
|
+
}
|
119
|
+
}
|
120
|
+
/*******************************************************************/
|
121
|
+
int MarkDisconectedIdenticalToReconnected ( InpInChI *pOneInput )
|
122
|
+
{
|
123
|
+
/* mark Disconnected InChI components that are exactly came as Reconnected ones */
|
124
|
+
/* Disconnected will have a negative number of the reconnected component */
|
125
|
+
/* Reconnected will have a positive number of the disconnected component */
|
126
|
+
int k1, k2, num_marked = 0;
|
127
|
+
for ( k1 = 0; k1 < inchi_max(pOneInput->nNumComponents[INCHI_BAS][TAUT_YES],
|
128
|
+
pOneInput->nNumComponents[INCHI_BAS][TAUT_NON]); k1 ++ ) {
|
129
|
+
for ( k2 = 0; k2 < inchi_max(pOneInput->nNumComponents[INCHI_REC][TAUT_YES],
|
130
|
+
pOneInput->nNumComponents[INCHI_REC][TAUT_NON]); k2 ++ ) {
|
131
|
+
int eqM = ( k1 < pOneInput->nNumComponents[INCHI_BAS][TAUT_YES] &&
|
132
|
+
k2 < pOneInput->nNumComponents[INCHI_REC][TAUT_YES] &&
|
133
|
+
!pOneInput->pInpInChI[INCHI_REC][TAUT_YES][k2].nLink && /* already linked */
|
134
|
+
!pOneInput->pInpInChI[INCHI_BAS][TAUT_YES][k1].bDeleted &&
|
135
|
+
pOneInput->pInpInChI[INCHI_BAS][TAUT_YES][k1].nNumberOfAtoms &&
|
136
|
+
pOneInput->pInpInChI[INCHI_BAS][TAUT_YES][k1].nNumberOfAtoms ==
|
137
|
+
pOneInput->pInpInChI[INCHI_REC][TAUT_YES][k2].nNumberOfAtoms &&
|
138
|
+
!pOneInput->pInpInChI[INCHI_REC][TAUT_YES][k2].bDeleted &&
|
139
|
+
!CompareReversedINChI( pOneInput->pInpInChI[INCHI_REC][TAUT_YES]+k2,
|
140
|
+
pOneInput->pInpInChI[INCHI_BAS][TAUT_YES]+k1,
|
141
|
+
NULL, NULL ));
|
142
|
+
int isF1 = (k1 < pOneInput->nNumComponents[INCHI_BAS][TAUT_NON] &&
|
143
|
+
0 == pOneInput->pInpInChI[INCHI_BAS][TAUT_NON][k1].bDeleted &&
|
144
|
+
0 < pOneInput->pInpInChI[INCHI_BAS][TAUT_NON][k1].nNumberOfAtoms );
|
145
|
+
int isF2 = (k2 < pOneInput->nNumComponents[INCHI_REC][TAUT_NON] &&
|
146
|
+
0 == pOneInput->pInpInChI[INCHI_REC][TAUT_NON][k2].bDeleted &&
|
147
|
+
0 < pOneInput->pInpInChI[INCHI_REC][TAUT_NON][k2].nNumberOfAtoms );
|
148
|
+
int eqF = isF1 && isF2 &&
|
149
|
+
!pOneInput->pInpInChI[INCHI_REC][TAUT_NON][k2].nLink &&
|
150
|
+
pOneInput->pInpInChI[INCHI_BAS][TAUT_NON][k1].nNumberOfAtoms ==
|
151
|
+
pOneInput->pInpInChI[INCHI_REC][TAUT_NON][k2].nNumberOfAtoms &&
|
152
|
+
!CompareReversedINChI( pOneInput->pInpInChI[INCHI_REC][TAUT_NON]+k2,
|
153
|
+
pOneInput->pInpInChI[INCHI_BAS][TAUT_NON]+k1,
|
154
|
+
NULL, NULL );
|
155
|
+
if ( eqM && (!isF1 && !isF2 || eqF ) ) {
|
156
|
+
pOneInput->pInpInChI[INCHI_BAS][TAUT_YES][k1].nLink = -(k2+1);
|
157
|
+
pOneInput->pInpInChI[INCHI_REC][TAUT_YES][k2].nLink = (k1+1);
|
158
|
+
if ( eqF ) {
|
159
|
+
pOneInput->pInpInChI[INCHI_BAS][TAUT_NON][k1].nLink = -(k2+1);
|
160
|
+
pOneInput->pInpInChI[INCHI_REC][TAUT_NON][k2].nLink = (k1+1);
|
161
|
+
}
|
162
|
+
num_marked ++;
|
163
|
+
break; /* equal InChI has been deleted from the disconnected layer, get next k1 */
|
164
|
+
}
|
165
|
+
}
|
166
|
+
}
|
167
|
+
return num_marked;
|
168
|
+
|
169
|
+
}
|
170
|
+
/**************************************************************/
|
171
|
+
void SetUpSrm( SRM *pSrm )
|
172
|
+
{
|
173
|
+
/* structure restore parms !!!!! */
|
174
|
+
memset( pSrm, 0, sizeof(pSrm[0]) );
|
175
|
+
pSrm->bFixStereoBonds = FIX_STEREO_BOND_ORDER;
|
176
|
+
pSrm->nMetal2EndpointMinBondOrder = 1;
|
177
|
+
pSrm->nMetal2EndpointInitEdgeFlow = 0;
|
178
|
+
if ( METAL_FREE_CHARGE_VAL == 1 ) {
|
179
|
+
pSrm->bMetalAddFlower = 1;
|
180
|
+
/* the next 3 parameters: */
|
181
|
+
/* 0, 0, 0 => all bonds 0, no init radical on metal */
|
182
|
+
/* 0, 0, 1 => all bonds 0, init radical on metal */
|
183
|
+
/* 0, 1, 0 => wrong */
|
184
|
+
/* 0, 1, 1 => all bonds 1, no init radical on metal */
|
185
|
+
/* 1, 0, 1 => min bond order 1, all bonds to metal have order 1 */
|
186
|
+
/* 1, 1, 0 => wrong */
|
187
|
+
/* 1, 1, 1 => wrong */
|
188
|
+
pSrm->nMetalMinBondOrder = 0;
|
189
|
+
pSrm->nMetalInitEdgeFlow = 1;
|
190
|
+
pSrm->nMetalInitBondOrder = 1;
|
191
|
+
pSrm->bStereoRemovesMetalFlag = pSrm->bFixStereoBonds;
|
192
|
+
pSrm->nMetalFlowerParam_D = 16;
|
193
|
+
pSrm->nMetalMaxCharge_D = 16;
|
194
|
+
} else {
|
195
|
+
pSrm->bMetalAddFlower = 0;
|
196
|
+
pSrm->nMetalMinBondOrder = 1;
|
197
|
+
pSrm->nMetalInitEdgeFlow = 0;
|
198
|
+
pSrm->nMetalInitBondOrder = 1;
|
199
|
+
pSrm->bStereoRemovesMetalFlag = pSrm->bFixStereoBonds;
|
200
|
+
pSrm->nMetalFlowerParam_D = 16;
|
201
|
+
pSrm->nMetalMaxCharge_D = 0;
|
202
|
+
}
|
203
|
+
/*
|
204
|
+
pSrm->nMetalInitBondOrder = pSrm->nMetalMinBondOrder
|
205
|
+
+ pSrm->nMetalInitEdgeFlow;
|
206
|
+
*/
|
207
|
+
pSrm->nMetal2EndpointInitBondOrder = pSrm->nMetal2EndpointMinBondOrder
|
208
|
+
+ pSrm->nMetal2EndpointInitEdgeFlow;
|
209
|
+
|
210
|
+
}
|
211
|
+
/**************************************************************************************/
|
212
|
+
int MergeStructureComponents( ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd, long num_inp, char *szCurHdr,
|
213
|
+
ICHICONST SRM *pSrm, int bReqNonTaut, StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM],
|
214
|
+
InpInChI *pOneInput )
|
215
|
+
{
|
216
|
+
int iInchiRec, iMobileH, iAlternH, num_components, tot_just_atoms, tot_removed_H, tot_atoms, cur_nA, cur_nH;
|
217
|
+
int k, i, j, ret, iCurAtomOffs, iNxtAtomOffs, iCurDelHOffs, iNxtDelHOffs, len, len2, iShiftH, icomp;
|
218
|
+
int *nAtomOffs=NULL, *nDelHOffs=NULL;
|
219
|
+
StrFromINChI *pStruct1;
|
220
|
+
inp_ATOM *at=NULL, *a;
|
221
|
+
|
222
|
+
ret = 0;
|
223
|
+
pOneInput->num_atoms = 0;
|
224
|
+
/* select highest detail level */
|
225
|
+
if ( num_components = pOneInput->nNumComponents[INCHI_REC][TAUT_NON] ) {
|
226
|
+
iInchiRec = INCHI_REC;
|
227
|
+
iMobileH = TAUT_NON;
|
228
|
+
} else
|
229
|
+
if ( num_components = pOneInput->nNumComponents[INCHI_REC][TAUT_YES] ) {
|
230
|
+
iInchiRec = INCHI_REC;
|
231
|
+
iMobileH = TAUT_YES;
|
232
|
+
} else
|
233
|
+
if ( num_components = pOneInput->nNumComponents[INCHI_BAS][TAUT_NON] ) {
|
234
|
+
iInchiRec = INCHI_BAS;
|
235
|
+
iMobileH = TAUT_NON;
|
236
|
+
} else
|
237
|
+
if ( num_components = pOneInput->nNumComponents[INCHI_BAS][TAUT_YES] ) {
|
238
|
+
iInchiRec = INCHI_BAS;
|
239
|
+
iMobileH = TAUT_YES;
|
240
|
+
} else {
|
241
|
+
return 0; /* no components available */
|
242
|
+
}
|
243
|
+
|
244
|
+
nAtomOffs = (int*)inchi_malloc((num_components+1) * sizeof(nAtomOffs[0]));
|
245
|
+
nDelHOffs = (int*)inchi_malloc((num_components+1) * sizeof(nDelHOffs[0]));
|
246
|
+
if ( !nAtomOffs || !nDelHOffs ) {
|
247
|
+
ret = RI_ERR_ALLOC;
|
248
|
+
goto exit_function;
|
249
|
+
}
|
250
|
+
/* count number of atoms and removed H */
|
251
|
+
tot_just_atoms = tot_removed_H = tot_atoms = 0;
|
252
|
+
iAlternH = (iMobileH==TAUT_NON && pOneInput->nNumComponents[iInchiRec][TAUT_YES])? TAUT_YES : -1;
|
253
|
+
nAtomOffs[0] = nDelHOffs[0] = 0;
|
254
|
+
for ( k = 0; k < num_components; k ++ ) {
|
255
|
+
pStruct1 = pStruct[iInchiRec][iMobileH][k].num_atoms? pStruct[iInchiRec][iMobileH]+k :
|
256
|
+
iAlternH>=0 &&
|
257
|
+
pStruct[iInchiRec][iAlternH][k].num_atoms? pStruct[iInchiRec][iAlternH]+k : NULL;
|
258
|
+
if ( !pStruct1 || !pStruct1->at2 || !pStruct1->num_atoms || pStruct1->bDeleted ) {
|
259
|
+
cur_nA = cur_nH = 0;
|
260
|
+
} else {
|
261
|
+
cur_nA = pStruct1->num_atoms;
|
262
|
+
cur_nH = pStruct1->num_deleted_H;
|
263
|
+
}
|
264
|
+
nAtomOffs[k+1] = nAtomOffs[k] + cur_nA;
|
265
|
+
nDelHOffs[k+1] = nDelHOffs[k] + cur_nH;
|
266
|
+
}
|
267
|
+
tot_just_atoms = nAtomOffs[num_components];
|
268
|
+
/* shift all H to the end */
|
269
|
+
for ( k = 0; k <= num_components; k ++ ) {
|
270
|
+
nDelHOffs[k] += tot_just_atoms;
|
271
|
+
}
|
272
|
+
tot_atoms = nDelHOffs[num_components];
|
273
|
+
|
274
|
+
/* merge atoms together: 1. Allocate */
|
275
|
+
if ( NULL == (at = (inp_ATOM *)inchi_malloc( (tot_atoms+1) * sizeof(at[0]) ) ) ) {
|
276
|
+
ret = RI_ERR_ALLOC;
|
277
|
+
goto exit_function;
|
278
|
+
}
|
279
|
+
if ( !tot_atoms ) {
|
280
|
+
ret = 0;
|
281
|
+
goto exit_function; /* empty structure */
|
282
|
+
}
|
283
|
+
/* merge atoms together: 2. Copy */
|
284
|
+
for ( k = 0; k < num_components; k ++ ) {
|
285
|
+
pStruct1 = pStruct[iInchiRec][iMobileH][k].num_atoms? pStruct[iInchiRec][iMobileH]+k :
|
286
|
+
iAlternH>=0 &&
|
287
|
+
pStruct[iInchiRec][iAlternH][k].num_atoms? pStruct[iInchiRec][iAlternH]+k : NULL;
|
288
|
+
if ( len = nAtomOffs[k+1] - nAtomOffs[k] ) {
|
289
|
+
memcpy( at + nAtomOffs[k], pStruct1->at2, len * sizeof(at[0]) );
|
290
|
+
if ( len2 = nDelHOffs[k+1] - nDelHOffs[k] ) {
|
291
|
+
memcpy( at + nDelHOffs[k], pStruct1->at2+len, len2 * sizeof(at[0]) );
|
292
|
+
}
|
293
|
+
}
|
294
|
+
}
|
295
|
+
/* merge atoms together: 3. Update atom numbers */
|
296
|
+
icomp = 0;
|
297
|
+
for ( k = 0; k < num_components; k ++ ) {
|
298
|
+
iCurAtomOffs = nAtomOffs[k];
|
299
|
+
iNxtAtomOffs = nAtomOffs[k+1];
|
300
|
+
iCurDelHOffs = nDelHOffs[k];
|
301
|
+
iNxtDelHOffs = nDelHOffs[k+1];
|
302
|
+
len = nAtomOffs[k+1] - nAtomOffs[k]; /* number of atoms in a component excluding explicit H */
|
303
|
+
iShiftH = iCurDelHOffs - len;
|
304
|
+
if ( !len ) {
|
305
|
+
continue;
|
306
|
+
}
|
307
|
+
icomp ++; /* current component number */
|
308
|
+
/* update atoms */
|
309
|
+
for ( i = iCurAtomOffs; i < iNxtAtomOffs; i ++ ) {
|
310
|
+
|
311
|
+
a = at+i;
|
312
|
+
|
313
|
+
a->endpoint = 0;
|
314
|
+
a->bAmbiguousStereo = 0;
|
315
|
+
a->at_type = 0;
|
316
|
+
a->bCutVertex = 0;
|
317
|
+
a->bUsed0DParity = 0;
|
318
|
+
a->cFlags = 0;
|
319
|
+
a->nBlockSystem = 0;
|
320
|
+
a->nNumAtInRingSystem = 0;
|
321
|
+
a->nRingSystem = 0;
|
322
|
+
|
323
|
+
for ( j = 0; j < a->valence; j ++ ) {
|
324
|
+
if ( a->neighbor[j] < len ) {
|
325
|
+
a->neighbor[j] += iCurAtomOffs; /* atom */
|
326
|
+
} else {
|
327
|
+
a->neighbor[j] += iShiftH; /* explicit H */
|
328
|
+
}
|
329
|
+
}
|
330
|
+
a->orig_at_number += iCurAtomOffs;
|
331
|
+
a->component = icomp;
|
332
|
+
if ( a->p_parity ) {
|
333
|
+
for ( j = 0; j < MAX_NUM_STEREO_ATOM_NEIGH; j ++ ) {
|
334
|
+
if ( a->p_orig_at_num[j] <= len ) {
|
335
|
+
/* originally, orig_at_num = atom_index+1, therefore <= instead of < */
|
336
|
+
a->p_orig_at_num[j] += iCurAtomOffs;
|
337
|
+
} else {
|
338
|
+
a->p_orig_at_num[j] += iShiftH;
|
339
|
+
}
|
340
|
+
}
|
341
|
+
}
|
342
|
+
for ( j = 0; j < MAX_NUM_STEREO_BONDS && a->sb_parity[j]; j ++ ) {
|
343
|
+
if ( a->sn_orig_at_num[j] <= len ) {
|
344
|
+
/* originally, orig_at_num = atom_index+1, therefore <= instead of < */
|
345
|
+
a->sn_orig_at_num[j] += iCurAtomOffs;
|
346
|
+
} else {
|
347
|
+
a->sn_orig_at_num[j] += iShiftH;
|
348
|
+
}
|
349
|
+
}
|
350
|
+
}
|
351
|
+
/* update fixed-H */
|
352
|
+
for ( i = iCurDelHOffs; i < iNxtDelHOffs; i ++ ) {
|
353
|
+
a = at+i;
|
354
|
+
a->neighbor[0] += iCurAtomOffs;
|
355
|
+
a->orig_at_number += iShiftH;
|
356
|
+
|
357
|
+
}
|
358
|
+
}
|
359
|
+
/* save the results */
|
360
|
+
pOneInput->atom = at;
|
361
|
+
pOneInput->num_atoms = tot_atoms;
|
362
|
+
at = NULL;
|
363
|
+
|
364
|
+
exit_function:
|
365
|
+
if ( at ) inchi_free( at ); /* in case of failure */
|
366
|
+
if ( nAtomOffs ) inchi_free( nAtomOffs );
|
367
|
+
if ( nDelHOffs ) inchi_free( nDelHOffs );
|
368
|
+
return ret;
|
369
|
+
}
|
370
|
+
#ifndef INCHI_ANSI_ONLY
|
371
|
+
static PER_DRAW_PARMS pdp;
|
372
|
+
/******************************************************************************************************/
|
373
|
+
int DisplayAllRestoredComponents( inp_ATOM *at, int num_at, const char *szCurHdr )
|
374
|
+
{
|
375
|
+
int ret;
|
376
|
+
char szTitle[512];
|
377
|
+
DRAW_PARMS dp;
|
378
|
+
TBL_DRAW_PARMS tdp;
|
379
|
+
if ( num_at <= 0 ) {
|
380
|
+
return 0;
|
381
|
+
}
|
382
|
+
memset( &dp, 0, sizeof(dp));
|
383
|
+
memset( &tdp, 0, sizeof(tdp) );
|
384
|
+
//memset( &pdp, 0, sizeof(pdp) );
|
385
|
+
dp.sdp.tdp = &tdp;
|
386
|
+
dp.pdp = &pdp;
|
387
|
+
dp.sdp.nFontSize = -9;
|
388
|
+
sprintf( szTitle, "All Components of Restored %s Structure", szCurHdr? szCurHdr : "(No structure name)");
|
389
|
+
ret = DisplayStructure( at, num_at, 0 /* nNumDeletedH*/, 0 /*bAdd_DT_to_num_H*/,
|
390
|
+
0 /*nNumRemovedProtons*/, NULL /*NUM_H *nNumRemovedProtonsIsotopic*/,
|
391
|
+
1 /*int bIsotopic*/, 0 /*bTautomeric*/,
|
392
|
+
NULL /* pINChI */, NULL /* INChI_Aux **cur_INChI_Aux*/,
|
393
|
+
0 /*bAbcNumbers*/, &dp, 0 /*INCHI_MODE nMode*/, szTitle );
|
394
|
+
return 0;
|
395
|
+
}
|
396
|
+
/******************************************************************************************************/
|
397
|
+
int DisplayOneRestoredComponent( StrFromINChI *pStruct, inp_ATOM *at,
|
398
|
+
int iComponent, int nNumComponents, int bMobileH,
|
399
|
+
const char *szCurHdr )
|
400
|
+
{
|
401
|
+
int ret, k;
|
402
|
+
int num_at = pStruct->num_atoms;
|
403
|
+
XYZ_COORD *pxyz = pStruct->pXYZ;
|
404
|
+
char szTitle[512];
|
405
|
+
DRAW_PARMS dp;
|
406
|
+
TBL_DRAW_PARMS tdp;
|
407
|
+
int iInchiRec = pStruct->iInchiRec;
|
408
|
+
int iMobileH = pStruct->iMobileH;
|
409
|
+
INChI **pInChI = NULL;
|
410
|
+
INChI_Aux **pAux = NULL;
|
411
|
+
int nNumRemovedProtons = pAux? pAux[iMobileH]->nNumRemovedProtons : 0;
|
412
|
+
NUM_H *nNumRemovedProtonsIsotopic = pAux? pAux[iMobileH]->nNumRemovedIsotopicH : NULL;
|
413
|
+
|
414
|
+
|
415
|
+
if ( num_at <= 0 || !pxyz ) {
|
416
|
+
return 0;
|
417
|
+
}
|
418
|
+
if ( iInchiRec && !pStruct->RevInChI.pINChI_Aux[iInchiRec][0] ) {
|
419
|
+
iInchiRec = 0;
|
420
|
+
}
|
421
|
+
k = iMobileH;
|
422
|
+
if ( !bRevInchiComponentExists( pStruct, iInchiRec, k, 0 ) ) {
|
423
|
+
k = ALT_TAUT(k);
|
424
|
+
}
|
425
|
+
pInChI = pStruct->RevInChI.pINChI[iInchiRec][0];
|
426
|
+
pAux = pStruct->RevInChI.pINChI_Aux[iInchiRec][0];
|
427
|
+
|
428
|
+
|
429
|
+
memset( &dp, 0, sizeof(dp));
|
430
|
+
memset( &tdp, 0, sizeof(tdp) );
|
431
|
+
//memset( &pdp, 0, sizeof(pdp) );
|
432
|
+
dp.sdp.tdp = &tdp;
|
433
|
+
dp.pdp = &pdp;
|
434
|
+
dp.sdp.nFontSize = -9;
|
435
|
+
sprintf( szTitle, "Restored %s Component %d of %d %c%c",
|
436
|
+
szCurHdr? szCurHdr : "(No structure name)", iComponent+1, nNumComponents,
|
437
|
+
pStruct->iInchiRec? 'R':'D', pStruct->iMobileH?'M':'F' );
|
438
|
+
ret = DisplayStructure( at, num_at, 0 /* nNumDeletedH*/, 0 /*bAdd_DT_to_num_H*/,
|
439
|
+
nNumRemovedProtons, /*NULL*/ nNumRemovedProtonsIsotopic,
|
440
|
+
1 /*int bIsotopic*/, k,
|
441
|
+
pInChI, pAux,
|
442
|
+
0 /*bAbcNumbers*/, &dp, 0 /*INCHI_MODE nMode*/, szTitle );
|
443
|
+
return 0;
|
444
|
+
}
|
445
|
+
/******************************************************************************************************/
|
446
|
+
int DisplayRestoredComponent( StrFromINChI *pStruct, int iComponent, int iAtNoOffset, INChI *pInChI, const char *szCurHdr )
|
447
|
+
{
|
448
|
+
int i, ret;
|
449
|
+
int num_at = pStruct->num_atoms;
|
450
|
+
int num_deleted_H = pStruct->num_deleted_H;
|
451
|
+
inp_ATOM *atom = pStruct->at2;
|
452
|
+
XYZ_COORD *pxyz = pStruct->pXYZ;
|
453
|
+
inp_ATOM *at = NULL;
|
454
|
+
char szTitle[512];
|
455
|
+
DRAW_PARMS dp;
|
456
|
+
TBL_DRAW_PARMS tdp;
|
457
|
+
if ( !atom || num_at <= 0 || !pxyz ) {
|
458
|
+
return 0;
|
459
|
+
}
|
460
|
+
at = (inp_ATOM *)inchi_calloc( num_at + num_deleted_H, sizeof(at[0]) );
|
461
|
+
if ( !at ) {
|
462
|
+
return RI_ERR_ALLOC;
|
463
|
+
}
|
464
|
+
memcpy( at, atom, (num_at + num_deleted_H) * sizeof(at[0]) );
|
465
|
+
for ( i = 0; i < num_at; i ++ ) {
|
466
|
+
at[i].x = pxyz[i].xyz[0];
|
467
|
+
at[i].y = pxyz[i].xyz[1];
|
468
|
+
at[i].z = pxyz[i].xyz[2];
|
469
|
+
}
|
470
|
+
memset( &dp, 0, sizeof(dp));
|
471
|
+
memset( &tdp, 0, sizeof(tdp) );
|
472
|
+
//memset( &pdp, 0, sizeof(pdp) );
|
473
|
+
dp.sdp.tdp = &tdp;
|
474
|
+
dp.pdp = &pdp;
|
475
|
+
dp.sdp.nFontSize = -9;
|
476
|
+
sprintf( szTitle, "DBG Restored %s Component %d %c%c", szCurHdr? szCurHdr : "(No structure name)", iComponent+1, pStruct->iInchiRec? 'R':'D', pStruct->iMobileH?'M':'F' );
|
477
|
+
ret = DisplayStructure( at, num_at, 0 /* nNumDeletedH*/, 0 /*bAdd_DT_to_num_H*/,
|
478
|
+
0 /*nNumRemovedProtons*/, NULL /*NUM_H *nNumRemovedProtonsIsotopic*/,
|
479
|
+
1 /*int bIsotopic*/, 0 /*bTautomeric*/,
|
480
|
+
&pInChI, NULL /* INChI_Aux **cur_INChI_Aux*/,
|
481
|
+
0 /*bAbcNumbers*/, &dp, 0 /*INCHI_MODE nMode*/, szTitle );
|
482
|
+
inchi_free( at );
|
483
|
+
return 0;
|
484
|
+
}
|
485
|
+
/**************************************************************************************/
|
486
|
+
int DisplayStructureComponents( ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd, long num_inp, char *szCurHdr,
|
487
|
+
ICHICONST SRM *pSrm, int bReqNonTaut, StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM],
|
488
|
+
InpInChI *pOneInput )
|
489
|
+
{
|
490
|
+
int iInchiRec, iMobileH, iCurMobH, iAlternH, num_components, tot_just_atoms, tot_removed_H, tot_atoms, cur_nA, cur_nH;
|
491
|
+
int k, i, j, ret, iCurAtomOffs, iNxtAtomOffs, iCurDelHOffs, iNxtDelHOffs, len, len2, iShiftH, icomp;
|
492
|
+
int *nAtomOffs=NULL, *nDelHOffs=NULL, bNoCoord=0, iNewCoord=0, nNewCoord=0;
|
493
|
+
double x_max=-1.0e16, x_min = 1.0e16, y_max=-1.0e16, y_min=1.0e16, delta = 0.0;
|
494
|
+
StrFromINChI *pStruct1;
|
495
|
+
inp_ATOM *at=NULL, *a;
|
496
|
+
|
497
|
+
if (!ip->bDisplayCompositeResults && !ip->bDisplay ) {
|
498
|
+
return 0;
|
499
|
+
}
|
500
|
+
|
501
|
+
ret = 0;
|
502
|
+
pOneInput->num_atoms = 0;
|
503
|
+
/* select highest detail level */
|
504
|
+
if ( num_components = pOneInput->nNumComponents[INCHI_REC][TAUT_NON] ) {
|
505
|
+
iInchiRec = INCHI_REC;
|
506
|
+
iMobileH = TAUT_NON;
|
507
|
+
} else
|
508
|
+
if ( num_components = pOneInput->nNumComponents[INCHI_REC][TAUT_YES] ) {
|
509
|
+
iInchiRec = INCHI_REC;
|
510
|
+
iMobileH = TAUT_YES;
|
511
|
+
} else
|
512
|
+
if ( num_components = pOneInput->nNumComponents[INCHI_BAS][TAUT_NON] ) {
|
513
|
+
iInchiRec = INCHI_BAS;
|
514
|
+
iMobileH = TAUT_NON;
|
515
|
+
} else
|
516
|
+
if ( num_components = pOneInput->nNumComponents[INCHI_BAS][TAUT_YES] ) {
|
517
|
+
iInchiRec = INCHI_BAS;
|
518
|
+
iMobileH = TAUT_YES;
|
519
|
+
} else {
|
520
|
+
return 0; /* no components available */
|
521
|
+
}
|
522
|
+
for ( k = 0; k < num_components; k ++ ) {
|
523
|
+
if ( pStruct[iInchiRec][iMobileH][k].bDeleted )
|
524
|
+
break;
|
525
|
+
}
|
526
|
+
num_components = k;
|
527
|
+
|
528
|
+
nAtomOffs = (int*)inchi_malloc((num_components+1) * sizeof(nAtomOffs[0]));
|
529
|
+
nDelHOffs = (int*)inchi_malloc((num_components+1) * sizeof(nDelHOffs[0]));
|
530
|
+
if ( !nAtomOffs || !nDelHOffs ) {
|
531
|
+
ret = RI_ERR_ALLOC;
|
532
|
+
goto exit_function;
|
533
|
+
}
|
534
|
+
/* count number of atoms and removed H */
|
535
|
+
tot_just_atoms = tot_removed_H = tot_atoms = 0;
|
536
|
+
iAlternH = (iMobileH==TAUT_NON && pOneInput->nNumComponents[iInchiRec][TAUT_YES])? TAUT_YES : -1;
|
537
|
+
nAtomOffs[0] = nDelHOffs[0] = 0;
|
538
|
+
for ( k = 0; k < num_components; k ++ ) {
|
539
|
+
pStruct1 = pStruct[iInchiRec][iMobileH][k].num_atoms? pStruct[iInchiRec][iMobileH]+k :
|
540
|
+
iAlternH>=0 &&
|
541
|
+
pStruct[iInchiRec][iAlternH][k].num_atoms? pStruct[iInchiRec][iAlternH]+k : NULL;
|
542
|
+
if ( !pStruct1 || !pStruct1->at2 || !pStruct1->num_atoms ) {
|
543
|
+
cur_nA = cur_nH = 0;
|
544
|
+
} else {
|
545
|
+
cur_nA = pStruct1->num_atoms;
|
546
|
+
cur_nH = pStruct1->num_deleted_H;
|
547
|
+
if ( cur_nA && !pStruct1->pXYZ ) {
|
548
|
+
if ( !k ) {
|
549
|
+
ret = 0; /* no coordinates available */
|
550
|
+
goto exit_function;
|
551
|
+
} else {
|
552
|
+
bNoCoord ++;
|
553
|
+
}
|
554
|
+
}
|
555
|
+
}
|
556
|
+
nAtomOffs[k+1] = nAtomOffs[k] + cur_nA;
|
557
|
+
nDelHOffs[k+1] = nDelHOffs[k] + cur_nH;
|
558
|
+
}
|
559
|
+
tot_just_atoms = nAtomOffs[num_components];
|
560
|
+
/* shift all H to the end */
|
561
|
+
for ( k = 0; k <= num_components; k ++ ) {
|
562
|
+
nDelHOffs[k] += tot_just_atoms;
|
563
|
+
}
|
564
|
+
tot_atoms = nDelHOffs[num_components];
|
565
|
+
|
566
|
+
/* merge atoms together: 1. Allocate */
|
567
|
+
if ( NULL == (at = (inp_ATOM *)inchi_malloc( (tot_atoms+1) * sizeof(at[0]) ) ) ) {
|
568
|
+
ret = RI_ERR_ALLOC;
|
569
|
+
goto exit_function;
|
570
|
+
}
|
571
|
+
if ( !tot_atoms ) {
|
572
|
+
ret = 0;
|
573
|
+
goto exit_function; /* empty structure */
|
574
|
+
}
|
575
|
+
/* merge atoms together: 2. Copy */
|
576
|
+
for ( k = 0; k < num_components; k ++ ) {
|
577
|
+
pStruct1 = pStruct[iInchiRec][iMobileH][k].num_atoms? pStruct[iInchiRec][iCurMobH=iMobileH]+k :
|
578
|
+
iAlternH>=0 &&
|
579
|
+
pStruct[iInchiRec][iAlternH][k].num_atoms? pStruct[iInchiRec][iCurMobH=iAlternH]+k : NULL;
|
580
|
+
if ( len = nAtomOffs[k+1] - nAtomOffs[k] ) {
|
581
|
+
XYZ_COORD *pxyz = pStruct1->pXYZ;
|
582
|
+
len2 = nDelHOffs[k+1] - nDelHOffs[k]; /* do not separate H from the atom: we will not need them */
|
583
|
+
iCurAtomOffs = nAtomOffs[k];
|
584
|
+
a = at + iCurAtomOffs;
|
585
|
+
memcpy( a, pStruct1->at2, (len+len2) * sizeof(at[0]) );
|
586
|
+
DisconnectedConnectedH( a, len, len2 );
|
587
|
+
if ( pxyz ) {
|
588
|
+
for ( i = 0; i < len; i ++ ) {
|
589
|
+
a[i].x = pxyz[i].xyz[0];
|
590
|
+
x_max = inchi_max( x_max, pxyz[i].xyz[0] );
|
591
|
+
x_min = inchi_min( x_min, pxyz[i].xyz[0] );
|
592
|
+
a[i].y = pxyz[i].xyz[1];
|
593
|
+
y_max = inchi_max( y_max, pxyz[i].xyz[1] );
|
594
|
+
y_min = inchi_min( y_min, pxyz[i].xyz[1] );
|
595
|
+
a[i].z = pxyz[i].xyz[2];
|
596
|
+
nNewCoord ++;
|
597
|
+
}
|
598
|
+
} else {
|
599
|
+
if ( !iNewCoord ) {
|
600
|
+
if ( !nNewCoord ) {
|
601
|
+
ret = 0;
|
602
|
+
goto exit_function; /* empty structure */
|
603
|
+
}
|
604
|
+
delta = inchi_max(x_max - x_min, y_max - y_min);
|
605
|
+
if ( delta == 0.0 ) {
|
606
|
+
delta = 0.5 * (x_max+x_min);
|
607
|
+
if ( delta == 0.0 )
|
608
|
+
delta = 1.0;
|
609
|
+
} else {
|
610
|
+
delta /= sqrt( (double)(nNewCoord+1) );
|
611
|
+
}
|
612
|
+
}
|
613
|
+
for ( i = 0; i < len; i ++ ) {
|
614
|
+
a[i].x = x_max + delta;
|
615
|
+
a[i].y = y_max - iNewCoord * delta;
|
616
|
+
a[i].z = 0.0;
|
617
|
+
iNewCoord ++;
|
618
|
+
}
|
619
|
+
if ( pStruct1->pXYZ = (XYZ_COORD *)inchi_calloc(len, sizeof(pStruct1->pXYZ[0]) ) ) {
|
620
|
+
|
621
|
+
for ( i = 0; i < len; i ++ ) {
|
622
|
+
pStruct1->pXYZ[i].xyz[0] = a[i].x;
|
623
|
+
pStruct1->pXYZ[i].xyz[1] = a[i].y;
|
624
|
+
pStruct1->pXYZ[i].xyz[2] = 0.0;
|
625
|
+
}
|
626
|
+
}
|
627
|
+
}
|
628
|
+
if ( ip->bDisplay || ip->bDisplayCompositeResults && 1 == num_components ) {
|
629
|
+
DisplayOneRestoredComponent( pStruct1, a, k, num_components, iCurMobH, szCurHdr );
|
630
|
+
}
|
631
|
+
if ( !pxyz && pStruct1->pXYZ ) {
|
632
|
+
inchi_free( pStruct1->pXYZ );
|
633
|
+
pStruct1->pXYZ = NULL;
|
634
|
+
}
|
635
|
+
}
|
636
|
+
}
|
637
|
+
/* merge atoms together: 3. Update atom numbers */
|
638
|
+
icomp = 0;
|
639
|
+
if ( ip->bDisplayCompositeResults && num_components > 1 ) {
|
640
|
+
for ( k = 0; k < num_components; k ++ ) {
|
641
|
+
/* display each restored component if requested */
|
642
|
+
iCurAtomOffs = nAtomOffs[k];
|
643
|
+
iNxtAtomOffs = nAtomOffs[k+1];
|
644
|
+
iCurDelHOffs = nDelHOffs[k];
|
645
|
+
iNxtDelHOffs = nDelHOffs[k+1];
|
646
|
+
len = nAtomOffs[k+1] - nAtomOffs[k]; /* number of atoms in a component excluding explicit H */
|
647
|
+
iShiftH = iCurDelHOffs - len;
|
648
|
+
if ( !len ) {
|
649
|
+
continue;
|
650
|
+
}
|
651
|
+
icomp ++; /* current component number */
|
652
|
+
/* update atoms */
|
653
|
+
for ( i = iCurAtomOffs; i < iNxtAtomOffs; i ++ ) {
|
654
|
+
a = at+i;
|
655
|
+
for ( j = 0; j < a->valence; j ++ ) {
|
656
|
+
if ( a->neighbor[j] < len ) {
|
657
|
+
a->neighbor[j] += iCurAtomOffs; /* atom */
|
658
|
+
} else {
|
659
|
+
ret = RI_ERR_PROGR; /* explicit H */
|
660
|
+
goto exit_function;
|
661
|
+
}
|
662
|
+
}
|
663
|
+
a->orig_at_number += iCurAtomOffs;
|
664
|
+
}
|
665
|
+
}
|
666
|
+
tot_atoms = nAtomOffs[num_components];
|
667
|
+
DisplayAllRestoredComponents( at, tot_atoms, szCurHdr );
|
668
|
+
|
669
|
+
}
|
670
|
+
|
671
|
+
exit_function:
|
672
|
+
if ( at ) inchi_free( at ); /* in case of failure */
|
673
|
+
if ( nAtomOffs ) inchi_free( nAtomOffs );
|
674
|
+
if ( nDelHOffs ) inchi_free( nDelHOffs );
|
675
|
+
return ret;
|
676
|
+
}
|
677
|
+
#endif
|
678
|
+
/**************************************************************************************/
|
679
|
+
int AllInchiToStructure( ICHICONST INPUT_PARMS *ip_inp, STRUCT_DATA *sd_inp, long num_inp, char *szCurHdr,
|
680
|
+
ICHICONST SRM *pSrm, int bHasSomeFixedH, StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM],
|
681
|
+
InpInChI *pOneInput )
|
682
|
+
{
|
683
|
+
int iInchiRec, iMobileH, cur_num_comp, bCurI2A_Flag, k, ret, num_err;
|
684
|
+
INPUT_PARMS *ip, ip_loc;
|
685
|
+
STRUCT_DATA *sd, sd_loc;
|
686
|
+
long ulProcessingTime = 0;
|
687
|
+
inchiTime ulTStart;
|
688
|
+
|
689
|
+
InchiTimeGet( &ulTStart );
|
690
|
+
ip = &ip_loc;
|
691
|
+
*ip = *ip_inp;
|
692
|
+
sd = &sd_loc;
|
693
|
+
memset( sd, 0, sizeof(*sd));
|
694
|
+
sd->ulStructTime = sd_inp->ulStructTime;
|
695
|
+
ret = 0;
|
696
|
+
num_err = 0;
|
697
|
+
for ( iInchiRec = 0; iInchiRec < INCHI_NUM; iInchiRec ++ ) { /* Disconnected/Connected */
|
698
|
+
for ( iMobileH = 0; iMobileH < TAUT_NUM; iMobileH ++ ) { /* Mobile/Fixed H */
|
699
|
+
cur_num_comp = pOneInput->nNumComponents[iInchiRec][iMobileH];
|
700
|
+
if ( !cur_num_comp ) {
|
701
|
+
continue;
|
702
|
+
}
|
703
|
+
/* allocate memory for all existing components */
|
704
|
+
pStruct[iInchiRec][iMobileH] = (StrFromINChI *)inchi_calloc( cur_num_comp, sizeof(pStruct[0][0][0]));
|
705
|
+
if ( !pStruct[iInchiRec][iMobileH] ) {
|
706
|
+
ret = RI_ERR_ALLOC;
|
707
|
+
goto exit_error;
|
708
|
+
}
|
709
|
+
/* set conversion mode */
|
710
|
+
bCurI2A_Flag = (iMobileH? 0: I2A_FLAG_FIXEDH) | (iInchiRec? I2A_FLAG_RECMET : 0);
|
711
|
+
if ( iMobileH ) {
|
712
|
+
ip->nMode &= ~REQ_MODE_BASIC;
|
713
|
+
} else {
|
714
|
+
ip->nMode |= REQ_MODE_BASIC;
|
715
|
+
}
|
716
|
+
/* InChI --> structure conversion for all components except duplicated */
|
717
|
+
for ( k = 0; k < cur_num_comp; k ++ ) { /* components */
|
718
|
+
if ( !iMobileH && !pOneInput->pInpInChI[iInchiRec][iMobileH][k].nNumberOfAtoms ||
|
719
|
+
pOneInput->pInpInChI[iInchiRec][iMobileH][k].bDeleted ||
|
720
|
+
pOneInput->pInpInChI[iInchiRec][iMobileH][k].nLink < 0 ) {
|
721
|
+
|
722
|
+
pStruct[iInchiRec][iMobileH][k].nLink = pOneInput->pInpInChI[iInchiRec][iMobileH][k].nLink;
|
723
|
+
pStruct[iInchiRec][iMobileH][k].bDeleted = pOneInput->pInpInChI[iInchiRec][iMobileH][k].bDeleted;
|
724
|
+
continue; /* do not create a structure out of an unavailable
|
725
|
+
Fixed-H InChI or out of the one present in Reconnected layer */
|
726
|
+
#ifdef NEVER /* a wrong attempt to process deleted components here */
|
727
|
+
if ( pStruct[iInchiRec][iMobileH][k].nLink = pOneInput->pInpInChI[iInchiRec][iMobileH][k].nLink ) {
|
728
|
+
continue; /* do not create a structure out of an unavailable
|
729
|
+
Fixed-H InChI or out of the one present in Reconnected layer */
|
730
|
+
} else
|
731
|
+
if ( iMobileH && pOneInput->pInpInChI[iInchiRec][iMobileH][k].nNumberOfAtoms &&
|
732
|
+
pOneInput->pInpInChI[iInchiRec][iMobileH][k].bDeleted &&
|
733
|
+
pOneInput->pInpInChI[iInchiRec][iMobileH][0].bDeleted ) {
|
734
|
+
/* all components are protons */
|
735
|
+
;
|
736
|
+
} else {
|
737
|
+
continue;
|
738
|
+
}
|
739
|
+
#endif
|
740
|
+
}
|
741
|
+
if ( bHasSomeFixedH && iMobileH && k < pOneInput->nNumComponents[iInchiRec][TAUT_NON] &&
|
742
|
+
pOneInput->pInpInChI[iInchiRec][TAUT_NON][k].nNumberOfAtoms ) {
|
743
|
+
continue; /* do not process Mobile-H if Fixed-H is requested and exists */
|
744
|
+
}
|
745
|
+
pStruct[iInchiRec][iMobileH][k].pSrm = pSrm;
|
746
|
+
pStruct[iInchiRec][iMobileH][k].iInchiRec = iInchiRec;
|
747
|
+
pStruct[iInchiRec][iMobileH][k].iMobileH = iMobileH;
|
748
|
+
|
749
|
+
/****************************************************/
|
750
|
+
/* */
|
751
|
+
/* Convert InChI of one component into a Structure */
|
752
|
+
/* */
|
753
|
+
/****************************************************/
|
754
|
+
|
755
|
+
ret = InChI2Atom( ip, sd, szCurHdr, num_inp, pStruct[iInchiRec][iMobileH]+k, k,
|
756
|
+
0 /* AtNoOffset*/, bCurI2A_Flag, bHasSomeFixedH, pOneInput );
|
757
|
+
pStruct[iInchiRec][iMobileH][k].nLink = pOneInput->pInpInChI[iInchiRec][iMobileH][k].nLink;
|
758
|
+
if ( ret < 0 ) {
|
759
|
+
#if( bRELEASE_VERSION != 1 )
|
760
|
+
#ifndef INCHI_LIBRARY
|
761
|
+
/* !!! Conversion Error -- Ignore for now !!! */
|
762
|
+
fprintf( stdout, "%ld %s Conversion failed: %d, %c%c comp %d\n",
|
763
|
+
num_inp, szCurHdr? szCurHdr : "Struct", ret, iInchiRec? 'R':'D', iMobileH? 'M':'F', k+1);
|
764
|
+
#endif
|
765
|
+
#endif
|
766
|
+
if ( ret == CT_USER_QUIT_ERR ) {
|
767
|
+
goto exit_error;
|
768
|
+
}
|
769
|
+
pStruct[iInchiRec][iMobileH][k].nError = ret;
|
770
|
+
ret = 0; /* force to ignore the errors for now !!!! */
|
771
|
+
num_err ++;
|
772
|
+
}
|
773
|
+
}
|
774
|
+
}
|
775
|
+
}
|
776
|
+
exit_error:
|
777
|
+
ulProcessingTime += InchiTimeElapsed( &ulTStart );
|
778
|
+
sd->ulStructTime += ulProcessingTime;
|
779
|
+
return ret<0? ret : num_err;
|
780
|
+
}
|
781
|
+
/**************************************************************************************/
|
782
|
+
int AddProtonAndIsoHBalanceToMobHStruct( ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd,
|
783
|
+
long num_inp, int bHasSomeFixedH, char *szCurHdr,
|
784
|
+
StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM], InpInChI *pOneInput)
|
785
|
+
{
|
786
|
+
COMPONENT_REM_PROTONS nToBeRemovedByNormFromRevrs[INCHI_NUM];
|
787
|
+
int nRemovedByNormFromRevrs[INCHI_NUM];
|
788
|
+
int nRemovedByRevrs[INCHI_NUM];
|
789
|
+
|
790
|
+
int nDeltaFromDisconnected = 0, nRemovedProtonsByNormFromRevrs, nRemovedProtonsByRevrs, num_changes = 0;
|
791
|
+
NUM_H nIsoDeltaFromDisconnected[NUM_H_ISOTOPES];
|
792
|
+
int iInchiRec, i, k, k1, ret = 0;
|
793
|
+
int nChargeInChI, nChargeRevrs;
|
794
|
+
|
795
|
+
if ( bHasSomeFixedH ) {
|
796
|
+
return 0; /* 2005-03-01 */
|
797
|
+
}
|
798
|
+
|
799
|
+
/* num protons removed by InChI Normalization from the original structure */
|
800
|
+
for ( i = 0; i < INCHI_NUM; i ++ ) {
|
801
|
+
nToBeRemovedByNormFromRevrs[i].nNumRemovedProtons = pOneInput->nNumProtons[i][TAUT_YES].nNumRemovedProtons;
|
802
|
+
for ( k = 0; k < NUM_H_ISOTOPES; k ++ ) {
|
803
|
+
nToBeRemovedByNormFromRevrs[i].nNumRemovedIsotopicH[k] = pOneInput->nNumProtons[i][TAUT_YES].nNumRemovedIsotopicH[k];
|
804
|
+
}
|
805
|
+
}
|
806
|
+
/* accumulate here num. protons removed by the normalization from the reversed structure */
|
807
|
+
nRemovedByNormFromRevrs[INCHI_BAS] =
|
808
|
+
nRemovedByNormFromRevrs[INCHI_REC] = 0;
|
809
|
+
nRemovedByRevrs[INCHI_REC] =
|
810
|
+
nRemovedByRevrs[INCHI_BAS] = 0;
|
811
|
+
/* protons added/removed by InChI Normalization to/from Restored Structure might have been added by StructureRestore */
|
812
|
+
for ( iInchiRec = 0; iInchiRec < INCHI_NUM; iInchiRec ++ ) {
|
813
|
+
for ( k = 0; k < pOneInput->nNumComponents[iInchiRec][TAUT_YES]; k ++ ) {
|
814
|
+
if ( !bInpInchiComponentExists( pOneInput, iInchiRec, TAUT_YES, k ) ) {
|
815
|
+
continue;
|
816
|
+
}
|
817
|
+
nRemovedProtonsByNormFromRevrs = 0; /* Num protons removed from the Restored Structure by InChI Normalization */
|
818
|
+
nRemovedProtonsByRevrs = 0; /* Num protons removed by the Reconstruction from the Restored Structure */
|
819
|
+
if ( iInchiRec == INCHI_REC || iInchiRec == INCHI_BAS && (k1=pStruct[iInchiRec][TAUT_YES][k].nLink) >= 0 ) {
|
820
|
+
|
821
|
+
REV_INCHI *pRevInChI = &pStruct[iInchiRec][TAUT_YES][k].RevInChI;
|
822
|
+
INChI_Aux **pINChI_Aux2 = pRevInChI->pINChI_Aux[iInchiRec][0]; /* component 0*/
|
823
|
+
INChI **pINChI_Revr = pRevInChI->pINChI[iInchiRec][0];
|
824
|
+
INChI *pINChI_Orig = pOneInput->pInpInChI[iInchiRec][TAUT_YES]+k;
|
825
|
+
nChargeRevrs = pINChI_Revr? pINChI_Revr[TAUT_YES]->nTotalCharge : NO_VALUE_INT;
|
826
|
+
nChargeInChI = pINChI_Orig->nTotalCharge;
|
827
|
+
if ( pINChI_Aux2 ) {
|
828
|
+
nRemovedProtonsByNormFromRevrs = pINChI_Aux2[TAUT_YES]->nNumRemovedProtons;
|
829
|
+
}
|
830
|
+
nRemovedProtonsByRevrs = pStruct[iInchiRec][TAUT_YES][k].nNumRemovedProtonsByRevrs;
|
831
|
+
pStruct[iInchiRec][TAUT_YES][k].nChargeRevrs = nChargeRevrs;
|
832
|
+
pStruct[iInchiRec][TAUT_YES][k].nChargeInChI = nChargeInChI;
|
833
|
+
} else
|
834
|
+
if ( 0 <= ( k1 = -(1+pStruct[iInchiRec][TAUT_YES][k].nLink) ) ) {
|
835
|
+
REV_INCHI *pRevInChI = &pStruct[INCHI_REC][TAUT_YES][k1].RevInChI;
|
836
|
+
INChI_Aux **pINChI_Aux2 = pRevInChI->pINChI_Aux[INCHI_BAS][0]; /* component 0 */
|
837
|
+
INChI **pINChI_Revr = pRevInChI->pINChI[INCHI_BAS][0];
|
838
|
+
INChI *pINChI_Orig = pOneInput->pInpInChI[INCHI_REC][TAUT_YES]+k1;
|
839
|
+
nChargeRevrs = pINChI_Revr? pINChI_Revr[TAUT_YES]->nTotalCharge : NO_VALUE_INT;
|
840
|
+
nChargeInChI = pINChI_Orig->nTotalCharge;
|
841
|
+
if ( pINChI_Aux2 ) {
|
842
|
+
nRemovedProtonsByNormFromRevrs = pINChI_Aux2[TAUT_YES]->nNumRemovedProtons;
|
843
|
+
}
|
844
|
+
/* this component cannot be disconnected because it is same as in reconnected layer */
|
845
|
+
nRemovedProtonsByRevrs = pStruct[INCHI_REC][TAUT_YES][k1].nNumRemovedProtonsByRevrs;
|
846
|
+
pStruct[iInchiRec][TAUT_YES][k1].nChargeRevrs = nChargeRevrs;
|
847
|
+
pStruct[iInchiRec][TAUT_YES][k1].nChargeInChI = nChargeInChI;
|
848
|
+
}
|
849
|
+
/* how many protons (to be removed by InChI Normalization) to add =
|
850
|
+
(proton balance in InChI} -
|
851
|
+
{number of protons known to be removed by InChI Normalization from Reconstructed structure} */
|
852
|
+
nToBeRemovedByNormFromRevrs[iInchiRec].nNumRemovedProtons -= nRemovedProtonsByNormFromRevrs;
|
853
|
+
nRemovedByNormFromRevrs[iInchiRec] += nRemovedProtonsByNormFromRevrs;
|
854
|
+
nRemovedByRevrs[iInchiRec] += nRemovedProtonsByRevrs;
|
855
|
+
pStruct[iInchiRec][TAUT_YES][k].nRemovedProtonsByNormFromRevrs = nRemovedProtonsByNormFromRevrs;
|
856
|
+
}
|
857
|
+
}
|
858
|
+
|
859
|
+
/* Since fixed-H layer is missing we need to add proton balance to the components */
|
860
|
+
memset( nIsoDeltaFromDisconnected, 0, sizeof(nIsoDeltaFromDisconnected) );
|
861
|
+
for ( iInchiRec = INCHI_REC; INCHI_BAS <= iInchiRec; iInchiRec -- ) {
|
862
|
+
/*
|
863
|
+
if ( !pOneInput->nNumComponents[iInchiRec][TAUT_NON] &&
|
864
|
+
pOneInput->nNumComponents[iInchiRec][TAUT_YES] ) {
|
865
|
+
*/
|
866
|
+
int bHasRecMobH = (iInchiRec==INCHI_BAS && pOneInput->nNumComponents[INCHI_REC][TAUT_YES]);
|
867
|
+
/* bHasRecMobH means all components that could not be disconnected are in reconnected part */
|
868
|
+
if ( iInchiRec==INCHI_BAS ) {
|
869
|
+
/* second pass: common structures have been changed */
|
870
|
+
nToBeRemovedByNormFromRevrs[INCHI_BAS].nNumRemovedProtons += nDeltaFromDisconnected;
|
871
|
+
}
|
872
|
+
/* after proton removal InChI is recalculated */
|
873
|
+
|
874
|
+
ret = AddRemProtonsInRestrStruct( ip, sd, num_inp, bHasSomeFixedH, pStruct[iInchiRec][TAUT_YES],
|
875
|
+
pOneInput->nNumComponents[iInchiRec][TAUT_YES],
|
876
|
+
bHasRecMobH? pStruct[INCHI_REC][TAUT_YES] : NULL,
|
877
|
+
bHasRecMobH? pOneInput->nNumComponents[INCHI_REC][TAUT_YES]:0,
|
878
|
+
&nToBeRemovedByNormFromRevrs[iInchiRec].nNumRemovedProtons,
|
879
|
+
(iInchiRec==INCHI_REC)?&nDeltaFromDisconnected : NULL);
|
880
|
+
if ( ret < 0 ) {
|
881
|
+
goto exit_function;
|
882
|
+
}
|
883
|
+
num_changes += ret;
|
884
|
+
/*
|
885
|
+
}
|
886
|
+
*/
|
887
|
+
}
|
888
|
+
/* if fixed-H layer is missing then we need to add isotopic exchangeable proton balance to the components */
|
889
|
+
for ( iInchiRec = INCHI_REC; INCHI_BAS <= iInchiRec; iInchiRec -- ) {
|
890
|
+
/*
|
891
|
+
if ( !pOneInput->nNumComponents[iInchiRec][TAUT_NON] &&
|
892
|
+
pOneInput->nNumComponents[iInchiRec][TAUT_YES] ) {
|
893
|
+
*/
|
894
|
+
int bHasRecMobH = (iInchiRec==INCHI_BAS && pOneInput->nNumComponents[INCHI_REC][TAUT_YES]);
|
895
|
+
/* bHasRecMobH means all components that could not be disconnected are in reconnected part */
|
896
|
+
if ( iInchiRec==INCHI_BAS ) {
|
897
|
+
/* second pass: common structures have been changed */
|
898
|
+
for ( k = 0; k < NUM_H_ISOTOPES; k ++ ) {
|
899
|
+
nToBeRemovedByNormFromRevrs[INCHI_BAS].nNumRemovedIsotopicH[k] += nIsoDeltaFromDisconnected[k];
|
900
|
+
}
|
901
|
+
}
|
902
|
+
/* after proton removal InChI is recalculated */
|
903
|
+
ret = AddRemIsoProtonsInRestrStruct( ip, sd, num_inp, bHasSomeFixedH, pStruct[iInchiRec][TAUT_YES],
|
904
|
+
pOneInput->nNumComponents[iInchiRec][TAUT_YES],
|
905
|
+
bHasRecMobH? pStruct[INCHI_REC][TAUT_YES] : NULL,
|
906
|
+
bHasRecMobH? pOneInput->nNumComponents[INCHI_REC][TAUT_YES]:0,
|
907
|
+
nToBeRemovedByNormFromRevrs[iInchiRec].nNumRemovedIsotopicH,
|
908
|
+
(iInchiRec==INCHI_REC)?nIsoDeltaFromDisconnected : NULL);
|
909
|
+
if ( ret < 0 ) {
|
910
|
+
goto exit_function;
|
911
|
+
}
|
912
|
+
num_changes += ret;
|
913
|
+
/*
|
914
|
+
}
|
915
|
+
*/
|
916
|
+
}
|
917
|
+
|
918
|
+
exit_function:
|
919
|
+
return ret;
|
920
|
+
}
|
921
|
+
|
922
|
+
/*************************************************************/
|
923
|
+
void FreeStrFromINChI( StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM], int nNumComponents[INCHI_NUM][TAUT_NUM] )
|
924
|
+
{
|
925
|
+
int iInchiRec, iMobileH, cur_num_comp, k, j;
|
926
|
+
StrFromINChI *pStruct1;
|
927
|
+
for ( iInchiRec = 0; iInchiRec < INCHI_NUM; iInchiRec ++ ) {
|
928
|
+
for ( iMobileH = 0; iMobileH < TAUT_NUM; iMobileH ++ ) {
|
929
|
+
cur_num_comp = nNumComponents[iInchiRec][iMobileH];
|
930
|
+
if ( !cur_num_comp || !(pStruct1=pStruct[iInchiRec][iMobileH]) ) {
|
931
|
+
continue;
|
932
|
+
}
|
933
|
+
for ( k = 0; k < cur_num_comp; k ++ ) {
|
934
|
+
if ( pStruct1[k].at ) {
|
935
|
+
inchi_free(pStruct1[k].at);
|
936
|
+
}
|
937
|
+
if ( pStruct1[k].at2 ) {
|
938
|
+
inchi_free(pStruct1[k].at2);
|
939
|
+
}
|
940
|
+
if ( pStruct1[k].st ) {
|
941
|
+
inchi_free(pStruct1[k].st);
|
942
|
+
}
|
943
|
+
if ( pStruct1[k].pVA ) {
|
944
|
+
inchi_free(pStruct1[k].pVA);
|
945
|
+
}
|
946
|
+
/*
|
947
|
+
if ( pStruct1[k].ti.t_group ) {
|
948
|
+
inchi_free( pStruct1[k].ti.t_group );
|
949
|
+
}
|
950
|
+
*/
|
951
|
+
if ( pStruct1[k].pXYZ ) {
|
952
|
+
inchi_free(pStruct1[k].pXYZ);
|
953
|
+
}
|
954
|
+
/*==== begin ====*/
|
955
|
+
free_t_group_info( &pStruct1[k].ti );
|
956
|
+
if ( pStruct1[k].endpoint ) {
|
957
|
+
inchi_free(pStruct1[k].endpoint);
|
958
|
+
}
|
959
|
+
if ( pStruct1[k].fixed_H ) {
|
960
|
+
inchi_free(pStruct1[k].fixed_H);
|
961
|
+
}
|
962
|
+
for ( j = 0; j < TAUT_NUM; j ++ ) {
|
963
|
+
if ( pStruct1[k].nAtno2Canon[j] )
|
964
|
+
inchi_free( pStruct1[k].nAtno2Canon[j] );
|
965
|
+
if ( pStruct1[k].nCanon2Atno[j] )
|
966
|
+
inchi_free( pStruct1[k].nCanon2Atno[j] );
|
967
|
+
}
|
968
|
+
/*===== end ======*/
|
969
|
+
/* free INChI memory */
|
970
|
+
FreeAllINChIArrays( pStruct1[k].RevInChI.pINChI,
|
971
|
+
pStruct1[k].RevInChI.pINChI_Aux,
|
972
|
+
pStruct1[k].RevInChI.num_components );
|
973
|
+
#ifdef NEVER
|
974
|
+
/* don't do that: these are just pointers to OneInput structure members */
|
975
|
+
Free_INChI( &pStruct1[k].pINChI );
|
976
|
+
Free_INChI_Aux( &pStruct1[k].pINChI_Aux );
|
977
|
+
if ( pStruct1[k].inp_norm_data ) {
|
978
|
+
FreeInpAtomData( pStruct1[k].inp_norm_data );
|
979
|
+
inchi_free( pStruct1[k].inp_norm_data );
|
980
|
+
}
|
981
|
+
#endif
|
982
|
+
}
|
983
|
+
inchi_free(pStruct[iInchiRec][iMobileH]);
|
984
|
+
pStruct[iInchiRec][iMobileH] = NULL;
|
985
|
+
}
|
986
|
+
}
|
987
|
+
}
|
988
|
+
/********************************************************************/
|
989
|
+
void FreeInpInChI( InpInChI *pOneInput )
|
990
|
+
{
|
991
|
+
int iINChI, k, j;
|
992
|
+
for ( iINChI = 0; iINChI < INCHI_NUM; iINChI ++ ) {
|
993
|
+
for ( j = 0; j < TAUT_NUM; j ++ ) {
|
994
|
+
if ( pOneInput->pInpInChI[iINChI][j] ) {
|
995
|
+
for ( k = 0; k < pOneInput->nNumComponents[iINChI][j]; k ++ ) {
|
996
|
+
Free_INChI_Members( &pOneInput->pInpInChI[iINChI][j][k] );
|
997
|
+
}
|
998
|
+
inchi_free(pOneInput->pInpInChI[iINChI][j]);
|
999
|
+
pOneInput->pInpInChI[iINChI][j] = NULL;
|
1000
|
+
}
|
1001
|
+
if ( pOneInput->nNumProtons[iINChI][j].pNumProtons ) {
|
1002
|
+
inchi_free( pOneInput->nNumProtons[iINChI][j].pNumProtons );
|
1003
|
+
pOneInput->nNumProtons[iINChI][j].pNumProtons = NULL;
|
1004
|
+
}
|
1005
|
+
}
|
1006
|
+
}
|
1007
|
+
if ( pOneInput->atom ) inchi_free(pOneInput->atom);
|
1008
|
+
memset( pOneInput, 0, sizeof(*pOneInput) );
|
1009
|
+
}
|
1010
|
+
|
1011
|
+
/***********************************************************************************************/
|
1012
|
+
int CompareAllOrigInchiToRevInChI(StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM], InpInChI *pOneInput, int bReqNonTaut,
|
1013
|
+
long num_inp, char *szCurHdr)
|
1014
|
+
{
|
1015
|
+
int i, iInchiRec, iMobileH, iMobileHpStruct, num_components, iComponent, ret;
|
1016
|
+
COMPONENT_REM_PROTONS nCurRemovedProtons, nNumRemovedProtons;
|
1017
|
+
INChI *pInChI[TAUT_NUM];
|
1018
|
+
INCHI_MODE CompareInchiFlags[TAUT_NUM];
|
1019
|
+
memset( pOneInput->CompareInchiFlags[0], 0, sizeof(pOneInput->CompareInchiFlags[0]) );
|
1020
|
+
memset( &nNumRemovedProtons, 0, sizeof(nNumRemovedProtons) );
|
1021
|
+
|
1022
|
+
/* do we have reconnected InChI ?*/
|
1023
|
+
iInchiRec = INCHI_REC;
|
1024
|
+
iMobileH = TAUT_NON;
|
1025
|
+
if ( !pOneInput->nNumComponents[iInchiRec][TAUT_YES] && !pOneInput->nNumComponents[iInchiRec][TAUT_NON] ) {
|
1026
|
+
iInchiRec = INCHI_BAS;
|
1027
|
+
}
|
1028
|
+
/* do we have Mobile or Fixed-H ? */
|
1029
|
+
if ( !pOneInput->nNumComponents[iInchiRec][TAUT_NON] || !bReqNonTaut ) {
|
1030
|
+
iMobileH = TAUT_YES; /* index for pOneInput */
|
1031
|
+
}
|
1032
|
+
/* if a restored structure has Fixed-H InChI then its mobile-H restored InChI is in Fixed-H pStruct */
|
1033
|
+
num_components = pOneInput->nNumComponents[iInchiRec][iMobileH];
|
1034
|
+
for ( iComponent = 0; iComponent < num_components; iComponent ++ ) {
|
1035
|
+
int bMobileH = iMobileH;
|
1036
|
+
pInChI[0] = pInChI[1] = NULL;
|
1037
|
+
if ( pOneInput->pInpInChI[iInchiRec][bMobileH][iComponent].nNumberOfAtoms &&
|
1038
|
+
!pOneInput->pInpInChI[iInchiRec][bMobileH][iComponent].bDeleted ) {
|
1039
|
+
/* the requested InChI layer exists */
|
1040
|
+
pInChI[0] = &pOneInput->pInpInChI[iInchiRec][bMobileH][iComponent];
|
1041
|
+
if ( bMobileH == TAUT_NON ) {
|
1042
|
+
pInChI[1] = &pOneInput->pInpInChI[iInchiRec][TAUT_YES][iComponent];
|
1043
|
+
}
|
1044
|
+
} else
|
1045
|
+
if ( bMobileH == TAUT_NON &&
|
1046
|
+
pOneInput->pInpInChI[iInchiRec][TAUT_YES][iComponent].nNumberOfAtoms &&
|
1047
|
+
!pOneInput->pInpInChI[iInchiRec][TAUT_YES][iComponent].bDeleted ) {
|
1048
|
+
/* the requested Fixed-H InChI layer does not exist; however, the Mobile-H does exist */
|
1049
|
+
bMobileH = TAUT_YES; /* only Mobile-H is available */
|
1050
|
+
pInChI[0] = &pOneInput->pInpInChI[iInchiRec][bMobileH][iComponent];
|
1051
|
+
}
|
1052
|
+
memset( CompareInchiFlags, 0, sizeof(CompareInchiFlags) );
|
1053
|
+
memset( &nCurRemovedProtons, 0, sizeof(nCurRemovedProtons) );
|
1054
|
+
iMobileHpStruct =
|
1055
|
+
#if( bRELEASE_VERSION == 0 )
|
1056
|
+
#ifndef INCHI_LIBRARY
|
1057
|
+
/* legacy: reproduce old output */
|
1058
|
+
OldPrintCompareOneOrigInchiToRevInChI(pStruct[iInchiRec][bMobileH]+iComponent, pInChI, bMobileH,
|
1059
|
+
iComponent, num_inp, szCurHdr);
|
1060
|
+
#endif
|
1061
|
+
#endif
|
1062
|
+
/* one component comparison result bits */
|
1063
|
+
ret = CompareOneOrigInchiToRevInChI( pStruct[iInchiRec][bMobileH]+iComponent, pInChI, bMobileH, iComponent,
|
1064
|
+
num_inp, szCurHdr, &nCurRemovedProtons, CompareInchiFlags);
|
1065
|
+
if ( ret >= 0 ) {
|
1066
|
+
/* no errors encountered -> accumulate removed protons from individual Mobile-H layers of components */
|
1067
|
+
nNumRemovedProtons.nNumRemovedProtons += nCurRemovedProtons.nNumRemovedProtons;
|
1068
|
+
for ( i = 0; i < NUM_H_ISOTOPES; i ++ ) {
|
1069
|
+
nNumRemovedProtons.nNumRemovedIsotopicH[i] += nCurRemovedProtons.nNumRemovedIsotopicH[i];
|
1070
|
+
}
|
1071
|
+
/* accumulate compare bits */
|
1072
|
+
for ( i = 0; i < TAUT_NUM; i ++ ) {
|
1073
|
+
pOneInput->CompareInchiFlags[0][i] |= CompareInchiFlags[i];
|
1074
|
+
}
|
1075
|
+
} else {
|
1076
|
+
goto exit_function;
|
1077
|
+
}
|
1078
|
+
}
|
1079
|
+
if ( iMobileH == TAUT_YES ) {
|
1080
|
+
if ( pOneInput->nNumProtons[iInchiRec][iMobileH].pNumProtons ) {
|
1081
|
+
ret = RI_ERR_PROGR; /* in Mobile-H case proton balances are split between compoments */
|
1082
|
+
} else {
|
1083
|
+
/* num removed protons in orig. InChI num removed protons in restored InChi */
|
1084
|
+
if ( nNumRemovedProtons.nNumRemovedProtons != pOneInput->nNumProtons[iInchiRec][iMobileH].nNumRemovedProtons ) {
|
1085
|
+
/* restored structure InChI has less or more removed protons */
|
1086
|
+
pOneInput->CompareInchiFlags[0][TAUT_YES] |= INCHIDIFF_MOBH_PROTONS;
|
1087
|
+
#if( bRELEASE_VERSION == 0 )
|
1088
|
+
/* debug output only */
|
1089
|
+
{
|
1090
|
+
int num_H_AddedByRevrs = pOneInput->nNumProtons[iInchiRec][iMobileH].nNumRemovedProtons
|
1091
|
+
- nNumRemovedProtons.nNumRemovedProtons;
|
1092
|
+
fprintf( stdout, "COMPARE_INCHI: %ld: %s %cM: Proton balance (Diff: %d, RevrsRem=%d)\n",
|
1093
|
+
num_inp, szCurHdr? szCurHdr : "Struct", iInchiRec? 'R':'D',
|
1094
|
+
pOneInput->nNumProtons[iInchiRec][iMobileH].nNumRemovedProtons,num_H_AddedByRevrs);
|
1095
|
+
}
|
1096
|
+
#endif
|
1097
|
+
}
|
1098
|
+
for ( i = 0; i < NUM_H_ISOTOPES; i ++ ) {
|
1099
|
+
if ( nNumRemovedProtons.nNumRemovedIsotopicH[i] != pOneInput->nNumProtons[iInchiRec][TAUT_YES].nNumRemovedIsotopicH[i] ) {
|
1100
|
+
pOneInput->CompareInchiFlags[0][TAUT_YES] |= INCHIDIFF_MOB_ISO_H;
|
1101
|
+
#if( bRELEASE_VERSION == 0 )
|
1102
|
+
/* debug output only */
|
1103
|
+
{
|
1104
|
+
int num_H_AddedByRevrs = pOneInput->nNumProtons[iInchiRec][TAUT_YES].nNumRemovedIsotopicH[i]
|
1105
|
+
- nNumRemovedProtons.nNumRemovedIsotopicH[i];
|
1106
|
+
fprintf( stdout, "COMPARE_INCHI: %ld: %s %cM: Iso Xchg %dH balance (Diff: %d, RevrsRem=%d)\n",
|
1107
|
+
num_inp, szCurHdr? szCurHdr : "Struct", iInchiRec? 'R':'D', i+1,
|
1108
|
+
pOneInput->nNumProtons[iInchiRec][TAUT_YES].nNumRemovedIsotopicH[i],num_H_AddedByRevrs);
|
1109
|
+
}
|
1110
|
+
#endif
|
1111
|
+
}
|
1112
|
+
}
|
1113
|
+
}
|
1114
|
+
}
|
1115
|
+
|
1116
|
+
exit_function:
|
1117
|
+
return ret;
|
1118
|
+
}
|
1119
|
+
/***********************************************************************************************/
|
1120
|
+
int CompareAllDisconnectedOrigInchiToRevInChI(StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM],
|
1121
|
+
InpInChI *pOneInput, int bHasSomeFixedH,
|
1122
|
+
long num_inp, char *szCurHdr)
|
1123
|
+
{
|
1124
|
+
int i, k, m, n, iInChI, iMobileH, bMobileH, ifk;
|
1125
|
+
int num_components_D, num_components_R;
|
1126
|
+
int nNumCompHaveSeparateProtons_D, nNumCompHaveSeparateProtons_R;
|
1127
|
+
int num_fragments_D, num_fragments_R, num_fragments_DR, num_fragments, iComponent, ret;
|
1128
|
+
int ifInChI, ifMobileH, bfMobileH, nLink;
|
1129
|
+
COMPONENT_REM_PROTONS nNumRemovedProtons_D; /* removed from the disconnected layer of the Input InChI */
|
1130
|
+
COMPONENT_REM_PROTONS nNumRemovedProtons_D_all; /* if only totals are avalable */
|
1131
|
+
COMPONENT_REM_PROTONS nNumRemovedProtons_R; /* removed from disconnected layer of the reconstructed struct */
|
1132
|
+
COMPONENT_REM_PROTONS nNumRemovedProtons_R_all;
|
1133
|
+
INCHI_MODE CompareInchiFlags[TAUT_NUM];
|
1134
|
+
StrFromINChI *pStruct1;
|
1135
|
+
INChI_Aux *pINChI_Aux;
|
1136
|
+
INCHI_SORT *pINChISort1 = NULL; /* from reversed structure */
|
1137
|
+
INCHI_SORT *pINChISort2 = NULL; /* original input InChI */
|
1138
|
+
int nNumNonTaut1=0, nNumNonTaut2=0;
|
1139
|
+
|
1140
|
+
ret = 0;
|
1141
|
+
memset( pOneInput->CompareInchiFlags[1], 0, sizeof(pOneInput->CompareInchiFlags[1]) );
|
1142
|
+
|
1143
|
+
/* count components that are not subject to disconnection */
|
1144
|
+
if ( !pOneInput->nNumComponents[INCHI_REC][TAUT_YES] &&
|
1145
|
+
!pOneInput->nNumComponents[INCHI_REC][TAUT_NON] ) {
|
1146
|
+
return 0; /* nothing to do */
|
1147
|
+
}
|
1148
|
+
|
1149
|
+
memset( &nNumRemovedProtons_D, 0, sizeof(nNumRemovedProtons_D) );
|
1150
|
+
memset( &nNumRemovedProtons_R, 0, sizeof(nNumRemovedProtons_R) );
|
1151
|
+
memset( &nNumRemovedProtons_D_all, 0, sizeof(nNumRemovedProtons_D_all) );
|
1152
|
+
memset( &nNumRemovedProtons_R_all, 0, sizeof(nNumRemovedProtons_R_all) );
|
1153
|
+
memset( CompareInchiFlags, 0, sizeof(CompareInchiFlags) );
|
1154
|
+
|
1155
|
+
num_components_D = inchi_max( pOneInput->nNumComponents[INCHI_BAS][TAUT_YES],
|
1156
|
+
pOneInput->nNumComponents[INCHI_BAS][TAUT_NON] );
|
1157
|
+
num_components_R = inchi_max( pOneInput->nNumComponents[INCHI_REC][TAUT_YES],
|
1158
|
+
pOneInput->nNumComponents[INCHI_REC][TAUT_NON] );
|
1159
|
+
/***********************************************************************************************/
|
1160
|
+
/* InpInChI: count fragments -- disconnected components that do not match reconnected */
|
1161
|
+
/* Accumulate removed H and isotopic H from ALL Fixed-H disconnected components except deleted */
|
1162
|
+
/* This segment collects info from the original InChI */
|
1163
|
+
/***********************************************************************************************/
|
1164
|
+
/*---- Original InChI ----*/
|
1165
|
+
num_fragments_D = 0;
|
1166
|
+
iInChI = INCHI_BAS;
|
1167
|
+
iMobileH = bHasSomeFixedH? !pOneInput->nNumComponents[iInChI][TAUT_NON] : TAUT_YES;
|
1168
|
+
nNumCompHaveSeparateProtons_D = 0;
|
1169
|
+
|
1170
|
+
/* in case of Mobile-H components here are the proton totals from the original InChI disconn. layer */
|
1171
|
+
nNumRemovedProtons_D.nNumRemovedProtons = pOneInput->nNumProtons[iInChI][TAUT_YES].nNumRemovedProtons;
|
1172
|
+
memcpy( nNumRemovedProtons_D.nNumRemovedIsotopicH,
|
1173
|
+
pOneInput->nNumProtons[iInChI][TAUT_YES].nNumRemovedIsotopicH,
|
1174
|
+
sizeof(nNumRemovedProtons_D.nNumRemovedIsotopicH) ); /* total for the disconnected layer */
|
1175
|
+
|
1176
|
+
for ( k = 0; k < num_components_D; k ++ ) {
|
1177
|
+
bMobileH = iMobileH;
|
1178
|
+
if ( !bInpInchiComponentExists( pOneInput, iInChI, bMobileH, k ) ) {
|
1179
|
+
if ( bInpInchiComponentExists( pOneInput, iInChI, TAUT_YES, k ) ) {
|
1180
|
+
bMobileH = TAUT_YES;
|
1181
|
+
} else {
|
1182
|
+
continue; /* component is missing ??? */
|
1183
|
+
}
|
1184
|
+
}
|
1185
|
+
if ( 0 > (nLink = pOneInput->pInpInChI[iInChI][bMobileH][k].nLink) ) {
|
1186
|
+
/* component in Disconnected layer is linked to the identical one in the Reconnected layer */
|
1187
|
+
if ( pOneInput->nNumProtons[INCHI_REC][TAUT_YES].pNumProtons ) {
|
1188
|
+
nNumCompHaveSeparateProtons_D ++;
|
1189
|
+
nLink = -(1+nLink);
|
1190
|
+
nNumRemovedProtons_D.nNumRemovedProtons += pOneInput->nNumProtons[INCHI_REC][TAUT_YES].pNumProtons[nLink].nNumRemovedProtons;
|
1191
|
+
for ( m = 0; m < NUM_H_ISOTOPES; m ++ ) {
|
1192
|
+
nNumRemovedProtons_D.nNumRemovedIsotopicH[m] += pOneInput->nNumProtons[INCHI_REC][TAUT_YES].pNumProtons[nLink].nNumRemovedIsotopicH[m];
|
1193
|
+
}
|
1194
|
+
}
|
1195
|
+
continue; /* same as reconnected */
|
1196
|
+
}
|
1197
|
+
/* component in the reconnected layer that was disconnected */
|
1198
|
+
nNumNonTaut2 += (bMobileH == TAUT_NON);
|
1199
|
+
if ( pOneInput->nNumProtons[iInChI][TAUT_YES].pNumProtons ) {
|
1200
|
+
nNumCompHaveSeparateProtons_D ++;
|
1201
|
+
nNumRemovedProtons_D.nNumRemovedProtons += pOneInput->nNumProtons[iInChI][TAUT_YES].pNumProtons[k].nNumRemovedProtons;
|
1202
|
+
for ( m = 0; m < NUM_H_ISOTOPES; m ++ ) {
|
1203
|
+
nNumRemovedProtons_D.nNumRemovedIsotopicH[m] += pOneInput->nNumProtons[iInChI][TAUT_YES].pNumProtons[k].nNumRemovedIsotopicH[m];
|
1204
|
+
}
|
1205
|
+
}
|
1206
|
+
num_fragments_D ++; /* number of disconnected fragments from original reconnected structure */
|
1207
|
+
}
|
1208
|
+
/* in case of Mobile-H components here are the proton totals from the original InChI */
|
1209
|
+
/*
|
1210
|
+
nNumRemovedProtons_D_all.nNumRemovedProtons = pOneInput->nNumProtons[iInChI][TAUT_YES].nNumRemovedProtons;
|
1211
|
+
memcpy( nNumRemovedProtons_D_all.nNumRemovedIsotopicH,
|
1212
|
+
pOneInput->nNumProtons[iInChI][TAUT_YES].nNumRemovedIsotopicH,
|
1213
|
+
sizeof(nNumRemovedProtons_D_all.nNumRemovedIsotopicH) );
|
1214
|
+
|
1215
|
+
*/
|
1216
|
+
/****************************************************************************************************/
|
1217
|
+
/* count fragments in reconstructed reconnected structure */
|
1218
|
+
/* accumulate removed H and isotopic H from ALL reconstructed reconnected components except deleted */
|
1219
|
+
/* This segment collects info from the reconstructed structure InChI */
|
1220
|
+
/****************************************************************************************************/
|
1221
|
+
/*---- InChI from the reconstructed reconnected structure ----*/
|
1222
|
+
num_fragments_R = 0;
|
1223
|
+
iInChI = INCHI_REC;
|
1224
|
+
iMobileH = bHasSomeFixedH? !pOneInput->nNumComponents[iInChI][TAUT_NON] : TAUT_YES;
|
1225
|
+
nNumCompHaveSeparateProtons_R = 0;
|
1226
|
+
for ( k = 0; k < num_components_R; k ++ ) {
|
1227
|
+
bMobileH = iMobileH;
|
1228
|
+
if ( !bInpInchiComponentExists( pOneInput, iInChI, bMobileH, k ) ) {
|
1229
|
+
if ( bInpInchiComponentExists( pOneInput, iInChI, TAUT_YES, k ) ) {
|
1230
|
+
bMobileH = TAUT_YES;
|
1231
|
+
} else {
|
1232
|
+
continue; /* component is missing ??? (Deleted proton in Mobile-H layer) */
|
1233
|
+
}
|
1234
|
+
}
|
1235
|
+
if ( 0 < pOneInput->pInpInChI[iInChI][bMobileH][k].nLink ) {
|
1236
|
+
/* this reconstructed reconnected component was NOT DISCONNECTED */
|
1237
|
+
/* same component is in the disconnected layer, it has no metal atoms or is an isolated metal atom */
|
1238
|
+
pStruct1 = pStruct[iInChI][bMobileH]+k;
|
1239
|
+
ifMobileH = TAUT_YES; /* Mobile-H Aux_Info contains number removed protons */
|
1240
|
+
ifInChI = INCHI_BAS; /* this component cannot be reconnected */
|
1241
|
+
ifk = 0; /* 0th component since it is InChI of a single component */
|
1242
|
+
/* The statement in the following line is *WRONG*, component number mixed with bMobileH: */
|
1243
|
+
/* in RevInchi, when only Mobile-H is present then its only non-NULL InChI has index 0==TAUT_NON */
|
1244
|
+
if ( bRevInchiComponentExists( pStruct1, ifInChI, ifMobileH, ifk ) ) {
|
1245
|
+
/* count protons */
|
1246
|
+
pINChI_Aux = pStruct1->RevInChI.pINChI_Aux[ifInChI][ifk][ifMobileH];
|
1247
|
+
if ( pINChI_Aux ) {
|
1248
|
+
nNumRemovedProtons_R.nNumRemovedProtons += pINChI_Aux->nNumRemovedProtons;
|
1249
|
+
for ( m = 0; m < NUM_H_ISOTOPES; m ++ ) {
|
1250
|
+
nNumRemovedProtons_R.nNumRemovedIsotopicH[m] += pINChI_Aux->nNumRemovedIsotopicH[m];
|
1251
|
+
}
|
1252
|
+
}
|
1253
|
+
}
|
1254
|
+
nNumCompHaveSeparateProtons_R += bRevInchiComponentExists( pStruct1, ifInChI, ALT_TAUT(ifMobileH), ifk );
|
1255
|
+
continue; /* same as disconnected, has no metal atoms */
|
1256
|
+
}
|
1257
|
+
/* this reconstructed reconnected component WAS DISCONNECTED; check its fragments */
|
1258
|
+
/* it does not have same component in the disconnected layer */
|
1259
|
+
pStruct1 = pStruct[iInChI][bMobileH]+k;
|
1260
|
+
num_fragments = pStruct1->RevInChI.num_components[INCHI_BAS];
|
1261
|
+
ifInChI = INCHI_BAS; /* disconnected layer */
|
1262
|
+
ifMobileH = bHasSomeFixedH? TAUT_NON : TAUT_YES;
|
1263
|
+
for ( ifk = 0; ifk < num_fragments; ifk ++ ) {
|
1264
|
+
bfMobileH = ifMobileH;
|
1265
|
+
if ( !bRevInchiComponentExists( pStruct1, ifInChI, bfMobileH, ifk ) ) {
|
1266
|
+
if ( bRevInchiComponentExists( pStruct1, ifInChI, TAUT_YES, ifk ) ) {
|
1267
|
+
bfMobileH = TAUT_YES;
|
1268
|
+
} else {
|
1269
|
+
continue; /* fragment does not exist ??? */
|
1270
|
+
}
|
1271
|
+
}
|
1272
|
+
nNumNonTaut1 += (bfMobileH == TAUT_NON);
|
1273
|
+
nNumCompHaveSeparateProtons_R += (bfMobileH == TAUT_NON);
|
1274
|
+
/* count protons from fragments made by metal disconnection */
|
1275
|
+
pINChI_Aux = pStruct1->RevInChI.pINChI_Aux[ifInChI][ifk][TAUT_YES];
|
1276
|
+
if ( pINChI_Aux ) {
|
1277
|
+
nNumRemovedProtons_R.nNumRemovedProtons += pINChI_Aux->nNumRemovedProtons;
|
1278
|
+
for ( m = 0; m < NUM_H_ISOTOPES; m ++ ) {
|
1279
|
+
nNumRemovedProtons_R.nNumRemovedIsotopicH[m] += pINChI_Aux->nNumRemovedIsotopicH[m];
|
1280
|
+
}
|
1281
|
+
}
|
1282
|
+
num_fragments_R ++; /* number of disconnected fragments from reconstructed reconnected structure */
|
1283
|
+
}
|
1284
|
+
}
|
1285
|
+
/*---------------- special treatment of the last reconstructed component -----------------*/
|
1286
|
+
/*---------------- this may contain separate protons added by the reconstruction ---------*/
|
1287
|
+
k = num_components_R - 1;
|
1288
|
+
pStruct1 = pStruct[iInChI][iMobileH]+k;
|
1289
|
+
if ( iMobileH == TAUT_YES && !bHasSomeFixedH &&
|
1290
|
+
bInpInchiComponentDeleted( pOneInput, iInChI, iMobileH, k ) &&
|
1291
|
+
(num_fragments = pStruct1->RevInChI.num_components[INCHI_BAS]) ) {
|
1292
|
+
|
1293
|
+
ifInChI = INCHI_BAS; /* disconnected layer */
|
1294
|
+
ifMobileH = TAUT_YES;
|
1295
|
+
for ( ifk = 0; ifk < num_fragments; ifk ++ ) {
|
1296
|
+
bfMobileH = ifMobileH;
|
1297
|
+
if ( !bRevInchiComponentDeleted( pStruct1, ifInChI, bfMobileH, ifk ) ) {
|
1298
|
+
continue; /* fragment does exist ??? Should not happen */
|
1299
|
+
}
|
1300
|
+
/*
|
1301
|
+
nNumNonTaut1 += (bfMobileH == TAUT_NON);
|
1302
|
+
nNumCompHaveSeparateProtons_R += (bfMobileH == TAUT_NON);
|
1303
|
+
*/
|
1304
|
+
/* count protons from fragments made by metal disconnection */
|
1305
|
+
pINChI_Aux = pStruct1->RevInChI.pINChI_Aux[ifInChI][ifk][TAUT_YES];
|
1306
|
+
if ( pINChI_Aux ) {
|
1307
|
+
nNumRemovedProtons_R.nNumRemovedProtons += pINChI_Aux->nNumRemovedProtons;
|
1308
|
+
for ( m = 0; m < NUM_H_ISOTOPES; m ++ ) {
|
1309
|
+
nNumRemovedProtons_R.nNumRemovedIsotopicH[m] += pINChI_Aux->nNumRemovedIsotopicH[m];
|
1310
|
+
}
|
1311
|
+
}
|
1312
|
+
/*num_fragments_R ++;*/ /* number of disconnected fragments from reconstructed reconnected structure */
|
1313
|
+
}
|
1314
|
+
}
|
1315
|
+
|
1316
|
+
|
1317
|
+
|
1318
|
+
num_fragments_DR = inchi_max( num_fragments_D, num_fragments_R );
|
1319
|
+
/* in case of correct reconstruction, num_fragments_D, num_fragments_R */
|
1320
|
+
|
1321
|
+
if ( !num_fragments_DR ) {
|
1322
|
+
return 0; /* no component was disconnected */
|
1323
|
+
}
|
1324
|
+
if ( num_fragments_D != num_fragments_R ) {
|
1325
|
+
for ( i = 0; i < TAUT_NUM; i ++ ) {
|
1326
|
+
if ( pOneInput->nNumComponents[INCHI_BAS][i] ) {
|
1327
|
+
pOneInput->CompareInchiFlags[1][i] |= INCHIDIFF_PROBLEM;
|
1328
|
+
}
|
1329
|
+
}
|
1330
|
+
return 1; /* severe error */
|
1331
|
+
}
|
1332
|
+
|
1333
|
+
|
1334
|
+
pINChISort1 = (INCHI_SORT *)inchi_calloc(num_fragments_DR, sizeof(pINChISort1[0]));
|
1335
|
+
pINChISort2 = (INCHI_SORT *)inchi_calloc(num_fragments_DR, sizeof(pINChISort2[0]));
|
1336
|
+
if ( !pINChISort1 || !pINChISort2 ) {
|
1337
|
+
ret = RI_ERR_ALLOC;
|
1338
|
+
goto exit_function;
|
1339
|
+
}
|
1340
|
+
|
1341
|
+
/* accumulate original InChI of fragments -- disconnected components that do not match reconnected */
|
1342
|
+
iInChI = INCHI_BAS;
|
1343
|
+
iMobileH = bHasSomeFixedH? !pOneInput->nNumComponents[iInChI][TAUT_NON] : TAUT_YES;
|
1344
|
+
for ( k = n = 0; k < num_components_D; k ++ ) {
|
1345
|
+
bMobileH = iMobileH;
|
1346
|
+
if ( !bInpInchiComponentExists( pOneInput, iInChI, bMobileH, k ) ) {
|
1347
|
+
if ( bInpInchiComponentExists( pOneInput, iInChI, TAUT_YES, k ) ) {
|
1348
|
+
bMobileH = TAUT_YES;
|
1349
|
+
} else {
|
1350
|
+
continue; /* component is missing ??? (Deleted proton in Mobile-H layer) */
|
1351
|
+
}
|
1352
|
+
}
|
1353
|
+
if ( 0 > pOneInput->pInpInChI[iInChI][bMobileH][k].nLink ) {
|
1354
|
+
continue; /* same as reconnected */
|
1355
|
+
}
|
1356
|
+
/* the component exists in disconnected layer of the orig. InChI only: it is a fragment */
|
1357
|
+
pINChISort2[n].pINChI[bMobileH] = pOneInput->pInpInChI[iInChI][bMobileH] + k;
|
1358
|
+
if ( bMobileH == TAUT_NON &&
|
1359
|
+
(bInpInchiComponentExists( pOneInput, iInChI, TAUT_YES, k ) ||
|
1360
|
+
bInpInchiComponentDeleted( pOneInput, iInChI, TAUT_YES, k ) ) ) {
|
1361
|
+
pINChISort2[n].pINChI[TAUT_YES] = pOneInput->pInpInChI[iInChI][TAUT_YES] + k;
|
1362
|
+
}
|
1363
|
+
/* the last sort key is a number of removed protons */
|
1364
|
+
pINChISort2[n].ord_number = pOneInput->nNumProtons[iInChI][TAUT_YES].pNumProtons?
|
1365
|
+
pOneInput->nNumProtons[iInChI][TAUT_YES].pNumProtons[k].nNumRemovedProtons : 0;
|
1366
|
+
pINChISort2[n].n1 = k; /* orig. InChI disconnected layer component number */
|
1367
|
+
pINChISort2[n].n2 = -1; /* no fragment index */
|
1368
|
+
n ++;
|
1369
|
+
}
|
1370
|
+
|
1371
|
+
/* accumulate fragments from the reconstructed structure */
|
1372
|
+
iInChI = INCHI_REC;
|
1373
|
+
iMobileH = bHasSomeFixedH? !pOneInput->nNumComponents[iInChI][TAUT_NON] : TAUT_YES;
|
1374
|
+
for ( k = n = 0; k < num_components_R; k ++ ) {
|
1375
|
+
bMobileH = iMobileH;
|
1376
|
+
if ( !bInpInchiComponentExists( pOneInput, iInChI, bMobileH, k ) ) {
|
1377
|
+
if ( bInpInchiComponentExists( pOneInput, iInChI, TAUT_YES, k ) ) {
|
1378
|
+
bMobileH = TAUT_YES;
|
1379
|
+
} else {
|
1380
|
+
continue; /* component is missing ??? (Deleted proton in Mobile-H layer) */
|
1381
|
+
}
|
1382
|
+
}
|
1383
|
+
/* the reconstructed structure */
|
1384
|
+
if ( 0 < pOneInput->pInpInChI[iInChI][bMobileH][k].nLink ) {
|
1385
|
+
continue; /* same as disconnected, has no metal atoms */
|
1386
|
+
}
|
1387
|
+
/* this reconstructed structure was disconnected */
|
1388
|
+
pStruct1 = pStruct[iInChI][bMobileH]+k;
|
1389
|
+
num_fragments = pStruct1->RevInChI.num_components[INCHI_BAS];
|
1390
|
+
ifInChI = INCHI_BAS;
|
1391
|
+
ifMobileH = bHasSomeFixedH? TAUT_NON : TAUT_YES;
|
1392
|
+
for ( i = 0; i < num_fragments; i ++ ) {
|
1393
|
+
bfMobileH = ifMobileH;
|
1394
|
+
if ( !bRevInchiComponentExists( pStruct1, ifInChI, bfMobileH, i ) ) {
|
1395
|
+
if ( bRevInchiComponentExists( pStruct1, ifInChI, TAUT_YES, i ) ) {
|
1396
|
+
bfMobileH = TAUT_YES;
|
1397
|
+
} else {
|
1398
|
+
continue; /* component is missing ??? */
|
1399
|
+
}
|
1400
|
+
}
|
1401
|
+
pINChISort1[n].pINChI[bfMobileH] = pStruct1->RevInChI.pINChI[ifInChI][i][bfMobileH];
|
1402
|
+
if ( bfMobileH == TAUT_NON /*&& bRevInchiComponentExists( pStruct1, ifInChI, TAUT_YES, i )*/ ) {
|
1403
|
+
pINChISort1[n].pINChI[TAUT_YES] = pStruct1->RevInChI.pINChI[ifInChI][i][TAUT_YES];
|
1404
|
+
/* remove Fixed-H InChI if is is identical to Mobile-H */
|
1405
|
+
/* do it exactly same way the identical components were removed from InpInChI */
|
1406
|
+
if ( !CompareReversedINChI( pINChISort1[n].pINChI[bfMobileH],
|
1407
|
+
pINChISort1[n].pINChI[TAUT_YES], NULL, NULL ) ) {
|
1408
|
+
pINChISort1[n].pINChI[bfMobileH] = NULL; /* remove Fixed-H layer */
|
1409
|
+
} else {
|
1410
|
+
pINChISort1[n].ord_number = pStruct1->RevInChI.pINChI_Aux[ifInChI][i][TAUT_YES]->nNumRemovedProtons;
|
1411
|
+
}
|
1412
|
+
}
|
1413
|
+
|
1414
|
+
pINChISort1[n].n1 = k; /* reconstructed reconnected structure component index */
|
1415
|
+
pINChISort1[n].n2 = i; /* index of a fragment made out of this component */
|
1416
|
+
n ++;
|
1417
|
+
}
|
1418
|
+
}
|
1419
|
+
|
1420
|
+
/* sort fragment InChI before comparing them */
|
1421
|
+
qsort( pINChISort1, num_fragments_D, sizeof(pINChISort1[0]), CompINChITaut2 );
|
1422
|
+
qsort( pINChISort2, num_fragments_R, sizeof(pINChISort2[0]), CompINChITaut2 );
|
1423
|
+
|
1424
|
+
/* compare fragments -- components present in disconnected layer only */
|
1425
|
+
for ( iComponent = 0; iComponent < num_fragments_DR; iComponent ++ ) {
|
1426
|
+
INChI *pInChI1[TAUT_NUM]; /* from reversed structure */
|
1427
|
+
INChI *pInChI2[TAUT_NUM]; /* original input InChI */
|
1428
|
+
for ( i = 0; i < TAUT_NUM; i ++ ) {
|
1429
|
+
pInChI1[i] = pINChISort1[iComponent].pINChI[i];
|
1430
|
+
pInChI2[i] = pINChISort2[iComponent].pINChI[i];
|
1431
|
+
}
|
1432
|
+
CompareTwoPairsOfInChI( pInChI1, pInChI2, !bHasSomeFixedH, CompareInchiFlags );
|
1433
|
+
}
|
1434
|
+
|
1435
|
+
if ( /*nNumNonTaut1 && nNumNonTaut2 &&*/ bHasSomeFixedH ) {
|
1436
|
+
if ( nNumCompHaveSeparateProtons_D || nNumCompHaveSeparateProtons_R ) {
|
1437
|
+
/* for each component, compare number removed protons */
|
1438
|
+
/* comparison does not make sense if Disconnected Fixed-H layer is not present */
|
1439
|
+
for ( iComponent = 0; iComponent < num_fragments_DR; iComponent ++ ) {
|
1440
|
+
NUM_H nNumRemovedIsotopicH1[NUM_H_ISOTOPES];
|
1441
|
+
NUM_H nNumRemovedIsotopicH2[NUM_H_ISOTOPES];
|
1442
|
+
|
1443
|
+
memset( nNumRemovedIsotopicH1, 0, sizeof(nNumRemovedIsotopicH1) );
|
1444
|
+
memset( nNumRemovedIsotopicH2, 0, sizeof(nNumRemovedIsotopicH2) );
|
1445
|
+
/* compare removed protons */
|
1446
|
+
if ( pINChISort1[iComponent].ord_number != pINChISort2[iComponent].ord_number ) {
|
1447
|
+
CompareInchiFlags[TAUT_YES] |= INCHIDIFF_MOBH_PROTONS; /* diff number of removed protons */
|
1448
|
+
}
|
1449
|
+
/* also compare removed isotopic atoms H */
|
1450
|
+
k = pINChISort2[iComponent].n1; /* input InChI, OneInput */
|
1451
|
+
if ( pOneInput->nNumProtons[INCHI_BAS][TAUT_YES].pNumProtons ) {
|
1452
|
+
memcpy( nNumRemovedIsotopicH2,
|
1453
|
+
pOneInput->nNumProtons[INCHI_BAS][TAUT_YES].pNumProtons[k].nNumRemovedIsotopicH,
|
1454
|
+
sizeof( nNumRemovedIsotopicH2 ) );
|
1455
|
+
}
|
1456
|
+
/* get fragments of reconstructed structure removed protons info */
|
1457
|
+
k = pINChISort1[iComponent].n1; /* restored component number */
|
1458
|
+
i = pINChISort1[iComponent].n2; /* subcomponent number */
|
1459
|
+
iInChI = INCHI_REC;
|
1460
|
+
iMobileH = bHasSomeFixedH? !pOneInput->nNumComponents[iInChI][TAUT_NON] : TAUT_YES;
|
1461
|
+
bMobileH = iMobileH;
|
1462
|
+
if ( !bInpInchiComponentExists( pOneInput, iInChI, bMobileH, k ) ) {
|
1463
|
+
if ( bInpInchiComponentExists( pOneInput, iInChI, TAUT_YES, k ) ) {
|
1464
|
+
bMobileH = TAUT_YES;
|
1465
|
+
} else {
|
1466
|
+
goto compare_iso_H;
|
1467
|
+
}
|
1468
|
+
}
|
1469
|
+
if ( pOneInput->pInpInChI[iInChI][bMobileH][k].nLink ) {
|
1470
|
+
continue;
|
1471
|
+
/*
|
1472
|
+
ret = RI_ERR_PROGR;
|
1473
|
+
goto exit_function;
|
1474
|
+
*/
|
1475
|
+
}
|
1476
|
+
pStruct1 = pStruct[iInChI][bMobileH]+k;
|
1477
|
+
num_fragments = pStruct1->RevInChI.num_components[INCHI_BAS];
|
1478
|
+
ifInChI = INCHI_BAS;
|
1479
|
+
ifMobileH = bHasSomeFixedH? TAUT_NON : TAUT_YES;
|
1480
|
+
if ( i < num_fragments ) {
|
1481
|
+
bfMobileH = ifMobileH;
|
1482
|
+
if ( !bRevInchiComponentExists( pStruct1, ifInChI, bfMobileH, i ) ) {
|
1483
|
+
if ( bRevInchiComponentExists( pStruct1, ifInChI, TAUT_YES, i ) ) {
|
1484
|
+
bfMobileH = TAUT_YES;
|
1485
|
+
} else {
|
1486
|
+
goto compare_iso_H;
|
1487
|
+
}
|
1488
|
+
}
|
1489
|
+
memcpy( nNumRemovedIsotopicH1,
|
1490
|
+
pStruct1->RevInChI.pINChI_Aux[ifInChI][i][TAUT_YES]->nNumRemovedIsotopicH,
|
1491
|
+
sizeof( nNumRemovedIsotopicH1 ) );
|
1492
|
+
}
|
1493
|
+
compare_iso_H:
|
1494
|
+
if ( memcmp( nNumRemovedIsotopicH1, nNumRemovedIsotopicH2, sizeof( nNumRemovedIsotopicH1 ) ) ) {
|
1495
|
+
CompareInchiFlags[TAUT_YES] |= INCHIDIFF_REM_ISO_H;
|
1496
|
+
}
|
1497
|
+
}
|
1498
|
+
}
|
1499
|
+
} else
|
1500
|
+
/*if ( !nNumNonTaut1 && !nNumNonTaut2 || !bHasSomeFixedH )*/ {
|
1501
|
+
/* compare totals for removed protons and isotopic H */
|
1502
|
+
if ( pOneInput->nNumProtons[INCHI_BAS][TAUT_YES].nNumRemovedProtons !=
|
1503
|
+
nNumRemovedProtons_R.nNumRemovedProtons ) {
|
1504
|
+
CompareInchiFlags[TAUT_YES] |= INCHIDIFF_MOBH_PROTONS;
|
1505
|
+
}
|
1506
|
+
if ( memcmp( pOneInput->nNumProtons[INCHI_BAS][TAUT_YES].nNumRemovedIsotopicH,
|
1507
|
+
nNumRemovedProtons_R.nNumRemovedIsotopicH,
|
1508
|
+
sizeof( nNumRemovedProtons_R.nNumRemovedIsotopicH ) ) ) {
|
1509
|
+
CompareInchiFlags[TAUT_YES] |= INCHIDIFF_REM_ISO_H;
|
1510
|
+
}
|
1511
|
+
}
|
1512
|
+
|
1513
|
+
if ( !nNumNonTaut1 == !nNumNonTaut2 ) {
|
1514
|
+
; /* difference if(nNumNonTaut1 != nNumNonTaut2) will be caught in InChI comparison */
|
1515
|
+
} else
|
1516
|
+
if ( nNumNonTaut1 ) {
|
1517
|
+
/* reconstructed has Fixed-H while the original has not: extra Fixed-H layer */
|
1518
|
+
CompareInchiFlags[TAUT_YES] |= INCHIDIFF_WRONG_TAUT;
|
1519
|
+
} else {
|
1520
|
+
/* the original InChI has Fixed-H while the reconstructed one has not: missing Fixed-H layer */
|
1521
|
+
CompareInchiFlags[TAUT_YES] |= INCHIDIFF_NO_TAUT;
|
1522
|
+
}
|
1523
|
+
for ( i = 0; i < TAUT_NUM; i ++ ) {
|
1524
|
+
pOneInput->CompareInchiFlags[1][i] |= CompareInchiFlags[i];
|
1525
|
+
}
|
1526
|
+
|
1527
|
+
/* compare totals */
|
1528
|
+
if ( nNumRemovedProtons_R.nNumRemovedProtons != nNumRemovedProtons_D.nNumRemovedProtons ) {
|
1529
|
+
CompareInchiFlags[TAUT_YES] |= INCHIDIFF_MOBH_PROTONS; /* diff number of removed protons */
|
1530
|
+
}
|
1531
|
+
if ( memcmp( nNumRemovedProtons_R.nNumRemovedIsotopicH,
|
1532
|
+
nNumRemovedProtons_D.nNumRemovedIsotopicH,
|
1533
|
+
sizeof( nNumRemovedProtons_D.nNumRemovedIsotopicH ) ) ) {
|
1534
|
+
CompareInchiFlags[TAUT_YES] |= INCHIDIFF_REM_ISO_H;
|
1535
|
+
}
|
1536
|
+
|
1537
|
+
exit_function:
|
1538
|
+
|
1539
|
+
if ( pINChISort1 ) inchi_free( pINChISort1 );
|
1540
|
+
if ( pINChISort2 ) inchi_free( pINChISort2 );
|
1541
|
+
|
1542
|
+
return ret;
|
1543
|
+
}
|
1544
|
+
/******************************************************************************************************/
|
1545
|
+
int CompareTwoPairsOfInChI( INChI *pInChI1[TAUT_NUM], INChI *pInChI2[TAUT_NUM],
|
1546
|
+
int bMobileH, INCHI_MODE CompareInchiFlags[] )
|
1547
|
+
{
|
1548
|
+
int iMobileH, err=0;
|
1549
|
+
INCHI_MODE cmp;
|
1550
|
+
for ( iMobileH = 0; iMobileH < TAUT_NUM; iMobileH ++ ) {
|
1551
|
+
if ( !pInChI1[iMobileH] != !pInChI2[iMobileH] ) {
|
1552
|
+
if ( iMobileH == TAUT_NON &&
|
1553
|
+
pInChI1[TAUT_YES] && pInChI1[TAUT_YES] ) {
|
1554
|
+
CompareInchiFlags[iMobileH] |= INCHIDIFF_COMP_HLAYER;
|
1555
|
+
} else {
|
1556
|
+
CompareInchiFlags[iMobileH] |= INCHIDIFF_COMP_NUMBER;
|
1557
|
+
}
|
1558
|
+
continue;
|
1559
|
+
}
|
1560
|
+
if ( pInChI1[iMobileH] && pInChI2[iMobileH] ) {
|
1561
|
+
cmp = CompareReversedINChI3( pInChI1[iMobileH], pInChI2[iMobileH], NULL, NULL, &err );
|
1562
|
+
if ( cmp ) {
|
1563
|
+
CompareInchiFlags[iMobileH] |= cmp;
|
1564
|
+
}
|
1565
|
+
}
|
1566
|
+
}
|
1567
|
+
return err;
|
1568
|
+
}
|
1569
|
+
/******************************************************************************************************/
|
1570
|
+
int CompareOneOrigInchiToRevInChI(StrFromINChI *pStruct, INChI *pInChI[TAUT_NUM], int bMobileH, int iComponent,
|
1571
|
+
long num_inp, char *szCurHdr,
|
1572
|
+
COMPONENT_REM_PROTONS *nCurRemovedProtons, INCHI_MODE CompareInchiFlags[])
|
1573
|
+
{
|
1574
|
+
int ret = pStruct->RevInChI.nRetVal, err=0;
|
1575
|
+
INCHI_MODE cmp;
|
1576
|
+
if ( ret == _IS_OKAY || ret == _IS_WARNING ) {
|
1577
|
+
/* ignore bMobileH for now */
|
1578
|
+
int i, i0, b /* created type */, b0 /* requested type*/, j, k;
|
1579
|
+
/* pINChI[iINCHI][iComponent][bTaut] */
|
1580
|
+
/* i0 = requested Rec/Disconnected: 1/0 */
|
1581
|
+
/* i = what InChI creaded out of the restored structure */
|
1582
|
+
/* b0 = requested Mobile/Fixed-H: 1/0 */
|
1583
|
+
/* b = what InChI creaded out of the restored structure */
|
1584
|
+
i = i0 = pStruct->iINCHI;
|
1585
|
+
b = b0 = pStruct->iMobileH;
|
1586
|
+
if ( i == INCHI_REC && !pStruct->RevInChI.num_components[i] ) {
|
1587
|
+
i = INCHI_BAS;
|
1588
|
+
}
|
1589
|
+
if ( b == TAUT_NON && (!pStruct->RevInChI.pINChI[i] ||
|
1590
|
+
!pStruct->RevInChI.pINChI[i][0][b] ||
|
1591
|
+
!pStruct->RevInChI.pINChI[i][0][b]->nNumberOfAtoms ) ) {
|
1592
|
+
b = TAUT_YES;
|
1593
|
+
}
|
1594
|
+
if ( pStruct->bDeleted && (!pInChI[0] || pInChI[0]->bDeleted ) ) {
|
1595
|
+
return 0;
|
1596
|
+
}
|
1597
|
+
|
1598
|
+
if ( pStruct->RevInChI.num_components[i] > 1 &&
|
1599
|
+
!pStruct->RevInChI.pINChI[i][1][b]->bDeleted ||
|
1600
|
+
pStruct->RevInChI.num_components[i] < 1 ) {
|
1601
|
+
CompareInchiFlags[bMobileH] |= INCHIDIFF_COMP_NUMBER;
|
1602
|
+
}
|
1603
|
+
if ( b != b0 || b != bMobileH || b0 != bMobileH || i > i0 ) {
|
1604
|
+
/* do not print messages about TAUT_YES instead of TAUT_NON */
|
1605
|
+
CompareInchiFlags[bMobileH] |= INCHIDIFF_COMP_HLAYER;
|
1606
|
+
}
|
1607
|
+
|
1608
|
+
if ( pStruct->RevInChI.num_components[i] ) {
|
1609
|
+
/* compare InChI from restored structure; '0' in [i][0][b] is the first component */
|
1610
|
+
if ( b == TAUT_YES && pStruct->RevInChI.pINChI[i][0][b]->bDeleted && (!pInChI[0] || pInChI[0]->bDeleted ) ) {
|
1611
|
+
/* the 1st component is made out of proton(s) and the input component is missing or also a proton */
|
1612
|
+
cmp = 0;
|
1613
|
+
} else {
|
1614
|
+
cmp = CompareReversedINChI3( pStruct->RevInChI.pINChI[i][0][b], pInChI[0], NULL, NULL, &err );
|
1615
|
+
if ( cmp ) {
|
1616
|
+
CompareInchiFlags[bMobileH] |= cmp;
|
1617
|
+
}
|
1618
|
+
}
|
1619
|
+
if ( b == b0 && b == TAUT_NON ) {
|
1620
|
+
if ( pStruct->RevInChI.pINChI[i][0][TAUT_YES] &&
|
1621
|
+
!pStruct->RevInChI.pINChI[i][0][TAUT_YES]->bDeleted ||
|
1622
|
+
pInChI[1] && !pInChI[1]->bDeleted ) {
|
1623
|
+
|
1624
|
+
/* in addition to fixed-H also compare mobile-H InChI */
|
1625
|
+
cmp = CompareReversedINChI3( pStruct->RevInChI.pINChI[i][0][TAUT_YES], pInChI[1], NULL, NULL, &err );
|
1626
|
+
if ( cmp ) {
|
1627
|
+
CompareInchiFlags[TAUT_YES] |= cmp;
|
1628
|
+
}
|
1629
|
+
}
|
1630
|
+
/* compare removed H */
|
1631
|
+
if ( pStruct->nNumRemovedProtonsMobHInChI != pStruct->RevInChI.pINChI_Aux[i][0][TAUT_YES]->nNumRemovedProtons ) {
|
1632
|
+
CompareInchiFlags[TAUT_YES] |= INCHIDIFF_MOBH_PROTONS;
|
1633
|
+
}
|
1634
|
+
}
|
1635
|
+
memset( nCurRemovedProtons, 0, sizeof(*nCurRemovedProtons) );
|
1636
|
+
for ( k = 0; k < pStruct->RevInChI.num_components[i]; k ++ ) {
|
1637
|
+
if ( !k || pStruct->RevInChI.pINChI[i][k][TAUT_YES]->bDeleted ) {
|
1638
|
+
/* get removed protons from the 1st component; add othere only if they are deleted protons */
|
1639
|
+
nCurRemovedProtons->nNumRemovedProtons += pStruct->RevInChI.pINChI_Aux[i][k][TAUT_YES]->nNumRemovedProtons;
|
1640
|
+
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
|
1641
|
+
nCurRemovedProtons->nNumRemovedIsotopicH[j] += pStruct->RevInChI.pINChI_Aux[i][k][TAUT_YES]->nNumRemovedIsotopicH[j];
|
1642
|
+
}
|
1643
|
+
}
|
1644
|
+
}
|
1645
|
+
}
|
1646
|
+
} else {
|
1647
|
+
CompareInchiFlags[bMobileH] |= INCHIDIFF_STR2INCHI_ERR;
|
1648
|
+
}
|
1649
|
+
return err;
|
1650
|
+
}
|
1651
|
+
/*************************************************************************************/
|
1652
|
+
INCHI_MODE CompareReversedStereoINChI3( INChI_Stereo *s1/* InChI from reversed struct */, INChI_Stereo *s2 /* input InChI */, ICR *picr)
|
1653
|
+
{
|
1654
|
+
int ret = 0;
|
1655
|
+
int j1, j2, num_eq, num_dif, num_extra_undf, num_miss_undf, num_in1_only, num_in2_only;
|
1656
|
+
int bAddSb = !(picr->num_sb_undef_in1_only + picr->num_sb_in1_only + picr->num_sb_in2_only);
|
1657
|
+
int bAddSc = !(picr->num_sc_undef_in1_only + picr->num_sc_in1_only + picr->num_sc_in2_only);
|
1658
|
+
|
1659
|
+
int nNumSc1 = s1? s1->nNumberOfStereoCenters : 0;
|
1660
|
+
int nNumSc2 = s2? s2->nNumberOfStereoCenters : 0;
|
1661
|
+
int nNumSb1 = s1? s1->nNumberOfStereoBonds : 0;
|
1662
|
+
int nNumSb2 = s2? s2->nNumberOfStereoBonds : 0;
|
1663
|
+
|
1664
|
+
if ( (nNumSc1 || nNumSc1) &&
|
1665
|
+
( nNumSc1 != nNumSc2 ||
|
1666
|
+
memcmp( s1->nNumber, s2->nNumber, nNumSc1*sizeof(s1->nNumber[0] ) ) ||
|
1667
|
+
memcmp( s1->t_parity, s2->t_parity, nNumSc1*sizeof(s1->t_parity[0]) ) ) ) {
|
1668
|
+
|
1669
|
+
num_eq = num_dif = num_extra_undf = num_miss_undf = num_in1_only = num_in2_only = 0;
|
1670
|
+
for ( j1 = j2 = 0; j1 < nNumSc1 && j2 < nNumSc2; ) {
|
1671
|
+
if ( s1->nNumber[j1] == s2->nNumber[j2] ) {
|
1672
|
+
if ( s1->t_parity[j1] == s2->t_parity[j2] ) {
|
1673
|
+
num_eq ++;
|
1674
|
+
} else {
|
1675
|
+
num_dif ++;
|
1676
|
+
}
|
1677
|
+
j1 ++;
|
1678
|
+
j2 ++;
|
1679
|
+
} else
|
1680
|
+
if ( s1->nNumber[j1] < s2->nNumber[j2] ) {
|
1681
|
+
num_in1_only ++;
|
1682
|
+
if ( s1->t_parity[j1] == AB_PARITY_UNDF ) {
|
1683
|
+
num_extra_undf ++;
|
1684
|
+
}
|
1685
|
+
if ( bAddSc ) {
|
1686
|
+
if ( picr->num_sc_in1_only < ICR_MAX_SC_IN1_ONLY )
|
1687
|
+
picr->sc_in1_only[picr->num_sc_in1_only ++] = j1;
|
1688
|
+
if ( s1->t_parity[j1] == AB_PARITY_UNDF ) {
|
1689
|
+
if ( picr->num_sc_undef_in1_only < ICR_MAX_SC_UNDF )
|
1690
|
+
picr->sc_undef_in1_only[picr->num_sc_undef_in1_only ++] = j1;
|
1691
|
+
}
|
1692
|
+
}
|
1693
|
+
j1 ++;
|
1694
|
+
} else {
|
1695
|
+
num_in2_only ++;
|
1696
|
+
if ( s2->t_parity[j2] == AB_PARITY_UNDF ) {
|
1697
|
+
num_miss_undf ++;
|
1698
|
+
}
|
1699
|
+
if ( bAddSc ) {
|
1700
|
+
if ( picr->num_sc_in2_only < ICR_MAX_SC_IN2_ONLY )
|
1701
|
+
picr->sc_in2_only[picr->num_sc_in2_only ++] = j2;
|
1702
|
+
if ( s2->t_parity[j2] == AB_PARITY_UNDF ) {
|
1703
|
+
if ( picr->num_sc_undef_in2_only < ICR_MAX_SC_UNDF )
|
1704
|
+
picr->sc_undef_in2_only[picr->num_sc_undef_in2_only ++] = j1;
|
1705
|
+
}
|
1706
|
+
}
|
1707
|
+
j2 ++;
|
1708
|
+
}
|
1709
|
+
}
|
1710
|
+
while ( j1 < nNumSc1 ) {
|
1711
|
+
if ( s1->t_parity[j1] == AB_PARITY_UNDF ) {
|
1712
|
+
num_extra_undf ++;
|
1713
|
+
}
|
1714
|
+
num_in1_only ++;
|
1715
|
+
if ( bAddSc ) {
|
1716
|
+
if ( picr->num_sc_in1_only < ICR_MAX_SC_IN1_ONLY )
|
1717
|
+
picr->sc_in1_only[picr->num_sc_in1_only ++] = j1;
|
1718
|
+
if ( s1->t_parity[j1] == AB_PARITY_UNDF ) {
|
1719
|
+
if ( picr->num_sc_undef_in1_only < ICR_MAX_SC_UNDF )
|
1720
|
+
picr->sc_undef_in1_only[picr->num_sc_undef_in1_only ++] = j1;
|
1721
|
+
}
|
1722
|
+
}
|
1723
|
+
j1 ++;
|
1724
|
+
}
|
1725
|
+
while ( j2 < nNumSc2 ) {
|
1726
|
+
if ( s2->t_parity[j2] == AB_PARITY_UNDF ) {
|
1727
|
+
num_miss_undf ++;
|
1728
|
+
}
|
1729
|
+
num_in2_only ++;
|
1730
|
+
if ( bAddSc ) {
|
1731
|
+
if ( picr->num_sc_in2_only < ICR_MAX_SC_IN2_ONLY )
|
1732
|
+
picr->sc_in2_only[picr->num_sc_in2_only ++] = j2;
|
1733
|
+
}
|
1734
|
+
j2 ++;
|
1735
|
+
}
|
1736
|
+
if ( num_dif ) {
|
1737
|
+
ret |= INCHIDIFF_SC_PARITY;
|
1738
|
+
}
|
1739
|
+
if ( num_in1_only ) {
|
1740
|
+
if ( num_extra_undf ) {
|
1741
|
+
ret |= INCHIDIFF_SC_EXTRA_UNDF;
|
1742
|
+
}
|
1743
|
+
if ( num_in1_only != num_extra_undf ) {
|
1744
|
+
ret |= INCHIDIFF_SC_EXTRA;
|
1745
|
+
}
|
1746
|
+
}
|
1747
|
+
if ( num_in2_only ) {
|
1748
|
+
if ( num_miss_undf ) {
|
1749
|
+
ret |= INCHIDIFF_SC_MISS_UNDF;
|
1750
|
+
}
|
1751
|
+
if ( num_in2_only != num_miss_undf ) {
|
1752
|
+
ret |= INCHIDIFF_SC_MISS;
|
1753
|
+
}
|
1754
|
+
}
|
1755
|
+
}
|
1756
|
+
if ( s1 && s2 && s1->nCompInv2Abs != s2->nCompInv2Abs && s1->nCompInv2Abs && s2->nCompInv2Abs ) {
|
1757
|
+
ret |= INCHIDIFF_SC_INV;
|
1758
|
+
}
|
1759
|
+
|
1760
|
+
if ( (nNumSb1 || nNumSb2 ) &&
|
1761
|
+
(nNumSb1 != nNumSb2 ||
|
1762
|
+
memcmp( s1->nBondAtom1, s2->nBondAtom1, nNumSb1*sizeof(s1->nBondAtom1[0]) ) ||
|
1763
|
+
memcmp( s1->nBondAtom2, s2->nBondAtom2, nNumSb1*sizeof(s1->nBondAtom2[0]) ) ||
|
1764
|
+
memcmp( s1->b_parity, s2->b_parity, nNumSb1*sizeof(s1->b_parity[0]) ) ) ) {
|
1765
|
+
|
1766
|
+
num_eq = num_dif = num_extra_undf = num_miss_undf = num_in1_only = num_in2_only = 0;
|
1767
|
+
for ( j1 = j2 = 0; j1 < nNumSb1 && j2 < nNumSb2; ) {
|
1768
|
+
if ( s1->nBondAtom1[j1] == s2->nBondAtom1[j2] &&
|
1769
|
+
s1->nBondAtom2[j1] == s2->nBondAtom2[j2] ) {
|
1770
|
+
if ( s1->b_parity[j1] == s2->b_parity[j2] ) {
|
1771
|
+
num_eq ++;
|
1772
|
+
} else {
|
1773
|
+
num_dif ++;
|
1774
|
+
}
|
1775
|
+
j1 ++;
|
1776
|
+
j2 ++;
|
1777
|
+
} else
|
1778
|
+
if ( s1->nBondAtom1[j1] < s2->nBondAtom1[j2] ||
|
1779
|
+
s1->nBondAtom1[j1] == s2->nBondAtom1[j2] && s1->nBondAtom2[j1] < s2->nBondAtom2[j2]) {
|
1780
|
+
num_in1_only ++;
|
1781
|
+
if ( s1->b_parity[j1] == AB_PARITY_UNDF ) {
|
1782
|
+
num_extra_undf ++;
|
1783
|
+
}
|
1784
|
+
if ( bAddSb ) {
|
1785
|
+
if ( picr->num_sb_in1_only < ICR_MAX_SB_IN1_ONLY )
|
1786
|
+
picr->sb_in1_only[picr->num_sb_in1_only ++] = j1;
|
1787
|
+
if ( s1->b_parity[j1] == AB_PARITY_UNDF ) {
|
1788
|
+
if ( picr->num_sb_undef_in1_only < ICR_MAX_SB_UNDF )
|
1789
|
+
picr->sb_undef_in1_only[picr->num_sb_undef_in1_only ++] = j1;
|
1790
|
+
}
|
1791
|
+
}
|
1792
|
+
j1 ++;
|
1793
|
+
} else {
|
1794
|
+
num_in2_only ++;
|
1795
|
+
if ( s2->b_parity[j2] == AB_PARITY_UNDF ) {
|
1796
|
+
num_miss_undf ++;
|
1797
|
+
}
|
1798
|
+
if ( bAddSb ) {
|
1799
|
+
if ( picr->num_sb_in2_only < ICR_MAX_SB_IN2_ONLY )
|
1800
|
+
picr->sb_in2_only[picr->num_sb_in2_only ++] = j2;
|
1801
|
+
if ( s2->b_parity[j2] == AB_PARITY_UNDF ) {
|
1802
|
+
if ( picr->num_sb_undef_in2_only < ICR_MAX_SB_UNDF )
|
1803
|
+
picr->sb_undef_in2_only[picr->num_sb_undef_in2_only ++] = j1;
|
1804
|
+
}
|
1805
|
+
}
|
1806
|
+
j2 ++;
|
1807
|
+
}
|
1808
|
+
}
|
1809
|
+
while ( j1 < nNumSb1 ) {
|
1810
|
+
num_in1_only ++;
|
1811
|
+
if ( s1->b_parity[j1] == AB_PARITY_UNDF ) {
|
1812
|
+
num_extra_undf ++;
|
1813
|
+
}
|
1814
|
+
if ( bAddSb ) {
|
1815
|
+
if ( picr->num_sb_in1_only < ICR_MAX_SB_IN1_ONLY )
|
1816
|
+
picr->sb_in1_only[picr->num_sb_in1_only ++] = j1;
|
1817
|
+
if ( s1->b_parity[j1] == AB_PARITY_UNDF ) {
|
1818
|
+
if ( picr->num_sb_undef_in1_only < ICR_MAX_SB_UNDF )
|
1819
|
+
picr->sb_undef_in1_only[picr->num_sb_undef_in1_only ++] = j1;
|
1820
|
+
}
|
1821
|
+
}
|
1822
|
+
j1 ++;
|
1823
|
+
}
|
1824
|
+
while ( j2 < nNumSb2 ) {
|
1825
|
+
num_in2_only ++;
|
1826
|
+
if ( s2->b_parity[j2] == AB_PARITY_UNDF ) {
|
1827
|
+
num_miss_undf ++;
|
1828
|
+
}
|
1829
|
+
if ( bAddSb ) {
|
1830
|
+
if ( picr->num_sb_in2_only < ICR_MAX_SB_IN2_ONLY )
|
1831
|
+
picr->sb_in2_only[picr->num_sb_in2_only ++] = j2;
|
1832
|
+
if ( s2->b_parity[j2] == AB_PARITY_UNDF ) {
|
1833
|
+
if ( picr->num_sb_undef_in2_only < ICR_MAX_SB_UNDF )
|
1834
|
+
picr->sb_undef_in2_only[picr->num_sb_undef_in2_only ++] = j1;
|
1835
|
+
}
|
1836
|
+
}
|
1837
|
+
j2 ++;
|
1838
|
+
}
|
1839
|
+
if ( num_dif ) {
|
1840
|
+
ret |= INCHIDIFF_SB_PARITY;
|
1841
|
+
}
|
1842
|
+
if ( num_in1_only ) {
|
1843
|
+
if ( num_extra_undf ) {
|
1844
|
+
ret |= INCHIDIFF_SB_EXTRA_UNDF;
|
1845
|
+
}
|
1846
|
+
if ( num_in1_only != num_extra_undf ) {
|
1847
|
+
ret |= INCHIDIFF_SB_EXTRA;
|
1848
|
+
}
|
1849
|
+
}
|
1850
|
+
if ( num_in2_only ) {
|
1851
|
+
if ( num_miss_undf ) {
|
1852
|
+
ret |= INCHIDIFF_SB_MISS_UNDF;
|
1853
|
+
}
|
1854
|
+
if ( num_in2_only != num_miss_undf ) {
|
1855
|
+
ret |= INCHIDIFF_SB_MISS;
|
1856
|
+
}
|
1857
|
+
}
|
1858
|
+
}
|
1859
|
+
|
1860
|
+
return ret;
|
1861
|
+
}
|
1862
|
+
/*********************************************************************************************************/
|
1863
|
+
INCHI_MODE CompareReversedINChI3( INChI *i1 /* InChI from reversed struct */, INChI *i2 /* input InChI */,
|
1864
|
+
INChI_Aux *a1, INChI_Aux *a2, int *err )
|
1865
|
+
{
|
1866
|
+
INCHI_MODE ret = 0;
|
1867
|
+
INChI_Stereo *Stereo1=NULL, *Stereo2=NULL;
|
1868
|
+
int n1, n2, m, j, j1, j2, ret2, num_H1, num_H2;
|
1869
|
+
ICR icr;
|
1870
|
+
ICR *picr = &icr;
|
1871
|
+
|
1872
|
+
*err = 0;
|
1873
|
+
|
1874
|
+
memset( picr, 0, sizeof(*picr) );
|
1875
|
+
|
1876
|
+
if ( i1 == NULL && i2 == NULL )
|
1877
|
+
return 0;
|
1878
|
+
if ( (i1 == NULL) ^ (i2 == NULL) ) {
|
1879
|
+
ret |= INCHIDIFF_PROBLEM; /* one InChI exists while another doesn't */
|
1880
|
+
goto exit_function;
|
1881
|
+
}
|
1882
|
+
|
1883
|
+
if ( i1->nErrorCode == i2->nErrorCode ) {
|
1884
|
+
if ( i1->nErrorCode ) {
|
1885
|
+
ret |= INCHIDIFF_PROBLEM; /* both InChI have same error codes */
|
1886
|
+
goto exit_function;
|
1887
|
+
}
|
1888
|
+
} else {
|
1889
|
+
ret |= INCHIDIFF_PROBLEM; /* at least one InChI has an error code */
|
1890
|
+
goto exit_function;
|
1891
|
+
}
|
1892
|
+
|
1893
|
+
if ( i1->nNumberOfAtoms != i2->nNumberOfAtoms ) {
|
1894
|
+
ret |= INCHIDIFF_NUM_AT;
|
1895
|
+
goto exit_function;
|
1896
|
+
}
|
1897
|
+
if ( i1->nNumberOfAtoms > 0 ) {
|
1898
|
+
if ( memcmp( i1->nAtom, i2->nAtom, i1->nNumberOfAtoms*sizeof(i1->nAtom[0]) ) ) {
|
1899
|
+
ret |= INCHIDIFF_ATOMS;
|
1900
|
+
goto exit_function;
|
1901
|
+
}
|
1902
|
+
/* INCHIDIFF_NON_TAUT_H, INCHIDIFF_MORE_FH, INCHIDIFF_LESS_FH */
|
1903
|
+
if ( memcmp( i1->nNum_H, i2->nNum_H, i1->nNumberOfAtoms*sizeof(i1->nNum_H[0]) ) ) {
|
1904
|
+
ret |= INCHIDIFF_POSITION_H;
|
1905
|
+
for ( j1 = 0; j1 < i1->nNumberOfAtoms; j1 ++ ) {
|
1906
|
+
if ( i1->nNum_H[j1] != i2->nNum_H[j1] && picr->num_diff_pos_H < ICR_MAX_DIFF_FIXED_H ) {
|
1907
|
+
picr->diff_pos_H_at[picr->num_diff_pos_H] = j1;
|
1908
|
+
picr->diff_pos_H_nH[picr->num_diff_pos_H] = i1->nNum_H[j1] - i2->nNum_H[j1];
|
1909
|
+
picr->num_diff_pos_H ++;
|
1910
|
+
}
|
1911
|
+
}
|
1912
|
+
}
|
1913
|
+
/* fixed H */
|
1914
|
+
if ( i1->nNum_H_fixed || i2->nNum_H_fixed ) {
|
1915
|
+
int bHasFixedH1 = 0, bHasFixedH2 = 0, i;
|
1916
|
+
if ( i1->nNum_H_fixed ) {
|
1917
|
+
for ( i = 0; i < i1->nNumberOfAtoms; i ++ ) {
|
1918
|
+
if ( i1->nNum_H_fixed[i] ) {
|
1919
|
+
bHasFixedH1 ++;
|
1920
|
+
}
|
1921
|
+
}
|
1922
|
+
}
|
1923
|
+
if ( i2->nNum_H_fixed ) {
|
1924
|
+
for ( i = 0; i < i2->nNumberOfAtoms; i ++ ) {
|
1925
|
+
if ( i2->nNum_H_fixed[i] ) {
|
1926
|
+
bHasFixedH2 ++;
|
1927
|
+
}
|
1928
|
+
}
|
1929
|
+
}
|
1930
|
+
if ( bHasFixedH1 && !bHasFixedH2 ) {
|
1931
|
+
for ( i = j = 0; i < i1->nNumberOfAtoms; i ++ ) {
|
1932
|
+
if ( i1->nNum_H_fixed[i] ) {
|
1933
|
+
if ( j < ICR_MAX_DIFF_FIXED_H ) {
|
1934
|
+
picr->fixed_H_at1_more[j] = i;
|
1935
|
+
picr->fixed_H_nH1_more[j] = i1->nNum_H_fixed[i];
|
1936
|
+
j ++;
|
1937
|
+
}
|
1938
|
+
}
|
1939
|
+
}
|
1940
|
+
picr->num_fixed_H1_more = j;
|
1941
|
+
ret |= INCHIDIFF_MORE_FH; /* Extra Fixed-H */
|
1942
|
+
} else
|
1943
|
+
if ( !bHasFixedH1 && bHasFixedH2 ) {
|
1944
|
+
for ( i = j = 0; i < i2->nNumberOfAtoms; i ++ ) {
|
1945
|
+
if ( i2->nNum_H_fixed[i] ) {
|
1946
|
+
if ( j < ICR_MAX_DIFF_FIXED_H ) {
|
1947
|
+
picr->fixed_H_at2_more[j] = i;
|
1948
|
+
picr->fixed_H_nH2_more[j] = i2->nNum_H_fixed[i];
|
1949
|
+
j ++;
|
1950
|
+
}
|
1951
|
+
}
|
1952
|
+
}
|
1953
|
+
picr->num_fixed_H2_more = j;
|
1954
|
+
ret |= INCHIDIFF_LESS_FH; /* Missed Fixed-H */
|
1955
|
+
} else
|
1956
|
+
if ( bHasFixedH1 && bHasFixedH2 &&
|
1957
|
+
memcmp( i1->nNum_H_fixed, i2->nNum_H_fixed, i1->nNumberOfAtoms*sizeof(i1->nNum_H_fixed[0]) ) ) {
|
1958
|
+
for ( i = j1 = j2 = 0; i < i1->nNumberOfAtoms; i ++ ) {
|
1959
|
+
if ( i1->nNum_H_fixed[i] > i2->nNum_H_fixed[i] ) {
|
1960
|
+
if ( j1 < ICR_MAX_DIFF_FIXED_H ) {
|
1961
|
+
picr->fixed_H_at1_more[j1] = i;
|
1962
|
+
picr->fixed_H_nH1_more[j1] = i1->nNum_H_fixed[i] - i2->nNum_H_fixed[i];
|
1963
|
+
j1 ++;
|
1964
|
+
}
|
1965
|
+
} else
|
1966
|
+
if ( i1->nNum_H_fixed[i] < i2->nNum_H_fixed[i] ) {
|
1967
|
+
if ( j2 < ICR_MAX_DIFF_FIXED_H ) {
|
1968
|
+
picr->fixed_H_at2_more[j2] = i;
|
1969
|
+
picr->fixed_H_nH2_more[j2] = i2->nNum_H_fixed[i] - i1->nNum_H_fixed[i];
|
1970
|
+
j2 ++;
|
1971
|
+
}
|
1972
|
+
}
|
1973
|
+
}
|
1974
|
+
ret |= (j1? INCHIDIFF_MORE_FH:0) | (j2? INCHIDIFF_LESS_FH:0);
|
1975
|
+
picr->num_fixed_H1_more = j1;
|
1976
|
+
picr->num_fixed_H2_more = j2;
|
1977
|
+
}
|
1978
|
+
}
|
1979
|
+
}
|
1980
|
+
/* compare formulas and H */
|
1981
|
+
num_H1 = 0;
|
1982
|
+
num_H2 = 0;
|
1983
|
+
ret2 = CompareHillFormulasNoH( i1->szHillFormula, i2->szHillFormula, &num_H1, &num_H2 );
|
1984
|
+
picr->tot_num_H1 = num_H1;
|
1985
|
+
picr->tot_num_H2 = num_H2;
|
1986
|
+
if ( ret2 ) {
|
1987
|
+
ret |= INCHIDIFF_NUM_EL;
|
1988
|
+
goto exit_function;
|
1989
|
+
}
|
1990
|
+
if ( num_H1 > num_H2 ) {
|
1991
|
+
ret |= INCHIDIFF_MORE_H;
|
1992
|
+
}
|
1993
|
+
if ( num_H1 < num_H2 ) {
|
1994
|
+
ret |= INCHIDIFF_LESS_H;
|
1995
|
+
}
|
1996
|
+
|
1997
|
+
if ( i1->lenConnTable != i2->lenConnTable ) {
|
1998
|
+
ret |= INCHIDIFF_CON_LEN;
|
1999
|
+
goto exit_function;
|
2000
|
+
} else
|
2001
|
+
if ( i1->lenConnTable > 0 && memcmp( i1->nConnTable, i2->nConnTable, i1->lenConnTable*sizeof(i1->nConnTable[0]) ) ) {
|
2002
|
+
ret |= INCHIDIFF_CON_TBL;
|
2003
|
+
goto exit_function;
|
2004
|
+
}
|
2005
|
+
/* output special cases: different number of t-groups, different sizes of t-groups, different endpoints */
|
2006
|
+
/* in isotopic or deprotonated cases i1->lenTautomer == 1 && i1->nTautomer[0] = 0 */
|
2007
|
+
/*
|
2008
|
+
if ( i1->lenTautomer != i2->lenTautomer && (i1->lenTautomer > 1 || i2->lenTautomer > 1) ) {
|
2009
|
+
ret |= INCHIDIFF_TAUT_LEN;
|
2010
|
+
}
|
2011
|
+
*/
|
2012
|
+
/* compare number of t-groups */
|
2013
|
+
n1 = i1->lenTautomer? i1->nTautomer[0] : 0;
|
2014
|
+
n2 = i2->lenTautomer? i2->nTautomer[0] : 0;
|
2015
|
+
if ( !n1 && n2 ) {
|
2016
|
+
ret |= INCHIDIFF_NO_TAUT;
|
2017
|
+
} else
|
2018
|
+
if ( n1 && !n2 ) {
|
2019
|
+
ret |= INCHIDIFF_WRONG_TAUT;
|
2020
|
+
} else
|
2021
|
+
if ( n1 == 1 && n2 > 1 ) {
|
2022
|
+
ret |= INCHIDIFF_SINGLE_TG;
|
2023
|
+
} else
|
2024
|
+
if ( n1 > 1 && n2 == 1 ) {
|
2025
|
+
ret |= INCHIDIFF_MULTIPLE_TG;
|
2026
|
+
} else
|
2027
|
+
if ( n1 != n2 ) {
|
2028
|
+
ret |= INCHIDIFF_NUM_TG;
|
2029
|
+
}
|
2030
|
+
if ( n1 || n2 ) {
|
2031
|
+
/* number of endpoints */
|
2032
|
+
int num1 = 0, num2 = 0, num_M1=0, num_M2=0;
|
2033
|
+
int len, num_eq, num_in1_only, num_in2_only;
|
2034
|
+
AT_NUMB *pe1 = (AT_NUMB *)inchi_malloc( (i1->lenTautomer+1) * sizeof(pe1[0]) );
|
2035
|
+
AT_NUMB *pe2 = (AT_NUMB *)inchi_malloc( (i2->lenTautomer+1) * sizeof(pe2[0]) );
|
2036
|
+
num_H1 = num_H2=0;
|
2037
|
+
/* collect endpoints, H, (-) */
|
2038
|
+
if ( !pe1 || !pe2 ) {
|
2039
|
+
if ( pe1 ) inchi_free( pe1 );
|
2040
|
+
if ( pe2 ) inchi_free( pe2 );
|
2041
|
+
*err = RI_ERR_ALLOC; /* allocation error */
|
2042
|
+
goto exit_function;
|
2043
|
+
}
|
2044
|
+
for ( m = 1; m < i1->lenTautomer; m += len ) {
|
2045
|
+
len = i1->nTautomer[m ++];
|
2046
|
+
num_H1 += i1->nTautomer[m];
|
2047
|
+
num_M1 += i1->nTautomer[m+1];
|
2048
|
+
for ( j = 2; j < len; j ++ ) {
|
2049
|
+
pe1[num1 ++] = i1->nTautomer[m + j];
|
2050
|
+
}
|
2051
|
+
}
|
2052
|
+
for ( m = 1; m < i2->lenTautomer; m += len ) {
|
2053
|
+
len = i2->nTautomer[m ++];
|
2054
|
+
num_H2 += i2->nTautomer[m];
|
2055
|
+
num_M2 += i2->nTautomer[m+1];
|
2056
|
+
for ( j = 2; j < len; j ++ ) {
|
2057
|
+
pe2[num2 ++] = i2->nTautomer[m + j];
|
2058
|
+
}
|
2059
|
+
}
|
2060
|
+
picr->num_taut_H1 = num_H1;
|
2061
|
+
picr->num_taut_H2 = num_H2;
|
2062
|
+
picr->num_taut_M1 = num_M1;
|
2063
|
+
picr->num_taut_M2 = num_M2;
|
2064
|
+
/* sort endpoints */
|
2065
|
+
insertions_sort_AT_NUMB( pe1, num1 );
|
2066
|
+
insertions_sort_AT_NUMB( pe2, num2 );
|
2067
|
+
/* compare */
|
2068
|
+
/*
|
2069
|
+
if ( num1 < num2 ) {
|
2070
|
+
ret |= INCHIDIFF_LESS_TG_ENDP;
|
2071
|
+
} else
|
2072
|
+
if ( num1 > num2 ) {
|
2073
|
+
ret |= INCHIDIFF_MORE_TG_ENDP;
|
2074
|
+
}
|
2075
|
+
*/
|
2076
|
+
/* compare all */
|
2077
|
+
num_eq = num_in1_only = num_in2_only = 0;
|
2078
|
+
for ( j1 = j2 = 0; j1 < num1 && j2 < num2; ) {
|
2079
|
+
if( pe1[j1] == pe2[j2] ) {
|
2080
|
+
j1 ++;
|
2081
|
+
j2 ++;
|
2082
|
+
num_eq ++;
|
2083
|
+
} else
|
2084
|
+
if ( pe1[j1] < pe2[j1] ) {
|
2085
|
+
if ( picr->num_endp_in1_only < ICR_MAX_ENDP_IN1_ONLY ) {
|
2086
|
+
picr->endp_in1_only[picr->num_endp_in1_only ++] = pe1[j1];
|
2087
|
+
}
|
2088
|
+
j1 ++;
|
2089
|
+
num_in1_only ++;
|
2090
|
+
} else {
|
2091
|
+
if ( picr->num_endp_in2_only < ICR_MAX_ENDP_IN2_ONLY ) {
|
2092
|
+
picr->endp_in2_only[picr->num_endp_in2_only ++] = pe2[j2];
|
2093
|
+
}
|
2094
|
+
j2 ++;
|
2095
|
+
num_in2_only ++;
|
2096
|
+
}
|
2097
|
+
}
|
2098
|
+
while ( j1 < num1 ) {
|
2099
|
+
if ( picr->num_endp_in1_only < ICR_MAX_ENDP_IN1_ONLY ) {
|
2100
|
+
picr->endp_in1_only[picr->num_endp_in1_only ++] = pe1[j1];
|
2101
|
+
}
|
2102
|
+
j1 ++;
|
2103
|
+
num_in1_only ++;
|
2104
|
+
}
|
2105
|
+
while ( j2 < num2 ) {
|
2106
|
+
if ( picr->num_endp_in2_only < ICR_MAX_ENDP_IN2_ONLY ) {
|
2107
|
+
picr->endp_in2_only[picr->num_endp_in2_only ++] = pe2[j2];
|
2108
|
+
}
|
2109
|
+
j2 ++;
|
2110
|
+
num_in2_only ++;
|
2111
|
+
}
|
2112
|
+
if ( num_in1_only ) {
|
2113
|
+
ret |= INCHIDIFF_EXTRA_TG_ENDP;
|
2114
|
+
}
|
2115
|
+
if ( num_in2_only ) {
|
2116
|
+
ret |= INCHIDIFF_MISS_TG_ENDP;
|
2117
|
+
}
|
2118
|
+
if ( !num_in1_only && !num_in2_only && num_eq ) {
|
2119
|
+
; /* same t-groups endpoints */
|
2120
|
+
} else {
|
2121
|
+
ret |= INCHIDIFF_DIFF_TG_ENDP;
|
2122
|
+
}
|
2123
|
+
inchi_free( pe1 );
|
2124
|
+
inchi_free( pe2 );
|
2125
|
+
|
2126
|
+
}
|
2127
|
+
|
2128
|
+
if ( (i1->lenTautomer > 1 && i2->lenTautomer > 1) &&
|
2129
|
+
( i1->lenTautomer != i2->lenTautomer ||
|
2130
|
+
memcmp( i1->nTautomer, i2->nTautomer, i1->lenTautomer*sizeof(i1->nTautomer[0]) ) ) )
|
2131
|
+
ret |= INCHIDIFF_TG;
|
2132
|
+
|
2133
|
+
if ( i1->nNumberOfIsotopicAtoms != i2->nNumberOfIsotopicAtoms ) {
|
2134
|
+
ret |= INCHIDIFF_NUM_ISO_AT;
|
2135
|
+
} else
|
2136
|
+
if ( i1->nNumberOfIsotopicAtoms > 0 && memcmp( i1->IsotopicAtom, i2->IsotopicAtom, i1->nNumberOfIsotopicAtoms*sizeof(i1->IsotopicAtom[0]) ) )
|
2137
|
+
ret |= INCHIDIFF_ISO_AT;
|
2138
|
+
if ( i1->nTotalCharge != i2->nTotalCharge )
|
2139
|
+
ret |= INCHIDIFF_CHARGE;
|
2140
|
+
if ( a1 && a1->nNumRemovedProtons && (!a2 || a2->nNumRemovedProtons != a1->nNumRemovedProtons) ) {
|
2141
|
+
ret |= INCHIDIFF_REM_PROT;
|
2142
|
+
}
|
2143
|
+
if ( a1 && (!a2 ||
|
2144
|
+
a2->nNumRemovedIsotopicH[0] != a1->nNumRemovedIsotopicH[0] ||
|
2145
|
+
a2->nNumRemovedIsotopicH[1] != a1->nNumRemovedIsotopicH[1] ||
|
2146
|
+
a2->nNumRemovedIsotopicH[2] != a1->nNumRemovedIsotopicH[2]) ) {
|
2147
|
+
ret |= INCHIDIFF_REM_ISO_H;
|
2148
|
+
}
|
2149
|
+
|
2150
|
+
/*
|
2151
|
+
if ( i1->nPossibleLocationsOfIsotopicH && i2->nPossibleLocationsOfIsotopicH ) {
|
2152
|
+
if ( i1->nPossibleLocationsOfIsotopicH[0] != i2->nPossibleLocationsOfIsotopicH[0] ||
|
2153
|
+
memcmp(i1->nPossibleLocationsOfIsotopicH, i2->nPossibleLocationsOfIsotopicH,
|
2154
|
+
sizeof(i1->nPossibleLocationsOfIsotopicH[0])*i1->nPossibleLocationsOfIsotopicH[0]) )
|
2155
|
+
return 18;
|
2156
|
+
} else
|
2157
|
+
if ( !i1->nPossibleLocationsOfIsotopicH != !i2->nPossibleLocationsOfIsotopicH ) {
|
2158
|
+
return 19;
|
2159
|
+
}
|
2160
|
+
*/
|
2161
|
+
if ( i1->StereoIsotopic &&
|
2162
|
+
i1->StereoIsotopic->nNumberOfStereoBonds + i1->StereoIsotopic->nNumberOfStereoCenters ) {
|
2163
|
+
Stereo1 = i1->StereoIsotopic;
|
2164
|
+
} else {
|
2165
|
+
Stereo1 = i1->Stereo;
|
2166
|
+
}
|
2167
|
+
if ( i2->StereoIsotopic &&
|
2168
|
+
i2->StereoIsotopic->nNumberOfStereoBonds + i2->StereoIsotopic->nNumberOfStereoCenters ) {
|
2169
|
+
Stereo2 = i2->StereoIsotopic;
|
2170
|
+
} else {
|
2171
|
+
Stereo2 = i2->Stereo;
|
2172
|
+
}
|
2173
|
+
ret |= CompareReversedStereoINChI3( Stereo1, Stereo2, picr );
|
2174
|
+
|
2175
|
+
exit_function:
|
2176
|
+
|
2177
|
+
picr->flags = ret;
|
2178
|
+
|
2179
|
+
return ret;
|
2180
|
+
}
|
2181
|
+
/* message group names */
|
2182
|
+
CMP_INCHI_MSG_GROUP CompareInchiMsgsGroup[] = {
|
2183
|
+
{IDGRP_ERR, " Error:"},
|
2184
|
+
{IDGRP_H, " Hydrogens:"},
|
2185
|
+
{IDGRP_MOB_GRP, " Mobile-H groups:"},
|
2186
|
+
{IDGRP_ISO_AT, " Isotopic:"},
|
2187
|
+
{IDGRP_CHARGE, " Charge(s):"},
|
2188
|
+
{IDGRP_PROTONS, " Proton balance:"},
|
2189
|
+
{IDGRP_ISO_H, " Exchangeable isotopic H:"},
|
2190
|
+
{IDGRP_SC, " Stereo centers/allenes:"},
|
2191
|
+
{IDGRP_SB, " Stereobonds/cumulenes:"},
|
2192
|
+
{IDGRP_HLAYER, " Fixed-H layer:"},
|
2193
|
+
{IDGRP_COMP, " Number of components:"},
|
2194
|
+
{IDGRP_CONV_ERR," Conversion encountered:"},
|
2195
|
+
{IDGRP_ZERO, ""}
|
2196
|
+
};
|
2197
|
+
/* messages */
|
2198
|
+
CMP_INCHI_MSG CompareInchiMsgs[] = {
|
2199
|
+
{INCHIDIFF_PROBLEM ,IDGRP_ERR, " Wrong result" }, /*0x00000001, severe: at least one InChI does not exist */
|
2200
|
+
{INCHIDIFF_POSITION_H ,IDGRP_H, " Locations or number" }, /*0x00000002, difference in non-taut {Mobile-H} or all H {Fixed-H} location/number */
|
2201
|
+
{INCHIDIFF_MORE_FH ,IDGRP_H, " Fixed-H" }, /*0x00000004, extra fixed H */
|
2202
|
+
{INCHIDIFF_LESS_FH ,IDGRP_H, " Fixed-H" }, /*0x00000004, missing fixed H */
|
2203
|
+
{INCHIDIFF_MORE_H ,IDGRP_H, " Number" }, /*0x00000008, formulas differ in number of H */
|
2204
|
+
{INCHIDIFF_LESS_H ,IDGRP_H, " Number" }, /*0x00000008, formulas differ in number of H */
|
2205
|
+
{INCHIDIFF_NO_TAUT ,IDGRP_MOB_GRP, " Missing" }, /*0x00000010, restored structure has no taut groups while the original InChI has some */
|
2206
|
+
{INCHIDIFF_WRONG_TAUT ,IDGRP_MOB_GRP, " Falsely present" }, /*0x00000020, restored has tautomerism while the original does not have it */
|
2207
|
+
{INCHIDIFF_SINGLE_TG ,IDGRP_MOB_GRP, " One instead of multiple" }, /*0x00000040, restored has 1 taut. group while the original InChI has multiple tg */
|
2208
|
+
{INCHIDIFF_MULTIPLE_TG ,IDGRP_MOB_GRP, " Multiple instead of one" }, /*0x00000080, restored has multiple tg while the original InChI has only one tg */
|
2209
|
+
{INCHIDIFF_EXTRA_TG_ENDP,IDGRP_MOB_GRP, " Attachment points" }, /*0x00000100, extra tautomeric endpoint{s} in restored structure */
|
2210
|
+
{INCHIDIFF_MISS_TG_ENDP ,IDGRP_MOB_GRP, " Attachment points" }, /*0x00000100, one or more tg endpoint is not in the restored structure */
|
2211
|
+
{INCHIDIFF_DIFF_TG_ENDP ,IDGRP_MOB_GRP, " Attachment points" }, /*0x00000100, lists of tg endpoints are different */
|
2212
|
+
{INCHIDIFF_NUM_TG ,IDGRP_MOB_GRP, " Number" }, /*0x00000200, different number of tautomeric groups */
|
2213
|
+
{INCHIDIFF_TG ,IDGRP_MOB_GRP, " Do not match" }, /*0x00000200, different tautomeric groups */
|
2214
|
+
{INCHIDIFF_NUM_ISO_AT ,IDGRP_ISO_AT, " Atoms do not match" }, /*0x00000400, ?severe: restored struct. has different number of isotopic atoms */
|
2215
|
+
{INCHIDIFF_ISO_AT ,IDGRP_ISO_AT, " Atoms do not match" }, /*0x00000400, ?severe: restored struct. has different locations/isotopes of isotopic atoms */
|
2216
|
+
{INCHIDIFF_REM_ISO_H ,IDGRP_ISO_H, " Does not match for a component" }, /*0x00000800, isotopic H removed */
|
2217
|
+
{INCHIDIFF_MOB_ISO_H ,IDGRP_ISO_H, " Do not match" }, /*0x00001000, different number of mobile exchangeable isotopic H */
|
2218
|
+
{INCHIDIFF_CHARGE ,IDGRP_CHARGE, " Do not match" }, /*0x00002000, restored structure has different charge */
|
2219
|
+
{INCHIDIFF_REM_PROT ,IDGRP_PROTONS, " Does not match for a component" }, /*0x00004000, proton{s} removed/added from the restored structure */
|
2220
|
+
{INCHIDIFF_MOBH_PROTONS ,IDGRP_PROTONS, " Does not match" }, /*0x00008000, different proton balance */
|
2221
|
+
{INCHIDIFF_SC_INV ,IDGRP_SC, " Falsely inverted" }, /*0x00010000, restores structure has different inversion stereocenter mark */
|
2222
|
+
{INCHIDIFF_SC_PARITY ,IDGRP_SC, " Wrong parity" }, /*0x00020000, restored structure has stereoatoms or allenes with different parity */
|
2223
|
+
{INCHIDIFF_SC_EXTRA_UNDF,IDGRP_SC, " Extra undefined" }, /*0x00040000, restored structure has extra undefined stereocenter{s} */
|
2224
|
+
{INCHIDIFF_SC_EXTRA ,IDGRP_SC, " Extra known" }, /*0x00080000, restored structure has extra stereocenter{s} */
|
2225
|
+
{INCHIDIFF_SC_MISS_UNDF ,IDGRP_SC, " Missing undefined" }, /*0x00100000, restored structure has not some undefined stereocenter{s} */
|
2226
|
+
{INCHIDIFF_SC_MISS ,IDGRP_SC, " Missing known" }, /*0x00200000, restored structure has not some stereocenters that are not undefined */
|
2227
|
+
{INCHIDIFF_SB_PARITY ,IDGRP_SB, " Wrong parity" }, /*0x00400000, restored structure has stereobonds or cumulenes with different parity */
|
2228
|
+
{INCHIDIFF_SB_EXTRA_UNDF,IDGRP_SB, " Extra undefined" }, /*0x00800000, restored structure has extra undefined stereobond{s} */
|
2229
|
+
{INCHIDIFF_SB_EXTRA ,IDGRP_SB, " Missing known" }, /*0x01000000, restored structure has extra stereobond{s} */
|
2230
|
+
{INCHIDIFF_SB_MISS_UNDF ,IDGRP_SB, " Missing undefined" }, /*0x02000000, restored structure has not some undefined stereocenters */
|
2231
|
+
{INCHIDIFF_SB_MISS ,IDGRP_SB, " Missing known" }, /*0x04000000, restored structure has not some stereobonds that are not undefined */
|
2232
|
+
{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 */
|
2233
|
+
{INCHIDIFF_COMP_NUMBER ,IDGRP_COMP, " Does not match" }, /*0x10000000, wrong number of components */
|
2234
|
+
{INCHIDIFF_STR2INCHI_ERR,IDGRP_CONV_ERR," Error" }, /*0x20000000 Restored structure to InChI conversion error */
|
2235
|
+
{INCHIDIFF_ZERO ,IDGRP_ZERO, "" }
|
2236
|
+
};
|
2237
|
+
|
2238
|
+
/*************************************************************************/
|
2239
|
+
int AddOneMsg( char *szMsg, int used_len, int tot_len, const char *szAddMsg, const char *szDelim )
|
2240
|
+
{
|
2241
|
+
const char ellip[] = "...";
|
2242
|
+
int len = strlen( szAddMsg );
|
2243
|
+
int len_delim = (used_len && szDelim)? strlen(szDelim) : 0;
|
2244
|
+
int len_to_copy;
|
2245
|
+
if ( len + len_delim + used_len < tot_len ) {
|
2246
|
+
if ( len_delim ) {
|
2247
|
+
strcpy( szMsg+used_len, szDelim );
|
2248
|
+
used_len += len_delim;
|
2249
|
+
}
|
2250
|
+
strcpy( szMsg+used_len, szAddMsg );
|
2251
|
+
used_len += len;
|
2252
|
+
} else
|
2253
|
+
if ( (len_to_copy = (tot_len - used_len - len_delim - (int)sizeof(ellip))) > 10 ) {
|
2254
|
+
if ( len_delim ) {
|
2255
|
+
strcpy( szMsg+used_len, szDelim );
|
2256
|
+
used_len += len_delim;
|
2257
|
+
}
|
2258
|
+
strncpy( szMsg+used_len, szAddMsg, len_to_copy );
|
2259
|
+
used_len += len_to_copy;
|
2260
|
+
strcpy( szMsg+used_len, ellip );
|
2261
|
+
used_len += sizeof( ellip ) - 1;
|
2262
|
+
}
|
2263
|
+
return used_len;
|
2264
|
+
}
|
2265
|
+
/*************************************************************************/
|
2266
|
+
int FillOutCompareMessage( char *szMsg, int nLenMsg, INCHI_MODE bits[] )
|
2267
|
+
{
|
2268
|
+
int bMobileH, k, n, len = strlen( szMsg );
|
2269
|
+
int iPrevGrpIdx, iCurGrpIdx, bFound;
|
2270
|
+
INCHI_MODE bit;
|
2271
|
+
static const char *hdr = " Problems/mismatches:";
|
2272
|
+
char szOneMsg[256];
|
2273
|
+
if ( bits[TAUT_YES] || bits[TAUT_NON] ) {
|
2274
|
+
if ( !strstr( szMsg, hdr ) ) {
|
2275
|
+
len = AddOneMsg( szMsg, len, nLenMsg, hdr, NULL );
|
2276
|
+
}
|
2277
|
+
for ( bMobileH = TAUT_YES; 0 <= bMobileH; bMobileH -- ) {
|
2278
|
+
if ( bits[bMobileH] ) {
|
2279
|
+
strcpy( szOneMsg, bMobileH==TAUT_YES? " Mobile-H(" : " Fixed-H(" );
|
2280
|
+
len = AddOneMsg( szMsg, len, nLenMsg, szOneMsg, NULL );
|
2281
|
+
}
|
2282
|
+
bit = 1;
|
2283
|
+
iPrevGrpIdx = -1;
|
2284
|
+
do {
|
2285
|
+
if ( bit & bits[bMobileH] ) {
|
2286
|
+
/* search for the message */
|
2287
|
+
bFound = 0;
|
2288
|
+
for ( k = 0; CompareInchiMsgs[k].nBit != INCHIDIFF_ZERO && !bFound; k ++ ) {
|
2289
|
+
if ( bit & (INCHI_MODE)CompareInchiMsgs[k].nBit ) {
|
2290
|
+
/* message found */
|
2291
|
+
for ( n = 0; CompareInchiMsgsGroup[n].nGroupID != IDGRP_ZERO; n ++ ) {
|
2292
|
+
if ( CompareInchiMsgsGroup[n].nGroupID == CompareInchiMsgs[k].nGroupID ) {
|
2293
|
+
iCurGrpIdx = n;
|
2294
|
+
if ( iCurGrpIdx != iPrevGrpIdx ) {
|
2295
|
+
if ( iPrevGrpIdx >= 0 ) {
|
2296
|
+
len = AddOneMsg( szMsg, len, nLenMsg, ";", NULL );
|
2297
|
+
}
|
2298
|
+
len = AddOneMsg( szMsg, len, nLenMsg, CompareInchiMsgsGroup[iCurGrpIdx].szGroupName, NULL );
|
2299
|
+
}
|
2300
|
+
len = AddOneMsg( szMsg, len, nLenMsg, CompareInchiMsgs[k].szMsg, iCurGrpIdx == iPrevGrpIdx? ",":NULL );
|
2301
|
+
iPrevGrpIdx = iCurGrpIdx;
|
2302
|
+
bFound = 1;
|
2303
|
+
break;
|
2304
|
+
}
|
2305
|
+
}
|
2306
|
+
}
|
2307
|
+
}
|
2308
|
+
}
|
2309
|
+
bit <<= 1;
|
2310
|
+
} while ( bit );
|
2311
|
+
if ( bits[bMobileH] ) {
|
2312
|
+
len = AddOneMsg( szMsg, len, nLenMsg, ")", NULL );
|
2313
|
+
}
|
2314
|
+
}
|
2315
|
+
}
|
2316
|
+
return len;
|
2317
|
+
}
|
2318
|
+
|
2319
|
+
#endif
|