rino 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|