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/dispstru.h
ADDED
@@ -0,0 +1,73 @@
|
|
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
|
+
#ifndef __DISP_STRU_H__
|
11
|
+
#define __DISP_STRU_H__
|
12
|
+
#include <windows.h>
|
13
|
+
|
14
|
+
/* local types */
|
15
|
+
/*****************************************************/
|
16
|
+
typedef struct tagInternalDrawParms {
|
17
|
+
double xmin, xmax, ymin, ymax;
|
18
|
+
int max_label_width_char;
|
19
|
+
int max_left_label_width_pix;
|
20
|
+
int max_right_label_width_pix;
|
21
|
+
int bInit;
|
22
|
+
} INT_DRAW_PARMS; /* internal: saved for redisplaying one structure */
|
23
|
+
|
24
|
+
|
25
|
+
/*****************************************************
|
26
|
+
* Window data
|
27
|
+
*/
|
28
|
+
typedef struct tagWindowData {
|
29
|
+
|
30
|
+
inp_ATOM *at0; /* [MAX_ATOMS]; */
|
31
|
+
inp_ATOM *at1; /* [MAX_ATOMS]; */
|
32
|
+
INF_ATOM_DATA inf_at_data;
|
33
|
+
/*inf_ATOM *inf_at;*/ /* [MAX_ATOMS]; */
|
34
|
+
int num_at;
|
35
|
+
int bOrigAtom;
|
36
|
+
int bHighlight;
|
37
|
+
int bEsc;
|
38
|
+
int bUserIntervened;
|
39
|
+
UINT nTimerId;
|
40
|
+
|
41
|
+
unsigned long ulDisplTime;
|
42
|
+
int nFontSize;
|
43
|
+
RECT rc; /* window rectangle size for saving */
|
44
|
+
INT_DRAW_PARMS idp; /* structure geom. parameters for redrawing */
|
45
|
+
TBL_DRAW_PARMS tdp; /* table data for displaying */
|
46
|
+
char *szTitle; /* for INCHI_LIB printing */
|
47
|
+
|
48
|
+
/* component equivalence info */
|
49
|
+
AT_NUMB *nEquLabels; /* num_at elements or NULL */
|
50
|
+
AT_NUMB nNumEquSets; /* number of equivalent sets or 0 */
|
51
|
+
AT_NUMB nCurEquLabel; /* in range 0..nNumEquSets; 0=>do not display equivalent components */
|
52
|
+
|
53
|
+
AT_NUMB nNewEquLabel; /* non-zero only if DISPLAY_EQU_COMPONENTS==1 */
|
54
|
+
|
55
|
+
} MY_WINDOW_DATA;
|
56
|
+
|
57
|
+
#ifndef INCHI_ALL_CPP
|
58
|
+
#ifdef __cplusplus
|
59
|
+
extern "C" {
|
60
|
+
#endif
|
61
|
+
#endif
|
62
|
+
|
63
|
+
void FreeWinData( MY_WINDOW_DATA* pWinData );
|
64
|
+
int CreateInputStructPicture( HDC hDC, MY_WINDOW_DATA *pWinData, RECT *rc, int bPrint, AT_NUMB nNewEquLabel );
|
65
|
+
|
66
|
+
#ifndef INCHI_ALL_CPP
|
67
|
+
#ifdef __cplusplus
|
68
|
+
}
|
69
|
+
#endif
|
70
|
+
#endif
|
71
|
+
|
72
|
+
|
73
|
+
#endif
|
data/ext/src/extr_ct.h
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
* International Union of Pure and Applied Chemistry (IUPAC)
|
3
3
|
* International Chemical Identifier (InChI)
|
4
4
|
* Version 1
|
5
|
-
* Software version 1.
|
6
|
-
*
|
5
|
+
* Software version 1.01
|
6
|
+
* July 21, 2006
|
7
7
|
* Developed at NIST
|
8
8
|
*/
|
9
9
|
|
@@ -175,6 +175,9 @@ typedef struct tagAtom {
|
|
175
175
|
#define BOND_MARK_ALT12NS 0x50 /* 1 or 2, non-stereo */
|
176
176
|
#define BOND_MARK_MASK 0x70
|
177
177
|
|
178
|
+
#define ACTUAL_ORDER(PBNS, IAT,IBOND, BTYPE) ( ((PBNS) && (PBNS)->edge && (PBNS)->vert &&\
|
179
|
+
((BTYPE)==BOND_ALT_123 || (BTYPE)==BOND_ALT_13 || (BTYPE)==BOND_ALT_23))? (PBNS)->edge[(PBNS)->vert[IAT].iedge[IBOND]].flow+BOND_TYPE_SINGLE:(BTYPE))
|
180
|
+
|
178
181
|
|
179
182
|
#define BITS_PARITY 0x07 /* mask to retrieve half-bond parity */
|
180
183
|
#define MASK_CUMULENE_LEN 0x38 /* mask to retrieve (cumulene chain length - 1)*MULT_STEREOBOND */
|
data/ext/src/ichi.h
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
* International Union of Pure and Applied Chemistry (IUPAC)
|
3
3
|
* International Chemical Identifier (InChI)
|
4
4
|
* Version 1
|
5
|
-
* Software version 1.
|
6
|
-
*
|
5
|
+
* Software version 1.01
|
6
|
+
* July 21, 2006
|
7
7
|
* Developed at NIST
|
8
8
|
*/
|
9
9
|
|
@@ -12,8 +12,8 @@
|
|
12
12
|
|
13
13
|
#include "comdef.h"
|
14
14
|
|
15
|
-
#define REQ_MODE_BASIC 0x000001 /* B
|
16
|
-
#define REQ_MODE_TAUT 0x000002 /* T
|
15
|
+
#define REQ_MODE_BASIC 0x000001 /* B include Fixed-H layer */
|
16
|
+
#define REQ_MODE_TAUT 0x000002 /* T include Mobile-H layer */
|
17
17
|
#define REQ_MODE_ISO 0x000004 /* I */
|
18
18
|
#define REQ_MODE_NON_ISO 0x000008 /* NI */
|
19
19
|
#define REQ_MODE_STEREO 0x000010 /* S */
|
@@ -45,7 +45,7 @@
|
|
45
45
|
/****************** chemical identifier member definitions *************/
|
46
46
|
typedef struct tagINChI_IsotopicAtom {
|
47
47
|
AT_NUMB nAtomNumber; /* Canonical atom number */
|
48
|
-
NUM_H nIsoDifference; /* 0=non-isotopic; 1=
|
48
|
+
NUM_H nIsoDifference; /* 0=non-isotopic; 1=rounded avg. atomic mass */
|
49
49
|
NUM_H nNum_H; /* number of 1H isotopic atoms attached */
|
50
50
|
NUM_H nNum_D; /* number of 2H isotopic atoms attached */
|
51
51
|
NUM_H nNum_T; /* number of 3H isotopic atoms attached */
|
@@ -98,6 +98,15 @@ typedef struct tagINChI_Stereo { /* [N] = allocated length */
|
|
98
98
|
#define INCHI_OUT_XML_TEXT_COMMENTS 0x0100 /* output xml text annotation */
|
99
99
|
#define INCHI_OUT_WINCHI_WINDOW 0x0200 /* output into wINChI text window */
|
100
100
|
#define INCHI_OUT_TABBED_OUTPUT 0x0400 /* tab-delimited (only for plain text) */
|
101
|
+
#define INCHI_OUT_SDFILE_ATOMS_DT 0x0800 /* SDfile output H isotopes as D and T */
|
102
|
+
#define INCHI_OUT_SDFILE_SPLIT 0x1000 /* Split SDfile into components */
|
103
|
+
|
104
|
+
#define INCHI_OUT_PRINT_OPTIONS (INCHI_OUT_EMBED_REC | \
|
105
|
+
INCHI_OUT_XML | \
|
106
|
+
INCHI_OUT_PLAIN_TEXT | \
|
107
|
+
INCHI_OUT_PLAIN_TEXT_COMMENTS | \
|
108
|
+
INCHI_OUT_XML_TEXT_COMMENTS)
|
109
|
+
|
101
110
|
|
102
111
|
/*******REQ_MODE_SB_IGN_ALL_UU*************** chemical identifier definition *****************/
|
103
112
|
typedef struct tagINChI { /* [N] = allocated length */
|
@@ -131,6 +140,7 @@ typedef struct tagINChI { /* [N] = allocated length */
|
|
131
140
|
int nNumberOfIsotopicAtoms;
|
132
141
|
INChI_IsotopicAtom *IsotopicAtom; /* [nNumberOfIsotopicAtoms] */
|
133
142
|
int nNumberOfIsotopicTGroups;
|
143
|
+
/* in reversing InChI keeps a pointer to stolen from AuxInfo coordinates */
|
134
144
|
INChI_IsotopicTGroup *IsotopicTGroup; /* [nNumberOfIsotopicAtoms] */
|
135
145
|
/* ---- stereo layer */
|
136
146
|
INChI_Stereo *Stereo;
|
@@ -144,7 +154,9 @@ typedef struct tagINChI { /* [N] = allocated length */
|
|
144
154
|
#if( bRELEASE_VERSION == 0 )
|
145
155
|
int bExtract;
|
146
156
|
#endif
|
147
|
-
|
157
|
+
#if( READ_INCHI_STRING == 1 )
|
158
|
+
int nLink; /* negative: ignore InChI; positive: index of (Reconnected component) + 1 linked to it */
|
159
|
+
#endif
|
148
160
|
} INChI;
|
149
161
|
|
150
162
|
typedef INChI *PINChI2[TAUT_NUM];
|
@@ -185,11 +197,12 @@ typedef struct tagINChI_Aux { /* [N] = allocated length */
|
|
185
197
|
MOL_COORD *szOrigCoord;
|
186
198
|
NUM_H nNumRemovedProtons;
|
187
199
|
NUM_H nNumRemovedIsotopicH[NUM_H_ISOTOPES]; /* isotopic H that may be exchanged and considered
|
188
|
-
randomly distributed, including removed protons
|
200
|
+
randomly distributed, including removed protons;
|
201
|
+
order: 0=>1H, 1=>D, 2=>T */
|
189
202
|
int bDeleted;
|
190
|
-
INCHI_MODE bTautFlags;
|
191
|
-
INCHI_MODE bTautFlagsDone;
|
192
|
-
INCHI_MODE bNormalizationFlags;
|
203
|
+
INCHI_MODE bTautFlags; /* t_group_info->bTautFlags */
|
204
|
+
INCHI_MODE bTautFlagsDone; /* t_group_info->bTautFlagsDone */
|
205
|
+
INCHI_MODE bNormalizationFlags; /* t_group_info->tni.bNormalizationFlags */
|
193
206
|
int nCanonFlags;
|
194
207
|
} INChI_Aux;
|
195
208
|
|
@@ -199,7 +212,10 @@ typedef INChI_Aux *PINChI_Aux2[TAUT_NUM];
|
|
199
212
|
typedef struct tagINChIforSort {
|
200
213
|
INChI *pINChI[TAUT_NUM];
|
201
214
|
INChI_Aux *pINChI_Aux[TAUT_NUM];
|
202
|
-
|
215
|
+
short ord_number; /* for stable sort */
|
216
|
+
short n1; /* points to the original; used in structure reconstruction only */
|
217
|
+
short n2; /* points to the original; used in structure reconstruction only */
|
218
|
+
short n3; /* points to the original; used in structure reconstruction only */
|
203
219
|
}INCHI_SORT;
|
204
220
|
|
205
221
|
|
data/ext/src/ichi_bns.c
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
* International Union of Pure and Applied Chemistry (IUPAC)
|
3
3
|
* International Chemical Identifier (InChI)
|
4
4
|
* Version 1
|
5
|
-
* Software version 1.
|
6
|
-
*
|
5
|
+
* Software version 1.01
|
6
|
+
* July 21, 2006
|
7
7
|
* Developed at NIST
|
8
8
|
*/
|
9
9
|
|
@@ -28,8 +28,6 @@
|
|
28
28
|
|
29
29
|
#define BNS_MARK_ONLY_BLOCKS 1 /* 1 => find only blocks, do not search for ring systems */
|
30
30
|
#define ALLOW_ONLY_SIMPLE_ALT_PATH 0 /* 0 => allow alt. path to contain same bond 2 times (in opposite directions) */
|
31
|
-
#define MAX_BOND_EDGE_CAP 2 /* triple bond */
|
32
|
-
#define AROM_BOND_EDGE_CAP 1
|
33
31
|
|
34
32
|
#define CHECK_TG_ALT_PATH 0 /* 1=> when chacking alt path of a tautomeric atom modify
|
35
33
|
t-group, not the atom */
|
@@ -37,9 +35,7 @@
|
|
37
35
|
|
38
36
|
#define FIX_CPOINT_BOND_CAP 1 /* 1=> fix bug in case of double bond from neutral cpoint */
|
39
37
|
|
40
|
-
#define
|
41
|
-
|
42
|
-
#define RESET_EDGE_FORBIDDEN_MASK 1 /* 1: previous; 0: do not apply "dge->forbidden &= pBNS->edge_forbidden_mask" */
|
38
|
+
#define RESET_EDGE_FORBIDDEN_MASK 1 /* 1: previous; 0: do not apply "edge->forbidden &= pBNS->edge_forbidden_mask" */
|
43
39
|
#if ( RESET_EDGE_FORBIDDEN_MASK == 1 )
|
44
40
|
#define IS_FORBIDDEN(EDGE_FORBIDDEN, PBNS) (EDGE_FORBIDDEN)
|
45
41
|
#else
|
@@ -219,23 +215,6 @@ typedef struct tagProtonRemovalMaskAndType {
|
|
219
215
|
#define AA_HARD_MSK_H (ATBIT_MSK_NP | ATBIT_MSK_OS)
|
220
216
|
#define AA_HARD_TYP_H (ATTYP_N | ATTYP_OS)
|
221
217
|
|
222
|
-
/*********************************************************************************/
|
223
|
-
#if( ADD_CAPACITY_RADICAL == 1 ) /* { */
|
224
|
-
/* -- do not treat triplets as moving dots -- 2004-02-18 --
|
225
|
-
#define MAX_AT_FLOW(X) (((X).chem_bonds_valence - (X).valence)+\
|
226
|
-
((is_centerpoint_elem((X).el_number)||get_endpoint_valence((X).el_number))?\
|
227
|
-
(((X).radical==RADICAL_DOUBLET)+2*((X).radical==RADICAL_TRIPLET)):0))
|
228
|
-
*/
|
229
|
-
#define MAX_AT_FLOW(X) (((X).chem_bonds_valence - (X).valence)+\
|
230
|
-
((is_centerpoint_elem((X).el_number)||get_endpoint_valence((X).el_number))?\
|
231
|
-
(((X).radical==RADICAL_DOUBLET)/*+2*((X).radical==RADICAL_TRIPLET)*/):0))
|
232
|
-
|
233
|
-
|
234
|
-
#else /* } ADD_CAPACITY_RADICAL { */
|
235
|
-
|
236
|
-
#define MAX_AT_FLOW(X) (((X).chem_bonds_valence - (X).valence)
|
237
|
-
|
238
|
-
#endif /* } ADD_CAPACITY_RADICAL */
|
239
218
|
|
240
219
|
/*********************************************************************************/
|
241
220
|
|
@@ -247,9 +226,6 @@ typedef struct tagProtonRemovalMaskAndType {
|
|
247
226
|
#define FIRST_INDX 1
|
248
227
|
*/
|
249
228
|
|
250
|
-
#define NO_VERTEX -2
|
251
|
-
#define BLOSSOM_BASE -1
|
252
|
-
|
253
229
|
|
254
230
|
#define TREE_NOT_IN_M 0 /* not in T or T' */
|
255
231
|
#define TREE_IN_2 1 /* in T' and not s-reachable */
|
@@ -261,83 +237,6 @@ typedef struct tagProtonRemovalMaskAndType {
|
|
261
237
|
/* #define TREE_IS_ON_SCANQ(X) (Tree[X] != TREE_NOT_IN_M) */
|
262
238
|
#define TREE_MARK(X, MARK) do{ if( Tree[X] < MARK ) Tree[X]=MARK; }while(0)
|
263
239
|
|
264
|
-
|
265
|
-
#define BNS_ADD_ATOMS 2 /* max. number of fictitious atoms to add (except t-gtoups) */
|
266
|
-
#define BNS_ADD_EDGES 1 /* max. number of edges to add to each atom (except edges to a t-group or c-group) */
|
267
|
-
#define BNS_ADD_SUPER_TGROUP 1 /* reserve one more edge for a t-group to connect to a single super-t-group */
|
268
|
-
#define NUM_KINDS_OF_GROUPS 2 /* 1 accounts for t-group kind, one more 1 accounts for c-group kind */
|
269
|
-
|
270
|
-
#define BNS_VERT_TYPE_ATOM 0x0001
|
271
|
-
#define BNS_VERT_TYPE_ENDPOINT 0x0002
|
272
|
-
#define BNS_VERT_TYPE_TGROUP 0x0004
|
273
|
-
#define BNS_VERT_TYPE_C_POINT 0x0008
|
274
|
-
#define BNS_VERT_TYPE_C_GROUP 0x0010
|
275
|
-
#define BNS_VERT_TYPE_SUPER_TGROUP 0x0020
|
276
|
-
#define BNS_VERT_TYPE_TEMP 0x0040
|
277
|
-
#define BNS_VERT_TYPE_C_NEGATIVE 0x0080 /* attribute, should be used with BNS_VERT_TYPE_C_GROUP */
|
278
|
-
#define BNS_VERT_TYPE_ACID 0x0100 /* only for this type are allowed paths: t_group-atom-c_group_neg (path_TACN) */
|
279
|
-
#define BNS_VERT_TYPE_ANY_GROUP (BNS_VERT_TYPE_TGROUP | BNS_VERT_TYPE_C_GROUP | BNS_VERT_TYPE_SUPER_TGROUP)
|
280
|
-
|
281
|
-
/*********************************************************************************
|
282
|
-
bChangeFlow:
|
283
|
-
1 => change flow inside the BNS search
|
284
|
-
3 => change flow inside the BNS search and undo the flow change in the BNS structure here
|
285
|
-
4 => change bonds in the structure according to the flow
|
286
|
-
8 => make altern. bonds in the structure
|
287
|
-
|
288
|
-
Note: (bChangeFlow & 1) == 1 is needed for multiple runs
|
289
|
-
**********************************************************************************/
|
290
|
-
|
291
|
-
/* "EF" = "Edge Flow" */
|
292
|
-
#define BNS_EF_CHNG_FLOW 1 /* change Balanced Network (BN) flow inside the BNS search */
|
293
|
-
#define BNS_EF_RSTR_FLOW 2 /* undo BN flow changes after BNS */
|
294
|
-
#define BNS_EF_CHNG_RSTR (BNS_EF_CHNG_FLOW | BNS_EF_RSTR_FLOW)
|
295
|
-
#define BNS_EF_CHNG_BONDS 4 /* change bonds in the structure according to the BN flow */
|
296
|
-
#define BNS_EF_ALTR_BONDS 8 /* make altern. bonds in the structure if the flow has changed */
|
297
|
-
#define BNS_EF_UPD_RAD_ORI 16 /* update BN flow0 & Atom radical values:
|
298
|
-
flow0 := flow, radical:=st_cap - st_flow */
|
299
|
-
#define BNS_EF_SET_NOSTEREO 32 /* in combination with BNS_EF_ALTR_BONDS only:
|
300
|
-
ALT12 bond cannot be stereogenic */
|
301
|
-
#define BNS_EF_UPD_H_CHARGE 64 /* update charges and H-counts according to change flow to c- and t-group vertices */
|
302
|
-
|
303
|
-
#define BNS_EF_SAVE_ALL (BNS_EF_CHNG_FLOW | BNS_EF_CHNG_BONDS | BNS_EF_UPD_RAD_ORI)
|
304
|
-
#define BNS_EF_ALTR_NS (BNS_EF_ALTR_BONDS | BNS_EF_SET_NOSTEREO)
|
305
|
-
|
306
|
-
/* edge to s or t */
|
307
|
-
#define EDGE_FLOW_ST_MASK 0x3fff /* mask for flow */
|
308
|
-
#define EDGE_FLOW_ST_PATH 0x4000 /* mark: the edge belongs to the augmenting path */
|
309
|
-
/* edges between other vertices */
|
310
|
-
#define EDGE_FLOW_MASK 0x3f /* mask for flow */
|
311
|
-
#define EDGE_FLOW_PATH 0x40 /* mark: the edge belongs to the augmenting path */
|
312
|
-
|
313
|
-
|
314
|
-
typedef enum tagAltPathConst {
|
315
|
-
iALTP_MAX_LEN, /* 0 */
|
316
|
-
iALTP_FLOW, /* 1 */
|
317
|
-
iALTP_PATH_LEN, /* 2 */
|
318
|
-
iALTP_START_ATOM, /* 3 */
|
319
|
-
iALTP_END_ATOM, /* 4 */
|
320
|
-
iALTP_NEIGHBOR, /* 5 */
|
321
|
-
iALTP_HDR_LEN = iALTP_NEIGHBOR
|
322
|
-
} ALT_CONST;
|
323
|
-
|
324
|
-
#define ALTP_PATH_LEN(altp) (altp)[iALTP_PATH_LEN].number /* number of bonds = number of atoms-1*/
|
325
|
-
#define ALTP_END_ATOM(altp) (altp)[iALTP_END_ATOM].number
|
326
|
-
#define ALTP_START_ATOM(altp) (altp)[iALTP_START_ATOM].number
|
327
|
-
#define ALTP_THIS_ATOM_NEIGHBOR(altp,X) (altp)[iALTP_NEIGHBOR+(X)].ineigh[0] /* 0 <= X < path_len */
|
328
|
-
#define ALTP_NEXT_ATOM_NEIGHBOR(altp,X) (altp)[iALTP_NEIGHBOR+(X)].ineigh[1]
|
329
|
-
#define ALTP_CUR_THIS_ATOM_NEIGHBOR(altp) (altp)[iALTP_NEIGHBOR+ALTP_PATH_LEN(altp)].ineigh[0] /* 0 <= X < path_len */
|
330
|
-
#define ALTP_CUR_NEXT_ATOM_NEIGHBOR(altp) (altp)[iALTP_NEIGHBOR+ALTP_PATH_LEN(altp)].ineigh[1]
|
331
|
-
#define ALTP_NEXT(altp) (++ALTP_PATH_LEN(altp))
|
332
|
-
#define ALTP_PREV(altp) (--ALTP_PATH_LEN(altp))
|
333
|
-
#define ALTP_MAY_ADD(altp) (iALTP_NEIGHBOR + (altp)[iALTP_PATH_LEN].number < (altp)[iALTP_MAX_LEN].number)
|
334
|
-
#define ALTP_ALLOCATED_LEN(altp) (altp)[iALTP_MAX_LEN].number
|
335
|
-
#define ALTP_DELTA(altp) (altp)[iALTP_FLOW].flow[0]
|
336
|
-
#define ALTP_OVERFLOW(altp) (altp)[iALTP_FLOW].flow[1]
|
337
|
-
|
338
|
-
#define Vertex_s 0
|
339
|
-
#define Vertex_t 1
|
340
|
-
|
341
240
|
/**********************************************************************************
|
342
241
|
* store changes done to check whether an alternating path exists
|
343
242
|
* (see bSetBnsToCheckAltPath, bRestoreBnsAfterCheckAltPath)
|
@@ -357,20 +256,8 @@ typedef struct tagAltPathChanges {
|
|
357
256
|
|
358
257
|
/* local functions */
|
359
258
|
|
360
|
-
|
361
|
-
|
362
|
-
int ReInitBnStructAltPaths( BN_STRUCT *pBNS );
|
363
|
-
/*
|
364
|
-
int ReInitBnStructAddGroups( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, T_GROUP_INFO *tgi, C_GROUP_INFO *cgi );
|
365
|
-
*/
|
366
|
-
int ReInitBnStructForMoveableAltBondTest( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms );
|
367
|
-
|
368
|
-
void ClearAllBnDataVertices( Vertex *v, Vertex value, int size );
|
369
|
-
void ClearAllBnDataEdges( Edge *e, Vertex value, int size );
|
370
|
-
BN_DATA *DeAllocateBnData( BN_DATA *pBD );
|
371
|
-
BN_DATA *AllocateAndInitBnData( int max_num_vertices );
|
372
|
-
int ReInitBnData( BN_DATA *pBD );
|
373
|
-
|
259
|
+
int RestoreRadicalsOnly( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at );
|
260
|
+
int bRadChangesAtomType( BN_STRUCT *pBNS, BN_DATA *pBD, Vertex v, Vertex v_1, Vertex v_2 );
|
374
261
|
int BnsAdjustFlowBondsRad( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at, int num_atoms );
|
375
262
|
int SetAtomRadAndChemValFromVertexCapFlow( BN_STRUCT *pBNS, inp_ATOM *atom, int v1 );
|
376
263
|
int bNeedToTestTheFlow( int bond_type, int nTestFlow, int bTestForNonStereoBond );
|
@@ -383,9 +270,9 @@ int CompTGroupNumber( const void *tg1, const void *tg2 );
|
|
383
270
|
int CompCGroupNumber( const void *cg1, const void *cg2 );
|
384
271
|
|
385
272
|
/* Rings, Blocks, Non-stereo bonds */
|
386
|
-
int ReInitBnStructForAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms );
|
387
|
-
int MarkRingSystemsAltBns( BN_STRUCT* pBNS );
|
388
|
-
int MarkNonStereoAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms );
|
273
|
+
int ReInitBnStructForAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int bUnknAltAsNoStereo );
|
274
|
+
int MarkRingSystemsAltBns( BN_STRUCT* pBNS, int bUnknAltAsNoStereo );
|
275
|
+
int MarkNonStereoAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int bUnknAltAsNoStereo );
|
389
276
|
|
390
277
|
/* called from BalancedNetworkSearch */
|
391
278
|
|
@@ -406,10 +293,6 @@ Vertex MakeBlossom( BN_STRUCT* pBNS, Vertex *ScanQ, int *pQSize,
|
|
406
293
|
int PullFlow( BN_STRUCT *pBNS, Edge *SwitchEdge, Vertex x, Vertex y, int delta, S_CHAR bReverse, int bChangeFlow );
|
407
294
|
int FindPathCap( BN_STRUCT* pBNS, Edge *SwitchEdge, Vertex x, Vertex y, int delta );
|
408
295
|
|
409
|
-
/* main function: find augmenting path */
|
410
|
-
int BalancedNetworkSearch ( BN_STRUCT* pBNS, BN_DATA *pBD, int bChangeFlow );
|
411
|
-
|
412
|
-
int RunBalancedNetworkSearch( BN_STRUCT *pBNS, BN_DATA *pBD, int bChangeFlow );
|
413
296
|
|
414
297
|
/*
|
415
298
|
int SetBondType( BNS_EDGE *edge, U_CHAR *bond_type12, U_CHAR *bond_type21, int delta, int bChangeFlow );
|
@@ -432,8 +315,7 @@ int bSetBondsAfterCheckOneBond( BN_STRUCT *pBNS, BNS_FLOW_CHANGES *fcd, int nTes
|
|
432
315
|
int BnsTestAndMarkAltBonds( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at, int num_atoms, BNS_FLOW_CHANGES *fcd, int bChangeFlow, int nBondTypeToTest );
|
433
316
|
int bIsAltBond( int bond_type );
|
434
317
|
/* fix bonds */
|
435
|
-
int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms );
|
436
|
-
int SetForbiddenEdges( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms );
|
318
|
+
int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int edge_forbidden_mask );
|
437
319
|
int TempFix_NH_NH_Bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms );
|
438
320
|
int CorrectFixing_NH_NH_Bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms );
|
439
321
|
|
@@ -444,6 +326,7 @@ int bRestoreBnsAfterCheckAltPath( BN_STRUCT *pBNS, ALT_PATH_CHANGES *apc, int bC
|
|
444
326
|
Vertex GetGroupVertex(BN_STRUCT *pBNS, Vertex v1, AT_NUMB type);
|
445
327
|
BNS_IEDGE GetEdgeToGroupVertex( BN_STRUCT *pBNS, Vertex v1, AT_NUMB type);
|
446
328
|
int bAddNewVertex( BN_STRUCT *pBNS, int nVertDoubleBond, int nCap, int nFlow, int nMaxAdjEdges, int *nDots );
|
329
|
+
int AddNewEdge( BNS_VERTEX *p1, BNS_VERTEX *p2, BN_STRUCT *pBNS, int nEdgeCap, int nEdgeFlow );
|
447
330
|
int bAddStCapToAVertex( BN_STRUCT *pBNS, Vertex v1, Vertex v2, VertexFlow *nOldCapVertSingleBond, int *nDots, int bAdjacentDonors );
|
448
331
|
|
449
332
|
static void remove_alt_bond_marks(inp_ATOM *at, int num_atoms);
|
@@ -479,11 +362,20 @@ int RemoveNPProtonsAndAcidCharges( inp_ATOM *at, int num_atoms, BN_AATG *pAATG,
|
|
479
362
|
Vertex GetPrevVertex( BN_STRUCT* pBNS, Vertex y, Edge *SwitchEdge, EdgeIndex *iuv );
|
480
363
|
int bIgnoreVertexNonTACN_atom( BN_STRUCT* pBNS, Vertex u, Vertex v );
|
481
364
|
int bIgnoreVertexNonTACN_group( BN_STRUCT* pBNS, Vertex v, Vertex w, Edge *SwitchEdge );
|
365
|
+
int bIsRemovedHfromNHaion( BN_STRUCT* pBNS, Vertex u, Vertex v );
|
366
|
+
int bIsAggressiveDeprotonation( BN_STRUCT* pBNS, Vertex v, Vertex w, Edge *SwitchEdge );
|
482
367
|
|
483
368
|
int bIsAtomTypeHard( inp_ATOM *at, int endpoint, int nType, int nMask, int nCharge );
|
484
369
|
int bIsHDonorAccAtomType( inp_ATOM *at, int endpoint, int *cSubType );
|
485
370
|
int bIsNegAtomType( inp_ATOM *at, int i, int *cSubType );
|
486
371
|
|
372
|
+
#if ( BNS_RAD_SEARCH == 1 )
|
373
|
+
int RegisterRadEndpoint( BN_STRUCT *pBNS, BN_DATA *pBD, Vertex u);
|
374
|
+
int cmp_rad_endpoints( const void *a1, const void *a2 );
|
375
|
+
int cmp_endpoints_rad( const void *a1, const void *a2 );
|
376
|
+
#endif
|
377
|
+
|
378
|
+
int bHasChargedNeighbor( inp_ATOM *at, int iat );
|
487
379
|
/*********************************************************************************/
|
488
380
|
|
489
381
|
/**** prim(v) is v' *****/
|
@@ -502,7 +394,6 @@ int bIsNegAtomType( inp_ATOM *at, int i, int *cSubType );
|
|
502
394
|
/* returns value > 0 if a bond has been changed */
|
503
395
|
int RestoreEdgeFlow( BNS_EDGE *edge, int delta, int bChangeFlow )
|
504
396
|
{
|
505
|
-
|
506
397
|
/*flow1 = edge->flow;*/ /* output from BNS */
|
507
398
|
switch ( bChangeFlow & BNS_EF_CHNG_RSTR ) {
|
508
399
|
case 0: /* the flow has not been permitted to change inside the BNS */
|
@@ -550,6 +441,8 @@ int SetAtomBondType( BNS_EDGE *edge, U_CHAR *bond_type12, U_CHAR *bond_type21, i
|
|
550
441
|
flow2 = edge->flow; /* output from BNS, the changed (new) value */
|
551
442
|
flow1 = edge->flow0; /* the original flow (old) value before the BNS */
|
552
443
|
break;
|
444
|
+
default:
|
445
|
+
return 0; /* added 2006-03-21 */
|
553
446
|
}
|
554
447
|
|
555
448
|
if ( (bChangeFlow & BNS_EF_CHNG_BONDS) && (bChangeFlow & BNS_EF_ALTR_NS) !=BNS_EF_ALTR_NS ) {
|
@@ -745,7 +638,12 @@ int AddChangedAtHChargeBNS( inp_ATOM *at, int num_atoms, int nAtTypeTotals[], S_
|
|
745
638
|
for ( i = 0, num = 0; i < num_atoms; i ++ ) {
|
746
639
|
if ( mark[i] ) {
|
747
640
|
mark[i] = 0;
|
641
|
+
#if( FIX_NORM_BUG_ADD_ION_PAIR == 1 )
|
642
|
+
/* add ignoring adjacent charges */
|
643
|
+
at[i].at_type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, -2 );
|
644
|
+
#else
|
748
645
|
at[i].at_type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 );
|
646
|
+
#endif
|
749
647
|
num ++;
|
750
648
|
}
|
751
649
|
}
|
@@ -1014,7 +912,11 @@ int SubtractOrChangeAtHChargeBNS( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms,
|
|
1014
912
|
if ( bSubtract ) {
|
1015
913
|
if ( !mark[v1] ) {
|
1016
914
|
/* first time the atom has been encountered: subtract */
|
915
|
+
#if( FIX_NORM_BUG_ADD_ION_PAIR == 1 )
|
916
|
+
type = GetAtomChargeType( at, v1, nAtTypeTotals, &mask, 2 );
|
917
|
+
#else
|
1017
918
|
type = GetAtomChargeType( at, v1, nAtTypeTotals, &mask, 1 );
|
919
|
+
#endif
|
1018
920
|
ret ++; /* number of changed atoms */
|
1019
921
|
mark[v1] ++;
|
1020
922
|
}
|
@@ -1410,14 +1312,68 @@ int bNeedToTestTheFlow( int bond_type, int nTestFlow, int bTestForNonStereoBond
|
|
1410
1312
|
}
|
1411
1313
|
return 1;
|
1412
1314
|
}
|
1413
|
-
|
1315
|
+
/***********************************************************************************/
|
1316
|
+
int nBondsValenceInpAt( const inp_ATOM *at, int *nNumAltBonds, int *nNumWrongBonds )
|
1317
|
+
{
|
1318
|
+
int j, bond_type, nBondsValence = 0, nAltBonds = 0, nNumWrong = 0;
|
1319
|
+
for ( j = 0; j < at->valence; j ++ ) {
|
1320
|
+
bond_type = at->bond_type[j] & BOND_TYPE_MASK;
|
1321
|
+
switch( bond_type ) {
|
1322
|
+
case 0: /* for structure from InChI reconstruction */
|
1323
|
+
case BOND_SINGLE:
|
1324
|
+
case BOND_DOUBLE:
|
1325
|
+
case BOND_TRIPLE:
|
1326
|
+
nBondsValence += bond_type;
|
1327
|
+
break;
|
1328
|
+
case BOND_ALTERN:
|
1329
|
+
nAltBonds ++;
|
1330
|
+
break;
|
1331
|
+
default:
|
1332
|
+
nNumWrong ++;
|
1333
|
+
}
|
1334
|
+
}
|
1335
|
+
switch ( nAltBonds ) {
|
1336
|
+
case 0:
|
1337
|
+
break;
|
1338
|
+
case 1:
|
1339
|
+
nBondsValence += 1; /* 1 or greater than 3 is wrong */
|
1340
|
+
nNumWrong ++;
|
1341
|
+
break;
|
1342
|
+
default:
|
1343
|
+
nBondsValence += nAltBonds+1;
|
1344
|
+
break;
|
1345
|
+
}
|
1346
|
+
if ( nNumAltBonds ) *nNumAltBonds = nAltBonds;
|
1347
|
+
if ( nNumWrongBonds ) *nNumWrongBonds = nNumWrong;
|
1348
|
+
return nBondsValence;
|
1349
|
+
}
|
1414
1350
|
/***************************************************************************************/
|
1415
1351
|
/* if radical or has aromatic bonds then augment to the lowest "multiplicity" */
|
1416
1352
|
int BnsAdjustFlowBondsRad( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at, int num_atoms )
|
1417
1353
|
{
|
1418
|
-
int bError, nOrigDelta, ret, num_removed;
|
1419
|
-
|
1420
|
-
|
1354
|
+
int bError=0, nOrigDelta=0, ret, num_removed;
|
1355
|
+
|
1356
|
+
#if( CHECK_AROMBOND2ALT == 1 )
|
1357
|
+
char *pcValMinusBondsVal = NULL;
|
1358
|
+
int i, nValMinusBondsVal, nAltBonds, bIgnore;
|
1359
|
+
|
1360
|
+
/* find valence excess (it may only be due to aromatic bonds) */
|
1361
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
1362
|
+
nValMinusBondsVal = (int)at[i].chem_bonds_valence - nBondsValenceInpAt( at+i, &nAltBonds, &bIgnore );
|
1363
|
+
bIgnore += (nAltBonds > 3);
|
1364
|
+
if ( !bIgnore && nValMinusBondsVal > 0 ) {
|
1365
|
+
if ( !pcValMinusBondsVal &&
|
1366
|
+
!(pcValMinusBondsVal = (char *)inchi_calloc(num_atoms, sizeof(pcValMinusBondsVal[0])))) {
|
1367
|
+
bError = BNS_OUT_OF_RAM;
|
1368
|
+
goto exit_function;
|
1369
|
+
}
|
1370
|
+
/* mark atoms that have extra unsatisfied valence due to aromatic bonds */
|
1371
|
+
pcValMinusBondsVal[i] = nValMinusBondsVal + (at[i].radical == RADICAL_DOUBLET);
|
1372
|
+
}
|
1373
|
+
}
|
1374
|
+
#endif /* CHECK_AROMBOND2ALT */
|
1375
|
+
|
1376
|
+
/* match bonds to valences */
|
1421
1377
|
do {
|
1422
1378
|
num_removed = 0;
|
1423
1379
|
ret = RunBalancedNetworkSearch( pBNS, pBD, BNS_EF_CHNG_FLOW );
|
@@ -1440,6 +1396,27 @@ int BnsAdjustFlowBondsRad( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at, int num_
|
|
1440
1396
|
ReInitBnStructAltPaths( pBNS );
|
1441
1397
|
}
|
1442
1398
|
} while ( num_removed && num_removed == pBNS->max_altp && !bError );
|
1399
|
+
|
1400
|
+
#if( CHECK_AROMBOND2ALT == 1 )
|
1401
|
+
/* check whether aromatic bonds have been replaces with alternating bonds */
|
1402
|
+
if ( !bError && pcValMinusBondsVal ) {
|
1403
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
1404
|
+
if ( !pcValMinusBondsVal[i] )
|
1405
|
+
continue;
|
1406
|
+
nValMinusBondsVal = (int)at[i].chem_bonds_valence - nBondsValenceInpAt( at+i, &nAltBonds, &bIgnore );
|
1407
|
+
if ( bIgnore ||
|
1408
|
+
1 != (int)pcValMinusBondsVal[i] - (nValMinusBondsVal + (at[i].radical == RADICAL_DOUBLET)) ) {
|
1409
|
+
/* radical excess has not been reduced */
|
1410
|
+
bError = BNS_ALTBOND_ERR;
|
1411
|
+
break;
|
1412
|
+
}
|
1413
|
+
}
|
1414
|
+
}
|
1415
|
+
|
1416
|
+
exit_function:
|
1417
|
+
if ( pcValMinusBondsVal ) inchi_free( pcValMinusBondsVal );
|
1418
|
+
#endif /* CHECK_AROMBOND2ALT */
|
1419
|
+
|
1443
1420
|
return bError? bError : nOrigDelta;
|
1444
1421
|
}
|
1445
1422
|
|
@@ -1551,7 +1528,7 @@ static void remove_alt_bond_marks(inp_ATOM *at, int num_atoms)
|
|
1551
1528
|
}
|
1552
1529
|
}
|
1553
1530
|
/***************************************************************************************/
|
1554
|
-
int SetForbiddenEdges( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
|
1531
|
+
int SetForbiddenEdges( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int forbidden_mask )
|
1555
1532
|
{
|
1556
1533
|
static U_CHAR el_number_O;
|
1557
1534
|
static U_CHAR el_number_C;
|
@@ -1559,9 +1536,10 @@ int SetForbiddenEdges( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
|
|
1559
1536
|
|
1560
1537
|
int i, j, neigh, num_found;
|
1561
1538
|
BNS_IEDGE iedge;
|
1562
|
-
S_CHAR edge_forbidden_mask = BNS_EDGE_FORBIDDEN_MASK
|
1539
|
+
/*S_CHAR edge_forbidden_mask = BNS_EDGE_FORBIDDEN_MASK;*/
|
1540
|
+
S_CHAR edge_forbidden_mask = forbidden_mask;
|
1563
1541
|
|
1564
|
-
pBNS->edge_forbidden_mask |=
|
1542
|
+
pBNS->edge_forbidden_mask |= forbidden_mask;
|
1565
1543
|
|
1566
1544
|
if ( !el_number_C ) {
|
1567
1545
|
el_number_O = (U_CHAR)get_periodic_table_number( "O" );
|
@@ -1623,7 +1601,7 @@ int SetForbiddenEdges( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
|
|
1623
1601
|
}
|
1624
1602
|
}
|
1625
1603
|
#if ( REMOVE_ION_PAIRS_FIX_BONDS == 1 )
|
1626
|
-
num_found += fix_special_bonds( pBNS, at, num_atoms );
|
1604
|
+
num_found += fix_special_bonds( pBNS, at, num_atoms, edge_forbidden_mask );
|
1627
1605
|
#endif
|
1628
1606
|
#if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
|
1629
1607
|
num_found += TempFix_NH_NH_Bonds( pBNS, at, num_atoms );
|
@@ -1696,12 +1674,16 @@ int CorrectFixing_NH_NH_Bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
|
|
1696
1674
|
#endif
|
1697
1675
|
/************************************************************************/
|
1698
1676
|
/* fixes bonds set by remove_ion_pairs() in strutil.c */
|
1699
|
-
int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
|
1677
|
+
int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int forbidden_mask )
|
1700
1678
|
{
|
1701
1679
|
int num_changes = 0;
|
1702
1680
|
|
1703
1681
|
/* 0 1 2 3 4 5 6 7 8 9 8 9 */
|
1682
|
+
#if( FIX_REM_ION_PAIRS_Si_BUG == 1 )
|
1683
|
+
static const char el[] = "N;P;As;Sb;O;S;Se;Te;C;Si;"; /* 8 elements + C, Si */
|
1684
|
+
#else
|
1704
1685
|
static const char el[] = "N;P;As;Sb;O;S;Se;Te;C;Si"; /* 8 elements + C, Si */
|
1686
|
+
#endif
|
1705
1687
|
static char en[12]; /* same number: 8 elements */
|
1706
1688
|
static int ne=0; /* will be 8 and 10 */
|
1707
1689
|
|
@@ -1722,7 +1704,8 @@ int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
|
|
1722
1704
|
int j[3], m[3], num_O, k_O, num_N, num_OH, num_OM, num_X, num_other, k_N;
|
1723
1705
|
|
1724
1706
|
BNS_IEDGE iedge;
|
1725
|
-
S_CHAR edge_forbidden_mask = BNS_EDGE_FORBIDDEN_MASK
|
1707
|
+
/*S_CHAR edge_forbidden_mask = BNS_EDGE_FORBIDDEN_MASK;*/
|
1708
|
+
S_CHAR edge_forbidden_mask = forbidden_mask;
|
1726
1709
|
|
1727
1710
|
pBNS->edge_forbidden_mask |= edge_forbidden_mask;
|
1728
1711
|
|
@@ -1735,7 +1718,8 @@ int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
|
|
1735
1718
|
elname[len] = '\0';
|
1736
1719
|
en[ne++] = get_periodic_table_number( elname );
|
1737
1720
|
}
|
1738
|
-
en[ne]
|
1721
|
+
en[ne] = '\0';
|
1722
|
+
en[ne+1] = '\0';
|
1739
1723
|
}
|
1740
1724
|
for ( i = 0, a = at; i < num_atoms; i ++, a++ ) {
|
1741
1725
|
if ( !a->charge && !a->radical &&
|
@@ -1747,15 +1731,25 @@ int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
|
|
1747
1731
|
if ( 2 == nNoMetalNumBonds(at, i) ) {
|
1748
1732
|
/* #N= */
|
1749
1733
|
/* fix bonds: double and triple: =N# so that bonds cannot be changed by the normalization */
|
1734
|
+
#if( FIX_N_V_METAL_BONDS_GPF == 1 )
|
1735
|
+
if ( 0 > (i1 = nNoMetalNeighIndex( at, i )) ||
|
1736
|
+
0 > (i2 = nNoMetalOtherNeighIndex( at, i,
|
1737
|
+
n1 = a->neighbor[i1]/* non-metal neighbor #1 */ ) ) ) {
|
1738
|
+
/*num_err ++; */ /* do not count would-be original InChI v.1 buffer overflow GPF */
|
1739
|
+
continue; /* v1 bug: 2 bonds to metal yield i1 < 0 and/or i2 < 0 => bounds violation */
|
1740
|
+
}
|
1741
|
+
#else
|
1750
1742
|
i1 = nNoMetalNeighIndex( at, i );
|
1751
1743
|
n1 = a->neighbor[i1]; /* non-metal neighbor #1 */
|
1752
1744
|
i2 = nNoMetalOtherNeighIndex( at, i, n1 );
|
1745
|
+
#endif
|
1753
1746
|
n2 = a->neighbor[i2]; /* non-metal neighbor #2 */
|
1754
1747
|
/* forbid all edges to non-metals */
|
1755
1748
|
iedge = pBNS->vert[i].iedge[i1];
|
1756
1749
|
pBNS->edge[iedge].forbidden |= edge_forbidden_mask; /* fix bond to neighbor #1 */
|
1757
1750
|
iedge = pBNS->vert[i].iedge[i2];
|
1758
1751
|
pBNS->edge[iedge].forbidden |= edge_forbidden_mask; /* fix bond to neighbor #1 */
|
1752
|
+
num_changes ++; /* added 11-15-2005 */
|
1759
1753
|
/* i n3 */
|
1760
1754
|
/* forbid single bond edge beyond the neighboring =N- as in #N=N- */
|
1761
1755
|
if ( (at[i].bond_type[i1] & BOND_TYPE_MASK) == BOND_TYPE_DOUBLE ) {
|
@@ -1823,7 +1817,7 @@ int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
|
|
1823
1817
|
} else
|
1824
1818
|
if ( 4 == nNoMetalNumBonds(at, i) ) {
|
1825
1819
|
/* | */
|
1826
|
-
/* found -N=
|
1820
|
+
/* found -N=N- */
|
1827
1821
|
/* | */
|
1828
1822
|
/* locate non-metal neighbor connected by a double bond;
|
1829
1823
|
* if it is =N- then fix the double bond and the single bond beyond the neighbor
|
@@ -1852,7 +1846,6 @@ int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
|
|
1852
1846
|
iedge = pBNS->vert[i].iedge[i2];
|
1853
1847
|
pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
|
1854
1848
|
num_changes ++;
|
1855
|
-
num_changes ++;
|
1856
1849
|
}
|
1857
1850
|
}
|
1858
1851
|
} else
|
@@ -2152,8 +2145,6 @@ int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
|
|
2152
2145
|
}
|
2153
2146
|
}
|
2154
2147
|
}
|
2155
|
-
|
2156
|
-
|
2157
2148
|
return num_changes;
|
2158
2149
|
}
|
2159
2150
|
|
@@ -2267,7 +2258,12 @@ int GetAtomChargeType( inp_ATOM *atom, int at_no, int nAtTypeTotals[], int *pMas
|
|
2267
2258
|
static U_CHAR el_number_I = 0;
|
2268
2259
|
|
2269
2260
|
inp_ATOM *at = atom + at_no;
|
2261
|
+
#if( FIX_NORM_BUG_ADD_ION_PAIR == 1 )
|
2262
|
+
int i, neigh, mask, bit, type, num_z, num_m, num_o, delta = bSubtract > 0 ? -1 : 1; /* 0 or -2 => add, 1 or 2 => subtract */
|
2263
|
+
int bNoAdjIon = (bSubtract==0 || bSubtract==1);
|
2264
|
+
#else
|
2270
2265
|
int i, neigh, mask, bit, type, num_z, num_m, num_o, delta = bSubtract? -1 : 1;
|
2266
|
+
#endif
|
2271
2267
|
int bUnsatNHasTerminalO = 0;
|
2272
2268
|
if ( !el_number_C ) {
|
2273
2269
|
el_number_C = (U_CHAR)get_periodic_table_number( "C" );
|
@@ -2339,9 +2335,23 @@ int GetAtomChargeType( inp_ATOM *atom, int at_no, int nAtTypeTotals[], int *pMas
|
|
2339
2335
|
/* check neighbors */
|
2340
2336
|
for ( i = 0, num_z = 0, num_m = 0, num_o = 0; i < at->valence; i ++ ) {
|
2341
2337
|
neigh = at->neighbor[i];
|
2338
|
+
#if( FIX_NORM_BUG_ADD_ION_PAIR == 1 )
|
2339
|
+
if ( atom[neigh].charge < -1 || atom[neigh].charge > 1 ) {
|
2340
|
+
goto exit_function; /* neighboring charge */
|
2341
|
+
}
|
2342
|
+
if ( atom[neigh].charge && at->charge ) {
|
2343
|
+
if ( bNoAdjIon ) {
|
2344
|
+
goto exit_function; /* neighboring charge */
|
2345
|
+
}
|
2346
|
+
type = ATT_NONE;
|
2347
|
+
mask = 0;
|
2348
|
+
goto count_mask_bits;
|
2349
|
+
}
|
2350
|
+
#else
|
2342
2351
|
if ( atom[neigh].charge < -1 || atom[neigh].charge > 1 || atom[neigh].charge && at->charge ) {
|
2343
2352
|
goto exit_function; /* neighboring charge */
|
2344
2353
|
}
|
2354
|
+
#endif
|
2345
2355
|
if ( detect_unusual_el_valence( atom[neigh].el_number, atom[neigh].charge, atom[neigh].radical,
|
2346
2356
|
atom[neigh].chem_bonds_valence, atom[neigh].num_H,
|
2347
2357
|
atom[neigh].valence ) ) {
|
@@ -2634,7 +2644,11 @@ int SimpleRemoveHplusNPO( inp_ATOM *at, int num_atoms, int nAtTypeTotals[], T_GR
|
|
2634
2644
|
AddOrRemoveExplOrImplH( -1, at, num_atoms, (AT_NUMB)i, t_group_info );
|
2635
2645
|
/*at[i].num_H --;*/
|
2636
2646
|
num_removed ++;
|
2637
|
-
|
2647
|
+
#if( FIX_NORM_BUG_ADD_ION_PAIR == 1 )
|
2648
|
+
type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add changed at[i] */
|
2649
|
+
#else
|
2650
|
+
type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* bug: subtract instead of add */
|
2651
|
+
#endif
|
2638
2652
|
/*
|
2639
2653
|
if ( nAtTypeTotals ) {
|
2640
2654
|
nAtTypeTotals[ATTOT_NUM_NP_Proton] --;
|
@@ -2876,9 +2890,9 @@ int CreateCGroupInBnStruct( inp_ATOM *at, int num_atoms,
|
|
2876
2890
|
for ( k = 0; k < vertex_cpoint->num_adj_edges; k ++ ) {
|
2877
2891
|
int iedge = vertex_cpoint->iedge[k];
|
2878
2892
|
VertexFlow nNewCap = vertex_cpoint->st_edge.cap;
|
2893
|
+
centerpoint = (pBNS->edge[iedge].neighbor12 ^ c_point);
|
2879
2894
|
if ( !pBNS->edge[iedge].cap ) {
|
2880
2895
|
/* single bond, possibly between c_point and centerpoint */
|
2881
|
-
centerpoint = (pBNS->edge[iedge].neighbor12 ^ c_point);
|
2882
2896
|
if ( centerpoint < pBNS->num_atoms &&
|
2883
2897
|
pBNS->vert[centerpoint].st_edge.cap >= 1 ) {
|
2884
2898
|
nNewCap = inchi_min( pBNS->vert[centerpoint].st_edge.cap, nNewCap );
|
@@ -2886,6 +2900,13 @@ int CreateCGroupInBnStruct( inp_ATOM *at, int num_atoms,
|
|
2886
2900
|
pBNS->edge[iedge].cap = nNewCap;
|
2887
2901
|
}
|
2888
2902
|
}
|
2903
|
+
#if( FIX_CPOINT_BOND_CAP2 == 1 ) /* multiple bond */
|
2904
|
+
else
|
2905
|
+
if ( centerpoint < pBNS->num_atoms &&
|
2906
|
+
edge->flow && pBNS->edge[iedge].cap < MAX_BOND_EDGE_CAP ) {
|
2907
|
+
pBNS->edge[iedge].cap ++;
|
2908
|
+
}
|
2909
|
+
#endif
|
2889
2910
|
}
|
2890
2911
|
#endif /* } FIX_CPOINT_BOND_CAP */
|
2891
2912
|
/* connect edge to c_point and fictpoint and increment the counters of neighbors and edges */
|
@@ -3451,7 +3472,11 @@ int HardRemoveAcidicProtons( inp_ATOM *at, int num_atoms, BN_AATG *pAATG, int nu
|
|
3451
3472
|
}
|
3452
3473
|
|
3453
3474
|
if ( nNumCanceledCharges ) {
|
3475
|
+
#if( FIX_CANCEL_CHARGE_COUNT_BUG == 1 )
|
3476
|
+
*nNumCanceledCharges += 2*nNumNeutralized;
|
3477
|
+
#else
|
3454
3478
|
*nNumCanceledCharges = 2*nNumNeutralized;
|
3479
|
+
#endif
|
3455
3480
|
}
|
3456
3481
|
|
3457
3482
|
return nNumMoved2AcidH;
|
@@ -3604,7 +3629,11 @@ int HardAddAcidicProtons( inp_ATOM *at, int num_atoms, BN_AATG *pAATG, int num2a
|
|
3604
3629
|
}
|
3605
3630
|
|
3606
3631
|
if ( nNumCanceledCharges ) {
|
3632
|
+
#if( FIX_CANCEL_CHARGE_COUNT_BUG == 1 )
|
3633
|
+
*nNumCanceledCharges += 2*nNumNeutralized;
|
3634
|
+
#else
|
3607
3635
|
*nNumCanceledCharges = 2*nNumNeutralized;
|
3636
|
+
#endif
|
3608
3637
|
}
|
3609
3638
|
|
3610
3639
|
return nNumMoved2AcidMinus;
|
@@ -3622,6 +3651,9 @@ int HardRemoveHplusNP( inp_ATOM *at, int num_atoms, int bCancelChargesAlways, in
|
|
3622
3651
|
int tg_H = 0;
|
3623
3652
|
#if ( MOVE_PPLUS_TO_REMOVE_PROTONS == 1 )
|
3624
3653
|
int cg_PlusP = 0;
|
3654
|
+
#endif
|
3655
|
+
#if ( FIX_REM_PROTON_COUNT_BUG == 1 )
|
3656
|
+
int nPrevRemovedProtons, nCurrRemovedProtons;
|
3625
3657
|
#endif
|
3626
3658
|
int ret = 0, ret2;
|
3627
3659
|
int nDelta, nNumChanges = 0, nNumRemovedProtons = 0, nNumNeutralized = 0, nPrevNumCharges;
|
@@ -3664,15 +3696,59 @@ int HardRemoveHplusNP( inp_ATOM *at, int num_atoms, int bCancelChargesAlways, in
|
|
3664
3696
|
tg_H = CreateTGroupInBnStruct( at, num_atoms, pBNS, PR_HARD_TYP_H, PR_HARD_MSK_H );
|
3665
3697
|
|
3666
3698
|
if ( tg_H >= num_atoms && cg_Plus >= num_atoms ) {
|
3699
|
+
|
3700
|
+
#if( FIX_N_MINUS_NORN_BUG == 1 )
|
3701
|
+
/* neutralize: remove ion pairs like >N(+)=-O(-) => >N-=O; >N(+)=-NH(-) => >N-=NH */
|
3702
|
+
if ( (nNumRemovedProtons || bCancelChargesAlways) && cg_Minus >= num_atoms && cg_Plus >= num_atoms &&
|
3703
|
+
pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] > abs(pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE]) ) {
|
3704
|
+
do {
|
3705
|
+
nPrevNumCharges = pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES];
|
3706
|
+
#if ( FIX_REM_PROTON_COUNT_BUG == 1 )
|
3707
|
+
nPrevRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
|
3708
|
+
#endif
|
3709
|
+
ret = bExistsAltPath( pBNS, pBD, pAATG, at, num_atoms,
|
3710
|
+
cg_Minus /*nVertDoubleBond*/, cg_Plus /*nVertSingleBond*/, ALT_PATH_MODE_REM_PROTON );
|
3711
|
+
if ( IS_BNS_ERROR( ret ) ) {
|
3712
|
+
return ret;
|
3713
|
+
}
|
3714
|
+
#if ( FIX_REM_PROTON_COUNT_BUG == 1 )
|
3715
|
+
nCurrRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
|
3716
|
+
if ( nCurrRemovedProtons != nPrevRemovedProtons ) {
|
3717
|
+
return BNS_RADICAL_ERR;
|
3718
|
+
}
|
3719
|
+
#endif
|
3720
|
+
if ( ret & 1 ) {
|
3721
|
+
nDelta = (ret & ~3) >> 2;
|
3722
|
+
nNumChanges += (0 != (ret & 2));
|
3723
|
+
if ( nDelta ) {
|
3724
|
+
/* radical pair has disappeared */
|
3725
|
+
; /* goto quick_exit;*/
|
3726
|
+
}
|
3727
|
+
if ( nPrevNumCharges > pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] ) {
|
3728
|
+
nNumNeutralized += (nPrevNumCharges - pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES])/2;
|
3729
|
+
}
|
3730
|
+
}
|
3731
|
+
} while ( ret & 1 );
|
3732
|
+
}
|
3733
|
+
#endif
|
3667
3734
|
/* find alt path to remove one proton */
|
3668
3735
|
do {
|
3669
3736
|
/* remove a proton */
|
3670
3737
|
nPrevNumCharges = pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES];
|
3738
|
+
#if ( FIX_REM_PROTON_COUNT_BUG == 1 )
|
3739
|
+
nPrevRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
|
3740
|
+
#endif
|
3671
3741
|
ret = bExistsAltPath( pBNS, pBD, pAATG, at, num_atoms,
|
3672
3742
|
tg_H /*nVertDoubleBond*/, cg_Plus /*nVertSingleBond*/, ALT_PATH_MODE_REM_PROTON );
|
3673
3743
|
if ( IS_BNS_ERROR( ret ) ) {
|
3674
3744
|
return ret;
|
3675
3745
|
}
|
3746
|
+
#if ( FIX_REM_PROTON_COUNT_BUG == 1 )
|
3747
|
+
nCurrRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
|
3748
|
+
if ( nCurrRemovedProtons != nPrevRemovedProtons + (ret & 1) ) {
|
3749
|
+
return BNS_RADICAL_ERR;
|
3750
|
+
}
|
3751
|
+
#endif
|
3676
3752
|
if ( ret & 1 ) {
|
3677
3753
|
nDelta = (ret & ~3) >> 2;
|
3678
3754
|
nNumChanges += (0 != (ret & 2));
|
@@ -3693,11 +3769,20 @@ int HardRemoveHplusNP( inp_ATOM *at, int num_atoms, int bCancelChargesAlways, in
|
|
3693
3769
|
pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] > abs(pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE]) ) {
|
3694
3770
|
do {
|
3695
3771
|
nPrevNumCharges = pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES];
|
3772
|
+
#if ( FIX_REM_PROTON_COUNT_BUG == 1 )
|
3773
|
+
nPrevRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
|
3774
|
+
#endif
|
3696
3775
|
ret = bExistsAltPath( pBNS, pBD, pAATG, at, num_atoms,
|
3697
3776
|
cg_Minus /*nVertDoubleBond*/, cg_Plus /*nVertSingleBond*/, ALT_PATH_MODE_REM_PROTON );
|
3698
3777
|
if ( IS_BNS_ERROR( ret ) ) {
|
3699
3778
|
return ret;
|
3700
3779
|
}
|
3780
|
+
#if ( FIX_REM_PROTON_COUNT_BUG == 1 )
|
3781
|
+
nCurrRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
|
3782
|
+
if ( nCurrRemovedProtons != nPrevRemovedProtons ) {
|
3783
|
+
return BNS_RADICAL_ERR;
|
3784
|
+
}
|
3785
|
+
#endif
|
3701
3786
|
if ( ret & 1 ) {
|
3702
3787
|
nDelta = (ret & ~3) >> 2;
|
3703
3788
|
nNumChanges += (0 != (ret & 2));
|
@@ -3761,7 +3846,11 @@ int HardRemoveHplusNP( inp_ATOM *at, int num_atoms, int bCancelChargesAlways, in
|
|
3761
3846
|
}
|
3762
3847
|
|
3763
3848
|
if ( nNumCanceledCharges ) {
|
3849
|
+
#if( FIX_CANCEL_CHARGE_COUNT_BUG == 1 )
|
3850
|
+
*nNumCanceledCharges += 2*nNumNeutralized;
|
3851
|
+
#else
|
3764
3852
|
*nNumCanceledCharges = 2*nNumNeutralized;
|
3853
|
+
#endif
|
3765
3854
|
}
|
3766
3855
|
|
3767
3856
|
return nNumRemovedProtons;
|
@@ -3986,7 +4075,7 @@ int mark_alt_bonds_and_taut_groups ( inp_ATOM *at, inp_ATOM *at_fixed_bonds_out,
|
|
3986
4075
|
/*
|
3987
4076
|
again:
|
3988
4077
|
*/
|
3989
|
-
/* allocate Balanced Network Data Strucures */
|
4078
|
+
/* allocate Balanced Network Data Strucures; replace Alternating bonds with Single */
|
3990
4079
|
if ( (pBNS = AllocateAndInitBnStruct( at, num_atoms, BNS_ADD_ATOMS, BNS_ADD_EDGES, max_altp, &num_changed_bonds )) &&
|
3991
4080
|
(pBD = AllocateAndInitBnData( pBNS->max_vertices )) ) {
|
3992
4081
|
|
@@ -3995,7 +4084,7 @@ again:
|
|
3995
4084
|
|
3996
4085
|
#if( BNS_PROTECT_FROM_TAUT == 1 )
|
3997
4086
|
/* protect bonds to acetyl and nitro */
|
3998
|
-
SetForbiddenEdges( pBNS, at, num_atoms );
|
4087
|
+
SetForbiddenEdges( pBNS, at, num_atoms, BNS_EDGE_FORBIDDEN_MASK );
|
3999
4088
|
#endif
|
4000
4089
|
/* set bonds in case of input "aromatic" bonds or multiple radicals */
|
4001
4090
|
ret = BnsAdjustFlowBondsRad( pBNS, pBD, at, num_atoms );
|
@@ -4042,6 +4131,11 @@ again:
|
|
4042
4131
|
#if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
|
4043
4132
|
pBNS->edge_forbidden_mask |= BNS_EDGE_FORBIDDEN_TEMP;
|
4044
4133
|
#endif
|
4134
|
+
/***********************************************************/
|
4135
|
+
/* */
|
4136
|
+
/* ( D E ) P R O T O N A T I O N */
|
4137
|
+
/* */
|
4138
|
+
/***********************************************************/
|
4045
4139
|
ret = RemoveNPProtonsAndAcidCharges( at, num_atoms, pAATG, pBNS, pBD );
|
4046
4140
|
#if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
|
4047
4141
|
pBNS->edge_forbidden_mask &= ~BNS_EDGE_FORBIDDEN_TEMP;
|
@@ -4088,6 +4182,8 @@ again:
|
|
4088
4182
|
*pbTautFlagsDone |= TG_FLAG_MOVE_POS_CHARGES_DONE;
|
4089
4183
|
}
|
4090
4184
|
} while ( ret > 0 );
|
4185
|
+
#if( BNS_RAD_SEARCH == 1 )
|
4186
|
+
#else
|
4091
4187
|
/* moveable charges may allow to cancel radicals -- check it */
|
4092
4188
|
if ( pBNS->tot_st_cap > pBNS->tot_st_flow ) {
|
4093
4189
|
ret = BnsAdjustFlowBondsRad( pBNS, pBD, at, num_atoms );
|
@@ -4108,6 +4204,7 @@ again:
|
|
4108
4204
|
goto exit_function;
|
4109
4205
|
}
|
4110
4206
|
}
|
4207
|
+
#endif
|
4111
4208
|
}
|
4112
4209
|
/************************************************************************/
|
4113
4210
|
/******** test bonds for bond tautomerism **************/
|
@@ -4156,6 +4253,8 @@ again:
|
|
4156
4253
|
bError = ret;
|
4157
4254
|
goto exit_function;
|
4158
4255
|
}
|
4256
|
+
#if( BNS_RAD_SEARCH == 1 )
|
4257
|
+
#else
|
4159
4258
|
/* discovered moveable charges and H-atoms may allow to cancel radicals */
|
4160
4259
|
if ( pBNS->tot_st_cap > pBNS->tot_st_flow ) {
|
4161
4260
|
ret = BnsAdjustFlowBondsRad( pBNS, pBD, at, num_atoms );
|
@@ -4176,7 +4275,7 @@ again:
|
|
4176
4275
|
goto exit_function;
|
4177
4276
|
}
|
4178
4277
|
}
|
4179
|
-
|
4278
|
+
#endif
|
4180
4279
|
/****************** update bonds normalization ***************/
|
4181
4280
|
if ( *pbTautFlags & TG_FLAG_MOVE_POS_CHARGES ) {
|
4182
4281
|
/******************* find moveable charges ***************/
|
@@ -4346,9 +4445,16 @@ again:
|
|
4346
4445
|
* and mark non-ring alt bonds non-stereogenic
|
4347
4446
|
************************************************/
|
4348
4447
|
|
4349
|
-
ReInitBnStructForAltBns( pBNS, at, num_atoms );
|
4350
|
-
MarkRingSystemsAltBns( pBNS );
|
4351
|
-
MarkNonStereoAltBns( pBNS, at, num_atoms );
|
4448
|
+
ReInitBnStructForAltBns( pBNS, at, num_atoms, 0 );
|
4449
|
+
MarkRingSystemsAltBns( pBNS, 0 );
|
4450
|
+
MarkNonStereoAltBns( pBNS, at, num_atoms, 0 );
|
4451
|
+
#if( FIX_EITHER_DB_AS_NONSTEREO == 1 )
|
4452
|
+
/* second time unknown ("Either") alternating bonds are treated as non-stereogenic */
|
4453
|
+
/* stereobonds bonds that lost stereo get "Either" stereo_type */
|
4454
|
+
ReInitBnStructForAltBns( pBNS, at, num_atoms, 1 );
|
4455
|
+
MarkRingSystemsAltBns( pBNS, 1 );
|
4456
|
+
MarkNonStereoAltBns( pBNS, at, num_atoms, 1 );
|
4457
|
+
#endif
|
4352
4458
|
} else {
|
4353
4459
|
bError = BNS_OUT_OF_RAM;
|
4354
4460
|
/*printf("BNS_OUT_OF_RAM-3\n");*/
|
@@ -4812,7 +4918,9 @@ int bAddNewVertex( BN_STRUCT *pBNS, int nVertDoubleBond, int nCap, int nFlow, in
|
|
4812
4918
|
if ( (pBNS->vert[vlast].iedge - pBNS->iedge) + pBNS->vert[vlast].max_adj_edges + nMaxAdjEdges >= pBNS->max_iedges ) {
|
4813
4919
|
return BNS_VERT_EDGE_OVFL; /* iedges overflow */
|
4814
4920
|
}
|
4815
|
-
|
4921
|
+
if ( pVert2->num_adj_edges >= pVert2->max_adj_edges || nMaxAdjEdges <= 0 ) {
|
4922
|
+
return BNS_VERT_EDGE_OVFL; /* neighbors overflow */
|
4923
|
+
}
|
4816
4924
|
/* fill out the new edge, set its cap and flow, connect */
|
4817
4925
|
/* memset( pEdge, 0, sizeof(*pEdge) ); */
|
4818
4926
|
pEdge->cap = pEdge->cap0 = nCap;
|
@@ -4827,12 +4935,13 @@ int bAddNewVertex( BN_STRUCT *pBNS, int nVertDoubleBond, int nCap, int nFlow, in
|
|
4827
4935
|
pNewVert->num_adj_edges = 0;
|
4828
4936
|
pNewVert->st_edge.cap0 = pNewVert->st_edge.cap = nCap;
|
4829
4937
|
pNewVert->st_edge.flow0 = pNewVert->st_edge.flow = nFlow;
|
4938
|
+
pNewVert->st_edge.pass = 0; /* add initialization; added 2006-03-25 */
|
4830
4939
|
pNewVert->iedge = pBNS->vert[vlast].iedge + pBNS->vert[vlast].max_adj_edges;
|
4831
4940
|
pNewVert->type = BNS_VERT_TYPE_TEMP;
|
4832
4941
|
*nDots += nCap - nFlow;
|
4833
4942
|
|
4834
|
-
pEdge->neigh_ord[
|
4835
|
-
pEdge->neigh_ord[
|
4943
|
+
pEdge->neigh_ord[v2>vnew] = pVert2->num_adj_edges;
|
4944
|
+
pEdge->neigh_ord[v2<vnew] = pNewVert->num_adj_edges;
|
4836
4945
|
|
4837
4946
|
/* connect new edge to v2 */
|
4838
4947
|
pVert2->iedge[pVert2->num_adj_edges ++] = iedge;
|
@@ -4852,6 +4961,48 @@ int bAddNewVertex( BN_STRUCT *pBNS, int nVertDoubleBond, int nCap, int nFlow, in
|
|
4852
4961
|
|
4853
4962
|
return vnew;
|
4854
4963
|
}
|
4964
|
+
|
4965
|
+
/*****************************************************************************************************/
|
4966
|
+
int AddNewEdge( BNS_VERTEX *p1, BNS_VERTEX *p2, BN_STRUCT *pBNS, int nEdgeCap, int nEdgeFlow )
|
4967
|
+
{
|
4968
|
+
int ip1 = p1 - pBNS->vert;
|
4969
|
+
int ip2 = p2 - pBNS->vert;
|
4970
|
+
int ie = pBNS->num_edges;
|
4971
|
+
BNS_EDGE *e = pBNS->edge + ie;
|
4972
|
+
/* debug: check bounds */
|
4973
|
+
if ( ip1 >= pBNS->max_vertices || ip1 < 0 ||
|
4974
|
+
ip2 >= pBNS->max_vertices || ip2 < 0 ||
|
4975
|
+
ie >= pBNS->max_edges || ie < 0 ||
|
4976
|
+
(p1->iedge - pBNS->iedge) < 0 ||
|
4977
|
+
(p1->iedge - pBNS->iedge) + p1->max_adj_edges > pBNS->max_iedges ||
|
4978
|
+
(p2->iedge - pBNS->iedge) < 0 ||
|
4979
|
+
(p2->iedge - pBNS->iedge) + p2->max_adj_edges > pBNS->max_iedges ||
|
4980
|
+
p1->num_adj_edges >= p1->max_adj_edges ||
|
4981
|
+
p2->num_adj_edges >= p2->max_adj_edges ) {
|
4982
|
+
return BNS_VERT_EDGE_OVFL;
|
4983
|
+
}
|
4984
|
+
/* clear the edge */
|
4985
|
+
memset( e, 0, sizeof(*e) );
|
4986
|
+
/* connect */
|
4987
|
+
e->neighbor1 = inchi_min( ip1, ip2 );
|
4988
|
+
e->neighbor12 = ip1 ^ ip2;
|
4989
|
+
p1->iedge[p1->num_adj_edges] = ie;
|
4990
|
+
p2->iedge[p2->num_adj_edges] = ie;
|
4991
|
+
e->neigh_ord[ip1 > ip2] = p1->num_adj_edges ++;
|
4992
|
+
e->neigh_ord[ip1 < ip2] = p2->num_adj_edges ++;
|
4993
|
+
e->cap = e->cap0 = nEdgeCap;
|
4994
|
+
e->flow = e->flow0 = nEdgeFlow;
|
4995
|
+
p1->st_edge.flow += nEdgeFlow;
|
4996
|
+
p2->st_edge.flow += nEdgeFlow;
|
4997
|
+
if ( p1->st_edge.cap < p1->st_edge.flow ) {
|
4998
|
+
p1->st_edge.cap = p1->st_edge.flow;
|
4999
|
+
}
|
5000
|
+
if ( p2->st_edge.cap < p2->st_edge.flow ) {
|
5001
|
+
p2->st_edge.cap = p2->st_edge.flow;
|
5002
|
+
}
|
5003
|
+
pBNS->num_edges ++;
|
5004
|
+
return ie;
|
5005
|
+
}
|
4855
5006
|
/**********************************************************************************/
|
4856
5007
|
BNS_IEDGE GetEdgeToGroupVertex( BN_STRUCT *pBNS, Vertex v1, AT_NUMB type)
|
4857
5008
|
{
|
@@ -5630,60 +5781,684 @@ int bIsBnsEndpoint( BN_STRUCT *pBNS, int v )
|
|
5630
5781
|
return 0;
|
5631
5782
|
}
|
5632
5783
|
/**********************************************************************************/
|
5633
|
-
|
5634
|
-
|
5635
|
-
|
5636
|
-
ret & 2 => Bonds changed to Alt
|
5637
|
-
(ret & ~3) >> 2 => nDelta: number of removed dots
|
5638
|
-
*/
|
5639
|
-
int bExistsAltPath( BN_STRUCT *pBNS, BN_DATA *pBD, BN_AATG *pAATG, inp_ATOM *at, int num_atoms,
|
5640
|
-
int nVertDoubleBond, int nVertSingleBond, int path_type )
|
5784
|
+
#if ( BNS_RAD_SEARCH == 1 )
|
5785
|
+
/**********************************************************************************/
|
5786
|
+
int bRadChangesAtomType( BN_STRUCT *pBNS, BN_DATA *pBD, Vertex v, Vertex v_1, Vertex v_2 )
|
5641
5787
|
{
|
5642
|
-
|
5643
|
-
|
5644
|
-
|
5645
|
-
|
5646
|
-
|
5647
|
-
|
5648
|
-
|
5649
|
-
|
5650
|
-
|
5651
|
-
|
5652
|
-
|
5653
|
-
|
5654
|
-
|
5655
|
-
|
5656
|
-
|
5657
|
-
|
5658
|
-
|
5659
|
-
|
5788
|
+
|
5789
|
+
EdgeIndex iuv;
|
5790
|
+
Vertex v_O, v_ChgOrH;
|
5791
|
+
/* the previous atom along the path: should be a terminal atom */
|
5792
|
+
if ( v_1 == NO_VERTEX ) {
|
5793
|
+
v_1 = GetPrevVertex( pBNS, v, pBD->SwitchEdge, &iuv );
|
5794
|
+
}
|
5795
|
+
v_O = v_1 / 2 - 1;
|
5796
|
+
if ( v_O < 0 || v_O >= pBNS->num_atoms ) {
|
5797
|
+
return 0;
|
5798
|
+
}
|
5799
|
+
/* make sure v_O is a terminal atom: its second neighbor is not an atom */
|
5800
|
+
if ( pBNS->vert[pBNS->edge[pBNS->vert[v_O].iedge[1]].neighbor12 ^ v_O].type & BNS_VERT_TYPE_ATOM ) {
|
5801
|
+
return 0;
|
5802
|
+
}
|
5803
|
+
/* the next to previous vertex vertex along the path: should be a Charge or Taut group vertex */
|
5804
|
+
if ( v_2 == NO_VERTEX ) {
|
5805
|
+
v_2 = GetPrevVertex( pBNS, v_1, pBD->SwitchEdge, &iuv );
|
5806
|
+
}
|
5807
|
+
v_ChgOrH = v_2 / 2 - 1;
|
5808
|
+
if ( v_ChgOrH < pBNS->num_atoms ) {
|
5809
|
+
return 0;
|
5810
|
+
}
|
5811
|
+
/* make sure v_ChgOrH is a charge or taut_group */
|
5812
|
+
if ( pBNS->vert[v_ChgOrH].type & (BNS_VERT_TYPE_TGROUP | BNS_VERT_TYPE_C_GROUP) )
|
5813
|
+
return 1;
|
5814
|
+
return 0;
|
5815
|
+
}
|
5816
|
+
/**********************************************************************************/
|
5817
|
+
int RegisterRadEndpoint( BN_STRUCT *pBNS, BN_DATA *pBD, Vertex u)
|
5818
|
+
{
|
5819
|
+
EdgeIndex iuv;
|
5820
|
+
int i, num_found;
|
5821
|
+
Vertex v, w;
|
5822
|
+
Vertex u_last, v2;
|
5823
|
+
switch( pBD->bRadSrchMode ) {
|
5824
|
+
case RAD_SRCH_NORM:
|
5825
|
+
/* go backwards along alt path and stop at the 1st found atom (not a fictitious vertex) */
|
5826
|
+
/* we need only vertices where a radical may be moved, therefore exclude u%2=1 (odd) vertices */
|
5827
|
+
/* atom number = u/2-1; u = 0 or 1 is 's' or 't' vertices, respectively, they are not atoms */
|
5828
|
+
num_found = 0;
|
5829
|
+
while ( u > Vertex_t && (u % 2 || u/2 > pBNS->num_atoms ) ) {
|
5830
|
+
u = GetPrevVertex( pBNS, u, pBD->SwitchEdge, &iuv );
|
5831
|
+
}
|
5832
|
+
w = u/2 - 1; /* Check whether u is a radical endpoint */
|
5833
|
+
if ( Vertex_t < u && w < pBNS->num_atoms &&
|
5834
|
+
pBNS->vert[w].st_edge.cap == (pBNS->vert[w].st_edge.flow & EDGE_FLOW_ST_MASK) ) {
|
5835
|
+
/* u is an atom; it is not a radical atom */
|
5836
|
+
/* now search for the starting radical atom by following the path back from u */
|
5837
|
+
v = u_last = u;
|
5838
|
+
while( v > Vertex_t ) {
|
5839
|
+
u = v;
|
5840
|
+
v = GetPrevVertex( pBNS, u, pBD->SwitchEdge, &iuv ); /* Radical endpoint */
|
5841
|
+
}
|
5842
|
+
/* check whether u is a radical atom */
|
5843
|
+
if ( !(u%2) && Vertex_t < u &&
|
5844
|
+
(u = u/2 - 1) < pBNS->num_atoms &&
|
5845
|
+
pBNS->vert[u].st_edge.cap > (pBNS->vert[u].st_edge.flow & EDGE_FLOW_ST_MASK) ) {
|
5846
|
+
/* at pBNS->vert[u] we have found the radical that originated the path */
|
5847
|
+
/* pBD->RadEndpoints[2k] is the radical, pBD->RadEndpoints[2k+1] is the farthest atom */
|
5848
|
+
/* to which the radical may be moved (farthest reachable atom) */
|
5849
|
+
|
5850
|
+
/* add *all* atoms that may receive radical from u_rad */
|
5851
|
+
/* exception: at2 in: ==(+/-/H)---at1==at2(possible rad endpoint) if pBNS->type_TACN */
|
5852
|
+
|
5853
|
+
for ( v = u_last; v > Vertex_t; v = GetPrevVertex( pBNS, v, pBD->SwitchEdge, &iuv ) ) {
|
5854
|
+
if ( !(v%2) && (v2 = v/2 - 1) < pBNS->num_atoms &&
|
5855
|
+
pBNS->vert[v2].st_edge.cap == (pBNS->vert[v2].st_edge.flow & EDGE_FLOW_ST_MASK) ) {
|
5856
|
+
/* check exception */
|
5857
|
+
if ( pBNS->type_TACN &&
|
5858
|
+
bRadChangesAtomType( pBNS, pBD, v, NO_VERTEX, NO_VERTEX ) ) {
|
5859
|
+
continue;
|
5860
|
+
}
|
5861
|
+
/* add */
|
5862
|
+
for ( i = 0; i < pBD->nNumRadEndpoints; i += 2 ) {
|
5863
|
+
/* check whether this pair, (u,w), has already been saved */
|
5864
|
+
if ( u == pBD->RadEndpoints[i] &&
|
5865
|
+
v2 == pBD->RadEndpoints[i+1] ) {
|
5866
|
+
break;
|
5867
|
+
}
|
5868
|
+
}
|
5869
|
+
if ( i >= pBD->nNumRadEndpoints ) {
|
5870
|
+
/* add new (u,w) pair */
|
5871
|
+
if ( pBD->nNumRadEndpoints+2 <= pBD->max_num_vertices ) {
|
5872
|
+
/* add */
|
5873
|
+
pBD->RadEndpoints[pBD->nNumRadEndpoints ++] = u; /* radical */
|
5874
|
+
pBD->RadEndpoints[pBD->nNumRadEndpoints ++] = v2; /* endpoint */
|
5875
|
+
num_found ++;
|
5876
|
+
/*return 1;*/ /* registered */
|
5877
|
+
} else {
|
5878
|
+
return BNS_VERT_EDGE_OVFL;
|
5879
|
+
}
|
5880
|
+
}
|
5881
|
+
}
|
5882
|
+
}
|
5883
|
+
if ( num_found ) {
|
5884
|
+
return 1;
|
5885
|
+
}
|
5886
|
+
}
|
5887
|
+
}
|
5660
5888
|
break;
|
5661
5889
|
|
5662
|
-
case
|
5663
|
-
/*
|
5664
|
-
|
5665
|
-
|
5666
|
-
|
5890
|
+
case RAD_SRCH_FROM_FICT:
|
5891
|
+
/* find nearest atom accessible from a fictitious vertex */
|
5892
|
+
/* go backwards along alt path and stop at the 1st found atom (not a fictitious vertex) */
|
5893
|
+
v = u;
|
5894
|
+
w = NO_VERTEX; /* the nearest atom -- radical-endpoint */
|
5895
|
+
u = NO_VERTEX; /* fictitious vertex carrying a radical */
|
5896
|
+
while ( v > Vertex_t ) {
|
5897
|
+
u = v;
|
5898
|
+
if ( !(v % 2) && v/2 <= pBNS->num_atoms &&
|
5899
|
+
pBNS->vert[v/2-1].st_edge.cap - pBNS->vert[v/2-1].st_edge.flow < 2 ) {
|
5900
|
+
w = v; /* vertex w is atom that may be singlet or doublet but not triplet */
|
5901
|
+
}
|
5902
|
+
v = GetPrevVertex( pBNS, u, pBD->SwitchEdge, &iuv );
|
5903
|
+
}
|
5904
|
+
v = u/2 - 1; /* vertex u may be the radical from which the path originated; w is the nearest atom */
|
5905
|
+
if ( w == NO_VERTEX || u == NO_VERTEX || w % 2 || u == w || v < pBNS->num_atoms ||
|
5906
|
+
pBNS->vert[v].st_edge.cap == pBNS->vert[v].st_edge.flow ||
|
5907
|
+
(w = w/2 - 1) >= pBNS->num_atoms ) {
|
5908
|
+
break; /* reject */
|
5909
|
+
}
|
5910
|
+
u = v;
|
5911
|
+
/* at pBNS->vert[u] we have found the radical that originated the path, w is the nearest atom */
|
5912
|
+
for ( i = 0; i < pBD->nNumRadEndpoints; i += 2 ) {
|
5913
|
+
if ( u == pBD->RadEndpoints[i] &&
|
5914
|
+
w == pBD->RadEndpoints[i+1] ) {
|
5915
|
+
break; /* this pair has already been stored */
|
5916
|
+
}
|
5917
|
+
}
|
5918
|
+
if ( i >= pBD->nNumRadEndpoints ) {
|
5919
|
+
/* a new pair has been found */
|
5920
|
+
if ( pBD->nNumRadEndpoints+2 <= pBD->max_num_vertices ) {
|
5921
|
+
/* add */
|
5922
|
+
pBD->RadEndpoints[pBD->nNumRadEndpoints ++] = u; /* radical */
|
5923
|
+
pBD->RadEndpoints[pBD->nNumRadEndpoints ++] = w; /* endpoint */
|
5924
|
+
return 1; /* registered */
|
5925
|
+
} else {
|
5926
|
+
return BNS_VERT_EDGE_OVFL;
|
5927
|
+
}
|
5928
|
+
}
|
5667
5929
|
break;
|
5930
|
+
}
|
5668
5931
|
|
5669
|
-
|
5670
|
-
|
5671
|
-
|
5672
|
-
|
5673
|
-
|
5674
|
-
|
5675
|
-
|
5676
|
-
|
5677
|
-
|
5678
|
-
|
5679
|
-
|
5680
|
-
|
5681
|
-
|
5682
|
-
|
5932
|
+
return 0; /* rejected */
|
5933
|
+
}
|
5934
|
+
/**********************************************************************************/
|
5935
|
+
int cmp_rad_endpoints( const void *a1, const void *a2 )
|
5936
|
+
{
|
5937
|
+
/* Vertex radical_vertex, radical_endpoint */
|
5938
|
+
const Vertex *p1 = (const Vertex *)a1;
|
5939
|
+
const Vertex *p2 = (const Vertex *)a2;
|
5940
|
+
if ( p1[0] < p2[0] )
|
5941
|
+
return -1;
|
5942
|
+
if ( p1[0] > p2[0] )
|
5943
|
+
return 1;
|
5944
|
+
if ( p1[1] < p2[1] )
|
5945
|
+
return -1;
|
5946
|
+
if ( p1[1] > p2[1] )
|
5947
|
+
return 1;
|
5948
|
+
return 0;
|
5949
|
+
}
|
5950
|
+
/**********************************************************************************/
|
5951
|
+
int RemoveRadEndpoints( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at )
|
5952
|
+
{
|
5953
|
+
BNS_EDGE *e;
|
5954
|
+
EdgeIndex ie;
|
5955
|
+
BNS_VERTEX *p1, *p2;
|
5956
|
+
Vertex v1, v2;
|
5957
|
+
int i, delta, rad;
|
5958
|
+
for ( i = pBD->nNumRadEdges-1; 0 <= i; i -- ) {
|
5959
|
+
ie = pBD->RadEdges[i];
|
5960
|
+
if ( ie < 0 || ie >= pBNS->num_edges ) {
|
5961
|
+
goto error_exit;
|
5962
|
+
}
|
5963
|
+
e = pBNS->edge + ie;
|
5964
|
+
v1 = e->neighbor1;
|
5965
|
+
v2 = e->neighbor12 ^ v1; /* v2 > v1 <=> v2 was added later */
|
5966
|
+
if ( ie + 1 != pBNS->num_edges ||
|
5967
|
+
v1 < 0 || v1 >= pBNS->num_vertices ||
|
5968
|
+
v2 < 0 || v2 >= pBNS->num_vertices ) {
|
5969
|
+
goto error_exit;
|
5970
|
+
}
|
5971
|
+
p1 = pBNS->vert + v1;
|
5972
|
+
p2 = pBNS->vert + v2;
|
5973
|
+
|
5974
|
+
if ( p2->iedge[p2->num_adj_edges-1] != ie ||
|
5975
|
+
p1->iedge[p1->num_adj_edges-1] != ie ) {
|
5976
|
+
goto error_exit;
|
5977
|
+
}
|
5978
|
+
p2->num_adj_edges --;
|
5979
|
+
p1->num_adj_edges --;
|
5980
|
+
p2->iedge[p2->num_adj_edges] = 0;
|
5981
|
+
p1->iedge[p1->num_adj_edges] = 0;
|
5982
|
+
p2->st_edge.flow -= e->flow;
|
5983
|
+
p1->st_edge.flow -= e->flow;
|
5984
|
+
|
5985
|
+
if ( !p2->num_adj_edges && v2 >= pBNS->num_atoms ) {
|
5986
|
+
if ( v2+1 != pBNS->num_vertices ) {
|
5987
|
+
goto error_exit;
|
5988
|
+
}
|
5989
|
+
memset( p2, 0, sizeof(*p2) );
|
5990
|
+
pBNS->num_vertices --;
|
5991
|
+
}
|
5992
|
+
if ( !p1->num_adj_edges && v1 >= pBNS->num_atoms ) {
|
5993
|
+
if ( v1+1 != pBNS->num_vertices ) {
|
5994
|
+
goto error_exit;
|
5995
|
+
}
|
5996
|
+
memset( p1, 0, sizeof(*p1) );
|
5997
|
+
pBNS->num_vertices --;
|
5998
|
+
}
|
5999
|
+
if ( at && v1 < pBNS->num_atoms ) {
|
6000
|
+
delta = p1->st_edge.cap - p1->st_edge.flow;
|
6001
|
+
rad = at[v1].radical;
|
6002
|
+
switch( delta ) {
|
6003
|
+
case 0:
|
6004
|
+
if ( rad == RADICAL_DOUBLET )
|
6005
|
+
rad = 0;
|
6006
|
+
break;
|
6007
|
+
case 1:
|
6008
|
+
if ( rad != RADICAL_DOUBLET )
|
6009
|
+
rad = RADICAL_DOUBLET;
|
6010
|
+
}
|
6011
|
+
at[v1].radical = rad;
|
6012
|
+
}
|
6013
|
+
memset( e, 0, sizeof(*e) );
|
6014
|
+
pBNS->num_edges --;
|
6015
|
+
}
|
6016
|
+
pBD->nNumRadEdges = 0;
|
6017
|
+
pBD->nNumRadicals = 0;
|
6018
|
+
pBD->bRadSrchMode = RAD_SRCH_NORM;
|
6019
|
+
return 0;
|
6020
|
+
error_exit:
|
6021
|
+
return BNS_PROGRAM_ERR;
|
6022
|
+
}
|
6023
|
+
/**********************************************************************************/
|
6024
|
+
int RestoreRadicalsOnly( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at )
|
6025
|
+
{
|
6026
|
+
BNS_EDGE *e;
|
6027
|
+
EdgeIndex ie;
|
6028
|
+
BNS_VERTEX *p1, *p2;
|
6029
|
+
Vertex v1, v2;
|
6030
|
+
int i, delta, rad;
|
6031
|
+
int p1_num_adj_edges, p2_num_adj_edges;
|
6032
|
+
|
6033
|
+
for ( i = pBD->nNumRadEdges-1; 0 <= i; i -- ) {
|
6034
|
+
ie = pBD->RadEdges[i];
|
6035
|
+
if ( ie < 0 || ie >= pBNS->num_edges ) {
|
6036
|
+
goto error_exit;
|
6037
|
+
}
|
6038
|
+
e = pBNS->edge + ie;
|
6039
|
+
v1 = e->neighbor1; /* atom */
|
6040
|
+
v2 = e->neighbor12 ^ v1; /* v2 > v1 <=> v2 was added later */
|
6041
|
+
if ( v1 < 0 || v1 >= pBNS->num_atoms ||
|
6042
|
+
v2 < pBNS->num_atoms || v2 >= pBNS->num_vertices ) {
|
6043
|
+
goto error_exit;
|
6044
|
+
}
|
6045
|
+
p1 = pBNS->vert + v1;
|
6046
|
+
p2 = pBNS->vert + v2;
|
6047
|
+
|
6048
|
+
p1_num_adj_edges = e->neigh_ord[0];
|
6049
|
+
p2_num_adj_edges = e->neigh_ord[1];
|
6050
|
+
|
6051
|
+
if ( p2->iedge[p2_num_adj_edges] != ie ||
|
6052
|
+
p1->iedge[p1_num_adj_edges] != ie ) {
|
6053
|
+
goto error_exit;
|
6054
|
+
}
|
6055
|
+
|
6056
|
+
if ( at && v1 < pBNS->num_atoms ) {
|
6057
|
+
delta = p1->st_edge.cap - p1->st_edge.flow + e->flow;
|
6058
|
+
rad = at[v1].radical;
|
6059
|
+
switch( delta ) {
|
6060
|
+
case 0:
|
6061
|
+
if ( rad == RADICAL_DOUBLET )
|
6062
|
+
rad = 0;
|
6063
|
+
break;
|
6064
|
+
case 1:
|
6065
|
+
if ( rad != RADICAL_DOUBLET )
|
6066
|
+
rad = RADICAL_DOUBLET;
|
6067
|
+
}
|
6068
|
+
at[v1].radical = rad;
|
6069
|
+
}
|
6070
|
+
}
|
6071
|
+
return 0;
|
6072
|
+
error_exit:
|
6073
|
+
return BNS_PROGRAM_ERR;
|
6074
|
+
}
|
6075
|
+
/**********************************************************************************/
|
6076
|
+
int SetRadEndpoints( BN_STRUCT *pBNS, BN_DATA *pBD, BRS_MODE bRadSrchMode )
|
6077
|
+
{
|
6078
|
+
int ret, i, j, k, num_new_edges, delta;
|
6079
|
+
BNS_VERTEX *pRad, *pEndp;
|
6080
|
+
Vertex wRad, vRad, vEndp, nNumRadicals;
|
6081
|
+
int nDots=0 /* added initialization, 2006-03 */, nNumEdges;
|
6082
|
+
if ( pBNS->tot_st_cap <= pBNS->tot_st_flow ) {
|
6083
|
+
return 0;
|
6084
|
+
}
|
6085
|
+
pBD->nNumRadEndpoints = 0;
|
6086
|
+
pBD->nNumRadEdges = 0;
|
6087
|
+
pBD->bRadSrchMode = bRadSrchMode;
|
6088
|
+
pBNS->alt_path = pBNS->altp[0];
|
6089
|
+
pBNS->bChangeFlow = 0;
|
6090
|
+
ret = BalancedNetworkSearch( pBNS, pBD, BNS_EF_RAD_SRCH );
|
6091
|
+
ReInitBnData( pBD );
|
6092
|
+
ReInitBnStructAltPaths( pBNS );
|
6093
|
+
if ( !ret && pBD->nNumRadEndpoints >= 2 ) {
|
6094
|
+
/* sort by radical locations */
|
6095
|
+
qsort( pBD->RadEndpoints, pBD->nNumRadEndpoints/2, 2*sizeof(pBD->RadEndpoints[0]), cmp_rad_endpoints );
|
6096
|
+
num_new_edges = 0;
|
6097
|
+
nNumRadicals = 0;
|
6098
|
+
/* create new vertices (type=BNS_VERT_TYPE_TEMP) and edges with flow=cap=1 */
|
6099
|
+
/* connecting the new vertices radical vertices */
|
6100
|
+
for ( i = 0; i < pBD->nNumRadEndpoints; i = j ) {
|
6101
|
+
wRad = pBD->RadEndpoints[i];
|
6102
|
+
pRad = pBNS->vert + wRad;
|
6103
|
+
delta = pRad->st_edge.cap - (pRad->st_edge.flow & EDGE_FLOW_ST_MASK);
|
6104
|
+
if ( delta <= 0 ) {
|
6105
|
+
delta = 1;
|
6106
|
+
}
|
6107
|
+
nNumEdges = 0;
|
6108
|
+
for ( j = i; j < pBD->nNumRadEndpoints && wRad == pBD->RadEndpoints[j] ; j += 2 ) {
|
6109
|
+
nNumEdges ++;
|
6110
|
+
}
|
6111
|
+
/* add new aux vertex to the radical atom/vertex */
|
6112
|
+
vRad = bAddNewVertex( pBNS, wRad, delta, delta, nNumEdges+1, &nDots );
|
6113
|
+
if ( IS_BNS_ERROR( vRad ) ) {
|
6114
|
+
ret = vRad;
|
6115
|
+
goto error_exit;
|
6116
|
+
}
|
6117
|
+
pRad = pBNS->vert + vRad;
|
6118
|
+
pBD->RadEdges[pBD->nNumRadEdges ++] = pRad->iedge[pRad->num_adj_edges-1];
|
6119
|
+
/* replace references to vertex wRad with vRad */
|
6120
|
+
for ( k = i, nNumEdges = 0; k < j; k += 2 ) {
|
6121
|
+
pBD->RadEndpoints[k] = vRad;
|
6122
|
+
}
|
6123
|
+
nNumRadicals ++;
|
6124
|
+
}
|
6125
|
+
/* all vRad vertex indices should be in the range vFirstNewVertex...vFirstNewVertex+nNumRadicals-1 */
|
6126
|
+
/* connect new vertices to the radical endpoints thus replacing radicals with even-length alternating cycles */
|
6127
|
+
for ( i = 0; i < pBD->nNumRadEndpoints; i = j ) {
|
6128
|
+
vRad = pBD->RadEndpoints[i];
|
6129
|
+
pRad = pBNS->vert + vRad;
|
6130
|
+
for ( j = i; j < pBD->nNumRadEndpoints && vRad == pBD->RadEndpoints[j] ; j += 2 ) {
|
6131
|
+
/* connect vew vertex pRad to radical endpoints */
|
6132
|
+
vEndp = pBD->RadEndpoints[j+1];
|
6133
|
+
pEndp = pBNS->vert + vEndp;
|
6134
|
+
ret = AddNewEdge( pRad, pEndp, pBNS, 1, 0 );
|
6135
|
+
if ( IS_BNS_ERROR( ret ) ) {
|
6136
|
+
goto error_exit;
|
6137
|
+
}
|
6138
|
+
pBD->RadEdges[pBD->nNumRadEdges ++] = ret;
|
6139
|
+
}
|
6140
|
+
}
|
6141
|
+
pBD->nNumRadicals = nNumRadicals;
|
6142
|
+
return nNumRadicals; /* done */
|
6143
|
+
}
|
6144
|
+
return 0; /* nothing to do */
|
5683
6145
|
|
5684
|
-
|
5685
|
-
|
5686
|
-
|
6146
|
+
error_exit:
|
6147
|
+
RemoveRadEndpoints( pBNS, pBD, NULL );
|
6148
|
+
return ret;
|
6149
|
+
|
6150
|
+
}
|
6151
|
+
/**********************************************************************************/
|
6152
|
+
#define MAX_NUM_RAD 256
|
6153
|
+
/***************************************************************************/
|
6154
|
+
int SetRadEndpoints2( BN_STRUCT *pBNS, BN_DATA *pBD, BRS_MODE bRadSrchMode )
|
6155
|
+
{
|
6156
|
+
int ret = 0, i, j, k, n, num_new_edges, delta = 1;
|
6157
|
+
BNS_VERTEX *pRad, *pEndp;
|
6158
|
+
Vertex wRad, vRad, vEndp, nNumRadicals;
|
6159
|
+
Vertex vRadList[MAX_NUM_RAD], vRadEqul[MAX_NUM_RAD];
|
6160
|
+
int nNumRad = 0;
|
6161
|
+
int edge_flow;
|
6162
|
+
int nDots=0 /* added initialization, 2006-03 */, nNumEdges;
|
6163
|
+
NodeSet VertSet;
|
6164
|
+
if ( pBNS->tot_st_cap <= pBNS->tot_st_flow ) {
|
6165
|
+
return 0;
|
6166
|
+
}
|
6167
|
+
/* find all radicals: their vertices have st_cap-st_flow=delta */
|
6168
|
+
/* save radical atom numbers in vRadList[] and remove radical by making st_cap=st_flow */
|
6169
|
+
for ( i = 0; i < pBNS->num_atoms; i ++ ) {
|
6170
|
+
if ( pBNS->vert[i].st_edge.cap - delta == (pBNS->vert[i].st_edge.flow & EDGE_FLOW_ST_MASK) ) {
|
6171
|
+
if ( nNumRad < MAX_NUM_RAD ) {
|
6172
|
+
pBNS->vert[i].st_edge.cap -= delta;
|
6173
|
+
pBNS->tot_st_cap -= delta;
|
6174
|
+
vRadList[nNumRad] = i; /* radical position; i > j <=> vRadList[i] > vRadList[j] */
|
6175
|
+
vRadEqul[nNumRad] = nNumRad; /* the smallest radical atom that has reachable
|
6176
|
+
* atoms in common with this radical atom
|
6177
|
+
* always keep vRadEqul[nNumRad] <= nNumRad */
|
6178
|
+
nNumRad ++;
|
6179
|
+
}
|
6180
|
+
}
|
6181
|
+
}
|
6182
|
+
if ( pBNS->tot_st_cap - pBNS->tot_st_flow > nNumRad ) {
|
6183
|
+
return BNS_CAP_FLOW_ERR; /* extra st_cap on non-atoms or program error */
|
6184
|
+
}
|
6185
|
+
memset( &VertSet, 0, sizeof(VertSet) );
|
6186
|
+
/* find reachable atoms by enabling each radical separately */
|
6187
|
+
for ( j = 0; j < nNumRad; j ++ ) {
|
6188
|
+
i = vRadList[j];
|
6189
|
+
pBD->nNumRadEndpoints = 0;
|
6190
|
+
pBD->nNumRadEdges = 0;
|
6191
|
+
pBD->bRadSrchMode = bRadSrchMode;
|
6192
|
+
pBNS->alt_path = pBNS->altp[0];
|
6193
|
+
pBNS->bChangeFlow = 0;
|
6194
|
+
pBNS->vert[i].st_edge.cap += delta; /* enable single radical */
|
6195
|
+
pBNS->tot_st_cap += delta;
|
6196
|
+
ret = BalancedNetworkSearch( pBNS, pBD, BNS_EF_RAD_SRCH ); /* find reachable atoms */
|
6197
|
+
ReInitBnData( pBD );
|
6198
|
+
ReInitBnStructAltPaths( pBNS );
|
6199
|
+
pBD->bRadSrchMode = RAD_SRCH_NORM;
|
6200
|
+
pBNS->vert[i].st_edge.cap -= delta; /* disable single radical */
|
6201
|
+
pBNS->tot_st_cap -= delta;
|
6202
|
+
if ( IS_BNS_ERROR( ret ) ) {
|
6203
|
+
goto error_exit;
|
6204
|
+
} else
|
6205
|
+
if ( ret ) {
|
6206
|
+
ret = BNS_RADICAL_ERR; /* found augmenting path: should not happen since only one radical was enabled */
|
6207
|
+
goto error_exit;
|
6208
|
+
}
|
6209
|
+
if ( !ret && pBD->nNumRadEndpoints >= 2 ) {
|
6210
|
+
/* sort by: primary_key=radical locations, secondary_key=radical endoint */
|
6211
|
+
qsort( pBD->RadEndpoints, pBD->nNumRadEndpoints/2, 2*sizeof(pBD->RadEndpoints[0]), cmp_rad_endpoints );
|
6212
|
+
if ( pBD->RadEndpoints[0] != i || pBD->RadEndpoints[pBD->nNumRadEndpoints-2] != i ) {
|
6213
|
+
ret = BNS_RADICAL_ERR; /* more than one radical vertex */
|
6214
|
+
goto error_exit;
|
6215
|
+
}
|
6216
|
+
if ( nNumRad > 1 ) {
|
6217
|
+
/* if more than one radical then save reachable atoms in bitmaps to allow */
|
6218
|
+
/* faster finding whether same atoms are reachable by two or more radicals */
|
6219
|
+
/* Later merge such sets */
|
6220
|
+
if ( NULL == VertSet.bitword ) {
|
6221
|
+
SetBitCreate( );
|
6222
|
+
if ( !NodeSetCreate( &VertSet, pBNS->num_atoms, nNumRad ) ) {
|
6223
|
+
ret = BNS_OUT_OF_RAM; /* out of RAM */
|
6224
|
+
goto error_exit;
|
6225
|
+
}
|
6226
|
+
}
|
6227
|
+
NodeSetFromRadEndpoints( &VertSet, j, pBD->RadEndpoints, pBD->nNumRadEndpoints);
|
6228
|
+
/* do not allow any radical center be treated as a reachable atom: */
|
6229
|
+
RemoveFromNodeSet( &VertSet, j, vRadList, nNumRad );
|
6230
|
+
}
|
6231
|
+
}
|
6232
|
+
}
|
6233
|
+
/* restore radical st_cap so that st_cap-st_flow=delta */
|
6234
|
+
for ( j = 0; j < nNumRad; j ++ ) {
|
6235
|
+
i = vRadList[j];
|
6236
|
+
pBNS->vert[i].st_edge.cap += delta;
|
6237
|
+
pBNS->tot_st_cap += delta;
|
6238
|
+
}
|
6239
|
+
/* merge lists that have common radical endpoints */
|
6240
|
+
/* defect: if vertex sets i and j do not intersect they will be compared 2 times */
|
6241
|
+
/* total up to nNumRad*(nNumRad-1)/2 calls to DoNodeSetsIntersect() */
|
6242
|
+
if ( nNumRad > 1 ) {
|
6243
|
+
for ( i = 0; i < nNumRad; i ++ ) {
|
6244
|
+
if ( vRadEqul[i] != i )
|
6245
|
+
continue;
|
6246
|
+
do {
|
6247
|
+
n = 0;
|
6248
|
+
for ( j = i+1; j < nNumRad; j ++ ) {
|
6249
|
+
if ( vRadEqul[j] != j )
|
6250
|
+
continue;
|
6251
|
+
if ( DoNodeSetsIntersect( &VertSet, i, j) ) {
|
6252
|
+
AddNodeSet2ToNodeSet1( &VertSet, i, j);
|
6253
|
+
vRadEqul[j] = i; /* Set j was copied to set i; i < j */
|
6254
|
+
n ++;
|
6255
|
+
}
|
6256
|
+
}
|
6257
|
+
} while( n );
|
6258
|
+
}
|
6259
|
+
/* fill out pBD->RadEndpoints[] */
|
6260
|
+
for ( i = 0, n = 0; i < nNumRad; i ++ ) {
|
6261
|
+
if ( i == vRadEqul[i] ) {
|
6262
|
+
if ( !IsNodeSetEmpty( &VertSet, i) ) {
|
6263
|
+
/* store equivalent radicals */
|
6264
|
+
for ( j = i+1; j < nNumRad; j ++ ) {
|
6265
|
+
if (i == vRadEqul[j] ) {
|
6266
|
+
pBD->RadEndpoints[n++] = vRadList[i];
|
6267
|
+
pBD->RadEndpoints[n++] = -vRadList[j]-2; /* equivalent radical, alvays not zero */
|
6268
|
+
}
|
6269
|
+
}
|
6270
|
+
/* store endpoints */
|
6271
|
+
n = AddNodesToRadEndpoints( &VertSet, i, pBD->RadEndpoints, vRadList[i], n, pBD->max_len_Pu_Pv );
|
6272
|
+
if ( n < 0 ) {
|
6273
|
+
ret = BNS_RADICAL_ERR; /* pBD->RadEndpoints overflow */
|
6274
|
+
goto error_exit;
|
6275
|
+
}
|
6276
|
+
} else {
|
6277
|
+
pBD->RadEndpoints[n++] = vRadList[i];
|
6278
|
+
pBD->RadEndpoints[n++] = -1; /* immobile radical, only one edge to add */
|
6279
|
+
}
|
6280
|
+
}
|
6281
|
+
}
|
6282
|
+
pBD->nNumRadEndpoints = n;
|
6283
|
+
NodeSetFree( &VertSet );
|
6284
|
+
} else
|
6285
|
+
if ( nNumRad == 1 && !pBD->nNumRadEndpoints ) {
|
6286
|
+
/* 2006-07-30: a single radical; no possible endpoint found */
|
6287
|
+
for ( i = 0, n = 0; i < nNumRad; i ++ ) {
|
6288
|
+
pBD->RadEndpoints[n++] = vRadList[i];
|
6289
|
+
pBD->RadEndpoints[n++] = -1; /* immobile radical, only one edge to add */
|
6290
|
+
}
|
6291
|
+
pBD->nNumRadEndpoints = n;
|
6292
|
+
}
|
6293
|
+
|
6294
|
+
if ( !ret && pBD->nNumRadEndpoints >= 2 ) {
|
6295
|
+
/* already sorted by radical locations */
|
6296
|
+
num_new_edges = 0;
|
6297
|
+
nNumRadicals = 0;
|
6298
|
+
/**************************************************************************
|
6299
|
+
* create new vertices (type=BNS_VERT_TYPE_TEMP) and edges with flow=cap=1
|
6300
|
+
* connecting the new vertices radical vertices
|
6301
|
+
*
|
6302
|
+
*
|
6303
|
+
* Original structure: atom A is a radical center A==B--C*--D==E
|
6304
|
+
* A*--B==C--D==E atoms C and E are reachable: A==B--C===D--E*
|
6305
|
+
*
|
6306
|
+
* Resultant temporary structure:
|
6307
|
+
* A---B==C--D==E
|
6308
|
+
* || / /
|
6309
|
+
* || / / The additional new vertex (*) and its
|
6310
|
+
* || / / 3 edges replace the radical with alternating
|
6311
|
+
* || / / circuits that allow same bond changes
|
6312
|
+
* || / / as moving the radical to atoms C or E.
|
6313
|
+
* ||// "Double bonds" here have edge cap=1, flow=1
|
6314
|
+
* (*) "Single bonds" have edge cap=1, flow=0
|
6315
|
+
*
|
6316
|
+
* The "equivalent radical centers" (which have at least one reachable atom
|
6317
|
+
* in common) are connected to (*) with "double bonds" (edge cap=1, flow=1).
|
6318
|
+
* Reachable non-radical atoms are connected by edges with cap=1, flow=0
|
6319
|
+
* After running BNS to find alt.path a "double bond" from (*) may move
|
6320
|
+
* to another atom thus muving the radical.
|
6321
|
+
*
|
6322
|
+
* Number of additional (*) vertices = number of sets of
|
6323
|
+
* "equivalent radical centers".
|
6324
|
+
* Each such a set may include one or more radical centers.
|
6325
|
+
*
|
6326
|
+
* The radicals will be re-created in RemoveRadEndpoints()
|
6327
|
+
***************************************************************************/
|
6328
|
+
for ( i = 0; i < pBD->nNumRadEndpoints; i = j ) {
|
6329
|
+
wRad = pBD->RadEndpoints[i];
|
6330
|
+
pRad = pBNS->vert + wRad;
|
6331
|
+
delta = pRad->st_edge.cap - (pRad->st_edge.flow & EDGE_FLOW_ST_MASK);
|
6332
|
+
if ( delta <= 0 ) {
|
6333
|
+
delta = 1;
|
6334
|
+
}
|
6335
|
+
nNumEdges = 0;
|
6336
|
+
for ( j = i; j < pBD->nNumRadEndpoints && wRad == pBD->RadEndpoints[j] ; j += 2 ) {
|
6337
|
+
nNumEdges += (pBD->RadEndpoints[j+1] != -1); /* immobile radicals have one edge only */
|
6338
|
+
}
|
6339
|
+
/* add new aux vertex to the radical atom/vertex making st_cap-st_flow=0 */
|
6340
|
+
/* in case of immobile radical there will be no additional eddges since nNumEdges=0 */
|
6341
|
+
vRad = bAddNewVertex( pBNS, wRad, delta, delta, nNumEdges+1, &nDots );
|
6342
|
+
if ( IS_BNS_ERROR( vRad ) ) {
|
6343
|
+
ret = vRad;
|
6344
|
+
goto error_exit;
|
6345
|
+
}
|
6346
|
+
pRad = pBNS->vert + vRad;
|
6347
|
+
pBD->RadEdges[pBD->nNumRadEdges ++] = pRad->iedge[pRad->num_adj_edges-1];
|
6348
|
+
/* replace references to vertex wRad with vRad */
|
6349
|
+
for ( k = i, nNumEdges = 0; k < j; k += 2 ) {
|
6350
|
+
pBD->RadEndpoints[k] = vRad;
|
6351
|
+
}
|
6352
|
+
nNumRadicals ++;
|
6353
|
+
}
|
6354
|
+
/* all vRad vertex indices should be in the range vFirstNewVertex...vFirstNewVertex+nNumRadicals-1 */
|
6355
|
+
/* connect new vertices to the radical endpoints thus replacing radicals with even-length alternating cycles */
|
6356
|
+
for ( i = 0; i < pBD->nNumRadEndpoints; i = j ) {
|
6357
|
+
vRad = pBD->RadEndpoints[i];
|
6358
|
+
pRad = pBNS->vert + vRad;
|
6359
|
+
for ( j = i; j < pBD->nNumRadEndpoints && vRad == pBD->RadEndpoints[j] ; j += 2 ) {
|
6360
|
+
/* connect vew vertex pRad to radical endpoints */
|
6361
|
+
vEndp = pBD->RadEndpoints[j+1];
|
6362
|
+
if ( vEndp == -1 )
|
6363
|
+
continue;
|
6364
|
+
if ( vEndp < 0 ) {
|
6365
|
+
edge_flow = 1;
|
6366
|
+
vEndp = -vEndp - 2; /* equivalent radical centers */
|
6367
|
+
} else {
|
6368
|
+
edge_flow = 0;
|
6369
|
+
}
|
6370
|
+
pEndp = pBNS->vert + vEndp;
|
6371
|
+
ret = AddNewEdge( pRad, pEndp, pBNS, 1, edge_flow );
|
6372
|
+
if ( IS_BNS_ERROR( ret ) ) {
|
6373
|
+
goto error_exit;
|
6374
|
+
}
|
6375
|
+
pBD->RadEdges[pBD->nNumRadEdges ++] = ret;
|
6376
|
+
}
|
6377
|
+
}
|
6378
|
+
pBD->nNumRadicals = nNumRadicals;
|
6379
|
+
return nNumRadicals; /* done */
|
6380
|
+
}
|
6381
|
+
return 0; /* nothing to do */
|
6382
|
+
|
6383
|
+
error_exit:
|
6384
|
+
RemoveRadEndpoints( pBNS, pBD, NULL );
|
6385
|
+
NodeSetFree( &VertSet );
|
6386
|
+
return ret;
|
6387
|
+
|
6388
|
+
}
|
6389
|
+
|
6390
|
+
|
6391
|
+
#else
|
6392
|
+
/**********************************************************************************/
|
6393
|
+
int SetRadEndpoints( BN_STRUCT *pBNS, BN_DATA *pBD, BRS_MODE bRadSrchMode )
|
6394
|
+
{
|
6395
|
+
return 0;
|
6396
|
+
}
|
6397
|
+
int RemoveRadEndpoints( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at )
|
6398
|
+
{
|
6399
|
+
return 0;
|
6400
|
+
}
|
6401
|
+
int SetRadEndpoints2( BN_STRUCT *pBNS, BN_DATA *pBD, BRS_MODE bRadSrchMode )
|
6402
|
+
{
|
6403
|
+
return 0;
|
6404
|
+
}
|
6405
|
+
#endif
|
6406
|
+
/**********************************************************************************/
|
6407
|
+
/* Return value ret bits if not IS_BNS_ERROR(ret):
|
6408
|
+
|
6409
|
+
ret & 1 => Success
|
6410
|
+
ret & 2 => Bonds changed to Alt
|
6411
|
+
(ret & ~3) >> 2 => nDelta: number of removed dots
|
6412
|
+
*/
|
6413
|
+
int bExistsAltPath( BN_STRUCT *pBNS, BN_DATA *pBD, BN_AATG *pAATG, inp_ATOM *at, int num_atoms,
|
6414
|
+
int nVertDoubleBond, int nVertSingleBond, int path_type )
|
6415
|
+
{
|
6416
|
+
ALT_PATH_CHANGES apc;
|
6417
|
+
int ret, ret_val, bError, bSuccess, bChangeFlow=0, nDots, nDelta, bDoMarkChangedBonds = 1;
|
6418
|
+
int bAdjustRadicals = 0;
|
6419
|
+
AT_NUMB type;
|
6420
|
+
BNS_FLOW_CHANGES fcd[4*BNS_MAX_NUM_FLOW_CHANGES+1];
|
6421
|
+
ENDPOINT_INFO eif;
|
6422
|
+
|
6423
|
+
/* initialize */
|
6424
|
+
switch( path_type ) {
|
6425
|
+
case ALT_PATH_MODE_TAUTOM:
|
6426
|
+
/* Check for alt path allowing to move H and (-). Purpose: confirm possible tautomerism */
|
6427
|
+
type = BNS_VERT_TYPE_ENDPOINT;
|
6428
|
+
bChangeFlow = BNS_EF_CHNG_RSTR;
|
6429
|
+
if ( !at[nVertSingleBond].endpoint &&
|
6430
|
+
(!nGetEndpointInfo( at, nVertSingleBond, &eif ) || !eif.cDonor ) )
|
6431
|
+
return 0;
|
6432
|
+
if ( !at[nVertDoubleBond].endpoint &&
|
6433
|
+
(!nGetEndpointInfo( at, nVertDoubleBond, &eif ) || !eif.cAcceptor ) )
|
6434
|
+
return 0;
|
6435
|
+
break;
|
6436
|
+
|
6437
|
+
case ALT_PATH_MODE_CHARGE:
|
6438
|
+
/* Find alt path allowing to move (+). Purpose: establish "charge groups",
|
6439
|
+
mark alt. bonds due to (+) charge movement */
|
6440
|
+
type = BNS_VERT_TYPE_C_POINT;
|
6441
|
+
bChangeFlow = (BNS_EF_CHNG_RSTR | BNS_EF_ALTR_BONDS);
|
6442
|
+
break;
|
6443
|
+
|
6444
|
+
case ALT_PATH_MODE_4_SALT:
|
6445
|
+
case ALT_PATH_MODE_4_SALT2:
|
6446
|
+
/* Find alt paths allowing to move (-) and H between "acidic oxygen atoms".
|
6447
|
+
Purpose: mark alt bonds due to this "long range" tautomerism. */
|
6448
|
+
type = BNS_VERT_TYPE_ENDPOINT;
|
6449
|
+
bChangeFlow = (BNS_EF_CHNG_RSTR | BNS_EF_ALTR_BONDS);
|
6450
|
+
if ( !bIsBnsEndpoint( pBNS, nVertSingleBond ) /* !at[nVertSingleBond].endpoint*/ &&
|
6451
|
+
(!nGetEndpointInfo( at, nVertSingleBond, &eif ) || !eif.cDonor ) )
|
6452
|
+
return 0;
|
6453
|
+
if ( !bIsBnsEndpoint( pBNS, nVertDoubleBond ) /* !at[nVertDoubleBond].endpoint*/ &&
|
6454
|
+
(!nGetEndpointInfo( at, nVertDoubleBond, &eif ) || !eif.cAcceptor ) )
|
6455
|
+
return 0;
|
6456
|
+
memset( &apc, 0, sizeof(apc) );
|
6457
|
+
break;
|
6458
|
+
|
6459
|
+
case ALT_PATH_MODE_REM2H_CHG:
|
6460
|
+
bChangeFlow |= BNS_EF_ALTR_BONDS; /* fall through */
|
6461
|
+
case ALT_PATH_MODE_REM2H_TST:
|
5687
6462
|
bChangeFlow |= BNS_EF_CHNG_RSTR;
|
5688
6463
|
type = BNS_VERT_TYPE_ENDPOINT;
|
5689
6464
|
/* allow non-tautomeric donors or any tautomeric atom */
|
@@ -5727,27 +6502,37 @@ int bExistsAltPath( BN_STRUCT *pBNS, BN_DATA *pBD, BN_AATG *pAATG, inp_ATOM *at,
|
|
5727
6502
|
bSuccess = 0;
|
5728
6503
|
nDelta = 0;
|
5729
6504
|
|
6505
|
+
ret = SetRadEndpoints2( pBNS, pBD, RAD_SRCH_NORM );
|
6506
|
+
if ( IS_BNS_ERROR( ret ) ) {
|
6507
|
+
return ret;
|
6508
|
+
}
|
6509
|
+
|
5730
6510
|
/* set BNS to check alt path */
|
5731
6511
|
ret = bSetBnsToCheckAltPath( pBNS, nVertDoubleBond, nVertSingleBond, type, path_type, &apc, fcd, &nDots );
|
5732
6512
|
switch( ret ) {
|
5733
6513
|
case BNS_CHK_ALTP_NO_ALTPATH:
|
5734
|
-
|
6514
|
+
ret = RemoveRadEndpoints( pBNS, pBD, NULL );
|
6515
|
+
return ret;
|
5735
6516
|
case BNS_CHK_ALTP_SAME_TGROUP:
|
5736
6517
|
bSuccess = 1;
|
5737
6518
|
goto reinit_BNS;
|
5738
6519
|
case BNS_CHK_ALTP_SAME_VERTEX:
|
5739
|
-
|
6520
|
+
ret = RemoveRadEndpoints( pBNS, pBD, NULL );
|
6521
|
+
return ret? ret : 1; /* very strange ... set a breakpoint here */
|
5740
6522
|
case BNS_CHK_ALTP_SET_SUCCESS:
|
5741
6523
|
break; /* actually check the existence of the altpath */
|
5742
6524
|
case BNS_CANT_SET_BOND:
|
5743
6525
|
goto reinit_BNS;
|
5744
6526
|
default:
|
6527
|
+
ret_val = RemoveRadEndpoints( pBNS, pBD, NULL );
|
5745
6528
|
if ( IS_BNS_ERROR( ret ) ) {
|
5746
6529
|
return ret;
|
5747
6530
|
}
|
5748
6531
|
return BNS_PROGRAM_ERR;
|
5749
6532
|
}
|
5750
6533
|
|
6534
|
+
bAdjustRadicals = ( (bChangeFlow & BNS_EF_UPD_RAD_ORI) && !(bChangeFlow & BNS_EF_RSTR_FLOW) );
|
6535
|
+
|
5751
6536
|
/*****************************************************************
|
5752
6537
|
* nDots = 2 for ALT_PATH_CHARGE (checking moveable positive charges)
|
5753
6538
|
* Now nDots for ALT_PATH_TAUTOM or ALT_PATH_4_SALT can be greater
|
@@ -5769,9 +6554,12 @@ int bExistsAltPath( BN_STRUCT *pBNS, BN_DATA *pBD, BN_AATG *pAATG, inp_ATOM *at,
|
|
5769
6554
|
if ( pAATG && pAATG->nMarkedAtom ) {
|
5770
6555
|
if ( pAATG->nAtTypeTotals && (bChangeFlow & BNS_EF_UPD_H_CHARGE) ) {
|
5771
6556
|
memset( pAATG->nMarkedAtom, 0, num_atoms*sizeof(pAATG->nMarkedAtom[0]) );
|
5772
|
-
/*
|
6557
|
+
/* mark atoms that have charge or H changed, check their input types (that is, before changes),
|
6558
|
+
and subtract their input charge/H from nAtTypeTotals */
|
5773
6559
|
SubtractOrChangeAtHChargeBNS( pBNS, at, num_atoms, pAATG->nAtTypeTotals, pAATG->nMarkedAtom, NULL, 1 );
|
5774
|
-
/* change */
|
6560
|
+
/* ZChange charges and/or H, update t_group_info, do not check types or change nAtTypeTotals */
|
6561
|
+
/* Atom types will be checked and nAtTypeTotals will be changed in
|
6562
|
+
AddChangedAtHChargeBNS() later */
|
5775
6563
|
SubtractOrChangeAtHChargeBNS( pBNS, at, num_atoms, NULL, NULL, pAATG->t_group_info, 0 );
|
5776
6564
|
} else
|
5777
6565
|
if ( !pAATG->nAtTypeTotals ){
|
@@ -5805,6 +6593,15 @@ int bExistsAltPath( BN_STRUCT *pBNS, BN_DATA *pBD, BN_AATG *pAATG, inp_ATOM *at,
|
|
5805
6593
|
bError = BNS_BOND_ERR;
|
5806
6594
|
}
|
5807
6595
|
if ( !bError && pAATG && pAATG->nMarkedAtom && (bChangeFlow & BNS_EF_UPD_H_CHARGE) ) {
|
6596
|
+
/* Update radicals to avoid errors in atom type check in AddChangedAtHChargeBNS() */
|
6597
|
+
if ( bAdjustRadicals ) {
|
6598
|
+
ret_val = RestoreRadicalsOnly( pBNS, pBD, at );
|
6599
|
+
if ( IS_BNS_ERROR( ret_val ) ) {
|
6600
|
+
bError = ret_val;
|
6601
|
+
}
|
6602
|
+
}
|
6603
|
+
/* Check atom types of marked atoms and add charge/H changes to nAtTypeTotals */
|
6604
|
+
/* Changing atoms were marked in the 1st call to SubtractOrChangeAtHChargeBNS(..., 1) above */
|
5808
6605
|
AddChangedAtHChargeBNS( at, num_atoms, pAATG->nAtTypeTotals, pAATG->nMarkedAtom );
|
5809
6606
|
if ( bChangeFlow & BNS_EF_CHNG_FLOW ) {
|
5810
6607
|
/* eliminate ambiguities in already changed flow:
|
@@ -5823,8 +6620,9 @@ reinit_BNS:
|
|
5823
6620
|
/* --- reinitialize to repeat the calculations --- */
|
5824
6621
|
bRestoreBnsAfterCheckAltPath( pBNS, &apc, bChangeFlow & BNS_EF_UPD_H_CHARGE );
|
5825
6622
|
bRestoreFlowAfterCheckOneBond( pBNS, fcd );
|
6623
|
+
ret_val = RemoveRadEndpoints( pBNS, pBD, bAdjustRadicals? at : NULL );
|
5826
6624
|
ReInitBnStructAltPaths( pBNS );
|
5827
|
-
return bError? bError : (bSuccess + 4*nDelta);
|
6625
|
+
return bError? bError : ret_val? ret_val : (bSuccess + 4*nDelta);
|
5828
6626
|
}
|
5829
6627
|
|
5830
6628
|
|
@@ -5840,12 +6638,23 @@ BN_STRUCT* AllocateAndInitBnStruct( inp_ATOM *at, int num_atoms, int nMaxAddAtom
|
|
5840
6638
|
int i, j, k, n_edges, num_bonds, num_edges, f1, f2, edge_cap, edge_flow, st_cap, st_flow, flag_alt_bond;
|
5841
6639
|
int tot_st_cap, tot_st_flow;
|
5842
6640
|
int max_tg, max_edges, max_vertices, len_alt_path, max_iedges, num_altp;
|
6641
|
+
#if( BNS_RAD_SEARCH == 1 )
|
6642
|
+
int num_rad = 0;
|
5843
6643
|
|
5844
|
-
|
6644
|
+
nMaxAddEdges += 1;
|
6645
|
+
#endif
|
6646
|
+
#if( FIX_NUM_TG == 1 )
|
6647
|
+
max_tg = inchi_max( num_atoms / 2, 5);
|
6648
|
+
#else
|
6649
|
+
max_tg = num_atoms;
|
6650
|
+
#endif
|
5845
6651
|
num_changed_bonds = 0;
|
5846
6652
|
|
5847
6653
|
for ( i = 0, num_bonds = 0; i < num_atoms; i ++ ) {
|
5848
6654
|
num_bonds += at[i].valence;
|
6655
|
+
#if( BNS_RAD_SEARCH == 1 )
|
6656
|
+
num_rad += (at[i].radical == RADICAL_DOUBLET);
|
6657
|
+
#endif
|
5849
6658
|
}
|
5850
6659
|
/* each atom has enough edges to belong to a tautomeric group + nMaxAddEdges */
|
5851
6660
|
/* number of atoms is large enough to accommodate max. possible number of t-groups + nMaxAddAtoms */
|
@@ -5855,6 +6664,12 @@ BN_STRUCT* AllocateAndInitBnStruct( inp_ATOM *at, int num_atoms, int nMaxAddAtom
|
|
5855
6664
|
max_vertices = num_atoms + nMaxAddAtoms + max_tg + 1;
|
5856
6665
|
/* +max_tg for edges between t-groups and super-tautomeric group */
|
5857
6666
|
max_edges = num_edges + (nMaxAddEdges + NUM_KINDS_OF_GROUPS)*max_vertices + max_tg;
|
6667
|
+
#if( BNS_RAD_SEARCH == 1 )
|
6668
|
+
if ( num_rad ) {
|
6669
|
+
max_vertices *= 2;
|
6670
|
+
max_edges *= 2;
|
6671
|
+
}
|
6672
|
+
#endif
|
5858
6673
|
max_iedges = 2*max_edges;
|
5859
6674
|
len_alt_path = max_vertices+iALTP_HDR_LEN+1; /* may overflow if an edge is traversed in 2 directions */
|
5860
6675
|
|
@@ -5942,8 +6757,9 @@ BN_STRUCT* AllocateAndInitBnStruct( inp_ATOM *at, int num_atoms, int nMaxAddAtom
|
|
5942
6757
|
}
|
5943
6758
|
bond_type = (at[i].bond_type[j] & BOND_TYPE_MASK);
|
5944
6759
|
bond_mark = (at[i].bond_type[j] & ~BOND_TYPE_MASK);
|
5945
|
-
if ( bond_type != BOND_SINGLE && bond_type != BOND_DOUBLE &&
|
5946
|
-
|
6760
|
+
if ( bond_type != BOND_SINGLE && bond_type != BOND_DOUBLE &&
|
6761
|
+
bond_type != BOND_TRIPLE /*&& bond_type != BOND_ALTERN*/ ) {
|
6762
|
+
/* make Unknown or Alternating bonds single */
|
5947
6763
|
bond_type = 1;
|
5948
6764
|
at[i].bond_type[j] = bond_mark | bond_type;
|
5949
6765
|
num_changed_bonds ++;
|
@@ -6429,15 +7245,22 @@ int AddCGroups2BnStruct( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, C_GROUP_I
|
|
6429
7245
|
for ( k = 0; k < vertex_cpoint->num_adj_edges; k ++ ) {
|
6430
7246
|
int iedge = vertex_cpoint->iedge[k];
|
6431
7247
|
VertexFlow nNewCap = vertex_cpoint->st_edge.cap;
|
7248
|
+
centerpoint = (pBNS->edge[iedge].neighbor12 ^ c_point);
|
6432
7249
|
if ( !pBNS->edge[iedge].cap ) {
|
6433
7250
|
/* single bond, possibly between c_point and centerpoint */
|
6434
|
-
centerpoint = (pBNS->edge[iedge].neighbor12 ^ c_point);
|
6435
7251
|
if ( centerpoint < pBNS->num_atoms &&
|
6436
7252
|
pBNS->vert[centerpoint].st_edge.cap >= 1 ) {
|
6437
7253
|
nNewCap = inchi_min( pBNS->vert[centerpoint].st_edge.cap, nNewCap );
|
6438
7254
|
nNewCap = inchi_min( nNewCap, MAX_BOND_EDGE_CAP );
|
6439
7255
|
pBNS->edge[iedge].cap = nNewCap;
|
6440
7256
|
}
|
7257
|
+
#if( FIX_CPOINT_BOND_CAP2 == 1 ) /* multiple bond */
|
7258
|
+
else
|
7259
|
+
if ( centerpoint < pBNS->num_atoms &&
|
7260
|
+
edge->flow && pBNS->edge[iedge].cap < MAX_BOND_EDGE_CAP ) {
|
7261
|
+
pBNS->edge[iedge].cap ++;
|
7262
|
+
}
|
7263
|
+
#endif
|
6441
7264
|
}
|
6442
7265
|
}
|
6443
7266
|
#endif /* } FIX_CPOINT_BOND_CAP */
|
@@ -6495,6 +7318,14 @@ BN_DATA *DeAllocateBnData( BN_DATA *pBD )
|
|
6495
7318
|
inchi_free( pBD->Pu );
|
6496
7319
|
if ( pBD->Pv )
|
6497
7320
|
inchi_free( pBD->Pv );
|
7321
|
+
#if( BNS_RAD_SEARCH == 1 )
|
7322
|
+
if ( pBD->RadEndpoints ) {
|
7323
|
+
inchi_free( pBD->RadEndpoints );
|
7324
|
+
}
|
7325
|
+
if ( pBD->RadEdges ) {
|
7326
|
+
inchi_free( pBD->RadEdges );
|
7327
|
+
}
|
7328
|
+
#endif
|
6498
7329
|
inchi_free( pBD );
|
6499
7330
|
}
|
6500
7331
|
return NULL;
|
@@ -6507,12 +7338,17 @@ BN_DATA *AllocateAndInitBnData( int max_num_vertices )
|
|
6507
7338
|
int max_len_Pu_Pv;
|
6508
7339
|
max_num_vertices = 2*max_num_vertices+2;
|
6509
7340
|
max_len_Pu_Pv = max_num_vertices/2+1;
|
7341
|
+
max_len_Pu_Pv += max_len_Pu_Pv % 2; /* even length */
|
6510
7342
|
if ( !(pBD = (BN_DATA *) inchi_calloc( 1, sizeof(BN_DATA) ) ) ||
|
6511
7343
|
!(pBD->BasePtr = (Vertex *) inchi_calloc( max_num_vertices, sizeof(Vertex) ) ) ||
|
6512
7344
|
!(pBD->SwitchEdge = (Edge *) inchi_calloc( max_num_vertices, sizeof(Edge ) ) ) ||
|
6513
7345
|
!(pBD->Tree = (S_CHAR *) inchi_calloc( max_num_vertices, sizeof(S_CHAR) ) ) ||
|
6514
7346
|
!(pBD->ScanQ = (Vertex *) inchi_calloc( max_num_vertices, sizeof(Vertex) ) ) ||
|
6515
7347
|
!(pBD->Pu = (Vertex *) inchi_calloc( max_len_Pu_Pv, sizeof(Vertex) ) ) ||
|
7348
|
+
#if( BNS_RAD_SEARCH == 1 )
|
7349
|
+
!(pBD->RadEndpoints = (Vertex *) inchi_calloc( max_len_Pu_Pv, sizeof(Vertex) ) ) ||
|
7350
|
+
!(pBD->RadEdges = (EdgeIndex*) inchi_calloc( max_len_Pu_Pv, sizeof(EdgeIndex) ) ) ||
|
7351
|
+
#endif
|
6516
7352
|
!(pBD->Pv = (Vertex *) inchi_calloc( max_len_Pu_Pv, sizeof(Vertex) ) )
|
6517
7353
|
) {
|
6518
7354
|
pBD = DeAllocateBnData( pBD );
|
@@ -6524,6 +7360,9 @@ BN_DATA *AllocateAndInitBnData( int max_num_vertices )
|
|
6524
7360
|
pBD->QSize = -1;
|
6525
7361
|
pBD->max_len_Pu_Pv = max_len_Pu_Pv;
|
6526
7362
|
pBD->max_num_vertices = max_num_vertices;
|
7363
|
+
#if( BNS_RAD_SEARCH == 1 )
|
7364
|
+
pBD->nNumRadEndpoints = 0;
|
7365
|
+
#endif
|
6527
7366
|
}
|
6528
7367
|
return pBD;
|
6529
7368
|
}
|
@@ -6846,12 +7685,14 @@ int rescap_mark( BN_STRUCT* pBNS, Vertex u, Vertex v, EdgeIndex iuv )
|
|
6846
7685
|
return bBackward;
|
6847
7686
|
}
|
6848
7687
|
/********************************************************************************
|
7688
|
+
Get previous vertex in the searched path
|
6849
7689
|
z is SwitchEdge_Vert2(y) != y. Go backward from z to y
|
6850
7690
|
*********************************************************************************/
|
6851
7691
|
Vertex GetPrevVertex( BN_STRUCT* pBNS, Vertex y, Edge *SwitchEdge, EdgeIndex *iuv )
|
6852
7692
|
{
|
6853
7693
|
Vertex w, z, x2, y2, n;
|
6854
7694
|
EdgeIndex iwy;
|
7695
|
+
|
6855
7696
|
w = SwitchEdge_Vert1(y);
|
6856
7697
|
z = SwitchEdge_Vert2(y);
|
6857
7698
|
iwy = SwitchEdge_IEdge(y);
|
@@ -6868,7 +7709,8 @@ Vertex GetPrevVertex( BN_STRUCT* pBNS, Vertex y, Edge *SwitchEdge, EdgeIndex *iu
|
|
6868
7709
|
iwy = SwitchEdge_IEdge(y2);
|
6869
7710
|
if ( w == x2 ) {
|
6870
7711
|
*iuv = iwy;
|
6871
|
-
return z;
|
7712
|
+
/*return z; */
|
7713
|
+
return (y + z)%2? z : prim(z);
|
6872
7714
|
}
|
6873
7715
|
n ++;
|
6874
7716
|
#ifdef _DEBUG
|
@@ -6896,6 +7738,51 @@ Vertex GetPrevVertex( BN_STRUCT* pBNS, Vertex y, Edge *SwitchEdge, EdgeIndex *iu
|
|
6896
7738
|
along an alternating path from another heteroatom (t-group will be detected).
|
6897
7739
|
|
6898
7740
|
**********************************************************************************/
|
7741
|
+
#if( FIX_TACN_POSSIBLE_BUG == 1 ) /* { */
|
7742
|
+
/*********************************************************************************/
|
7743
|
+
int bIgnoreVertexNonTACN_atom( BN_STRUCT* pBNS, Vertex u, Vertex v )
|
7744
|
+
{
|
7745
|
+
#define TYPE_T 1 /* t-group [also called H-group] */
|
7746
|
+
#define TYPE_CN 2 /* (-)c-group */
|
7747
|
+
int i, degree, ret, u_is_taut=0, w_is_taut, num_allowed=0, num_found_groups=0;
|
7748
|
+
Vertex w;
|
7749
|
+
EdgeIndex ivw;
|
7750
|
+
if ( !pBNS->type_TACN || u <= 1 || v <= 1 ||
|
7751
|
+
(pBNS->vert[v/2-1].type & pBNS->type_TACN) ) {
|
7752
|
+
return 0; /* add/remove H(+) is allowed for acidic atoms */
|
7753
|
+
}
|
7754
|
+
if ( !pBNS->type_T || !pBNS->type_CN )
|
7755
|
+
return 0; /* should not happen */
|
7756
|
+
u_is_taut = ((pBNS->vert[u/2-1].type & pBNS->type_T) == pBNS->type_T )? TYPE_T :
|
7757
|
+
((pBNS->vert[u/2-1].type & pBNS->type_CN) == pBNS->type_CN)? TYPE_CN : 0;
|
7758
|
+
if ( u_is_taut ) {
|
7759
|
+
/* u is either t-group vertex or (-) c-group */
|
7760
|
+
degree = GetVertexDegree( pBNS, v );
|
7761
|
+
for ( i = 0; i < degree; i ++ ) {
|
7762
|
+
/* v = vert[u].neighbor[i]; */
|
7763
|
+
w = GetVertexNeighbor( pBNS, v, i, &ivw );
|
7764
|
+
if ( w == NO_VERTEX || w <= 1 ) {
|
7765
|
+
continue; /* the atom has only single bonds or it is s or t, ignore it */
|
7766
|
+
}
|
7767
|
+
if ( w != u && (ret = rescap(pBNS, v, w, ivw)) > 0 ) {
|
7768
|
+
num_allowed ++;
|
7769
|
+
w_is_taut = ((pBNS->vert[w/2-1].type & pBNS->type_CN) == pBNS->type_CN)? TYPE_CN :
|
7770
|
+
((pBNS->vert[w/2-1].type & pBNS->type_T) == pBNS->type_T )? TYPE_T : 0;
|
7771
|
+
if ( (u_is_taut | w_is_taut) == (TYPE_T | TYPE_CN) ) {
|
7772
|
+
num_found_groups ++;
|
7773
|
+
}
|
7774
|
+
}
|
7775
|
+
}
|
7776
|
+
if ( num_found_groups && num_allowed == 1 ) {
|
7777
|
+
return 1; /* reject */
|
7778
|
+
}
|
7779
|
+
}
|
7780
|
+
return 0;
|
7781
|
+
#undef TYPE_T
|
7782
|
+
#undef TYPE_CN
|
7783
|
+
}
|
7784
|
+
#else /* } FIX_TACN_POSSIBLE_BUG { */
|
7785
|
+
/*********************************************************************************/
|
6899
7786
|
int bIgnoreVertexNonTACN_atom( BN_STRUCT* pBNS, Vertex u, Vertex v )
|
6900
7787
|
{
|
6901
7788
|
int i, degree, ret, u_is_taut=0, num_allowed=0, num_found_groups=0;
|
@@ -6903,12 +7790,13 @@ int bIgnoreVertexNonTACN_atom( BN_STRUCT* pBNS, Vertex u, Vertex v )
|
|
6903
7790
|
EdgeIndex ivw;
|
6904
7791
|
if ( !pBNS->type_TACN || u <= 1 || v <= 1 ||
|
6905
7792
|
(pBNS->vert[v/2-1].type & pBNS->type_TACN) ) {
|
6906
|
-
return 0;
|
7793
|
+
return 0; /* add/remove H(+) is allowed for acidic atoms */
|
6907
7794
|
}
|
6908
7795
|
if ( !pBNS->type_T || !pBNS->type_CN )
|
6909
7796
|
return 0; /* should not happen */
|
6910
7797
|
if ( (u_is_taut = (pBNS->vert[u/2-1].type & pBNS->type_T) == pBNS->type_T) ||
|
6911
7798
|
( (pBNS->vert[u/2-1].type & pBNS->type_CN) == pBNS->type_CN) ) {
|
7799
|
+
/* u is either t-group vertex or (-) c-group */
|
6912
7800
|
degree = GetVertexDegree( pBNS, v );
|
6913
7801
|
for ( i = 0; i < degree; i ++ ) {
|
6914
7802
|
/* v = vert[u].neighbor[i]; */
|
@@ -6925,12 +7813,13 @@ int bIgnoreVertexNonTACN_atom( BN_STRUCT* pBNS, Vertex u, Vertex v )
|
|
6925
7813
|
}
|
6926
7814
|
}
|
6927
7815
|
if ( num_found_groups && num_allowed == 1 ) {
|
6928
|
-
return 1;
|
7816
|
+
return 1; /* reject */
|
6929
7817
|
}
|
6930
7818
|
|
6931
7819
|
}
|
6932
7820
|
return 0;
|
6933
7821
|
}
|
7822
|
+
#endif /* } FIX_TACN_POSSIBLE_BUG */
|
6934
7823
|
/*********************************************************************************
|
6935
7824
|
the purpose is to avoid paths
|
6936
7825
|
(H-group)[u]---atom[v]---((-)-cgroup)[w], where
|
@@ -6940,6 +7829,55 @@ int bIgnoreVertexNonTACN_atom( BN_STRUCT* pBNS, Vertex u, Vertex v )
|
|
6940
7829
|
only one chemical bond. Only because of this an early rejection of
|
6941
7830
|
the vertex v (before it gets on SCANQ) is possible.
|
6942
7831
|
**********************************************************************************/
|
7832
|
+
#if( FIX_TACN_POSSIBLE_BUG == 1 ) /* { */
|
7833
|
+
/*********************************************************************************/
|
7834
|
+
int bIgnoreVertexNonTACN_group( BN_STRUCT* pBNS, Vertex v, Vertex w, Edge *SwitchEdge )
|
7835
|
+
{
|
7836
|
+
#define TYPE_T 1 /* t-group [also called H-group] */
|
7837
|
+
#define TYPE_CN 2 /* (-)c-group */
|
7838
|
+
int u_is_taut=0, w_is_taut=0;
|
7839
|
+
Vertex u;
|
7840
|
+
EdgeIndex iuv;
|
7841
|
+
if ( v <= 1 || w <= 1 )
|
7842
|
+
return 0;
|
7843
|
+
#if ( CHECK_TACN == 1 )
|
7844
|
+
if ( !pBNS->type_TACN ||
|
7845
|
+
(pBNS->vert[v/2-1].type & pBNS->type_TACN) ) {
|
7846
|
+
return 0;
|
7847
|
+
}
|
7848
|
+
if ( !pBNS->type_T || !pBNS->type_CN )
|
7849
|
+
return 0; /* should not happen */
|
7850
|
+
#endif
|
7851
|
+
u = GetPrevVertex( pBNS, v, SwitchEdge, &iuv );
|
7852
|
+
/*
|
7853
|
+
u = SwitchEdge_Vert1(v);
|
7854
|
+
iuv = SwitchEdge_IEdge(v);
|
7855
|
+
*/
|
7856
|
+
if ( u == NO_VERTEX || iuv < 0 )
|
7857
|
+
return 0; /* should not happen */
|
7858
|
+
/* check edge adjacency */
|
7859
|
+
if ( pBNS->edge[iuv].neighbor1 != (u/2-1) && pBNS->edge[iuv].neighbor1 != v/2-1 ||
|
7860
|
+
(pBNS->edge[iuv].neighbor12 ^ (u/2-1)) != (v/2-1) ) {
|
7861
|
+
return 0; /* !!! should not happen !!! */
|
7862
|
+
}
|
7863
|
+
|
7864
|
+
#if ( CHECK_TACN == 1 )
|
7865
|
+
u_is_taut = ((pBNS->vert[u/2-1].type & pBNS->type_T) == pBNS->type_T )? TYPE_T :
|
7866
|
+
((pBNS->vert[u/2-1].type & pBNS->type_CN) == pBNS->type_CN)? TYPE_CN : 0;
|
7867
|
+
w_is_taut = ((pBNS->vert[w/2-1].type & pBNS->type_T) == pBNS->type_T )? TYPE_T :
|
7868
|
+
((pBNS->vert[w/2-1].type & pBNS->type_CN) == pBNS->type_CN)? TYPE_CN : 0;
|
7869
|
+
if ( (u_is_taut | w_is_taut) == (TYPE_T | TYPE_CN ) ) {
|
7870
|
+
/* rescap must have already been checked */
|
7871
|
+
return 1;
|
7872
|
+
}
|
7873
|
+
#endif
|
7874
|
+
|
7875
|
+
return 0;
|
7876
|
+
#undef TYPE_T
|
7877
|
+
#undef TYPE_CN
|
7878
|
+
}
|
7879
|
+
#else /* } FIX_TACN_POSSIBLE_BUG { */
|
7880
|
+
/*********************************************************************************/
|
6943
7881
|
int bIgnoreVertexNonTACN_group( BN_STRUCT* pBNS, Vertex v, Vertex w, Edge *SwitchEdge )
|
6944
7882
|
{
|
6945
7883
|
int u_is_taut=0, w_is_taut=0;
|
@@ -6981,6 +7919,131 @@ int bIgnoreVertexNonTACN_group( BN_STRUCT* pBNS, Vertex v, Vertex w, Edge *Switc
|
|
6981
7919
|
|
6982
7920
|
return 0;
|
6983
7921
|
}
|
7922
|
+
#endif /* } FIX_TACN_POSSIBLE_BUG { */
|
7923
|
+
|
7924
|
+
#if( FIX_KEEP_H_ON_NH_ANION == 1 )
|
7925
|
+
/*********************************************************************************/
|
7926
|
+
/* detect an attempt to remove H from -NH(-) to make =N(-); */
|
7927
|
+
/* all taut atoma except N are 'acidic' */
|
7928
|
+
/*********************************************************************************/
|
7929
|
+
int bIsRemovedHfromNHaion( BN_STRUCT* pBNS, Vertex u, Vertex v )
|
7930
|
+
{
|
7931
|
+
int i, u2, v2, vat2;
|
7932
|
+
Vertex vtg, vat;
|
7933
|
+
BNS_VERTEX *pvAT, *pvCN;
|
7934
|
+
BNS_EDGE *pEdge;
|
7935
|
+
if ( !pBNS->type_TACN || u <= 1 || v <= 1 ||
|
7936
|
+
u%2 || !(v%2) /* the edge flow may only increase */ ) {
|
7937
|
+
return 0;
|
7938
|
+
}
|
7939
|
+
if ((pBNS->vert[u2 = u/2-1].type & pBNS->type_TACN) ||
|
7940
|
+
(pBNS->vert[v2 = v/2-1].type & pBNS->type_TACN) ) {
|
7941
|
+
return 0; /* add/remove H is allowed for acidic atoms */
|
7942
|
+
}
|
7943
|
+
if ( !pBNS->type_T || !pBNS->type_CN )
|
7944
|
+
return 0; /* should not happen */
|
7945
|
+
/* find which of u, v vertices is N and which is t-group */
|
7946
|
+
if ( ((pBNS->vert[u2].type & pBNS->type_T) == pBNS->type_T ) && v2 < pBNS->num_atoms ) {
|
7947
|
+
vtg = u;
|
7948
|
+
vat = v;
|
7949
|
+
} else
|
7950
|
+
if ( ((pBNS->vert[v2].type & pBNS->type_T) == pBNS->type_T ) && u2 < pBNS->num_atoms ) {
|
7951
|
+
vtg = v;
|
7952
|
+
vat = u;
|
7953
|
+
} else {
|
7954
|
+
return 0;
|
7955
|
+
}
|
7956
|
+
vat2 = vat/2-1;
|
7957
|
+
pvAT = pBNS->vert + vat2; /* atom */
|
7958
|
+
for ( i = pvAT->num_adj_edges-1; 0 <= i; i -- ) {
|
7959
|
+
pEdge = pBNS->edge + pvAT->iedge[i];
|
7960
|
+
pvCN = pBNS->vert + (pEdge->neighbor12 ^ vat2);
|
7961
|
+
if ( ((pvCN->type & pBNS->type_CN) == pBNS->type_CN) && pEdge->flow > 0 ) {
|
7962
|
+
return 1; /* detected */
|
7963
|
+
}
|
7964
|
+
}
|
7965
|
+
return 0;
|
7966
|
+
}
|
7967
|
+
#endif
|
7968
|
+
#if ( FIX_AVOID_ADP == 1 )
|
7969
|
+
/************************************************************************
|
7970
|
+
Detect (tg)-N=A-A=A-A=N-(tg)
|
7971
|
+
u v w
|
7972
|
+
k = 5 4 3 2 1 0 1 2
|
7973
|
+
^
|
7974
|
+
odd number means ADP
|
7975
|
+
*************************************************************************/
|
7976
|
+
int bIsAggressiveDeprotonation( BN_STRUCT* pBNS, Vertex v, Vertex w, Edge *SwitchEdge )
|
7977
|
+
{
|
7978
|
+
#define TYPE_T 1 /* t-group [also called H-group] */
|
7979
|
+
#define TYPE_CN 2 /* (-)c-group */
|
7980
|
+
#define TYPE_AT 4
|
7981
|
+
int k, v2, u2, w2, u2_next, type0, type1, type2, type;
|
7982
|
+
Vertex u, u_next;
|
7983
|
+
EdgeIndex iuv;
|
7984
|
+
if ( v <= 1 || w <= 1 )
|
7985
|
+
return 0;
|
7986
|
+
|
7987
|
+
if ( !pBNS->type_TACN || !pBNS->type_T || !pBNS->type_CN )
|
7988
|
+
return 0; /* should not happen */
|
7989
|
+
v2 = v/2 - 1;
|
7990
|
+
w2 = w/2 - 1;
|
7991
|
+
if ( v2 >= pBNS->num_atoms || w2 < pBNS->num_atoms )
|
7992
|
+
goto cross_edge;
|
7993
|
+
|
7994
|
+
if ( !((pBNS->vert[w2].type & pBNS->type_T) == pBNS->type_T ) &&
|
7995
|
+
!((pBNS->vert[w2].type & pBNS->type_CN) == pBNS->type_CN) )
|
7996
|
+
goto cross_edge;
|
7997
|
+
/* v ia an atom, w is a t-group, v != w' */
|
7998
|
+
for ( k = 0, u = v; 1 < (u_next = u, u = GetPrevVertex( pBNS, u, SwitchEdge, &iuv )); k ++ ) {
|
7999
|
+
u2 = u/2 - 1;
|
8000
|
+
if ( u2 >= pBNS->num_atoms ) {
|
8001
|
+
/* moving backward along the alt path we have found a vertex
|
8002
|
+
that is not an atom. Possibly it is a t- or (-)c-group */
|
8003
|
+
if ( !( k % 2 ) ) {
|
8004
|
+
return 0; /* even vertex -- always okay */
|
8005
|
+
}
|
8006
|
+
if ( !((pBNS->vert[u2].type & pBNS->type_T) == pBNS->type_T ) &&
|
8007
|
+
!((pBNS->vert[u2].type & pBNS->type_CN) == pBNS->type_CN) ) {
|
8008
|
+
/* not a t- or (-)c-group */
|
8009
|
+
return 0;
|
8010
|
+
}
|
8011
|
+
u2_next = u_next/2 - 1;
|
8012
|
+
if ( !(pBNS->vert[v2 ].type & pBNS->type_TACN) &&
|
8013
|
+
!(pBNS->vert[u2_next].type & pBNS->type_TACN) ) {
|
8014
|
+
/* none of the atoms at the ends are N */
|
8015
|
+
return 0;
|
8016
|
+
}
|
8017
|
+
return 1;
|
8018
|
+
}
|
8019
|
+
}
|
8020
|
+
return 0;
|
8021
|
+
cross_edge:
|
8022
|
+
/*****************************************************************************
|
8023
|
+
* v and w (v=w') are same vertex reached with opposite "phases".
|
8024
|
+
* w cannot be (t) because this would have been detected earlier -- ???
|
8025
|
+
* (t)-A=A-A=A-A=A-(t)
|
8026
|
+
* v
|
8027
|
+
* 3 2 1 0 1 2 3 4
|
8028
|
+
* kv kw
|
8029
|
+
* (kv + kw)%2 == 1 <==> aggressive deprotonation
|
8030
|
+
*****************************************************************************/
|
8031
|
+
if ( v == prim(w) ) {
|
8032
|
+
type0 = 0;
|
8033
|
+
if ( v2 >= pBNS->num_atoms ) {
|
8034
|
+
type0 = ((pBNS->vert[v2].type & pBNS->type_T) == pBNS->type_T )? TYPE_T :
|
8035
|
+
((pBNS->vert[v2].type & pBNS->type_CN) == pBNS->type_CN)? TYPE_CN : 0;
|
8036
|
+
}
|
8037
|
+
|
8038
|
+
|
8039
|
+
|
8040
|
+
}
|
8041
|
+
|
8042
|
+
|
8043
|
+
return 0;
|
8044
|
+
}
|
8045
|
+
#endif
|
8046
|
+
|
6984
8047
|
/*********************************************************************************/
|
6985
8048
|
int rescap( BN_STRUCT* pBNS, Vertex u, Vertex v, EdgeIndex iuv )
|
6986
8049
|
{
|
@@ -7107,12 +8170,20 @@ int BalancedNetworkSearch ( BN_STRUCT* pBNS, BN_DATA *pBD, int bChangeFlow )
|
|
7107
8170
|
Vertex *Pv = pBD->Pv;
|
7108
8171
|
int max_len_Pu_Pv= pBD->max_len_Pu_Pv;
|
7109
8172
|
|
7110
|
-
|
7111
|
-
|
7112
8173
|
/* added to translate into C */
|
7113
8174
|
int i, k, degree, delta, ret = 0;
|
7114
8175
|
Vertex u, b_u, v, b_v, w;
|
7115
8176
|
EdgeIndex iuv;
|
8177
|
+
#if( BNS_RAD_SEARCH == 1 )
|
8178
|
+
int n, bRadSearch = (BNS_EF_RAD_SRCH & bChangeFlow) && pBD->RadEndpoints;
|
8179
|
+
BRS_MODE bRadSrchMode = RAD_SRCH_NORM;
|
8180
|
+
int bRadSearchPrelim = 0;
|
8181
|
+
if ( bRadSearch ) {
|
8182
|
+
pBD->nNumRadEndpoints = 0;
|
8183
|
+
bRadSrchMode = pBD->bRadSrchMode;
|
8184
|
+
bRadSearchPrelim = pBNS->type_TACN && bRadSrchMode == RAD_SRCH_NORM;
|
8185
|
+
}
|
8186
|
+
#endif
|
7116
8187
|
|
7117
8188
|
/* -- Always --
|
7118
8189
|
Vertex_s = FIRST_INDX;
|
@@ -7129,12 +8200,23 @@ int BalancedNetworkSearch ( BN_STRUCT* pBNS, BN_DATA *pBD, int bChangeFlow )
|
|
7129
8200
|
/* since u is on the queue, it has a blossom C(U) with base b_u */
|
7130
8201
|
b_u = FindBase( u, BasePtr );
|
7131
8202
|
degree = GetVertexDegree( pBNS, u );
|
8203
|
+
#if( BNS_RAD_SEARCH == 1 )
|
8204
|
+
n = 0;
|
8205
|
+
#endif
|
7132
8206
|
for ( i = 0; i < degree; i ++ ) {
|
7133
8207
|
/* v = vert[u].neighbor[i]; */
|
7134
8208
|
v = GetVertexNeighbor( pBNS, u, i, &iuv );
|
7135
8209
|
if ( v == NO_VERTEX ) {
|
7136
8210
|
continue; /* the atom has only single bonds, ignore it */
|
7137
8211
|
}
|
8212
|
+
#if( BNS_RAD_SEARCH == 1 )
|
8213
|
+
if ( !k && bRadSrchMode == RAD_SRCH_FROM_FICT && v/2 <= pBNS->num_atoms ) {
|
8214
|
+
continue; /* start from fict. vertices only */
|
8215
|
+
}
|
8216
|
+
if ( bRadSearchPrelim && v/2 > pBNS->num_atoms ) {
|
8217
|
+
continue; /* during initial add/remove H allow radical movement only through real atoms */
|
8218
|
+
}
|
8219
|
+
#endif
|
7138
8220
|
if ( /* PrevPt[u] != v ** avoid edges of T */
|
7139
8221
|
( SwitchEdge_Vert1(u) != v || SwitchEdge_Vert2(u) != u ) /* avoid edges of T */
|
7140
8222
|
&& (ret = rescap(pBNS, u, v, iuv)) > 0 ) {
|
@@ -7147,6 +8229,17 @@ int BalancedNetworkSearch ( BN_STRUCT* pBNS, BN_DATA *pBD, int bChangeFlow )
|
|
7147
8229
|
if ( bIgnoreVertexNonTACN_group( pBNS, u, v, SwitchEdge ) ) {
|
7148
8230
|
continue;
|
7149
8231
|
}
|
8232
|
+
#if( FIX_KEEP_H_ON_NH_ANION == 1 )
|
8233
|
+
if ( bIsRemovedHfromNHaion( pBNS, u, v ) ) {
|
8234
|
+
continue;
|
8235
|
+
}
|
8236
|
+
#endif
|
8237
|
+
#if ( FIX_AVOID_ADP == 1 )
|
8238
|
+
if ( bIsAggressiveDeprotonation( pBNS, u, v, SwitchEdge ) ) {
|
8239
|
+
continue;
|
8240
|
+
}
|
8241
|
+
#endif
|
8242
|
+
|
7150
8243
|
}
|
7151
8244
|
/*----------------------------------------------------------------------*/
|
7152
8245
|
b_v = FindBase(v, BasePtr); /* Notation: b_x is a base of x */
|
@@ -7217,14 +8310,23 @@ int BalancedNetworkSearch ( BN_STRUCT* pBNS, BN_DATA *pBD, int bChangeFlow )
|
|
7217
8310
|
|
7218
8311
|
BasePtr[prim(v)] = v;
|
7219
8312
|
BasePtr[v] = BLOSSOM_BASE; /* create a trivial blossom C(v) with base v */
|
8313
|
+
#if( BNS_RAD_SEARCH == 1 )
|
8314
|
+
n ++;
|
8315
|
+
#endif
|
7220
8316
|
} else
|
7221
8317
|
if ( TREE_IS_S_REACHABLE(prim(v)) /*Is_s_Reachable(prim(v)*/
|
7222
8318
|
/* if v' is reachable, an st-path is given by P(u)-uv-P'(v') */
|
7223
8319
|
/*&& PrevPt[prim(u)] != prim(v) ** avoid edges of T' */
|
7224
8320
|
&& (SwitchEdge_Vert1(prim(u)) != prim(v) || SwitchEdge_Vert2(prim(u)) != prim(u)) /* avoid edges of T' */
|
7225
8321
|
&& b_u != b_v
|
7226
|
-
&& !(pBNS->type_TACN && bIgnoreVertexNonTACN_group( pBNS, prim(v), u, SwitchEdge ))
|
7227
|
-
|
8322
|
+
&& !(pBNS->type_TACN && bIgnoreVertexNonTACN_group( pBNS, prim(v), u, SwitchEdge ))
|
8323
|
+
#if( FIX_KEEP_H_ON_NH_ANION == 1 )
|
8324
|
+
&& !(pBNS->type_TACN && bIsRemovedHfromNHaion( pBNS, prim(v), u ))
|
8325
|
+
#endif
|
8326
|
+
) {
|
8327
|
+
#if( BNS_RAD_SEARCH == 1 )
|
8328
|
+
n ++;
|
8329
|
+
#endif
|
7228
8330
|
/* there is now a valid sv-path via u avoiding b_v (unless v==b_v)
|
7229
8331
|
=> u, v, u', and v' now all become part of the same connected component of M[C] */
|
7230
8332
|
w = MakeBlossom( pBNS, ScanQ, &QSize, Pu, Pv, max_len_Pu_Pv, SwitchEdge, BasePtr, u, v, iuv, b_u, b_v, Tree );
|
@@ -7239,9 +8341,8 @@ int BalancedNetworkSearch ( BN_STRUCT* pBNS, BN_DATA *pBD, int bChangeFlow )
|
|
7239
8341
|
delta = FindPathCap( pBNS, SwitchEdge, Vertex_s, Vertex_t, 10000 ); /* compute the residual capacity of P + P' */
|
7240
8342
|
if ( IS_BNS_ERROR( delta ) ) {
|
7241
8343
|
pBD->QSize = QSize;
|
7242
|
-
return delta;
|
8344
|
+
return delta; /* error */
|
7243
8345
|
}
|
7244
|
-
|
7245
8346
|
#if( ALLOW_ONLY_SIMPLE_ALT_PATH == 1 )
|
7246
8347
|
if ( pBNS->bNotASimplePath || abs(delta) > 1 ) {
|
7247
8348
|
delta = 0;
|
@@ -7258,11 +8359,19 @@ int BalancedNetworkSearch ( BN_STRUCT* pBNS, BN_DATA *pBD, int bChangeFlow )
|
|
7258
8359
|
} else
|
7259
8360
|
if ( IS_BNS_ERROR( ret ) ) {
|
7260
8361
|
pBD->QSize = QSize;
|
7261
|
-
return ret;
|
8362
|
+
return ret; /* error */
|
7262
8363
|
}
|
7263
|
-
|
7264
|
-
|
7265
8364
|
}
|
8365
|
+
#if( BNS_RAD_SEARCH == 1 )
|
8366
|
+
if ( bRadSearch && !n ) {
|
8367
|
+
/* the BNS stopped at u */
|
8368
|
+
n = RegisterRadEndpoint( pBNS, pBD, u);
|
8369
|
+
if ( IS_BNS_ERROR( n ) ) {
|
8370
|
+
pBD->QSize = QSize;
|
8371
|
+
return n;
|
8372
|
+
}
|
8373
|
+
}
|
8374
|
+
#endif
|
7266
8375
|
k ++; /* advance ScanQ */
|
7267
8376
|
} while( k <= QSize );
|
7268
8377
|
/* if this point is reached, no valid augmenting path exists, ScanQ contains
|
@@ -7538,6 +8647,16 @@ int FindPathCap( BN_STRUCT* pBNS, Edge *SwitchEdge, Vertex x, Vertex y, int delt
|
|
7538
8647
|
*/
|
7539
8648
|
Vertex w, z, iwz;
|
7540
8649
|
int cap, delta2;
|
8650
|
+
static int level;
|
8651
|
+
|
8652
|
+
if ( level ++ > 50 ) {
|
8653
|
+
#ifdef _DEBUG
|
8654
|
+
int stop = 1;
|
8655
|
+
#else
|
8656
|
+
;
|
8657
|
+
#endif
|
8658
|
+
}
|
8659
|
+
|
7541
8660
|
|
7542
8661
|
w = SwitchEdge_Vert1(y);
|
7543
8662
|
z = SwitchEdge_Vert2(y); /* wz is on the path P */
|
@@ -7547,6 +8666,7 @@ int FindPathCap( BN_STRUCT* pBNS, Edge *SwitchEdge, Vertex x, Vertex y, int delt
|
|
7547
8666
|
cap = rescap_mark( pBNS, w, z, iwz );
|
7548
8667
|
|
7549
8668
|
if ( IS_BNS_ERROR( cap ) ) {
|
8669
|
+
level --;
|
7550
8670
|
return cap;
|
7551
8671
|
}
|
7552
8672
|
if ( cap < delta ) {
|
@@ -7561,6 +8681,7 @@ int FindPathCap( BN_STRUCT* pBNS, Edge *SwitchEdge, Vertex x, Vertex y, int delt
|
|
7561
8681
|
delta2 = FindPathCap( pBNS, SwitchEdge, prim(y), prim(z), delta );
|
7562
8682
|
delta = inchi_min( delta2, delta );
|
7563
8683
|
}
|
8684
|
+
level --;
|
7564
8685
|
return delta;
|
7565
8686
|
}
|
7566
8687
|
|
@@ -7569,18 +8690,19 @@ int FindPathCap( BN_STRUCT* pBNS, Edge *SwitchEdge, Vertex x, Vertex y, int delt
|
|
7569
8690
|
#define BT_ALTERN_BOND 1 /* 1-2, possibly stereo */
|
7570
8691
|
#define BT_OTHER_ALTERN_BOND 2 /* 1-3, 2-3, 1-2-3 alternating non-stereo non-taut bonds */
|
7571
8692
|
|
7572
|
-
#define BT_ALT_BOND_MASK (BT_ALTERN_BOND|BT_OTHER_ALTERN_BOND)
|
7573
|
-
|
7574
8693
|
#define BT_ALTERN_NS_BOND 4
|
7575
8694
|
|
7576
|
-
#define BT_NONTAUT_BOND_MASK (BT_ALTERN_BOND|BT_OTHER_ALTERN_BOND|BT_ALTERN_NS_BOND)
|
7577
|
-
|
7578
8695
|
#define BT_TAUTOM_BOND 8
|
7579
8696
|
|
8697
|
+
#define BT_ALTERN_UNKN_BOND 16
|
8698
|
+
|
7580
8699
|
#define BT_IGNORE_BOND 0
|
7581
8700
|
|
7582
8701
|
#define BT_NONSTEREO_MASK (BT_TAUTOM_BOND|BT_ALTERN_NS_BOND)
|
7583
8702
|
|
8703
|
+
#define BT_ALT_BOND_MASK (BT_ALTERN_BOND|BT_OTHER_ALTERN_BOND)
|
8704
|
+
|
8705
|
+
#define BT_NONTAUT_BOND_MASK (BT_ALTERN_BOND|BT_OTHER_ALTERN_BOND|BT_ALTERN_NS_BOND)
|
7584
8706
|
|
7585
8707
|
/* BNS members redefinitions for finding non-stereo bonds */
|
7586
8708
|
/* BNS_EDGE */
|
@@ -7603,7 +8725,7 @@ int FindPathCap( BN_STRUCT* pBNS, Edge *SwitchEdge, Vertex x, Vertex y, int delt
|
|
7603
8725
|
|
7604
8726
|
|
7605
8727
|
/********************************************************************************/
|
7606
|
-
int MarkRingSystemsAltBns( BN_STRUCT* pBNS )
|
8728
|
+
int MarkRingSystemsAltBns( BN_STRUCT* pBNS, int bUnknAltAsNoStereo )
|
7607
8729
|
{
|
7608
8730
|
AT_NUMB *nStackAtom = NULL;
|
7609
8731
|
int nTopStackAtom;
|
@@ -7627,10 +8749,10 @@ int MarkRingSystemsAltBns( BN_STRUCT* pBNS )
|
|
7627
8749
|
nRingStack = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nRingStack[0]));
|
7628
8750
|
nDfsNumber = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nDfsNumber[0]));
|
7629
8751
|
nLowNumber = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nLowNumber[0]));
|
7630
|
-
nBondStack = (AT_NUMB *)inchi_malloc(num_edges*sizeof(nBondStack[0]));
|
8752
|
+
nBondStack = (AT_NUMB *)(num_edges? inchi_malloc(num_edges*sizeof(nBondStack[0])):NULL); /* special case: no bonds 2006-03 */
|
7631
8753
|
cNeighNumb = (S_CHAR *)inchi_malloc(num_atoms*sizeof(cNeighNumb[0]));
|
7632
8754
|
/* check allocation */
|
7633
|
-
if ( !nStackAtom || !nRingStack || !nDfsNumber || !nLowNumber || !nBondStack || !cNeighNumb
|
8755
|
+
if ( !nStackAtom || !nRingStack || !nDfsNumber || !nLowNumber || !nBondStack && num_edges || !cNeighNumb
|
7634
8756
|
) {
|
7635
8757
|
nNumRingSystems = CT_OUT_OF_RAM; /* program error */ /* <BRKPT> */
|
7636
8758
|
goto exit_function;
|
@@ -7693,7 +8815,10 @@ found_alt:
|
|
7693
8815
|
|
7694
8816
|
do {
|
7695
8817
|
/* advance */
|
7696
|
-
while ( (int)at[i=nStackAtom[nTopStackAtom]].valenceAltBns > (j = (int)cNeighNumb[i]) )
|
8818
|
+
/*while ( (int)at[i=nStackAtom[nTopStackAtom]].valenceAltBns > (j = (int)cNeighNumb[i]) )*/
|
8819
|
+
/* replaced due to missing sequence point */
|
8820
|
+
while ( i=(int)nStackAtom[nTopStackAtom], j = (int)cNeighNumb[i], (int)at[i].valenceAltBns > j )
|
8821
|
+
{
|
7697
8822
|
cNeighNumb[i] ++;
|
7698
8823
|
if ( !(bond[w=at[i].iedge[j]].nBondTypeInpAltBns & BT_ALT_BOND_MASK) ) {
|
7699
8824
|
continue;
|
@@ -7797,7 +8922,10 @@ found_alt2:
|
|
7797
8922
|
do {
|
7798
8923
|
/* advance */
|
7799
8924
|
advance_ring:
|
7800
|
-
if ( (int)at[i=nStackAtom[nTopStackAtom]].valenceAltBns > (j = (int)cNeighNumb[i]) )
|
8925
|
+
/*if ( (int)at[i=nStackAtom[nTopStackAtom]].valenceAltBns > (j = (int)cNeighNumb[i]) )*/
|
8926
|
+
/* replaced due to missing sequence point */
|
8927
|
+
if ( i=(int)nStackAtom[nTopStackAtom], j = (int)cNeighNumb[i], (int)at[i].valenceAltBns > j )
|
8928
|
+
{
|
7801
8929
|
cNeighNumb[i] ++;
|
7802
8930
|
if ( !(bond[at[i].iedge[j]].nBondTypeInpAltBns & BT_ALTERN_BOND) ) {
|
7803
8931
|
goto advance_ring;
|
@@ -7876,7 +9004,7 @@ exit_function:
|
|
7876
9004
|
}
|
7877
9005
|
|
7878
9006
|
/*********************************************************************************/
|
7879
|
-
int ReInitBnStructForAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
|
9007
|
+
int ReInitBnStructForAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int bUnknAltAsNoStereo )
|
7880
9008
|
{
|
7881
9009
|
Vertex v, v2;
|
7882
9010
|
int ret, bond_type, num_to_test, j;
|
@@ -7884,6 +9012,11 @@ int ReInitBnStructForAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
|
|
7884
9012
|
BNS_VERTEX *pAtom;
|
7885
9013
|
/* strip all t-groups and c-groups */
|
7886
9014
|
num_to_test = 0;
|
9015
|
+
if ( bUnknAltAsNoStereo ) {
|
9016
|
+
for ( j = 0; j < pBNS->num_edges; j ++ ) {
|
9017
|
+
pBNS->edge[j].pass = 0;
|
9018
|
+
}
|
9019
|
+
}
|
7887
9020
|
ret = ReInitBnStruct( pBNS, at, num_atoms, 0 );
|
7888
9021
|
if ( ret || pBNS->num_atoms != num_atoms || pBNS->num_vertices != num_atoms || pBNS->num_bonds != pBNS->num_edges ) {
|
7889
9022
|
ret = BNS_REINIT_ERR;
|
@@ -7900,6 +9033,13 @@ int ReInitBnStructForAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
|
|
7900
9033
|
if ( at[v].endpoint || at[v2].endpoint ) {
|
7901
9034
|
bond_type = 0; /* any bond to an endpoint considered non-stereogenic */
|
7902
9035
|
}
|
9036
|
+
#if( FIX_EITHER_DB_AS_NONSTEREO == 1 )
|
9037
|
+
if ( bUnknAltAsNoStereo ) {
|
9038
|
+
if ( bond_type == BOND_ALTERN && at[v].bond_stereo[j] == STEREO_DBLE_EITHER ) {
|
9039
|
+
bond_type = 0; /* treat unknown (Either) ALT bond as non-stereo */
|
9040
|
+
}
|
9041
|
+
}
|
9042
|
+
#endif
|
7903
9043
|
switch ( bond_type ) {
|
7904
9044
|
|
7905
9045
|
case BOND_ALTERN :
|
@@ -7954,7 +9094,7 @@ exit_function:
|
|
7954
9094
|
}
|
7955
9095
|
|
7956
9096
|
/************************************************************************************/
|
7957
|
-
int MarkNonStereoAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
|
9097
|
+
int MarkNonStereoAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int bUnknAltAsNoStereo )
|
7958
9098
|
{
|
7959
9099
|
int num_bonds = pBNS->num_bonds;
|
7960
9100
|
int ret;
|
@@ -7968,27 +9108,53 @@ int MarkNonStereoAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
|
|
7968
9108
|
ret = BNS_REINIT_ERR;
|
7969
9109
|
goto exit_function;
|
7970
9110
|
}
|
7971
|
-
|
7972
|
-
|
7973
|
-
|
7974
|
-
|
7975
|
-
|
9111
|
+
if ( bUnknAltAsNoStereo ) {
|
9112
|
+
for ( ibond=0; ibond < num_bonds; ibond ++ ) {
|
9113
|
+
pBond = pBNS->edge + ibond;
|
9114
|
+
if ( pBond->nBondTypeInpAltBns != BT_ALTERN_BOND && pBond->nBondTypeInpAltBns != BT_IGNORE_BOND ) {
|
9115
|
+
continue;
|
9116
|
+
}
|
9117
|
+
iat1 = pBond->neighbor1;
|
9118
|
+
iat2 = pBond->neighbor12 ^ iat1;
|
9119
|
+
ib1 = pBond->neigh_ord[0];
|
9120
|
+
ib2 = pBond->neigh_ord[1];
|
9121
|
+
if ( /* alt bond non-adjacent to a taut. endpoint: */
|
9122
|
+
(pBond->nBondTypeInpAltBns == BT_ALTERN_BOND &&
|
9123
|
+
pBond->nNumAtInBlockAltBns <= 3 ) /* non-ring bond */ ||
|
9124
|
+
/* alt bond adjacent to a taut. endpoint: */
|
9125
|
+
(pBond->nBondTypeInpAltBns == BT_IGNORE_BOND &&
|
9126
|
+
(at[iat1].bond_type[ib1] & BOND_TYPE_MASK) == BOND_ALTERN )
|
9127
|
+
) {
|
9128
|
+
if ( (at[iat1].bond_type[ib1] & BOND_TYPE_MASK) == BOND_ALTERN ) {
|
9129
|
+
/* bond_type = BOND_ALT12NS; */
|
9130
|
+
at[iat1].bond_stereo[ib1] =
|
9131
|
+
at[iat2].bond_stereo[ib2] =STEREO_DBLE_EITHER;
|
9132
|
+
ret ++;
|
9133
|
+
}
|
9134
|
+
}
|
9135
|
+
}
|
9136
|
+
} else {
|
9137
|
+
for ( ibond=0; ibond < num_bonds; ibond ++ ) {
|
9138
|
+
pBond = pBNS->edge + ibond;
|
9139
|
+
if ( pBond->nBondTypeInpAltBns != BT_ALTERN_BOND && pBond->nBondTypeInpAltBns != BT_IGNORE_BOND ) {
|
9140
|
+
continue;
|
9141
|
+
}
|
9142
|
+
iat1 = pBond->neighbor1;
|
9143
|
+
iat2 = pBond->neighbor12 ^ iat1;
|
9144
|
+
ib1 = pBond->neigh_ord[0];
|
9145
|
+
ib2 = pBond->neigh_ord[1];
|
9146
|
+
if ( /* alt bond non-adjacent to a taut. endpoint: */
|
9147
|
+
(pBond->nBondTypeInpAltBns == BT_ALTERN_BOND &&
|
9148
|
+
pBond->nNumAtInBlockAltBns <= 3 ) /* non-ring bond */ ||
|
9149
|
+
/* alt bond adjacent to a taut. endpoint: */
|
9150
|
+
(pBond->nBondTypeInpAltBns == BT_IGNORE_BOND &&
|
9151
|
+
(at[iat1].bond_type[ib1] & BOND_TYPE_MASK) == BOND_ALTERN )
|
9152
|
+
) {
|
9153
|
+
at[iat1].bond_type[ib1] =
|
9154
|
+
at[iat2].bond_type[ib2] =BOND_ALT12NS;
|
9155
|
+
ret ++;
|
9156
|
+
}
|
7976
9157
|
}
|
7977
|
-
iat1 = pBond->neighbor1;
|
7978
|
-
iat2 = pBond->neighbor12 ^ iat1;
|
7979
|
-
ib1 = pBond->neigh_ord[0];
|
7980
|
-
ib2 = pBond->neigh_ord[1];
|
7981
|
-
if ( /* alt bond non-adjacent to a taut. endpoint: */
|
7982
|
-
(pBond->nBondTypeInpAltBns == BT_ALTERN_BOND &&
|
7983
|
-
pBond->nNumAtInBlockAltBns <= 3 ) ||
|
7984
|
-
/* alt bond adjacent to a taut. endpoint: */
|
7985
|
-
(pBond->nBondTypeInpAltBns == BT_IGNORE_BOND &&
|
7986
|
-
(at[iat1].bond_type[ib1] & BOND_TYPE_MASK) == BOND_ALTERN )
|
7987
|
-
) {
|
7988
|
-
at[iat1].bond_type[ib1] =
|
7989
|
-
at[iat2].bond_type[ib2] =BOND_ALT12NS;
|
7990
|
-
ret ++;
|
7991
|
-
}
|
7992
9158
|
}
|
7993
9159
|
|
7994
9160
|
exit_function:
|
@@ -7996,4 +9162,384 @@ exit_function:
|
|
7996
9162
|
return ret;
|
7997
9163
|
}
|
7998
9164
|
|
9165
|
+
#if( READ_INCHI_STRING == 1 )
|
9166
|
+
/*****************************************************************/
|
9167
|
+
#ifndef RI_ERR_ALLOC
|
9168
|
+
/* from ichirvrs.h */
|
9169
|
+
#define RI_ERR_ALLOC (-1)
|
9170
|
+
#define RI_ERR_SYNTAX (-2)
|
9171
|
+
#define RI_ERR_PROGR (-3)
|
9172
|
+
#endif
|
9173
|
+
/*****************************************************************/
|
9174
|
+
int bHasChargedNeighbor( inp_ATOM *at, int iat )
|
9175
|
+
{
|
9176
|
+
int i;
|
9177
|
+
for( i = 0; i < at[iat].valence; i ++ ) {
|
9178
|
+
if ( at[(int)at[iat].neighbor[i]].charge )
|
9179
|
+
return 1;
|
9180
|
+
}
|
9181
|
+
return 0;
|
9182
|
+
}
|
9183
|
+
/***********************************************************************************************
|
9184
|
+
*num_protons_to_add = nToBeRemovedByNormFromRevrs
|
9185
|
+
|
9186
|
+
nToBeRemovedByNormFromRevrs > 0: less protons should be allowed to be
|
9187
|
+
added by the Normalization of the Reconstructed Structure
|
9188
|
+
nToBeRemovedByNormFromRevrs < 0: prepare more H(+) to be removed by
|
9189
|
+
the InChI Normalization of the Reconstructed Structure
|
9190
|
+
|
9191
|
+
OrigStruct -> NormOrig + n(orig)*H(+)
|
9192
|
+
RevrStruct -> NormRevr + n(revr)*H(+)
|
9193
|
+
nToBeRemovedByNormFromRevrs = n(orig) - n(revr) [each may be negative]
|
9194
|
+
|
9195
|
+
n(orig) > n(revr) or nToBeRemovedByNormFromRevrs > 0 means:
|
9196
|
+
-----------------------------------------------------------
|
9197
|
+
- Too many protons were added by the Normalization to the Reconstructed Structure
|
9198
|
+
(a) n(revr) < 0 => protons were added while they should not have been added;
|
9199
|
+
Solution: "neutralize" (-) charged proton acceptors by moving charges to other atoms
|
9200
|
+
on the condition ADP cannot add in another way;
|
9201
|
+
(b) n(orig) > n(revr) => 0 => too few protons were removed
|
9202
|
+
Solution: (the easiest) attach H(+) to =O or -N< or -N=
|
9203
|
+
Solution: move (+) from N or OH to an atom adjacent to (-) charge or to
|
9204
|
+
an atom that is not N.
|
9205
|
+
|
9206
|
+
n(orig) < n(revr) or nToBeRemovedByNormFromRevrs < 0 means:
|
9207
|
+
-----------------------------------------------------------
|
9208
|
+
- Too few protons were added by the Normalization to the Reconstructed Stucture
|
9209
|
+
(a) n(orig) < 0 => protons were not added while they should have been added;
|
9210
|
+
Solution: move (-) to O by replacing =O with -O(-)
|
9211
|
+
(b) 0 <= n(orig) < n(revr) => too many protons were removed
|
9212
|
+
|
9213
|
+
Note: it is critically important to takr into account cumbersome Normalization
|
9214
|
+
Total Charge: if it is >= 0 then no H(+) may be removed from -OH or by ADP
|
9215
|
+
However, if N(+) is present then ADP will always try to remove a proton
|
9216
|
+
*********************************************************************************************/
|
9217
|
+
int AddRemoveProtonsRestr( inp_ATOM *at, int num_atoms, int *num_protons_to_add,
|
9218
|
+
int nNumProtAddedByRestr, INCHI_MODE bNormalizationFlags,
|
9219
|
+
int num_tg, int nChargeRevrs, int nChargeInChI )
|
9220
|
+
{
|
9221
|
+
int i, j, ret = 0;
|
9222
|
+
int nAtTypeTotals[ATTOT_ARRAY_LEN];
|
9223
|
+
int num_prot = *num_protons_to_add;
|
9224
|
+
int type, mask, bSuccess, nTotCharge, nNumSuccess = 0;
|
9225
|
+
int max_j_Aa=-1, max_j_Ar=-1;
|
9226
|
+
|
9227
|
+
/* for the reference:
|
9228
|
+
|
9229
|
+
#define FLAG_NORM_CONSIDER_TAUT ( FLAG_PROTON_NPO_SIMPLE_REMOVED | \
|
9230
|
+
FLAG_PROTON_NP_HARD_REMOVED | \
|
9231
|
+
FLAG_PROTON_AC_SIMPLE_ADDED | \
|
9232
|
+
FLAG_PROTON_AC_SIMPLE_REMOVED | \
|
9233
|
+
FLAG_PROTON_AC_HARD_REMOVED | \
|
9234
|
+
FLAG_PROTON_AC_HARD_ADDED | \
|
9235
|
+
FLAG_PROTON_SINGLE_REMOVED | \
|
9236
|
+
FLAG_PROTON_CHARGE_CANCEL )
|
9237
|
+
|
9238
|
+
#define FLAG_FORCE_SALT_TAUT ( FLAG_PROTON_NP_HARD_REMOVED | \
|
9239
|
+
FLAG_PROTON_AC_HARD_REMOVED | \
|
9240
|
+
FLAG_PROTON_AC_HARD_ADDED )
|
9241
|
+
|
9242
|
+
*/
|
9243
|
+
/* if ChargeRevrs > nChargeInChI then we should prevent proton addition or facilitate proton removal
|
9244
|
+
a typical case is (=) on N or O instead of C(-)
|
9245
|
+
|
9246
|
+
if ChargeRevrs < nChargeInChI then we should prevent proton removal or facilitate proton addition
|
9247
|
+
*/
|
9248
|
+
|
9249
|
+
mark_at_type( at, num_atoms, nAtTypeTotals );
|
9250
|
+
for ( i = nTotCharge = 0; i < num_atoms; i ++ ) {
|
9251
|
+
nTotCharge += at[i].charge;
|
9252
|
+
}
|
9253
|
+
/* size for SimpleAddAcidicProtons() */
|
9254
|
+
for ( max_j_Aa = 0; AaTypMask[2*max_j_Aa]; max_j_Aa ++ )
|
9255
|
+
;
|
9256
|
+
/* size for SimpleRemoveAcidicProtons */
|
9257
|
+
for ( max_j_Ar = 0; ArTypMask[2*max_j_Ar]; max_j_Ar ++ )
|
9258
|
+
;
|
9259
|
+
if ( num_prot < 0 && nAtTypeTotals[ATTOT_TOT_CHARGE]-nNumProtAddedByRestr <= 0 ) {
|
9260
|
+
/* remove proton(s) */
|
9261
|
+
/* use test from SimpleAddAcidicProtons() to test whether removal of H(+) from =C-OH, etc. is correct */
|
9262
|
+
for ( i = 0; i < num_atoms && num_prot; i ++ ) {
|
9263
|
+
/* choose an atom */
|
9264
|
+
if ( at[i].sb_parity[0] || at[i].p_parity || at[i].charge ||
|
9265
|
+
!at[i].num_H || at[i].radical || bHasChargedNeighbor( at, i ) ) {
|
9266
|
+
continue;
|
9267
|
+
}
|
9268
|
+
/* try to remove a proton and check whether InChI would add it back */
|
9269
|
+
at[i].charge --;
|
9270
|
+
at[i].num_H --;
|
9271
|
+
type = GetAtomChargeType( at, i, NULL, &mask, 0 );
|
9272
|
+
at[i].charge ++;
|
9273
|
+
at[i].num_H ++;
|
9274
|
+
|
9275
|
+
if ( type ) {
|
9276
|
+
for ( bSuccess = 0, j = 0; j < max_j_Aa; j ++ ) {
|
9277
|
+
if ( bSuccess = (type & AaTypMask[2*j]) && (mask && AaTypMask[2*j+1]) ) {
|
9278
|
+
break; /* the proton may be added to this atom */
|
9279
|
+
}
|
9280
|
+
}
|
9281
|
+
if ( bSuccess ) {
|
9282
|
+
type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* subtract at[i] */
|
9283
|
+
at[i].charge --;
|
9284
|
+
at[i].num_H --;
|
9285
|
+
type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add changed at[i] */
|
9286
|
+
num_prot ++; /* success */
|
9287
|
+
nNumSuccess ++;
|
9288
|
+
}
|
9289
|
+
}
|
9290
|
+
}
|
9291
|
+
}
|
9292
|
+
if ( num_prot < 0 && num_tg && nAtTypeTotals[ATTOT_TOT_CHARGE]-nNumProtAddedByRestr <= 0 ) {
|
9293
|
+
/* alternative proton removal: O=C-NH => (-)O-C=N, O and N are taut. endpoints */
|
9294
|
+
int endp2, centp, k, i0, k0;
|
9295
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
9296
|
+
/* choose an atom */
|
9297
|
+
if ( !at[i].endpoint || at[i].sb_parity[0] || at[i].p_parity ||
|
9298
|
+
at[i].radical || at[i].charge || bHasChargedNeighbor( at, i ) ) {
|
9299
|
+
continue;
|
9300
|
+
}
|
9301
|
+
/* looking for tautomeric =O */
|
9302
|
+
if ( 1 != at[i].valence || BOND_TYPE_DOUBLE != at[i].bond_type[0] || at[i].num_H ||
|
9303
|
+
2 != get_endpoint_valence( at[i].el_number ) ) {
|
9304
|
+
continue;
|
9305
|
+
}
|
9306
|
+
centp = at[i].neighbor[0];
|
9307
|
+
if ( at[centp].sb_parity[0] || at[centp].p_parity || !is_centerpoint_elem( at[centp].el_number ) ) {
|
9308
|
+
continue;
|
9309
|
+
}
|
9310
|
+
/* found a possible centerpoint, looking for -NH endpoint */
|
9311
|
+
for ( k = 0; k < at[centp].valence; k ++ ) {
|
9312
|
+
if ( at[centp].bond_type[k] != BOND_TYPE_SINGLE ) {
|
9313
|
+
continue;
|
9314
|
+
}
|
9315
|
+
endp2 = at[centp].neighbor[k];
|
9316
|
+
if ( at[endp2].endpoint != at[i].endpoint ||
|
9317
|
+
!at[endp2].num_H || at[endp2].charge ||
|
9318
|
+
at[endp2].sb_parity[0] || at[endp2].p_parity ||
|
9319
|
+
at[endp2].valence != at[endp2].chem_bonds_valence ||
|
9320
|
+
3 != at[endp2].chem_bonds_valence + at[endp2].num_H ||
|
9321
|
+
3 != get_endpoint_valence( at[endp2].el_number ) ) {
|
9322
|
+
continue;
|
9323
|
+
}
|
9324
|
+
/* find bonds in reciprocal ajacency lists */
|
9325
|
+
for ( i0 = 0; i0 < at[centp].valence && i != at[centp].neighbor[i0]; i0 ++ )
|
9326
|
+
;
|
9327
|
+
for ( k0 = 0; k0 < at[endp2].valence && centp != at[endp2].neighbor[k0]; k0 ++ )
|
9328
|
+
;
|
9329
|
+
if ( i0 == at[centp].valence || k0 == at[endp2].valence ) {
|
9330
|
+
return RI_ERR_PROGR;
|
9331
|
+
}
|
9332
|
+
/* -NH has been found */
|
9333
|
+
type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* subtract at[i] */
|
9334
|
+
type = GetAtomChargeType( at, endp2, nAtTypeTotals, &mask, 1 ); /* subtract at[endp2] */
|
9335
|
+
|
9336
|
+
at[i].bond_type[0] --;
|
9337
|
+
at[centp].bond_type[i0] --;
|
9338
|
+
at[i].chem_bonds_valence --;
|
9339
|
+
at[i].charge --;
|
9340
|
+
|
9341
|
+
at[endp2].bond_type[k0] ++;
|
9342
|
+
at[centp].bond_type[k] ++;
|
9343
|
+
at[endp2].chem_bonds_valence ++;
|
9344
|
+
at[endp2].num_H --;
|
9345
|
+
|
9346
|
+
num_prot ++;
|
9347
|
+
nNumSuccess ++;
|
9348
|
+
|
9349
|
+
type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add at[i] */
|
9350
|
+
type = GetAtomChargeType( at, endp2, nAtTypeTotals, &mask, 0 ); /* add at[endp2] */
|
9351
|
+
}
|
9352
|
+
}
|
9353
|
+
}
|
9354
|
+
if ( num_prot > 0 ) {
|
9355
|
+
/* add protons */
|
9356
|
+
/* 1. Use test from SimpleRemoveAcidicProtons() to test whether addition of H(+) to =C-O(-), etc. is correct */
|
9357
|
+
for ( i = 0; i < num_atoms && num_prot && nAtTypeTotals[ATTOT_TOT_CHARGE]-nNumProtAddedByRestr >= 0; i ++ ) {
|
9358
|
+
/* choose an atom */
|
9359
|
+
if ( at[i].sb_parity[0] || at[i].p_parity || at[i].num_H ||
|
9360
|
+
at[i].charge != -1 || at[i].radical || bHasChargedNeighbor( at, i ) ) {
|
9361
|
+
continue;
|
9362
|
+
}
|
9363
|
+
/* try to add a proton and check whether InChI would remove it back */
|
9364
|
+
at[i].charge ++;
|
9365
|
+
at[i].num_H ++;
|
9366
|
+
type = GetAtomChargeType( at, i, NULL, &mask, 0 );
|
9367
|
+
at[i].charge --;
|
9368
|
+
at[i].num_H --;
|
9369
|
+
|
9370
|
+
if ( type ) {
|
9371
|
+
for ( bSuccess = 0, j = 0; j < max_j_Ar; j ++ ) {
|
9372
|
+
if ( bSuccess = (type & ArTypMask[2*j]) && (mask && ArTypMask[2*j+1]) ) {
|
9373
|
+
break;
|
9374
|
+
}
|
9375
|
+
}
|
9376
|
+
if ( bSuccess ) {
|
9377
|
+
type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* subtract at[i] */
|
9378
|
+
at[i].charge ++;
|
9379
|
+
at[i].num_H ++;
|
9380
|
+
type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add changed at[i] */
|
9381
|
+
num_prot --; /* success */
|
9382
|
+
nNumSuccess ++;
|
9383
|
+
}
|
9384
|
+
}
|
9385
|
+
}
|
9386
|
+
/* 2. Use test from SimpleRemoveHplusNPO() */
|
9387
|
+
for ( i = 0; i < num_atoms && num_prot; i ++ ) {
|
9388
|
+
/* choose an atom */
|
9389
|
+
if ( at[i].sb_parity[0] || at[i].p_parity ||
|
9390
|
+
at[i].charge || at[i].radical || bHasChargedNeighbor( at, i ) ) {
|
9391
|
+
continue;
|
9392
|
+
}
|
9393
|
+
/* try to add a proton and check whether InChI would remove it back */
|
9394
|
+
at[i].num_H ++;
|
9395
|
+
at[i].charge ++;
|
9396
|
+
bSuccess = (PR_SIMPLE_TYP & (type = GetAtomChargeType( at, i, NULL, &mask, 0 )) ) &&
|
9397
|
+
(PR_SIMPLE_MSK & mask );
|
9398
|
+
at[i].num_H --; /* failed */
|
9399
|
+
at[i].charge --;
|
9400
|
+
if ( bSuccess ) {
|
9401
|
+
type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* subtract at[i] */
|
9402
|
+
at[i].num_H ++;
|
9403
|
+
at[i].charge ++;
|
9404
|
+
type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add changed at[i] */
|
9405
|
+
num_prot --; /* succeeded */
|
9406
|
+
nNumSuccess ++;
|
9407
|
+
}
|
9408
|
+
}
|
9409
|
+
}
|
9410
|
+
|
9411
|
+
if ( num_prot < 0 && (bNormalizationFlags & FLAG_PROTON_AC_HARD_ADDED) && 1 == num_tg &&
|
9412
|
+
nAtTypeTotals[ATTOT_TOT_CHARGE]-nNumProtAddedByRestr <= 0 ) {
|
9413
|
+
/* try to remove protons from tautomeric N (specific ADP must be present) */
|
9414
|
+
int nNumAcceptors_DB_O=0, nNumDonors_SB_NH=0, num_max, num_success;
|
9415
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
9416
|
+
/* choose an atom */
|
9417
|
+
if ( !at[i].endpoint || at[i].radical ||
|
9418
|
+
at[i].sb_parity[0] || at[i].p_parity || bHasChargedNeighbor( at, i ) ) {
|
9419
|
+
continue;
|
9420
|
+
}
|
9421
|
+
type = GetAtomChargeType( at, i, NULL, &mask, 0 );
|
9422
|
+
if ( (type & AA_HARD_TYP_CO) && (mask & AA_HARD_MSK_CO) ) {
|
9423
|
+
nNumAcceptors_DB_O ++;
|
9424
|
+
} else
|
9425
|
+
if ( (type == ATT_ATOM_N ) && (mask == ATBIT_NP_H) && !at[i].charge &&
|
9426
|
+
at[i].valence == at[i].chem_bonds_valence ) {
|
9427
|
+
nNumDonors_SB_NH ++;
|
9428
|
+
}
|
9429
|
+
}
|
9430
|
+
num_max = inchi_min( nNumAcceptors_DB_O, nNumDonors_SB_NH );
|
9431
|
+
for ( i = 0, num_success = 0; i < num_atoms && num_success < num_max && num_prot < 0; i ++ ) {
|
9432
|
+
/* choose an atom */
|
9433
|
+
if ( !at[i].endpoint|| at[i].radical || at[i].sb_parity[0] ||
|
9434
|
+
at[i].p_parity || bHasChargedNeighbor( at, i ) ) {
|
9435
|
+
continue;
|
9436
|
+
}
|
9437
|
+
type = GetAtomChargeType( at, i, NULL, &mask, 0 );
|
9438
|
+
if ( (type == ATT_ATOM_N ) && (mask == ATBIT_NP_H) && !at[i].charge &&
|
9439
|
+
at[i].valence == at[i].chem_bonds_valence ) {
|
9440
|
+
type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* subtract at[i] */
|
9441
|
+
at[i].num_H --;
|
9442
|
+
at[i].charge --;
|
9443
|
+
type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add changed at[i] */
|
9444
|
+
num_prot ++;
|
9445
|
+
num_success ++;
|
9446
|
+
nNumSuccess ++;
|
9447
|
+
}
|
9448
|
+
}
|
9449
|
+
}
|
9450
|
+
/*exit_function:*/
|
9451
|
+
*num_protons_to_add = num_prot;
|
9452
|
+
return ret<0? ret : nNumSuccess;
|
9453
|
+
}
|
9454
|
+
/*****************************************************************/
|
9455
|
+
int AddRemoveIsoProtonsRestr( inp_ATOM *at, int num_atoms, NUM_H num_protons_to_add[], int num_tg )
|
9456
|
+
{
|
9457
|
+
int i, j, k, n, ret = 0;
|
9458
|
+
int nNumSuccess = 0, min_at, max_at, num_H, num_iso_H, num_expl_H, num_expl_iso_H;
|
9459
|
+
int iCurIso; /* 0=> 1H, 1=> D, 2=> T */
|
9460
|
+
int iCurMode, iCurMode1, iCurMode2; /* 0=> Not Endpoints, 1=> Endpoints */
|
9461
|
+
static U_CHAR el_number_H = 0;
|
9462
|
+
|
9463
|
+
/* distribute isotopes from heaviest to lightest; pick up atoms in order 1. Not endpoints; 2. Endpoints */
|
9464
|
+
iCurMode1 = 0;
|
9465
|
+
iCurMode2 = num_tg ? 1 : 0;
|
9466
|
+
if ( !el_number_H ) {
|
9467
|
+
el_number_H = (U_CHAR) get_periodic_table_number( "H" );
|
9468
|
+
}
|
9469
|
+
for ( iCurMode = iCurMode1; iCurMode <= iCurMode2; iCurMode ++ ) {
|
9470
|
+
for ( iCurIso = 2; 0 <= iCurIso; iCurIso -- ) {
|
9471
|
+
/* check for isotopic H to add */
|
9472
|
+
if ( !num_protons_to_add[iCurIso] ) {
|
9473
|
+
continue;
|
9474
|
+
}
|
9475
|
+
if ( 0 > num_protons_to_add[iCurIso] ) {
|
9476
|
+
ret = RI_ERR_PROGR;
|
9477
|
+
goto exit_function;
|
9478
|
+
}
|
9479
|
+
/* limits for atom scanning */
|
9480
|
+
min_at = 0;
|
9481
|
+
max_at = num_atoms;
|
9482
|
+
/* cycle withio the limits */
|
9483
|
+
for ( i = min_at; i < max_at && 0 < num_protons_to_add[iCurIso]; i ++ ) {
|
9484
|
+
/* pick an atom */
|
9485
|
+
if ( iCurMode ) {
|
9486
|
+
if ( at[i].endpoint )
|
9487
|
+
j = i; /* atom number */
|
9488
|
+
else
|
9489
|
+
continue;
|
9490
|
+
} else
|
9491
|
+
if ( !at[i].endpoint &&
|
9492
|
+
1 == bHeteroAtomMayHaveXchgIsoH( at, i ) ) { /* atom number */
|
9493
|
+
j = i;
|
9494
|
+
} else
|
9495
|
+
if ( at[i].el_number == el_number_H && at[i].charge == 1 &&
|
9496
|
+
!at[i].valence && !at[i].radical && !at[i].iso_atw_diff ) {
|
9497
|
+
/* proton, not isotopic; make it isotopic */
|
9498
|
+
at[i].iso_atw_diff = 1 + iCurIso;
|
9499
|
+
num_protons_to_add[iCurIso] --;
|
9500
|
+
nNumSuccess ++;
|
9501
|
+
continue;
|
9502
|
+
} else {
|
9503
|
+
continue;
|
9504
|
+
}
|
9505
|
+
/* j is the atom number */
|
9506
|
+
/* count implicit H */
|
9507
|
+
num_H = at[j].num_H;
|
9508
|
+
num_iso_H = NUM_ISO_H(at,j);
|
9509
|
+
while ( num_H > 0 && num_protons_to_add[iCurIso] > 0 ) {
|
9510
|
+
/* substitute one implicit H with an isotopic atom H */
|
9511
|
+
at[j].num_iso_H[iCurIso] ++;
|
9512
|
+
at[j].num_H --;
|
9513
|
+
num_protons_to_add[iCurIso] --;
|
9514
|
+
num_H --;
|
9515
|
+
num_iso_H ++;
|
9516
|
+
nNumSuccess ++;
|
9517
|
+
}
|
9518
|
+
/* count explicit H */
|
9519
|
+
num_expl_H = num_expl_iso_H = 0;
|
9520
|
+
for ( k = 0; k < at[j].valence && num_atoms <= (n=at[j].neighbor[k]); k ++ ) {
|
9521
|
+
num_expl_H += (0 == at[n].iso_atw_diff);
|
9522
|
+
num_expl_iso_H += (0 != at[n].iso_atw_diff);
|
9523
|
+
}
|
9524
|
+
while ( num_expl_H > 0 && num_protons_to_add[iCurIso] > 0 ) {
|
9525
|
+
/* substitute one explicit H with an isotopic atom H */
|
9526
|
+
n = at[j].neighbor[num_expl_H];
|
9527
|
+
if ( at[n].iso_atw_diff ) {
|
9528
|
+
ret = RI_ERR_PROGR;
|
9529
|
+
goto exit_function;
|
9530
|
+
}
|
9531
|
+
at[n].iso_atw_diff = 1 + iCurIso;
|
9532
|
+
num_expl_H --;
|
9533
|
+
num_expl_iso_H ++;
|
9534
|
+
num_protons_to_add[iCurIso] --;
|
9535
|
+
nNumSuccess ++;
|
9536
|
+
}
|
9537
|
+
}
|
9538
|
+
}
|
9539
|
+
}
|
9540
|
+
exit_function:
|
9541
|
+
return ret<0? ret : nNumSuccess;
|
9542
|
+
}
|
9543
|
+
|
9544
|
+
#endif
|
7999
9545
|
|