Branch data Line data Source code
1 : : /*
2 : : * International Chemical Identifier (InChI)
3 : : * Version 1
4 : : * Software version 1.07
5 : : * April 30, 2024
6 : : *
7 : : * MIT License
8 : : *
9 : : * Copyright (c) 2024 IUPAC and InChI Trust
10 : : *
11 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
12 : : * of this software and associated documentation files (the "Software"), to deal
13 : : * in the Software without restriction, including without limitation the rights
14 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 : : * copies of the Software, and to permit persons to whom the Software is
16 : : * furnished to do so, subject to the following conditions:
17 : : *
18 : : * The above copyright notice and this permission notice shall be included in all
19 : : * copies or substantial portions of the Software.
20 : : *
21 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 : : * SOFTWARE.
28 : : *
29 : : * The InChI library and programs are free software developed under the
30 : : * auspices of the International Union of Pure and Applied Chemistry (IUPAC).
31 : : * Originally developed at NIST.
32 : : * Modifications and additions by IUPAC and the InChI Trust.
33 : : * Some portions of code were developed/changed by external contributors
34 : : * (either contractor or volunteer) which are listed in the file
35 : : * 'External-contributors' included in this distribution.
36 : : *
37 : : * info@inchi-trust.org
38 : : *
39 : : */
40 : :
41 : : #include <stdlib.h>
42 : : #include <string.h>
43 : :
44 : : /* */
45 : : /*#define CHECK_WIN32_VC_HEAP*/
46 : :
47 : : #include "mode.h"
48 : :
49 : : #if ( READ_INCHI_STRING == 1 )
50 : :
51 : : #include "ichitime.h"
52 : : #include "ichirvrs.h"
53 : : #include "ichicant.h"
54 : : #include "ichi_io.h"
55 : : /* djb-rwth: these two headers have to be included as well */
56 : : #include "ichimain.h"
57 : : #include "inpdef.h"
58 : :
59 : : #include "bcf_s.h"
60 : :
61 : : /**************************************************************************************************
62 : :
63 : : ChargeStruct fictitios structures MY_CONST CN_LIST cnList[*]
64 : : ============================================================
65 : :
66 : :
67 : : bond flow (+) => Positive charge c-group
68 : : ----------------- (-) => Negative charge c-group
69 : : Single 0 (+C) => Positive charge group for C, Si, Ge, Sn, Pb
70 : : Double 1 (-C) => Negative charge group for C, Si, Ge, Sn, Pb
71 : : Triple 2 (.) => additional one unit of st_cap
72 : :
73 : : A) Interpretation:
74 : :
75 : : X-(-) or X=(+) => zero charge
76 : : X=(-) or X-(+) => charge = -1 or +1, respectively
77 : :
78 : : B) Information to keep:
79 : :
80 : : ordering zero-based number of the edge
81 : : to (+) or (-) from the Interpretation (A) section
82 : :
83 : : vCap = vertex cap
84 : : vFlow = vertex flow
85 : : val = number of edges incident to the vertex
86 : : neigh = 1-based ordering number of the adjacent vertex; 0 => no more adjacent vertices
87 : : cap = cap of the edge to the adjacent vertex
88 : : flow = flow of the edge to the adjacent vertex
89 : :
90 : : atom (c-point) always has number 1
91 : : c-group(s) always are the last vertices
92 : : always adjacent_neigh_number > vertex_number, that is, neigh > vertex
93 : :
94 : : Contribution to the Total Charge:
95 : : ----------------------------------
96 : : edge_cap(+) - edge_flow(+) - edge_flow(-) - Delta(+) - Delta(-)
97 : :
98 : : where edge_cap(+) is edge capacity to c-group (+);
99 : : edge_flow(+) is edge capacity to c-group (?), (?)= (+) or (-);
100 : : Delta(?) = st_cap(?) - st_floe(?) of the c-group vertex (?), (?)= (+) or (-);
101 : :
102 : : ***************************************************************************************************/
103 : : /**************************************************************************************************
104 : :
105 : : Important:
106 : : vCap and vFlow Note: since metal charge group (vert. 2-4) MUST be registered before
107 : : marked with empty the "metal flower" (5-8) all charge group vertex numbers are
108 : : comments for vertices less than metal flower vertices: (2,3,4) < (5,6,7,8)
109 : : 1 and 5(M) should This MAY be neded for c-group enumeration. The order is:
110 : : be set separately t-groups, c-groups, M-flower. All types BNS_VT_M_GROUP allows to avoid duplications.
111 : :
112 : : 3(+)
113 : : || (Metal)
114 : : || \|/ init charge=0; MAX_METAL_CHARGE = 16
115 : : 4(-) 5(M) 2 -Fe- CAP(BOND_TO_BNS_VT_M_GROUP) = NUM_BONDS*CAP
116 : : \ | / |
117 : : \ | /
118 : : 1 X(V), V=valence
119 : : */
120 : : MY_CONST C_NODE cnMe[5] = {
121 : : /* vertex type vCap vFlow val; neigh cap flow; neigh cap flow; neigh cap flow vertex */
122 : : { {BNS_VERT_TYPE_ATOM,0/**/ ,0/**/,3}, {{ 2, 16,0, 0 },{ 4, 16,0, 0 }, { 0, 0,0, 0 }} }, /* 1 */
123 : : { {BNS_VT_CHRG_STRUCT,16, 16, 2}, {{ 3, 16,0,16 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 2 */
124 : : { {BNS_VT_C_POS_M, 16, 16, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 2 }, { 0, 0,0, 0 }} }, /* 3 */
125 : : { {BNS_VT_C_NEG_M, 0 + 16, 0, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 4 */
126 : : { {BNS_VT_M_GROUP, 0/**/ ,0/**/,3}, {{ 1, 3,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 5 */
127 : : };
128 : : /*
129 : : #define cn_bits_Me (-1)
130 : : */
131 : :
132 : : /**************************************************************************************************
133 : : c=2 5(+.)
134 : : _____ / (PNPN)
135 : : 4=====3 |||| init charge=0
136 : : c=2 \ / c=1 -N-
137 : : 2 |
138 : : ||||
139 : : 1 X+(V), X(V+1), X+(V+2), X(V+3); V=valence
140 : : */
141 : : MY_CONST C_NODE cnPNPN[5] = {
142 : : /* vertex type vCap vFlow val; neigh cap flow; neigh cap flow; neigh cap flow vertex */
143 : : { {BNS_VERT_TYPE_ATOM, 3, 3, 1}, {{ 2, 3,0, 3 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 1 */
144 : : { {BNS_VT_CHRG_STRUCT, 3, 3, 3}, {{ 3, 1,0, 0 },{ 4, 2,0, 0 }, { 0, 0,0, 0 }} }, /* 2 */
145 : : { {BNS_VT_CHRG_STRUCT, 2, 2, 3}, {{ 5, 1,0, 0 },{ 4, 2,0, 2 }, { 0, 0,0, 0 }} }, /* 3 */
146 : : { {BNS_VT_CHRG_STRUCT, 2, 2, 2}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 4 */
147 : : { {BNS_VT_C_POS, 1 + 1, 0, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 5 */
148 : : };
149 : : /*
150 : : #define cn_bits_PNPN MAKE_CN_BITS(cn_bits_P, cn_bits_N, cn_bits_P, cn_bits_N)
151 : : */
152 : : /**************************************************************************************************
153 : : 5(+)
154 : : c=1 // (NPNP)
155 : : 4=====3 |||| init charge=0
156 : : c=1 \ / c=2 -N-
157 : : 2 |
158 : : ||||
159 : : 1 X(V), X+(V+1), X(V+2), X+(V+3); V=valence
160 : : */
161 : : MY_CONST C_NODE cnNPNP[5] = {
162 : : /* vertex type vCap vFlow val; neigh cap flow; neigh cap flow; neigh cap flow vertex */
163 : : { {BNS_VERT_TYPE_ATOM, 3, 3, 1}, {{ 2, 3,0, 3 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 1 */
164 : : { {BNS_VT_CHRG_STRUCT, 3, 3, 3}, {{ 3, 2,0, 0 },{ 4, 1,0, 0 }, { 0, 0,0, 0 }} }, /* 2 */
165 : : { {BNS_VT_CHRG_STRUCT, 2, 2, 3}, {{ 5, 1,0, 1 },{ 4, 1,0, 1 }, { 0, 0,0, 0 }} }, /* 3 */
166 : : { {BNS_VT_CHRG_STRUCT, 1, 1, 2}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 4 */
167 : : { {BNS_VT_C_POS, 0 + 1, 1, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 5 */
168 : : };
169 : : /*
170 : : #define cn_bits_NPNP MAKE_CN_BITS(cn_bits_N, cn_bits_P, cn_bits_N, cn_bits_P)
171 : : */
172 : : /********************* end new ********************************************************************/
173 : :
174 : :
175 : : /**************************************************************************************************
176 : : 5(+)
177 : : // (NPN)
178 : : 4=====3 ||| init charge=0
179 : : \ / -N-
180 : : 2 |
181 : : |||
182 : : 1 X(V), X+(V+1), X(V+2); V=valence
183 : : */
184 : : MY_CONST C_NODE cnNPN[5] = {
185 : : /* vertex type vCap vFlow val; neigh cap flow; neigh cap flow; neigh cap flow vertex */
186 : : { {BNS_VERT_TYPE_ATOM, 2, 2, 1}, {{ 2, 2,0, 2 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 1 */
187 : : { {BNS_VT_CHRG_STRUCT, 2, 2, 3}, {{ 3, 1,0, 0 },{ 4, 1,0, 0 }, { 0, 0,0, 0 }} }, /* 2 */
188 : : { {BNS_VT_CHRG_STRUCT, 2, 2, 3}, {{ 5, 1,0, 1 },{ 4, 1,0, 1 }, { 0, 0,0, 0 }} }, /* 3 */
189 : : { {BNS_VT_CHRG_STRUCT, 1, 1, 2}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 4 */
190 : : { {BNS_VT_C_POS, 1, 1, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 5 */
191 : : };
192 : : /*
193 : : #define cn_bits_NPN MAKE_CN_BITS(cn_bits_N, cn_bits_P, cn_bits_N, 0)
194 : : */
195 : : /**************************************************************************************************
196 : : 5(+.)
197 : : / (PNP)
198 : : 4=====3 ||| init charge=0
199 : : \ / -Cl-
200 : : 2 /\
201 : : |||
202 : : 1 X+(V), X(V+1), X+(V+2); V=valence
203 : : */
204 : : MY_CONST C_NODE cnPNP[5] = {
205 : : /* vertex type vCap vFlow val; neigh cap flow; neigh cap flow; neigh cap flow vertex */
206 : : { {BNS_VERT_TYPE_ATOM, 2, 2, 1}, {{ 2, 2,0, 2 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 1 */
207 : : { {BNS_VT_CHRG_STRUCT, 2, 2, 3}, {{ 3, 1,0, 0 },{ 4, 1,0, 0 }, { 0, 0,0, 0 }} }, /* 2 */
208 : : { {BNS_VT_CHRG_STRUCT, 1, 1, 3}, {{ 5, 1,0, 0 },{ 4, 1,0, 1 }, { 0, 0,0, 0 }} }, /* 3 */
209 : : { {BNS_VT_CHRG_STRUCT, 1, 1, 2}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 4 */
210 : : { {BNS_VT_C_POS, 1 + 1, 0, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 5 */
211 : : };
212 : : /*
213 : : #define cn_bits_PNP MAKE_CN_BITS(cn_bits_P, cn_bits_N, cn_bits_P, 0)
214 : : */
215 : : /**************************************************************************************************
216 : :
217 : : (MNP)
218 : : \ / init charge=0
219 : : N(.)
220 : : 3(-) 2(+) / \
221 : : \ //
222 : : 1(.) X-(V), X(V+1), X+(V+2); V=valence
223 : : */
224 : : MY_CONST C_NODE cnMNP[3] = {
225 : : /* vertex type vCap vFlow val; neigh cap flow; neigh cap flow; neigh cap flow vertex */
226 : : { {BNS_VERT_TYPE_ATOM, 2, 1, 2}, {{ 2, 1,0, 1 },{ 3, 1,0, 0 }, { 0, 0,0, 0 }} }, /* 1 */
227 : : { {BNS_VT_C_POS, 1, 1, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 2 */
228 : : { {BNS_VT_C_NEG, 0 + 1, 0, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} } /* 3 */
229 : : };
230 : : /*
231 : : #define cn_bits_MNP MAKE_CN_BITS(cn_bits_M, cn_bits_N, cn_bits_P, 0)
232 : : */
233 : : #ifdef NEVER
234 : : /************************** not used **************************************************************
235 : : (PNM)
236 : : 5(-) 4(+) \\ /
237 : : \ // B(.) init charge=0
238 : : 3 2 / \
239 : : \\ /
240 : : 1(.) X+(V), X(V+1), X+(V+2); V=valence
241 : : */
242 : : MY_CONST C_NODE cnPNM[5] = {
243 : : /* vertex type vCap vFlow val; neigh cap flow; neigh cap flow; neigh cap flow vertex */
244 : : { {BNS_VERT_TYPE_ATOM, 2, 1, 2}, {{ 2, 1,0, 0 },{ 3, 1,0, 1 }, { 0, 0,0, 0 }} }, /* 1 */
245 : : { {BNS_VT_CHRG_STRUCT, 1, 1, 2}, {{ 4, 1,0, 1 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 2 */
246 : : { {BNS_VT_CHRG_STRUCT, 1, 1, 2}, {{ 5, 1,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 3 */
247 : : { {BNS_VT_C_POS, 1, 1, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 4 */
248 : : { {BNS_VT_C_NEG, 0 + 1, 0, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 5 */
249 : : };
250 : :
251 : : #define cn_bits_PNM MAKE_CN_BITS(cn_bits_P, cn_bits_N, cn_bits_M, 0)
252 : :
253 : : #endif
254 : :
255 : : /**************************************************************************************************
256 : : 4(-) 3(+.) (PNM)
257 : : \ / ||| init charge=0
258 : : 2 --P--
259 : : ||| / \
260 : : 1 X-(V), X(V+1), X+(V+2); V=valence
261 : : */
262 : : MY_CONST C_NODE cnPNM[4] = {
263 : : /* vertex type vCap vFlow val; neigh cap flow; neigh cap flow; neigh cap flow vertex */
264 : : { {BNS_VERT_TYPE_ATOM, 2, 2, 1}, {{ 2, 2,0, 2 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 1 */
265 : : { {BNS_VT_CHRG_STRUCT, 2, 2, 3}, {{ 3, 1,0, 0 },{ 4, 1,0, 0 }, { 0, 0,0, 0 }} }, /* 2 */
266 : : { {BNS_VT_C_POS, 1 + 1, 0, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 3 */
267 : : { {BNS_VT_C_NEG, 0 + 1, 0, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 4 */
268 : : }; /* explanaton of vCap: ^ ^ */
269 : : /* additional dot:/ \ capacity of the edge to (+) or (-) vertex */
270 : : /*
271 : : #define cn_bits_PNM MAKE_CN_BITS(cn_bits_P, cn_bits_N, cn_bits_M, 0)
272 : : */
273 : : /**************************************************************************************************
274 : : 5(+C)
275 : : // init charge=0
276 : : 6(-C) 4
277 : : \ / (EN) E=either +1 or -1
278 : : 3 |
279 : : || -C(.)-
280 : : 2 |
281 : : |
282 : : 1(.) X-(V), X+(V), X(V+1); V=valence
283 : : */
284 : : MY_CONST C_NODE cnEN[6] = {
285 : : /* vertex type vCap vFlow val; neigh cap flow; neigh cap flow; neigh cap flow vertex */
286 : : { {BNS_VERT_TYPE_ATOM, 1, 0, 1}, {{ 2, 1,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 1 */
287 : : { {BNS_VT_CHRG_STRUCT, 1, 1, 2}, {{ 3, 1,0, 1 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 2 */
288 : : { {BNS_VT_CHRG_STRUCT, 1, 1, 3}, {{ 4, 1,0, 0 },{ 6, 1,0, 0 }, { 0, 0,0, 0 }} }, /* 3 */
289 : : { {BNS_VT_CHRG_STRUCT, 1, 1, 2}, {{ 5, 1,0, 1 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 4 */
290 : : { {BNS_VT_C_POS_C, 0 + 1, 1, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 5 */
291 : : { {BNS_VT_C_NEG_C, 0 + 1, 0, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} } /* 6 */
292 : : };
293 : : /*
294 : : #define cn_bits_EN MAKE_CN_BITS(cn_bits_P | cn_bits_M, cn_bits_N, 0, 0)
295 : : */
296 : : /**************************************************************************************************
297 : : 5(-)
298 : : / (NMN) init charge=0
299 : : 4=====3 |||
300 : : \ / -X-
301 : : 2 /\
302 : : |||
303 : : 1 X(V), X-(V+1), X(V+2); V=valence
304 : : */
305 : : MY_CONST C_NODE cnNMN[5] = {
306 : : /* vertex type vCap vFlow val; neigh cap flow; neigh cap flow; neigh cap flow vertex */
307 : : { {BNS_VERT_TYPE_ATOM, 2, 2, 1}, {{ 2, 2,0, 2 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 1 */
308 : : { {BNS_VT_CHRG_STRUCT, 2, 2, 3}, {{ 3, 1,0, 0 },{ 4, 1,0, 0 }, { 0, 0,0, 0 }} }, /* 2 */
309 : : { {BNS_VT_CHRG_STRUCT, 1, 1, 3}, {{ 5, 1,0, 0 },{ 4, 1,0, 1 }, { 0, 0,0, 0 }} }, /* 3 */
310 : : { {BNS_VT_CHRG_STRUCT, 1, 1, 2}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 4 */
311 : : { {BNS_VT_C_NEG, 0 + 1, 0, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} } /* 5 */
312 : : };
313 : : /*
314 : : #define cn_bits_NMN MAKE_CN_BITS(cn_bits_N, cn_bits_M, cn_bits_N, 0)
315 : : */
316 : : /**************************************************************************************************
317 : : 4(+)
318 : : // (NE) E=either +1 or -1
319 : : 5(-) 3 ||
320 : : \ / -X- init charge=0
321 : : 2 |
322 : : ||
323 : : 1 X(V), X+(V+1), X-(V+1); V=valence
324 : : */
325 : : MY_CONST C_NODE cnNE[5] = {
326 : : /* vertex type vCap vFlow val; neigh cap flow; neigh cap flow; neigh cap flow vertex */
327 : : { {BNS_VERT_TYPE_ATOM, 1, 1, 1}, {{ 2, 1,0, 1 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 1 */
328 : : { {BNS_VT_CHRG_STRUCT, 1, 1, 3}, {{ 3, 1,0, 0 },{ 5, 1,0, 0 }, { 0, 0,0, 0 }} }, /* 2 */
329 : : { {BNS_VT_CHRG_STRUCT, 1, 1, 2}, {{ 4, 1,0, 1 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 3 */
330 : : { {BNS_VT_C_POS, 0 + 1, 1, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 4 */
331 : : { {BNS_VT_C_NEG, 0 + 1, 0, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} } /* 5 */
332 : : };
333 : : /*
334 : : #define cn_bits_NE MAKE_CN_BITS(cn_bits_N, cn_bits_P | cn_bits_M, 0, 0)
335 : : */
336 : : /**************************************************************************************************
337 : : 6(-) 5(+)
338 : : \ // (NEN)
339 : : 4=====3 ||| init charge=0
340 : : \ / -X-
341 : : 2 |
342 : : |||
343 : : 1 X(V), X+(V+1), X-(V+1), X(V+2); V=valence
344 : : */
345 : : MY_CONST C_NODE cnNEN[6] = {
346 : : /* vertex type vCap vFlow val; neigh cap flow; neigh cap flow; neigh cap flow vertex */
347 : : { {BNS_VERT_TYPE_ATOM, 2, 2, 1}, {{ 2, 2,0, 2 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 1 */
348 : : { {BNS_VT_CHRG_STRUCT, 2, 2, 3}, {{ 3, 1,0, 0 },{ 4, 1,0, 0 }, { 0, 0,0, 0 }} }, /* 2 */
349 : : { {BNS_VT_CHRG_STRUCT, 2, 2, 3}, {{ 5, 1,0, 1 },{ 4, 1,0, 1 }, { 0, 0,0, 0 }} }, /* 3 */
350 : : { {BNS_VT_CHRG_STRUCT, 1, 1, 3}, {{ 6, 1,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 4 */
351 : : { {BNS_VT_C_POS, 0 + 1, 1, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 5 */
352 : : { {BNS_VT_C_NEG, 0 + 1, 0, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 6 */
353 : : };
354 : : /*
355 : : #define cn_bits_NEN MAKE_CN_BITS(cn_bits_N, cn_bits_M | cn_bits_N, cn_bits_N, 0)
356 : : */
357 : : /*=======================================================*/
358 : : /**************************************************************************************************
359 : : (NP)
360 : : ||
361 : : -X- init charge=0
362 : : 2(+) |
363 : : ||
364 : : 1 X(V), X+(V+1); V=valence
365 : : */
366 : : MY_CONST C_NODE cnNP[2] = {
367 : : /* vertex type vCap vFlow val; neigh cap flow; neigh cap flow; neigh cap flow vertex */
368 : : { {BNS_VERT_TYPE_ATOM, 1, 1, 1}, {{ 2, 1,0, 1 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 1 */
369 : : { {BNS_VT_C_POS, 0 + 1, 1, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 2 */
370 : : };
371 : : /*
372 : : #define cn_bits_NP MAKE_CN_BITS(cn_bits_N, cn_bits_P, 0, 0)
373 : : */
374 : : /**************************************************************************************************
375 : : (PN)
376 : : 3(+.) || init charge=0 [because cap(+)-flow(+)-Delta=1-0-1=0]
377 : : | -X-
378 : : 2 |
379 : : ||
380 : : 1 X+(V), X(V+1); V=valence
381 : : */
382 : : MY_CONST C_NODE cnPN[3] = {
383 : : /* vertex type vCap vFlow val; neigh cap flow; neigh cap flow; neigh cap flow vertex */
384 : : { {BNS_VERT_TYPE_ATOM, 1, 1, 1}, {{ 2, 1,0, 1 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 1 */
385 : : { {BNS_VT_CHRG_STRUCT, 1, 1, 2}, {{ 3, 1,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 2 */
386 : : { {BNS_VT_C_POS, 1 + 1, 0, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 3 */
387 : : };
388 : : /*
389 : : #define cn_bits_PN MAKE_CN_BITS(cn_bits_P, cn_bits_N, 0, 0)
390 : : */
391 : : /**************************************************************************************************
392 : : (NM)
393 : : 3(-) || init charge=0
394 : : | -X-
395 : : 2 |
396 : : ||
397 : : 1 X(V), X-(V+1); V=valence
398 : : */
399 : : MY_CONST C_NODE cnNM[3] = {
400 : : /* vertex type vCap vFlow; val; neigh cap flow; neigh cap flow; neigh cap flow vertex */
401 : : { {BNS_VERT_TYPE_ATOM, 1, 1, 1}, {{ 2, 1,0, 1 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 1 */
402 : : { {BNS_VT_CHRG_STRUCT, 1, 1, 2}, {{ 3, 1,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 2 */
403 : : { {BNS_VT_C_NEG, 0 + 1, 0, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 3 */
404 : : };
405 : : /*
406 : : #define cn_bits_NM MAKE_CN_BITS(cn_bits_N, cn_bits_M, 0, 0)
407 : : */
408 : : /**************************************************************************************************
409 : : (MN)
410 : : |
411 : : -X- init charge=0
412 : : 2(-) |
413 : : |
414 : : 1(.) X-(V), X(V+1); V=valence
415 : : */
416 : : MY_CONST C_NODE cnMN[2] = {
417 : : /* vertex type vCap vFlow val; neigh cap flow; neigh cap flow; neigh cap flow vertex */
418 : : { {BNS_VERT_TYPE_ATOM, 1, 0, 1}, {{ 2, 1,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 1 */
419 : : { {BNS_VT_C_NEG, 0 + 1, 0, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 2 */
420 : : };
421 : : /*
422 : : #define cn_bits_MN MAKE_CN_BITS(cn_bits_M, cn_bits_N, 0, 0)
423 : : */
424 : : /**************************************************************************************************
425 : : (P)
426 : : |
427 : : -X- init charge=0
428 : : 2(+.) |
429 : : |
430 : : 1 X+(V); V=valence; all chemical (real) bonds to X have cap=0
431 : : */
432 : : MY_CONST C_NODE cnP_[2] = {
433 : : /* vertex type vCap vFlow val; neigh cap flow; neigh cap flow; neigh cap flow vertex */
434 : : { {BNS_VERT_TYPE_ATOM, 0, 0, 1}, {{ 2, 1,1, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 1 */
435 : : { {BNS_VT_C_POS, 1 + 1, 0, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 2 */
436 : : };
437 : : /*
438 : : #define cn_bits_P_ MAKE_CN_BITS(cn_bits_P, 0, 0, 0)
439 : : */
440 : : #ifdef NEVER
441 : : /**************************************************************************************************
442 : : (M)
443 : : |
444 : : -X- init charge=-1 on atom
445 : : 2(-) |
446 : : |
447 : : 1(.) X+(V); V=valence; all chemical (real) bonds to X have cap=0
448 : : */
449 : : MY_CONST C_NODE cnM_[2] = {
450 : : /* vertex type vCap vFlow val; neigh cap flow; neigh cap flow; neigh cap flow vertex */
451 : : { {BNS_VERT_TYPE_ATOM, 1, 0, 1}, {{ 2, 1,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 1 */
452 : : { {BNS_VT_C_NEG, 0 + 1, 0, 1}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 2 */
453 : : };
454 : : #endif
455 : :
456 : : MY_CONST C_NODE cnM_[1] = {
457 : : /* vertex type vCap vFlow val; neigh cap flow; neigh cap flow; neigh cap flow vertex */
458 : : { {BNS_VERT_TYPE_ATOM, 0, 0, 0}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 1 */
459 : : };
460 : : /*
461 : : #define cn_bits_M_ MAKE_CN_BITS(cn_bits_M, 0, 0, 0)
462 : : */
463 : : /**************************************************************************************************
464 : :
465 : :
466 : : -X- init charge=0
467 : : |
468 : :
469 : : 1 X(V); V=valence;
470 : : */
471 : : MY_CONST C_NODE cnN_[1] = {
472 : : /* vertex type vCap vFlow val; neigh cap flow; neigh cap flow; neigh cap flow vertex */
473 : : { {BNS_VERT_TYPE_ATOM, 0, 0, 0}, {{ 0, 0,0, 0 },{ 0, 0,0, 0 }, { 0, 0,0, 0 }} }, /* 1 */
474 : : };
475 : : /*
476 : : #define cn_bits_N_ MAKE_CN_BITS(cn_bits_N, 0, 0, 0)
477 : : */
478 : : /**************************************************************************************************/
479 : :
480 : :
481 : : MY_CONST CN_LIST cnList[] = {
482 : : {cnPNPN, cn_bits_PNPN, 0, sizeof( cnPNPN ) / sizeof( cnPNPN[0] )}, /* 0 */
483 : : {cnNPNP, cn_bits_NPNP, 0, sizeof( cnNPNP ) / sizeof( cnNPNP[0] )}, /* 1 */
484 : : {cnNPN, cn_bits_NPN, 0, sizeof( cnNPN ) / sizeof( cnNPN[0] )}, /* 2 */
485 : : {cnPNP, cn_bits_PNP, 0, sizeof( cnPNP ) / sizeof( cnPNP[0] )}, /* 3 */
486 : : {cnMNP, cn_bits_MNP, 0, sizeof( cnMNP ) / sizeof( cnMNP[0] )}, /* 4 */
487 : : {cnPNM, cn_bits_PNM, 0, sizeof( cnPNM ) / sizeof( cnPNM[0] )}, /* 5 */
488 : : {cnEN, cn_bits_EN , 0, sizeof( cnEN ) / sizeof( cnEN[0] )}, /* 6 */
489 : : {cnNMN, cn_bits_NMN, 0, sizeof( cnNMN ) / sizeof( cnNMN[0] )}, /* 7 */
490 : : {cnNE, cn_bits_NE , 0, sizeof( cnNE ) / sizeof( cnNE[0] )}, /* 8 */
491 : : {cnNEN, cn_bits_NEN, 0, sizeof( cnNEN ) / sizeof( cnNEN[0] )}, /* 9 */
492 : : {cnNP, cn_bits_NP, 0, sizeof( cnNP ) / sizeof( cnNP[0] )}, /* 10 */
493 : : {cnPN, cn_bits_PN, 0, sizeof( cnPN ) / sizeof( cnPN[0] )}, /* 11 */
494 : : {cnNM, cn_bits_NM, 0, sizeof( cnNM ) / sizeof( cnNM[0] )}, /* 12 */
495 : : {cnMN, cn_bits_MN, 0, sizeof( cnMN ) / sizeof( cnMN[0] )}, /* 13 */
496 : : {cnP_, cn_bits_P_, 0, sizeof( cnP_ ) / sizeof( cnP_[0] )}, /* 14 */
497 : : {cnM_, cn_bits_M_, -1, sizeof( cnM_ ) / sizeof( cnM_[0] )}, /* 15 */
498 : : {cnN_, cn_bits_N_, 0, sizeof( cnN_ ) / sizeof( cnN_[0] )}, /* 16 */
499 : : {cnMe, cn_bits_Me, 0, sizeof( cnMe ) / sizeof( cnMe[0] )} /* 17 */
500 : : };
501 : :
502 : : #define cnListIndexMe (17) /* index of {cnMe, cn_bits_Me,... } element of cnList[] */
503 : :
504 : : const int cnListNumEl = (int) ( sizeof( cnList ) / sizeof( cnList[0] ) );
505 : :
506 : :
507 : :
508 : : /****************************************************************************/
509 : 0 : void clear_t_group_info( T_GROUP_INFO *ti )
510 : : {
511 [ # # ]: 0 : if (!ti)
512 : : {
513 : 0 : return;
514 : : }
515 : : else
516 : : {
517 : 0 : T_GROUP *t_group = ti->t_group;
518 : 0 : int max_num_t_groups = ti->max_num_t_groups;
519 : 0 : AT_NUMB *tGroupNumber = ti->tGroupNumber;
520 : 0 : int num_t_groups = ti->num_t_groups;
521 : 0 : AT_NUMB *nEndpointAtomNumber = ti->nEndpointAtomNumber;
522 : 0 : int nNumEndpoints = ti->nNumEndpoints;
523 : 0 : AT_NUMB *nIsotopicEndpointAtomNumber = ti->nIsotopicEndpointAtomNumber;
524 : 0 : int nNumIsotopicEndpoints = ti->nNumIsotopicEndpoints;
525 : 0 : memset( ti, 0, sizeof( *ti ) ); /* djb-rwth: memset_s C11/Annex K variant? */
526 [ # # ]: 0 : if (t_group)
527 : : {
528 : 0 : memset( t_group, 0, sizeof( t_group[0] )*max_num_t_groups ); /* djb-rwth: memset_s C11/Annex K variant? */
529 : : }
530 : : else
531 : : {
532 : 0 : max_num_t_groups = 0;
533 : : }
534 [ # # ]: 0 : if (tGroupNumber)
535 : : {
536 : 0 : memset( tGroupNumber, 0, sizeof( tGroupNumber[0] )*num_t_groups ); /* djb-rwth: memset_s C11/Annex K variant? */
537 : : }
538 : : else
539 : : {
540 : 0 : num_t_groups = 0;
541 : : }
542 [ # # ]: 0 : if (nEndpointAtomNumber)
543 : : {
544 : 0 : memset( nEndpointAtomNumber, 0, sizeof( nEndpointAtomNumber[0] )*nNumEndpoints ); /* djb-rwth: memset_s C11/Annex K variant? */
545 : : }
546 : : else
547 : : {
548 : 0 : nNumEndpoints = 0;
549 : : }
550 [ # # ]: 0 : if (nIsotopicEndpointAtomNumber)
551 : : {
552 : 0 : memset( nIsotopicEndpointAtomNumber, 0, sizeof( nIsotopicEndpointAtomNumber[0] )*nNumIsotopicEndpoints ); /* djb-rwth: memset_s C11/Annex K variant? */
553 : : }
554 : : else
555 : : {
556 : 0 : nNumIsotopicEndpoints = 0;
557 : : }
558 : :
559 : 0 : ti->t_group = t_group;
560 : 0 : ti->max_num_t_groups = max_num_t_groups;
561 : 0 : ti->tGroupNumber = tGroupNumber;
562 : 0 : ti->num_t_groups = num_t_groups;
563 : 0 : ti->nEndpointAtomNumber = nEndpointAtomNumber;
564 : 0 : ti->nNumEndpoints = nNumEndpoints;
565 : 0 : ti->nIsotopicEndpointAtomNumber = nIsotopicEndpointAtomNumber;
566 : :
567 : 0 : ti->nNumIsotopicEndpoints = nNumIsotopicEndpoints;
568 : : }
569 : :
570 : 0 : return;
571 : : }
572 : :
573 : :
574 : : /****************************************************************************/
575 : 0 : int GetTgroupInfoFromInChI( T_GROUP_INFO *ti,
576 : : inp_ATOM *at,
577 : : AT_NUMB *endpoint,
578 : : INChI *pInChI )
579 : : {
580 : : int ret, i, j, k, itg, num_atoms, len_tg, num_t_groups; /* djb-rwth: removing redundant variables */
581 : 0 : AT_NUMB *tGroupNumber = NULL;
582 : : /* djb-rwth: removing redundant variables */
583 : 0 : AT_NUMB *tiGroupNumber = NULL;
584 : :
585 : 0 : ret = 0;
586 : :
587 : 0 : clear_t_group_info( ti );
588 [ # # # # ]: 0 : if (pInChI && pInChI->lenTautomer > 1 &&
589 [ # # # # ]: 0 : pInChI->nTautomer && pInChI->nTautomer[0] > 0)
590 : : {
591 : 0 : num_atoms = pInChI->nNumberOfAtoms;
592 : : /* djb-rwth: removing redundant code */
593 : 0 : num_t_groups = pInChI->nTautomer[0];
594 : 0 : len_tg = pInChI->lenTautomer - T_GROUP_HDR_LEN*pInChI->nTautomer[0] - 1; /* number of endpoints */
595 : :
596 : : /* allocation ti->t_group */
597 [ # # # # ]: 0 : if (ti->max_num_t_groups != num_atoms / 2 + 1 || !ti->t_group)
598 : : {
599 : 0 : ti->max_num_t_groups = num_atoms / 2 + 1;
600 [ # # ]: 0 : if (ti->t_group)
601 [ # # ]: 0 : inchi_free( ti->t_group );
602 : 0 : ti->t_group = (T_GROUP *) inchi_calloc( (long long)ti->max_num_t_groups + 1, sizeof( ti->t_group[0] ) ); /* djb-rwth: correcting 0 bytes allocation */
603 : : }
604 : :
605 : : /* allocation ti->tGroupNumber */
606 [ # # # # ]: 0 : if (ti->num_t_groups != num_t_groups || !ti->tGroupNumber)
607 : : {
608 : 0 : ti->num_t_groups = num_t_groups;
609 [ # # ]: 0 : if (ti->tGroupNumber)
610 [ # # ]: 0 : inchi_free( ti->tGroupNumber );
611 : 0 : ti->tGroupNumber = (AT_NUMB *) inchi_calloc( ( (long long)ti->num_t_groups + 1 )*TGSO_TOTAL_LEN, sizeof( ti->tGroupNumber[0] ) ); /* djb-rwth: cast operator added */
612 : : }
613 : :
614 : : /* allocation ti->tGroupNumber */
615 [ # # # # ]: 0 : if (len_tg != ti->nNumEndpoints || !ti->nEndpointAtomNumber)
616 : : {
617 : 0 : ti->nNumEndpoints = len_tg;
618 [ # # ]: 0 : if (ti->nEndpointAtomNumber)
619 [ # # ]: 0 : inchi_free( ti->nEndpointAtomNumber );
620 : 0 : ti->nEndpointAtomNumber = (AT_NUMB *) inchi_calloc( (long long)len_tg + 1, sizeof( ti->nEndpointAtomNumber[0] ) ); /* djb-rwth: cast operator added */
621 : : }
622 : :
623 : : /* check */
624 [ # # # # : 0 : if (!ti->t_group || !ti->tGroupNumber || !ti->nEndpointAtomNumber)
# # ]
625 : : {
626 : 0 : ret = RI_ERR_ALLOC;
627 : 0 : goto exit_function;
628 : : }
629 : :
630 : 0 : tGroupNumber = ti->tGroupNumber;
631 : : /* djb-rwth: removing redundant code */
632 : 0 : tiGroupNumber = tGroupNumber + TGSO_SYMM_IORDER * (long long)ti->num_t_groups; /* djb-rwth: cast operator added */
633 : :
634 : :
635 : : INCHI_HEAPCHK
636 : :
637 : 0 : j = 1; /* index in pInChI->nTautomer[] */
638 : 0 : i = 0; /* index in ti->nEndpointAtomNumber[] */
639 : :
640 : : /* djb-rwth: fixing oss-fuzz issues #67681, #67641 */
641 [ # # # # ]: 0 : for (itg = 0; itg < pInChI->nTautomer[0] && itg <= ti->max_num_t_groups; itg++)
642 : : {
643 : 0 : len_tg = pInChI->nTautomer[j]; /* t-group length not including pInChI->nTautomer[j] */
644 : 0 : ti->t_group[itg].num[0] = pInChI->nTautomer[j + 1] + pInChI->nTautomer[j + 2]; /* num mobile H & (-) */
645 : 0 : ti->t_group[itg].num[1] = pInChI->nTautomer[j + 2]; /* num mobile (-) */
646 : 0 : tGroupNumber[itg] = tiGroupNumber[itg] = itg; /* index */
647 : 0 : ti->t_group[itg].nGroupNumber = /*tSymmRank[itg] = tiSymmRank[itg] =*/ itg + 1; /* t-group number */
648 : 0 : j += T_GROUP_HDR_LEN; /* skip t-group header */
649 : 0 : len_tg -= T_GROUP_HDR_LEN - 1;
650 : :
651 : 0 : ti->t_group[itg].nNumEndpoints = len_tg;
652 : 0 : ti->t_group[itg].nFirstEndpointAtNoPos = i;
653 : :
654 [ # # ]: 0 : while (len_tg > 0)
655 : : {
656 : 0 : k = ti->nEndpointAtomNumber[i] = pInChI->nTautomer[j] - 1; /* djb-rwth: buffer overrun avoided implicitly in loop condition */
657 : : #if ( FIX_GAF_2019_1==1 )
658 [ # # # # ]: 0 : if (k<0 || k>num_atoms)
659 : : {
660 : 0 : ret = RI_ERR_PROGR;
661 : 0 : goto exit_function;
662 : : }
663 : : #endif
664 [ # # ]: 0 : if (at)
665 : : {
666 : 0 : at[k].endpoint = itg + 1;
667 : : }
668 [ # # ]: 0 : if (endpoint)
669 : : {
670 : 0 : endpoint[k] = itg + 1;
671 : : }
672 : 0 : len_tg--;
673 : 0 : j++;
674 : 0 : i++;
675 : : }
676 : : }
677 : :
678 [ # # ]: 0 : if (i != ti->nNumEndpoints)
679 : : {
680 : 0 : ret = RI_ERR_PROGR;
681 : : }
682 : :
683 : : INCHI_HEAPCHK
684 : : }
685 : :
686 : 0 : exit_function:
687 : 0 : return ret;
688 : : }
689 : :
690 : :
691 : : /****************************************************************************/
692 : 0 : int FillOutpStructEndpointFromInChI( INChI *pInChI, AT_NUMB **pEndpoint )
693 : : {
694 : 0 : int num_at = pInChI->nNumberOfAtoms;
695 : 0 : AT_NUMB *endpoint = *pEndpoint;
696 : : int itg, i, j, k, len_tg;
697 : :
698 [ # # # # ]: 0 : if (!endpoint && !( endpoint = (AT_NUMB*) inchi_malloc( num_at * sizeof( endpoint[0] ) ) ))
699 : : {
700 : 0 : return RI_ERR_ALLOC;
701 : : }
702 : :
703 : 0 : memset( endpoint, 0, num_at * sizeof( endpoint[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
704 [ # # # # ]: 0 : if (pInChI->lenTautomer <= 1 || !pInChI->nTautomer)
705 : : {
706 : 0 : goto exit_function;
707 : : }
708 : :
709 : 0 : j = 1; /* index in pInChI->nTautomer[] */
710 : 0 : i = 0; /* index in ti->nEndpointAtomNumber[] */
711 [ # # ]: 0 : for (itg = 0; itg < pInChI->nTautomer[0]; itg++)
712 : : {
713 : 0 : len_tg = pInChI->nTautomer[j]; /* t-group length not including pInChI->nTautomer[j] */
714 : 0 : j += T_GROUP_HDR_LEN; /* skip t-group header */
715 : 0 : len_tg -= T_GROUP_HDR_LEN - 1;
716 : : /* ti->t_group[itg].nNumEndpoints = len_tg; */
717 [ # # ]: 0 : for (; 0 < len_tg--; j++, i++)
718 : : {
719 : 0 : k = pInChI->nTautomer[j] - 1;
720 : 0 : endpoint[k] = itg + 1;
721 : : }
722 : : }
723 : :
724 : 0 : exit_function:
725 : 0 : *pEndpoint = endpoint;
726 : :
727 : 0 : return 0;
728 : : }
729 : :
730 : :
731 : : /************************************************************************************/
732 : 0 : int cmp_charge_val( const void *a1, const void *a2, void *p )
733 : : {
734 : 0 : const CHARGE_VAL *p1 = (const CHARGE_VAL *) a1;
735 : 0 : const CHARGE_VAL *p2 = (const CHARGE_VAL *) a2;
736 : : int diff;
737 : :
738 [ # # ]: 0 : if ((diff = (int) p1->nValence - (int) p2->nValence)) /* smaller valence first */ /* djb-rwth: addressing LLVM warning */
739 : 0 : return diff;
740 [ # # ]: 0 : if ((diff = abs( (int) p1->nCharge ) - abs( (int) p2->nCharge ))) /* smaller abs charge first */ /* djb-rwth: addressing LLVM warning */
741 : 0 : return diff;
742 [ # # ]: 0 : if ((diff = (int) p2->nCharge - (int) p1->nCharge)) /* (+) first, (-) second */ /* djb-rwth: addressing LLVM warning */
743 : 0 : return diff;
744 : 0 : return (int) p1->nValenceOrderingNumber - (int) p2->nValenceOrderingNumber;
745 : : }
746 : :
747 : :
748 : : /************************************************************************************/
749 : 0 : int bMayBeACationInMobileHLayer( inp_ATOM *at, VAL_AT *pVA, int iat, int bMobileH )
750 : : {
751 : : int j, neigh;
752 : : U_CHAR cVal; /* moved from below 2024-09-01 DT */
753 [ # # # # ]: 0 : if (!bMobileH || !at[iat].num_H)
754 : : {
755 : 0 : return 1;
756 : : }
757 : :
758 : : /* cVal, cation valence */
759 [ # # # ]: 0 : switch ( at[iat].el_number ) {
760 : 0 : case EL_NUMBER_N: /* fallthrough */
761 : : case EL_NUMBER_P:
762 : 0 : cVal = 4;
763 : 0 : break;
764 : 0 : case EL_NUMBER_O: /* fallthrough */
765 : : case EL_NUMBER_S:
766 : : case EL_NUMBER_SE:
767 : : case EL_NUMBER_TE:
768 : 0 : cVal = 3;
769 : 0 : break;
770 : 0 : default:
771 : 0 : return 1;
772 : : }
773 : :
774 [ # # ]: 0 : if (at[iat].valence + at[iat].num_H <= cVal)
775 : : {
776 [ # # ]: 0 : for (j = 0; j < at[iat].valence; j++)
777 : : {
778 : 0 : neigh = at[iat].neighbor[j];
779 [ # # # # : 0 : if (at[neigh].valence == 4 && at[neigh].chem_bonds_valence == 4 && !at[neigh].num_H &&
# # ]
780 [ # # # # ]: 0 : pVA[neigh].cNumValenceElectrons == 3 && pVA[neigh].cPeriodicRowNumber == 1)
781 : : {
782 : 0 : return 1;
783 : : }
784 : : }
785 : 0 : return 0;
786 : : }
787 : 0 : return 1;
788 : : }
789 : :
790 : :
791 : : /************************************************************************************/
792 : 0 : int clean_charge_val( struct tagCANON_GLOBALS *pCG, CHARGE_VAL *pChargeVal, int len, inp_ATOM *atom, VAL_AT *pVA,
793 : : int iat, int bIsMetal, int bMobileH, AT_NUMB *endpoint )
794 : : {
795 : 0 : inp_ATOM *at = atom + iat;
796 : 0 : int nPeriodicNum = at->el_number;
797 : 0 : int num_bonds = at->valence;
798 : 0 : int min_valence = at->valence + at->num_H;
799 : : /* in fixed-H case treat tautomeric -O as tautomeric to avoid #O(+) */
800 : 0 : int bTautomeric = ( at->endpoint != 0 );
801 [ # # # # : 0 : int bFixedHTautomeric = !bMobileH && ( endpoint && endpoint[iat] &&
# # ]
802 [ # # # # ]: 0 : pVA[iat].cNumValenceElectrons == 6 && 1 == num_bonds &&
803 [ # # # # ]: 0 : !at->num_H && !bIsMetal );
804 : : /* int bIsMetal = is_el_a_metal( nPeriodicNum );*/
805 : 0 : int bDoNotAddH = if_skip_add_H( nPeriodicNum );
806 : : int nPeriod, nNumEqAbsCharges;
807 : 0 : int nNumValenceEl = get_sp_element_type( nPeriodicNum, &nPeriod ) - 1;
808 : :
809 : : int i, j;
810 : :
811 [ # # ]: 0 : if (!len)
812 : 0 : return len;
813 : :
814 : 0 : insertions_sort( pCG, pChargeVal, len, sizeof( pChargeVal[0] ), cmp_charge_val );
815 : :
816 : : /* metals -- very preliminary code */
817 [ # # # # ]: 0 : if (bIsMetal && bDoNotAddH)
818 : : {
819 : : /* keep the 1st found */
820 : 0 : return inchi_min( 1, len );
821 : : }
822 : : /* Mobile-H layer cannot have H on positively charged N, P (all IV), O, S, Se, Te (all III) */
823 : :
824 : : /*
825 : : if ( abs( pChargeVal[0].nCharge ) > 1 && pChargeVal[0].nValence >= min_valence ) {
826 : : return inchi_min( 1, len );
827 : : }
828 : : */
829 : 0 : nNumEqAbsCharges = 0;
830 [ # # # # : 0 : for (i = j = 0; i < len && j < ( nNumEqAbsCharges ? 3 + nNumEqAbsCharges : 4 ); i++)
# # ]
831 : : {
832 : : /* for now accept only charge = 0, -1, +1 */
833 [ # # ]: 0 : if (abs( pChargeVal[i].nCharge ) > 1)
834 : : {
835 : 0 : continue;
836 : : }
837 [ # # ]: 0 : if (BOND_TYPE_TRIPLE + BOND_TYPE_DOUBLE * ( min_valence - 1 ) < pChargeVal[i].nValence)
838 : : {
839 : 0 : continue; /* not more than one triple and the rest - double bonds per atom */
840 : : }
841 [ # # # # : 0 : if (( bTautomeric || (j && bFixedHTautomeric) ) && pChargeVal[i].nCharge < 0) /* djb-rwth: addressing LLVM warning */
# # # # ]
842 : : {
843 : 0 : continue; /* negative charge must be included in the tautomeric group */
844 : : }
845 [ # # # # : 0 : if (( bTautomeric || bFixedHTautomeric ) && pChargeVal[i].nCharge > 0)
# # ]
846 : : {
847 : 0 : continue; /* positive charge for now cannot reach a tautomeric group */
848 : : }
849 [ # # # # : 0 : if (j && !bMayBeACationInMobileHLayer( atom, pVA, iat, bMobileH ) && pChargeVal[i].nCharge > 0)
# # ]
850 : : {
851 [ # # ]: 0 : if (i + 1 < len &&
852 [ # # ]: 0 : pChargeVal[i].nValence == pChargeVal[i + 1].nValence &&
853 [ # # ]: 0 : pChargeVal[i].nCharge == -pChargeVal[i + 1].nCharge)
854 : : {
855 : : /* (-) if exists is always after (+) */
856 : 0 : i += 1; /* also skip the next element */
857 : : }
858 : 0 : continue; /* in case of Mobile-H, a hydrogen cannot be on a (+)-charged heteroatom */
859 : : }
860 : :
861 : : /* accept same valence opposite charges only for C and its group in Periodic Table */
862 [ # # # # ]: 0 : if (j && !bTautomeric &&
863 [ # # ]: 0 : pChargeVal[i].nValence == pChargeVal[j - 1].nValence &&
864 [ # # ]: 0 : pChargeVal[i].nCharge == -pChargeVal[j - 1].nCharge)
865 : : {
866 [ # # # # : 0 : if (nNumValenceEl == VALUE_OCTET / 2 && pChargeVal[i].nCharge && !nNumEqAbsCharges)
# # ]
867 : : {
868 : 0 : pChargeVal[j++] = pChargeVal[i];
869 : 0 : nNumEqAbsCharges++;
870 : : }
871 : 0 : continue;
872 : : }
873 : : /* do not accept valence=5 for neutral NHn in case of not Mobile-H 2005-01-26 ???? */
874 [ # # # # : 0 : if (nNumValenceEl == 5 && nPeriod == 1 && at->num_H &&
# # # # ]
875 [ # # ]: 0 : j && !bMobileH &&
876 [ # # # # ]: 0 : pChargeVal[i].nValence == 5 && !pChargeVal[i].nCharge)
877 : : {
878 : 0 : continue;
879 : : }
880 : : /* do not accept gaps in allowed valences */
881 [ # # # # ]: 0 : if (j && pChargeVal[i].nValence > pChargeVal[j - 1].nValence + 1)
882 : : {
883 : 0 : break;
884 : : }
885 : 0 : pChargeVal[j++] = pChargeVal[i];
886 : : }
887 : 0 : len = j;
888 [ # # # # : 0 : if (!nNumEqAbsCharges && num_bonds < 3 && len == 4)
# # ]
889 : : {
890 : 0 : len--; /* prohibit =S# where # is a triple bond */
891 : : }
892 : 0 : return len;
893 : : }
894 : :
895 : :
896 : : /****************************************************************************
897 : : int GetAtomRestoreInfo( CANON_GLOBALS *pCG, inp_ATOM *atom, int iat, VAL_AT *pVArray )
898 : :
899 : :
900 : : pVA->cDoNotAddH
901 : : pVA->cMetal
902 : : pVA->cNumValenceElectrons
903 : : pVA->cPeriodicRowNumber
904 : : pVA->cInitFreeValences
905 : : pVA->cnListIndex = index+1
906 : :
907 : : return value:
908 : : -1 => error
909 : : 0 => do not know what to do; leave the atom unchanged
910 : : 1 => success
911 : : ****************************************************************************/
912 : 0 : int GetAtomRestoreInfo(struct tagCANON_GLOBALS* pCG,
913 : : inp_ATOM* atom, int iat, VAL_AT* pVArray,
914 : : ICHICONST SRM* pSrm, int bMobileH, AT_NUMB* endpoint)
915 : : {
916 : : /* #defines from util.c */
917 : : #define MIN_ATOM_CHARGE (-2)
918 : : #define MAX_ATOM_CHARGE 2
919 : : #define NEUTRAL_STATE (-MIN_ATOM_CHARGE)
920 : : #define NUM_ATOM_CHARGES (MAX_ATOM_CHARGE - MIN_ATOM_CHARGE + 1)
921 : : #define MAX_NUM_VALENCES 5 /* max. number + 1 to provide zero termination */
922 : :
923 : : int i, j, j2, k, k2, charge, cur_charge, num_non_bonding_electrons;
924 : : int nNumStates, nNumSelectedStates, num_H, num_bonds;
925 : : int nOctetNeutralValenceExcess, nFirstNeutralValenceExcess;
926 : : int nFoundNeutralValenceExcess, nFoundNeutralValenceOrdNumber;
927 : : int nLastFoundValenceOrdNumber, nLastFoundValenceState;
928 : : int cn_bits, cn_bits_array[5], len_cn_bits_array;
929 : 0 : inp_ATOM* at = atom + iat;
930 : 0 : VAL_AT* pVA = pVArray + iat;
931 : 0 : int nPeriodicNum = at->el_number;
932 : : int cur_chem_valence, cur_chem_valence_fixed, min_chem_valence, known_chem_valence;
933 : : int metal_bonds_chem_valence, not_metal_bonds_chem_valence, alt_bonds_delta_valence, bonds_chem_valence, bond_type;
934 : : CHARGE_VAL ChargeVal[NUM_ATOM_CHARGES * MAX_NUM_VALENCES];
935 : :
936 : 0 : memset(ChargeVal, 0, sizeof(ChargeVal));
937 : :
938 : 0 : pVA->cDoNotAddH = if_skip_add_H(nPeriodicNum); /* InChI never adds H to this atom */
939 : : /*pVA->cMetal = is_el_a_metal( nPeriodicNum );*/ /* the atom is a metal */
940 : :
941 : : /* count bonds to metal atoms; metals have already been marked */
942 : 0 : metal_bonds_chem_valence = not_metal_bonds_chem_valence = alt_bonds_delta_valence = 0;
943 : :
944 [ # # ]: 0 : if (pVA->cMetal)
945 : : {
946 : 0 : j = at->valence; /* all bonds to metal */
947 [ # # ]: 0 : for (i = k = j2 = k2 = 0; i < at->valence; i++)
948 : : {
949 : 0 : bond_type = (at->bond_type[i] & BOND_TYPE_MASK);
950 [ # # ]: 0 : if (bond_type <= BOND_TYPE_TRIPLE)
951 : : {
952 : 0 : metal_bonds_chem_valence += inchi_max(BOND_TYPE_SINGLE, bond_type);
953 : : }
954 : : else
955 : : {
956 : 0 : metal_bonds_chem_valence += BOND_TYPE_SINGLE;
957 : 0 : k++; /* count alternating bonds */
958 : : }
959 : : }
960 : : }
961 : : else
962 : : {
963 [ # # ]: 0 : for (i = j = j2 = k = k2 = 0; i < at->valence; i++)
964 : : {
965 : 0 : bond_type = (at->bond_type[i] & BOND_TYPE_MASK);
966 [ # # ]: 0 : if (pVArray[(int)at->neighbor[i]].cMetal)
967 : : {
968 : 0 : j++; /* number of bonds to metal atoms */
969 [ # # ]: 0 : if (bond_type <= BOND_TYPE_TRIPLE)
970 : : {
971 : 0 : metal_bonds_chem_valence += inchi_max(BOND_TYPE_SINGLE, bond_type);
972 : : }
973 : : else
974 : : {
975 : 0 : metal_bonds_chem_valence += BOND_TYPE_SINGLE;
976 : 0 : k++; /* count alternating bonds */
977 : : }
978 : : }
979 : : else
980 : : {
981 : 0 : j2++;
982 [ # # ]: 0 : if (bond_type <= BOND_TYPE_TRIPLE)
983 : : {
984 : 0 : not_metal_bonds_chem_valence += inchi_max(BOND_TYPE_SINGLE, bond_type);
985 : : }
986 : : else
987 : : {
988 : 0 : not_metal_bonds_chem_valence += BOND_TYPE_SINGLE;
989 : 0 : k2++; /* count alternating bonds */
990 : : }
991 : : }
992 : : }
993 : : }
994 : :
995 : 0 : bonds_chem_valence = metal_bonds_chem_valence + not_metal_bonds_chem_valence;
996 : :
997 [ # # ]: 0 : if (at->chem_bonds_valence > bonds_chem_valence)
998 : : {
999 [ # # ]: 0 : if (at->chem_bonds_valence - bonds_chem_valence > 1)
1000 : : {
1001 : 0 : at->chem_bonds_valence = bonds_chem_valence + 1; /* should not happen */
1002 : : }
1003 : 0 : alt_bonds_delta_valence = at->chem_bonds_valence - bonds_chem_valence;
1004 : : }
1005 : :
1006 : 0 : pVA->cNumBondsToMetal = j;
1007 : :
1008 [ # # ]: 0 : if (nPeriodicNum == EL_NUMBER_H)
1009 : : {
1010 : : /* ignore bridging H; ??? later add ??? */
1011 : 0 : return 0;
1012 : : }
1013 : :
1014 : 0 : num_H = at->num_H;
1015 : 0 : num_bonds = at->valence;
1016 : :
1017 [ # # # # ]: 0 : if (!num_bonds && !num_H)
1018 : : {
1019 : 0 : return 0; /* do not know the answer: isolated atom */
1020 : : }
1021 : : /* at the beginning all bonds are single */
1022 : 0 : min_chem_valence = num_bonds + num_H;
1023 : 0 : cur_chem_valence = bonds_chem_valence + alt_bonds_delta_valence + num_H; /* includes double & alternating bond contribution */
1024 : :
1025 : : /* number of non-bonding electrons in case of all single bonds */
1026 : 0 : num_non_bonding_electrons = (int)pVA->cNumValenceElectrons - min_chem_valence;
1027 : : /* Octet rule: charge = bonds_valence + NumValenceElectrons - 8 */
1028 : 0 : charge = min_chem_valence + (int)pVA->cNumValenceElectrons - VALUE_OCTET; /* wrong */
1029 : :
1030 : : /* typical (ad hoc) minimal neutral valence */
1031 : 0 : known_chem_valence = (pVA->cNumValenceElectrons > VALUE_OCTET / 2) ?
1032 [ # # ]: 0 : VALUE_OCTET - pVA->cNumValenceElectrons :
1033 : 0 : pVA->cNumValenceElectrons;
1034 : : /* excess of typical valence over all-single-bonds valence */
1035 : 0 : nOctetNeutralValenceExcess = known_chem_valence - min_chem_valence;
1036 : : /* (NB=num.bonds, NV=neutral valence, NVX=neutral valence excess, LFVS=last found valence state, val.=valence)
1037 : :
1038 : : element NB knownFst octet Last octetNVX firstNVX foundNVX chargeLFVS LFVS
1039 : : valence val. NV>=
1040 : :
1041 : : -B 1 3 3 3 2 2 = 2 +2
1042 : : >B 2 3 3 3 1 1 = 1 +1
1043 : : >B- 3 3 3 3 0 0 = 0 0
1044 : : >B< 4 3 3 3 -1 -1 <> N/A -1
1045 : :
1046 : : -C 1 4 4 4 3 3 = 3 N/A
1047 : : >C 2 4 4 4 2 2 = 2 +2 (-2)
1048 : : >C- 3 4 4 4 1 1 = 1 +1 (-1)
1049 : : >C< 4 4 4 4 0 0 = 0 0
1050 : : C(V) 5 4 4 N/A -1 -1 <> N/A N/A
1051 : :
1052 : : -Si 1 4 4 4 3 3 = 3 N/A
1053 : : >Si 2 4 4 4 2 2 = 2 +2 (-2)
1054 : : >Si- 3 4 4 4 1 1 = 1 +1 (-1)
1055 : : >Si- 4 4 4 4 0 0 = 0 0
1056 : : Si(V) 5 4 4 N/A -1 -1 <> N/A -1
1057 : :
1058 : : -N 1 3 3 3 2 2 = 2 -2
1059 : : >N 2 3 3 3 1 1 = 1 -1
1060 : : >N- 3 3 3 3 0 0 = 0 0 (+2)
1061 : : >N< 4 3 3 5 -1 -1 <> 1 +1
1062 : : N(V) 5 3 3 5 -2 -2 <> 0 0
1063 : : N(VI) 6 3 3 N/A -3 -3 <> N/A N/A
1064 : : N(VII) 7 3 3 N/A -4 -4 <> N/A N/A
1065 : :
1066 : : -P 1 3 3 3 2 2 = 2 -2
1067 : : >P 2 3 3 3 1 1 = 1 -1
1068 : : >P- 3 3 3 3 0 0 = 0 0 (-2, +2)
1069 : : >P< 4 3 3 5 -1 -1 <> 1 +1 (-1)
1070 : : P(V) 5 3 3 5 -2 -2 <> 0 0 (-2)
1071 : : P(VI) 6 3 3 N/A -3 -3 <> N/A -1
1072 : : P(VII) 7 3 3 N/A -4 -4 <> N/A -2
1073 : : P(VIII) 8 3 3 N/A -5 -5 <> N/A N/A
1074 : :
1075 : : -O 1 2 2 2 1 1 = 1 -1
1076 : : >O 2 2 2 2 0 0 = 0 0
1077 : : >O- 3 2 2 N/A -1 -1 <> N/A +1
1078 : : >O< 4 2 2 N/A -2 -2 <> N/A +2
1079 : : O(V) 5 2 2 N/A -3 -3 <> N/A +1
1080 : : O(VI) 6 2 2 N/A -4 -4 <> N/A N/A
1081 : :
1082 : : -S 1 2 2 2 1 1 = 1 -1
1083 : : >S 2 2 2 2 0 0 = 0 0 NPNP - prohibit
1084 : : >S- 3 2 2 4 -1 -1 <> 1 +1 (-1) PNPN
1085 : : >S< 4 2 2 4 -2 -2 <> 0 0 (+2)
1086 : : S(V) 5 2 2 6 -3 -3 <> 1 +1 (-1)
1087 : : S(VI) 6 2 2 6 -4 -4 <> 0 0
1088 : : S(VII) 7 2 2 N/A -5 -5 <> 0 -1
1089 : : S(VIII) 8 2 2 N/A -6 -6 <> N/A N/A
1090 : :
1091 : : -F 1 1 1 1 0 0 = 0 0
1092 : : >F 2 1 1 1 -1 -1 <> N/A +1
1093 : : >F- 3 1 1 1 -2 -2 <> N/A +2
1094 : : >F< 4 1 1 1 -3 -3 <> N/A N/A
1095 : : F(V) 5 1 1 1 -4 -4 <> N/A +2
1096 : : F(VI) 6 1 1 1 -5 -5 <> N/A N/A
1097 : :
1098 : : -Cl 1 1 1 1 0 0 = 0 0 NPNP - prohibit
1099 : : >Cl 2 1 1 3 -1 -1 <> 1 +1 PNPN - prohibit
1100 : : >Cl- 3 1 1 3 -2 -2 <> 0 0 (+2) NPNP
1101 : : >Cl< 4 1 1 5 -3 -3 <> 1 +1 PNPN
1102 : : Cl(V) 5 1 1 5 -4 -4 <> 0 0
1103 : : Cl(VI) 6 1 1 7 -5 -5 <> 1 +1
1104 : : Cl(VII) 7 1 1 7 -6 -6 <> 0 0
1105 : : Cl(VIII) 8 1 1 N/A -7 -7 <> N/A N/A
1106 : :
1107 : :
1108 : : NB = num_bonds+num_H
1109 : :
1110 : : knownFst valence = nFirstNeutralValenceExcess + min_chem_valence
1111 : : octet val. = nOctetNeutralValenceExcess + min_chem_valence
1112 : : Last NV>= = nFoundNeutralValenceExcess + min_chem_valence
1113 : :
1114 : : octetNVX = nOctetNeutralValenceExcess
1115 : : firstNVX = nFirstNeutralValenceExcess
1116 : : foundNVX = nFoundNeutralValenceExcess
1117 : :
1118 : : chargeLFVS = ChargeVal[nLastFoundValenceState].nCharge
1119 : :
1120 : : */
1121 : : /* minimal known neutral atom valence; different for Sn(2/4), Tl(1/3), Pb(2/4): (known/typical ad hoc) */
1122 : 0 : known_chem_valence = get_el_valence( nPeriodicNum, 0, 0 );
1123 : :
1124 [ # # ]: 0 : if (pSrm->bMetalAddFlower)
1125 : : {
1126 : : /* bond orders of bonds to metal may be as they are (pSrm->nMetalInitBondOrder==1)
1127 : : or decreased by one (pSrm->nMetalInitBondOrder==0)
1128 : : nMetalInitBondOrder == nMetalMinBondOrder + nMetalInitEdgeFlow
1129 : : */
1130 : 0 : cur_chem_valence_fixed = cur_chem_valence - pVA->cNumBondsToMetal * ( 1 - pSrm->nMetalInitBondOrder );
1131 : 0 : pVA->cInitOrigValenceToMetal = metal_bonds_chem_valence;
1132 : 0 : pVA->cInitValenceToMetal = metal_bonds_chem_valence - pVA->cNumBondsToMetal * ( 1 - pSrm->nMetalInitBondOrder );
1133 : 0 : pVA->cInitFlowToMetal = pVA->cInitValenceToMetal - pVA->cNumBondsToMetal * pSrm->nMetalMinBondOrder;
1134 [ # # ]: 0 : if (pVA->cMetal)
1135 : : {
1136 : 0 : pVA->cInitFreeValences += alt_bonds_delta_valence;
1137 : : }
1138 [ # # ]: 0 : if (pSrm->nMetalInitEdgeFlow < pSrm->nMetalInitBondOrder - pSrm->nMetalMinBondOrder)
1139 : : {
1140 : : /* single bond has zero initial flow + 2 radicals at incident atoms */
1141 [ # # ]: 0 : if (pVA->cInitFlowToMetal <= pVA->cNumBondsToMetal)
1142 : : {
1143 [ # # ]: 0 : if (pVA->cMetal)
1144 : : {
1145 : 0 : pVA->cInitFreeValences += pVA->cInitFlowToMetal;
1146 : : }
1147 : 0 : pVA->cInitFlowToMetal = 0;
1148 : : }
1149 : : else
1150 : : {
1151 [ # # ]: 0 : if (pVA->cMetal)
1152 : : {
1153 : 0 : pVA->cInitFreeValences += pVA->cNumBondsToMetal * ( 1 - pSrm->nMetalInitEdgeFlow );
1154 : : }
1155 : 0 : pVA->cInitFlowToMetal -= pVA->cNumBondsToMetal * ( 1 - pSrm->nMetalInitEdgeFlow );
1156 : : }
1157 : : }
1158 : : }
1159 : : else
1160 : : {
1161 : : /* treat metal atoms as ordinary non-metal atoms */
1162 : 0 : cur_chem_valence_fixed = cur_chem_valence;
1163 : 0 : pVA->cInitFlowToMetal = metal_bonds_chem_valence - pVA->cNumBondsToMetal;
1164 : 0 : pVA->cInitValenceToMetal = metal_bonds_chem_valence;
1165 : 0 : pVA->cInitOrigValenceToMetal = metal_bonds_chem_valence;
1166 : : }
1167 : :
1168 : :
1169 [ # # # # ]: 0 : if (pVA->cMetal && pSrm->bMetalAddFlower)
1170 : : {
1171 : 0 : pVA->cnListIndex = cnListIndexMe + 1;
1172 : : /*
1173 : : pVA->cInitOrigValenceToMetal += alt_bonds_delta_valence;
1174 : : pVA->cInitValenceToMetal += alt_bonds_delta_valence;
1175 : : pVA->cInitFreeValences = (pSrm->nMetalInitBondOrder + alt_bonds_delta_valence
1176 : : - (pSrm->nMetalMinBondOrder + pSrm->nMetalInitEdgeFlow)) * pVA->cNumBondsToMetal;
1177 : : */
1178 : 0 : return 0; /* metal */
1179 : : }
1180 : :
1181 [ # # ]: 0 : if (!known_chem_valence)
1182 : : {
1183 : : /* a noble gas like He, Ne, ... */
1184 : 0 : pVA->cInitFreeValences = at->chem_bonds_valence - at->valence;
1185 : 0 : return TREAT_ATOM_AS_METAL; /* do not know anything about this atom; needs 2nd pass */
1186 : : }
1187 : :
1188 : 0 : nFirstNeutralValenceExcess = known_chem_valence - min_chem_valence;
1189 : :
1190 : 0 : nFoundNeutralValenceExcess = NO_VALUE_INT;
1191 : 0 : nFoundNeutralValenceOrdNumber = NO_VALUE_INT;
1192 : 0 : nLastFoundValenceOrdNumber = NO_VALUE_INT;
1193 : 0 : nLastFoundValenceState = NO_VALUE_INT;
1194 : :
1195 : : /* find the lowest known valence >= all-single-bonds valence */
1196 [ # # ]: 0 : for (cur_charge = MIN_ATOM_CHARGE, nNumStates = 0; cur_charge <= MAX_ATOM_CHARGE; cur_charge++)
1197 : : {
1198 [ # # ]: 0 : for (i = 0; i < MAX_NUM_VALENCES; i++)
1199 : : {
1200 : 0 : known_chem_valence = get_el_valence(nPeriodicNum, cur_charge, i);
1201 [ # # # # ]: 0 : if (cur_chem_valence_fixed > known_chem_valence || !known_chem_valence)
1202 : : {
1203 : 0 : continue; /* known valence < all-single-bonds valence */
1204 : : }
1205 [ # # ]: 0 : if (BOND_TYPE_TRIPLE + BOND_TYPE_DOUBLE * (num_bonds - 1) + num_H < known_chem_valence)
1206 : : {
1207 : 0 : continue; /* not more than one triple and the rest - double bonds per atom */
1208 : : }
1209 : :
1210 : : /* keep all found */
1211 : 0 : ChargeVal[nNumStates].nValence = known_chem_valence;
1212 : 0 : ChargeVal[nNumStates].nCharge = cur_charge;
1213 : 0 : ChargeVal[nNumStates].nValenceOrderingNumber = i;
1214 [ # # # # ]: 0 : if (!cur_charge && nFoundNeutralValenceExcess == NO_VALUE_INT)
1215 : : {
1216 : : /* neutral state; compare to the lowest typical valence */
1217 : 0 : nFoundNeutralValenceExcess = known_chem_valence - min_chem_valence;
1218 : 0 : nFoundNeutralValenceOrdNumber = i;
1219 : : }
1220 [ # # ]: 0 : if (min_chem_valence == known_chem_valence)
1221 : : {
1222 [ # # ]: 0 : if (nLastFoundValenceState == NO_VALUE_INT)
1223 : : {
1224 : : /* accept the first found */
1225 : 0 : nLastFoundValenceState = nNumStates;
1226 : : }
1227 : : else
1228 [ # # ]: 0 : if (abs(ChargeVal[nLastFoundValenceState].nCharge) >= abs(cur_charge))
1229 : : {
1230 : : /* accept smaller abs(charge); if abs(charges) are same, accept (+) */
1231 : 0 : nLastFoundValenceState = nNumStates;
1232 : : }
1233 : : }
1234 : :
1235 : 0 : nNumStates++;
1236 : : }
1237 : : }
1238 : :
1239 : : /***********************************************************************************/
1240 : : /* select only appropriate charge & valence so that a suitable ChargeStruct exists */
1241 : : /***********************************************************************************/
1242 : :
1243 : 0 : nNumSelectedStates = clean_charge_val( pCG, ChargeVal, nNumStates, atom,
1244 : 0 : pVArray, iat, pVA->cMetal,
1245 : : bMobileH, endpoint );
1246 : :
1247 [ # # ]: 0 : if (!nNumSelectedStates)
1248 : : {
1249 : 0 : return TREAT_ATOM_AS_METAL; /* nothing to do */
1250 : : }
1251 : :
1252 : : /***********************************************************************************/
1253 : : /* Find an appropriate ChargeStruct index for the ChargeVal found */
1254 : : /***********************************************************************************/
1255 : 0 : cn_bits = 0;
1256 : 0 : memset( cn_bits_array, 0, sizeof( cn_bits_array ) ); /* djb-rwth: memset_s C11/Annex K variant? */
1257 : : /***** set bits identifying a suitable ChargeStruct ******/
1258 [ # # # # ]: 0 : for (i = len_cn_bits_array = 0; i < nNumSelectedStates && len_cn_bits_array < 4; i++)
1259 : : {
1260 [ # # # # ]: 0 : switch (ChargeVal[i].nCharge)
1261 : : {
1262 : 0 : case -1:
1263 : 0 : cn_bits_array[len_cn_bits_array] |= cn_bits_M; /* Minus 1 */
1264 : 0 : break;
1265 : 0 : case 0:
1266 : 0 : cn_bits_array[len_cn_bits_array] |= cn_bits_N; /* Neutral */
1267 : 0 : break;
1268 : 0 : case 1:
1269 : 0 : cn_bits_array[len_cn_bits_array] |= cn_bits_P; /* Plus 1 */
1270 : 0 : break;
1271 : 0 : default:
1272 : 0 : return RI_ERR_PROGR; /* program error */
1273 : : }
1274 [ # # ]: 0 : if (i + 1 < nNumSelectedStates &&
1275 [ # # ]: 0 : ChargeVal[i].nValence == ChargeVal[i + 1].nValence &&
1276 [ # # ]: 0 : ChargeVal[i].nCharge &&
1277 [ # # ]: 0 : ChargeVal[i].nCharge == -ChargeVal[i + 1].nCharge)
1278 : : {
1279 : : ; /* add opposite charge to the same element of cn_bits_array[] */
1280 : : }
1281 : : else
1282 : : {
1283 : 0 : len_cn_bits_array++;
1284 : : }
1285 : : }
1286 [ # # # # ]: 0 : if (!len_cn_bits_array || len_cn_bits_array > 4)
1287 : : {
1288 : 0 : return RI_ERR_PROGR; /* program error */
1289 : : }
1290 : : /* accommodate added 4-state ChargeStruct: +/- cannot be in case of 4 states */
1291 [ # # # # ]: 0 : if (len_cn_bits_array + 1 == nNumSelectedStates && nNumSelectedStates == 4)
1292 : : {
1293 : 0 : len_cn_bits_array--;
1294 : 0 : nNumSelectedStates--;
1295 : 0 : cn_bits_array[len_cn_bits_array] = 0;
1296 : : }
1297 : : /* fix for terminal hydrogenless -C as in isocyano or CO: there is no just cnE_[] ChargeStruct */
1298 [ # # ]: 0 : if (len_cn_bits_array == 1 &&
1299 [ # # ]: 0 : cn_bits_array[0] == ( cn_bits_P | cn_bits_M ) &&
1300 [ # # ]: 0 : ChargeVal[0].nValence + 1 > BOND_TYPE_TRIPLE + BOND_TYPE_DOUBLE * ( num_bonds - 1 ) + num_H)
1301 : : {
1302 : 0 : cn_bits_array[len_cn_bits_array++] = cn_bits_N;
1303 : 0 : ChargeVal[nNumSelectedStates].nValence = ChargeVal[nNumSelectedStates - 1].nValence;
1304 : 0 : ChargeVal[nNumSelectedStates].nCharge = 0;
1305 : 0 : ChargeVal[nNumSelectedStates].nValenceOrderingNumber = 0;
1306 : : }
1307 : :
1308 : 0 : make_cn_bits:
1309 : 0 : cn_bits = MAKE_CN_BITS( cn_bits_array[0], cn_bits_array[1], cn_bits_array[2], cn_bits_array[3] );
1310 : :
1311 : : /*********** find ChargeStructure **************/
1312 [ # # ]: 0 : for (i = 0, j = -1; i < cnListNumEl; i++)
1313 : : {
1314 [ # # ]: 0 : if (cnList[i].bits == cn_bits)
1315 : : {
1316 : 0 : j = i;
1317 : 0 : break; /* found */
1318 : : }
1319 : : }
1320 : :
1321 [ # # ]: 0 : if (j < 0)
1322 : : {
1323 : : /* ChargeStructure was not found */
1324 [ # # # # ]: 0 : if (1 < len_cn_bits_array && len_cn_bits_array + 1 == nNumSelectedStates)
1325 : : {
1326 : : /* a pair of opposite charges was combined */
1327 : 0 : len_cn_bits_array--;
1328 : 0 : cn_bits_array[len_cn_bits_array] = 0;
1329 : 0 : goto make_cn_bits;
1330 : : }
1331 [ # # ]: 0 : else if (nNumSelectedStates == 4)
1332 : : {
1333 : : /* reduce number of states */
1334 : 0 : len_cn_bits_array--;
1335 : 0 : cn_bits_array[len_cn_bits_array] = 0;
1336 : 0 : nNumSelectedStates--;
1337 : 0 : goto make_cn_bits;
1338 : : }
1339 : 0 : return RI_ERR_PROGR; /* charge structure not found */
1340 : : }
1341 : :
1342 : : /********** ChargeStructure has been found **********/
1343 : 0 : pVA->cnListIndex = j + 1; /* charge structure index + 1 */
1344 : 0 : pVA->cInitCharge = cnList[j].nInitialCharge;
1345 : : /********** Calculate "Free Valence" ****************/
1346 : : #if ( ALLOW_METAL_BOND_ZERO == 1 )
1347 : :
1348 : : #if ( INIT_METAL_BOND_ZERO == 1 )
1349 : : if (pVA->cMetal)
1350 : : {
1351 : : j = 0;
1352 : : }
1353 : : else
1354 : : {
1355 : : j = ChargeVal[0].nValence - cur_chem_valence_fixed;
1356 : : }
1357 : : #else
1358 : 0 : j = ChargeVal[0].nValence - cur_chem_valence_fixed;
1359 : : #endif
1360 : :
1361 : : #else
1362 : : j = ChargeVal[0].nValence - cur_chem_valence_fixed;
1363 : : #endif
1364 [ # # ]: 0 : if (j < 0)
1365 : : {
1366 : 0 : return RI_ERR_PROGR; /* program error */
1367 : : }
1368 : 0 : pVA->cInitFreeValences = j; /* number of initial unsatisfied valences; should be combined with */
1369 : : /* (cap - flow) of vertex=0 in the charge structure[pVA->cnListIndex-1] */
1370 : 0 : return 1; /* success */
1371 : :
1372 : : #undef MIN_ATOM_CHARGE
1373 : : #undef MAX_ATOM_CHARGE
1374 : : #undef NEUTRAL_STATE
1375 : : #undef NUM_ATOM_CHARGES
1376 : : #undef MAX_NUM_VALENCES
1377 : : }
1378 : :
1379 : :
1380 : : #ifdef NEVER
1381 : : /****************************************************************************/
1382 : : int get_bonds_valences( int nPeriodicNum, int bonds_valence, int num_H, VAL_AT *pVA )
1383 : : {
1384 : : int i, j, charge, chem_valence, known_chem_valence;
1385 : : #define MAX_NUM_VALENCES 5 /* defined in util.c */
1386 : :
1387 : : memset( pVA, 0, sizeof( pVA[0] ) );
1388 : :
1389 : : if (!bonds_valence && !num_H)
1390 : : return 0; /* do not know the answer */
1391 : :
1392 : : chem_valence = bonds_valence + num_H;
1393 : : for (charge = VAL_MIN_CHARGE; charge <= VAL_MAX_CHARGE; charge++)
1394 : : {
1395 : : for (i = 0, j = 0; i < MAX_NUM_VALENCES, j < VAL_NUMBER; i++)
1396 : : {
1397 : : if (chem_valence <= ( known_chem_valence = get_el_valence( nPeriodicNum, charge, i ) ))
1398 : : {
1399 : : if (!charge)
1400 : : {
1401 : : pVA->cValence[j][VAL_NEUTR_ORDER] = i + 1;
1402 : : }
1403 : : pVA->cValence[j++][charge + VAL_BASE] = known_chem_valence - num_H;
1404 : : }
1405 : : }
1406 : : }
1407 : : pVA->cDoNotAddH = if_skip_add_H( nPeriodicNum );
1408 : : pVA->cMetal = is_el_a_metal( nPeriodicNum );
1409 : : return pVA->cValence[0][VAL_BASE]; /* 0 means do not know the answer */
1410 : : #undef MAX_NUM_VALENCES
1411 : : }
1412 : : #endif
1413 : : /*********** calculate s or p-element type ************/
1414 : 0 : int get_sp_element_type( int nPeriodicNumber, int *nRow )
1415 : : /*
1416 : : num el
1417 : : el neg
1418 : : 1 => H ATYPE_H 1 1 21
1419 : : 2 => Li, Na, K, Rb, Cs, Fr ATYPE_Na 2 1 10 09 08 08 07
1420 : : 3 => Be, Mg, Ca, Sr, Ba, Ra ATYPE_Mg 3 2 15 12 10 10 09
1421 : : 4 => B, Al, Ga, In, Tl ATYPE_B 4 3 20 15 18 17 18
1422 : : 5 => C, Si, Ge, Sn, Pb ATYPE_C 5 4 25 18 18 18 18
1423 : : 6 => N, P, As, Sb, Bi ATYPE_N 6 5 30 21 20 19 19
1424 : : 7 => O, S, Se, Te, Po ATYPE_O 7 6 35 25 24 21 20
1425 : : 8 => F, Cl, Br, I, At ATYPE_Cl 8 7 40 30 28 25 22
1426 : :
1427 : : number of valence electrons = (type>1)? type-1: type
1428 : :
1429 : : */
1430 : : {
1431 : 0 : int row = 0, type = 0;
1432 [ # # ]: 0 : if (nPeriodicNumber == 1)
1433 : : {
1434 : 0 : type = 1; /* H: 1 */
1435 : 0 : row = 0;
1436 : : }
1437 [ # # ]: 0 : else if (nPeriodicNumber == 2)
1438 : : {
1439 : 0 : type = 0; row = 0;
1440 : : }
1441 [ # # ]: 0 : else if (nPeriodicNumber <= 10)
1442 : : {
1443 : : /* Li: 2, Be: 3, B: 4, C: 5, N: 6, O: 7, F: 8, Ne: 9; later subtract 1 */
1444 : 0 : type = nPeriodicNumber - 1; row = 1;
1445 : : }
1446 [ # # ]: 0 : else if (nPeriodicNumber <= 18)
1447 : : {
1448 : 0 : type = nPeriodicNumber - 9; row = 2;
1449 : : }
1450 [ # # ]: 0 : else if (nPeriodicNumber <= 20)
1451 : : {
1452 : 0 : type = nPeriodicNumber - 17; row = 3;
1453 : : }
1454 [ # # ]: 0 : else if (nPeriodicNumber <= 30)
1455 : : {
1456 : 0 : type = 0; row = 3;
1457 : : }
1458 [ # # ]: 0 : else if (nPeriodicNumber <= 36)
1459 : : {
1460 : 0 : type = nPeriodicNumber - 27; row = 3;
1461 : : }
1462 [ # # ]: 0 : else if (nPeriodicNumber <= 38)
1463 : : {
1464 : 0 : type = nPeriodicNumber - 35; row = 4;
1465 : : }
1466 [ # # ]: 0 : else if (nPeriodicNumber <= 48)
1467 : : {
1468 : 0 : type = 0; row = 4;
1469 : : }
1470 [ # # ]: 0 : else if (nPeriodicNumber <= 54)
1471 : : {
1472 : 0 : type = nPeriodicNumber - 45; row = 4;
1473 : : }
1474 [ # # ]: 0 : else if (nPeriodicNumber <= 56)
1475 : : {
1476 : 0 : type = nPeriodicNumber - 53; row = 5;
1477 : : }
1478 [ # # ]: 0 : else if (nPeriodicNumber <= 80)
1479 : : {
1480 : 0 : type = 0; row = 5;
1481 : : }
1482 [ # # ]: 0 : else if (nPeriodicNumber <= 86)
1483 : : {
1484 : 0 : type = nPeriodicNumber - 77; row = 5;
1485 : : }
1486 [ # # ]: 0 : else if (nPeriodicNumber <= 88)
1487 : : {
1488 : 0 : type = nPeriodicNumber - 85; row = 6;
1489 : : }
1490 : : else
1491 : : {
1492 : 0 : type = 0; row = 6;
1493 : : }
1494 : :
1495 : 0 : *nRow = row;
1496 : :
1497 [ # # ]: 0 : return type == 9 ? 0 : type;
1498 : : }
1499 : :
1500 : :
1501 : : /****************************************************************************/
1502 : 0 : int ReallocTCGroups( ALL_TC_GROUPS *pTCGroups, int nAdd )
1503 : : {
1504 : 0 : TC_GROUP *pTCGroup = (TC_GROUP *) inchi_malloc( sizeof( pTCGroup[0] )*( (long long)pTCGroups->max_tc_groups + nAdd ) ); /* djb-rwth: cast operator added */
1505 : :
1506 [ # # ]: 0 : if (pTCGroup)
1507 : : {
1508 [ # # ]: 0 : if (pTCGroups->num_tc_groups)
1509 : : {
1510 : 0 : memcpy(pTCGroup, pTCGroups->pTCG, sizeof(pTCGroup[0]) * pTCGroups->num_tc_groups);
1511 : : }
1512 : 0 : memset( pTCGroup + pTCGroups->max_tc_groups, 0, sizeof( pTCGroup[0] )*nAdd ); /* djb-rwth: memset_s C11/Annex K variant? */
1513 [ # # ]: 0 : if (pTCGroups->pTCG)
1514 : : {
1515 [ # # ]: 0 : inchi_free( pTCGroups->pTCG );
1516 : : }
1517 : 0 : pTCGroups->pTCG = pTCGroup;
1518 : 0 : pTCGroups->max_tc_groups += nAdd;
1519 : 0 : return 0;
1520 : : }
1521 : :
1522 : 0 : return RI_ERR_ALLOC;
1523 : : }
1524 : :
1525 : :
1526 : : /****************************************************************************/
1527 : 0 : int RegisterTCGroup( ALL_TC_GROUPS *pTCGroups, int nGroupType, int nGroupOrdNum,
1528 : : int nVertexCap, int nVertexFlow, int nEdgeCap, int nEdgeFlow, int nNumEdges )
1529 : : {
1530 : 0 : int i, ret = 0;
1531 : :
1532 : : /* search */
1533 [ # # ]: 0 : for (i = 0; i < pTCGroups->num_tc_groups; i++)
1534 : : {
1535 [ # # ]: 0 : if (pTCGroups->pTCG[i].type == nGroupType &&
1536 [ # # ]: 0 : pTCGroups->pTCG[i].ord_num == nGroupOrdNum)
1537 : : {
1538 : 0 : break;
1539 : : }
1540 : : }
1541 : :
1542 [ # # ]: 0 : if (i == pTCGroups->num_tc_groups)
1543 : : {
1544 : : /* add one more group */
1545 [ # # ]: 0 : if (pTCGroups->num_tc_groups == pTCGroups->max_tc_groups)
1546 : : {
1547 : 0 : ret = ReallocTCGroups( pTCGroups, INC_NUM_TCGROUPS );
1548 [ # # ]: 0 : if (ret)
1549 : : {
1550 : 0 : goto exit_function;
1551 : : }
1552 : : }
1553 : :
1554 : 0 : ret = i + 1; /* added new group */
1555 : 0 : pTCGroups->num_tc_groups++;
1556 : 0 : pTCGroups->pTCG[i].type = nGroupType;
1557 : 0 : pTCGroups->pTCG[i].ord_num = nGroupOrdNum;
1558 : : }
1559 : :
1560 : 0 : pTCGroups->pTCG[i].num_edges += nNumEdges;
1561 : :
1562 : 0 : pTCGroups->pTCG[i].st_cap += nVertexCap;
1563 : 0 : pTCGroups->pTCG[i].st_flow += nVertexFlow;
1564 : :
1565 : 0 : pTCGroups->pTCG[i].edges_cap += nEdgeCap;
1566 : 0 : pTCGroups->pTCG[i].edges_flow += nEdgeFlow;
1567 : :
1568 : 0 : exit_function:
1569 : 0 : return ret;
1570 : : }
1571 : :
1572 : :
1573 : : /****************************************************************************/
1574 : 0 : int nTautEndpointEdgeCap( inp_ATOM *at, VAL_AT *pVA, int i )
1575 : : {
1576 : : /* There are 3 sources of cap-flow = number of unsatisfied valences:
1577 : : -----------------------------------------------------------------
1578 : : 1. pVA[i].cInitFreeValences
1579 : : 2. pCN[0].v.cap - pCN[0].v.flow
1580 : : 3. st[i].chem_bonds_valence - SUM(SINGLE, DOUBLE, TRIPLE bond orders)
1581 : : Reasons: (a) This sum will not include 'ALTERN' bonds
1582 : : (b) until now at[i].chem_bonds_valence was used as a
1583 : : number of satisfied valences. In case of adjacent
1584 : : stereobonds marked as BOND_TYPE_ALTERN the value of
1585 : : at[i].chem_bonds_valence may be = at[i].valence+1.
1586 : : 4. Since tautomerism is defined for a neutral atom, do not add
1587 : : initial flows from the atom to the ChargeStruct
1588 : : CORRECTION: tautomeric endpoints do not have ChargeStruct.
1589 : :
1590 : : */
1591 : : int j, k, nEdgeCap, bonds_valence, stereo_bond_excess_valence;
1592 [ # # ]: 0 : MY_CONST C_NODE *pCN = pVA[i].cnListIndex > 0 ? cnList[pVA[i].cnListIndex - 1].pCN : NULL;
1593 : :
1594 : :
1595 : : /* 1: free valences to reach the minimum known atom valence */
1596 : 0 : nEdgeCap = pVA[i].cInitFreeValences;
1597 : :
1598 : : /* 2: atom free valence in the ChargeStruct */
1599 [ # # ]: 0 : if (pCN)
1600 : : {
1601 : 0 : nEdgeCap += pCN[0].v.cap - pCN[0].v.flow; /* normally should not happen */
1602 : : }
1603 : :
1604 : : /* 3: atom free valence due to known from stereochemistry stereogenic bond types */
1605 : : /*
1606 : : for ( j = 0, bonds_valence = 0; j < at[i].valence; j ++ )
1607 : : {
1608 : : if ( at[i].bond_type[j] <= BOND_TYPE_TRIPLE )
1609 : : {
1610 : : bonds_valence += at[i].bond_type[j];
1611 : : }
1612 : : }
1613 : : */
1614 : :
1615 : : /* bonds > SINGLE are assumed fixed stereobonds; fixed bond cannot increase t-group edge flow */
1616 [ # # # # ]: 0 : for (stereo_bond_excess_valence = 0, j = 0; j < MAX_NUM_STEREO_BONDS && at[i].sb_parity[j]; j++)
1617 : : {
1618 : 0 : k = at[i].sb_ord[j];
1619 [ # # ]: 0 : if (at[i].bond_type[k] < BOND_TYPE_TRIPLE)
1620 : : {
1621 : 0 : stereo_bond_excess_valence += at[i].bond_type[k] - BOND_TYPE_SINGLE;
1622 : : }
1623 : : }
1624 : :
1625 : : /*
1626 : : bonds_valence = (at[i].chem_bonds_valence - bonds_valence) + (bonds_valence -at[i].valence - stereo_bond_excess_valence);
1627 : : */
1628 : 0 : bonds_valence = ( at[i].chem_bonds_valence - at[i].valence ) - stereo_bond_excess_valence;
1629 : :
1630 : :
1631 : : /*---- add 1, 2, 3 ----*/
1632 [ # # ]: 0 : if (bonds_valence >= 0)
1633 : : {
1634 : 0 : nEdgeCap += bonds_valence;
1635 : : }
1636 : : else
1637 : : {
1638 : 0 : nEdgeCap = RI_ERR_PROGR;
1639 : : }
1640 : :
1641 : 0 : return nEdgeCap;
1642 : : }
1643 : :
1644 : :
1645 : : /****************************************************************************/
1646 : : /* If Metal flowers are allowed ( pSrm->bMetalAddFlower != 0), then: */
1647 : : /* */
1648 : : /* bond to a metal atom min_bond_order[i] = pSrm->nMetalMinBondOrder */
1649 : : /* taut endpoint - metal min_bond_order[i] = pSrm->nMetal2EndpointMinBondOrder */
1650 : : /* single bond to metal atom: initial_bond_order[i] = pSrm->nMetalInitBondOrder */
1651 : : /* n-order bond to metal atom initial_bond_order[i] = pSrm->nMetalInitBondOrder + n-1 */
1652 : : /* = bond_order[i]-BOND_TYPE_SINGLE+pSrm->nMetalInitBondOrder */
1653 : : /* single t-endpoint--atom bond initial_bond_order[i] = pSrm->nMetal2EndpointInitBondOrder */
1654 : : /* n-order t-endpoint--metal bond initial_bond_order[i] = pSrm->nMetal2EndpointInitBondOrder+n-1 */
1655 : : /* = bond_order[i]-BOND_TYPE_SINGLE+pSrm->nMetal2EndpointInitBondOrder*/
1656 : : /* */
1657 : : /* Exceptions from simple atom-metal conditions: */
1658 : : /* 1. Atom is a tautomeric endpoint: use pSrm->nMetal2Endpoint* instead of pSrm->nMetal* */
1659 : : /* 2. Atom is sp3-stereogenic and pSrm->bFixStereoBonds != 0: use atom-atom rules */
1660 : : /* 3. Atom has a sp2-stereo and pSrm->bFixStereoBonds != 0: use atom-atom rules */
1661 : : /* */
1662 : : /* Atom-atom rules (applies to all atoms if pSrm->bMetalAddFlower=0) */
1663 : : /* */
1664 : : /* min_bond_order[i] = BOND_TYPE_SINGLE (BOND_TYPE_SINGLE = 1) */
1665 : : /* initial_bond_order[i] = bond_type[i] */
1666 : : /* */
1667 : : /* General rules: */
1668 : : /* initial_bond_flow[i] = initial_bond_order[i]-min_bond_order[i] */
1669 : : /* atom[k] initial_st_cap = at[k].chem_bonds_valence - SUM{i; initial_bond_order[i]} */
1670 : : /* bond_cap[i] = BOND_TYPE_TRIPLE - min_bond_order[i] */
1671 : : /* (reason: quadruple and higher order bonds are not allowed) */
1672 : : /* Exception: in case of metal-atom bond, if pSrm->nMetal2EndpointInitEdgeFlow = 0 AND */
1673 : : /* pSrm->nMetalInitBondOrder - pSrm->nMetalMinBondOrder = 1 then */
1674 : : /* reduce bond to metal order by 1 and increase st_cap of both neighbors by 1: */
1675 : : /* initial_bond_flow[i] --; metal_initial_st_cap += num_bonds; */
1676 : : /* ==== Note: ONLY the INCREASE is already included in pVA->cInitFreeValences of both atoms */
1677 : : /* */
1678 : : /* Notes: initial_st_cap does not include: */
1679 : : /* 1. atom[k] additional st_cap from ChargeStruct pCN[0].v.cap */
1680 : : /* 2. pVA[k].cInitFreeValences due to a difference between the smallest known valence and st_cap */
1681 : : /* */
1682 : : /* here k=atom at[k] index, */
1683 : : /* i=bond index; i = 0..at[k].valence; */
1684 : : /* SUM{i; M[i]} is a sum of M[i] over all i */
1685 : : /* bond_order[i] = at[k].bond_type[i] >= BOND_TYPE_SINGLE - input bond order */
1686 : : /****************************************************************************/
1687 : :
1688 : : /***************** new *************************************************************************************/
1689 : :
1690 : 0 : int BondFlowMaxcapMinorder( inp_ATOM *atom,
1691 : : VAL_AT *pVA,
1692 : : ICHICONST SRM *pSrm,
1693 : : int iat,
1694 : : int ineigh,
1695 : : int *pnMaxcap,
1696 : : int *pnMinorder,
1697 : : int *pbNeedsFlower )
1698 : : {
1699 : :
1700 : 0 : int nFlow, nMaxcap, nMinorder, nInitorder, bNeedsFlower = 0;
1701 : 0 : inp_ATOM *at = atom + iat;
1702 : 0 : int neigh = at->neighbor[ineigh];
1703 : 0 : int bond_type = at->bond_type[ineigh] & BOND_TYPE_MASK;
1704 : 0 : int nMetal = ( 0 != pVA[iat].cMetal ) + ( 0 != pVA[neigh].cMetal );
1705 : 0 : int nEndpoint = ( 0 != at->endpoint ) + ( 0 != atom[neigh].endpoint );
1706 [ # # # # : 0 : int nStereo = ( at->p_parity || at->sb_parity[0] ) + ( atom[neigh].p_parity || atom[neigh].sb_parity[0] );
# # # # ]
1707 : :
1708 [ # # ]: 0 : if (bond_type > BOND_TYPE_TRIPLE)
1709 : : {
1710 : 0 : bond_type = BOND_TYPE_SINGLE;
1711 : : }
1712 : :
1713 : : /* M=metal, A=non-metal atom, e=endpoint */
1714 [ # # # # : 0 : if ((nStereo && pSrm->bFixStereoBonds) || !nMetal || !pSrm->bMetalAddFlower) /* djb-rwth: addressing LLVM warning */
# # # # ]
1715 : : {
1716 : : /* atom-atom rules, no metal atoms involved (1: A-A, A-Ae, Ae-Ae) */
1717 : 0 : nMinorder = BOND_TYPE_SINGLE;
1718 : 0 : nInitorder = bond_type;
1719 : 0 : nFlow = nInitorder - nMinorder;
1720 : : }
1721 [ # # # # ]: 0 : else if (nMetal && !nEndpoint)
1722 : : {
1723 : : /* M-a, M-M */
1724 : : /* atom - metal or metal-metal, none of them is an endpoint (2: M-M, M-A) */
1725 : 0 : nMinorder = pSrm->nMetalMinBondOrder;
1726 : 0 : nInitorder = pSrm->nMetalInitBondOrder + bond_type - BOND_TYPE_SINGLE;
1727 : 0 : nFlow = nInitorder - nMinorder;
1728 [ # # ]: 0 : if (!pSrm->nMetalInitEdgeFlow &&
1729 [ # # # # ]: 0 : pSrm->nMetalInitBondOrder > pSrm->nMetalMinBondOrder &&
1730 : : nFlow > 0)
1731 : : {
1732 : : /* reduce initial flow by 1 and increase st_cap on metal by 1 */
1733 : 0 : nFlow--;
1734 : : }
1735 : 0 : bNeedsFlower = ( 0 != pVA[iat].cMetal );
1736 : : }
1737 : : else
1738 [ # # # # : 0 : if ((pVA[iat].cMetal && !at->endpoint && !pVA[neigh].cMetal && atom[neigh].endpoint) ||
# # # # ]
1739 [ # # # # : 0 : (pVA[neigh].cMetal && !atom[neigh].endpoint && !pVA[iat].cMetal && at->endpoint)) /* djb-rwth: addressing LLVM warnings */
# # # # ]
1740 : : {
1741 : : /* M-ae */
1742 : : /* metal connected to a non-metal endpoint (3: M-Ae) */
1743 : 0 : nMinorder = pSrm->nMetal2EndpointMinBondOrder;
1744 : 0 : nInitorder = pSrm->nMetal2EndpointInitBondOrder + bond_type - BOND_TYPE_SINGLE;
1745 : 0 : nFlow = nInitorder - nMinorder;
1746 [ # # ]: 0 : if (!pSrm->nMetal2EndpointInitEdgeFlow &&
1747 [ # # # # ]: 0 : pSrm->nMetal2EndpointInitBondOrder > pSrm->nMetal2EndpointMinBondOrder &&
1748 : : nFlow > 0)
1749 : : {
1750 : : /* reduce initial flow by 1 and increase st_cap on metal by 1 */
1751 : 0 : nFlow--;
1752 : : }
1753 : 0 : bNeedsFlower = ( 0 != pVA[iat].cMetal );
1754 : : }
1755 : : else
1756 : : {
1757 : : /* endpoint is metal => no flower (4: M-Me, Me-Me, Me-A, Me-Ae) */
1758 : 0 : nMinorder = pSrm->nMetal2EndpointMinBondOrder;
1759 : 0 : nInitorder = pSrm->nMetal2EndpointInitBondOrder + bond_type - BOND_TYPE_SINGLE;
1760 : 0 : nFlow = nInitorder - nMinorder;
1761 [ # # ]: 0 : if (!pSrm->nMetal2EndpointInitEdgeFlow &&
1762 [ # # # # ]: 0 : pSrm->nMetal2EndpointInitBondOrder > pSrm->nMetal2EndpointMinBondOrder &&
1763 : : nFlow > 0)
1764 : : {
1765 : : /* reduce initial flow by 1 and increase st_cap on metal by 1 */
1766 : 0 : nFlow--;
1767 : : }
1768 [ # # # # ]: 0 : bNeedsFlower = ( pVA[iat].cMetal && !at->endpoint );
1769 : : }
1770 : :
1771 : 0 : nMaxcap = BOND_TYPE_TRIPLE - nMinorder;
1772 [ # # ]: 0 : if (pnMaxcap)
1773 : : {
1774 : 0 : *pnMaxcap = nMaxcap;
1775 : : }
1776 [ # # ]: 0 : if (pnMinorder)
1777 : : {
1778 : 0 : *pnMinorder = nMinorder;
1779 : : }
1780 [ # # ]: 0 : if (pbNeedsFlower)
1781 : : {
1782 : 0 : *pbNeedsFlower = bNeedsFlower;
1783 : : }
1784 : :
1785 : 0 : return nFlow;
1786 : : }
1787 : :
1788 : :
1789 : : /*********** new *******************************************************************************************/
1790 : 0 : int AtomStcapStflow( inp_ATOM *atom, VAL_AT *pVA, ICHICONST SRM *pSrm, int iat, int *pnStcap, int *pnStflow,
1791 : : EdgeFlow *pnMGroupEdgeCap, EdgeFlow *pnMGroupEdgeFlow )
1792 : : {
1793 : : int ineigh, bFlower;
1794 : 0 : int nStflow = 0, nMaxBondCap, nMinBondOrder, bNeedsFlower = 0;
1795 : 0 : int valence = atom[iat].valence;
1796 : 0 : int nStcap = atom[iat].chem_bonds_valence;
1797 : 0 : int nMGroupEdgeCap = 0, nMGroupEdgeFlow = 0, nFlow;
1798 : :
1799 [ # # ]: 0 : if (pSrm->bMetalAddFlower)
1800 : : {
1801 : 0 : nStcap -= pVA[iat].cInitOrigValenceToMetal - pVA[iat].cInitValenceToMetal;
1802 : : }
1803 : :
1804 [ # # ]: 0 : for (ineigh = 0; ineigh < valence; ineigh++)
1805 : : {
1806 : 0 : nFlow = BondFlowMaxcapMinorder( atom, pVA, pSrm, iat, ineigh, &nMaxBondCap, &nMinBondOrder, &bFlower );
1807 : 0 : nStflow += nFlow;
1808 : 0 : nStcap -= nMinBondOrder;
1809 [ # # ]: 0 : if (bFlower)
1810 : : {
1811 : 0 : bNeedsFlower++;
1812 : 0 : nMGroupEdgeFlow += nFlow;
1813 : 0 : nMGroupEdgeCap += BOND_TYPE_TRIPLE - nMinBondOrder + pSrm->nMetalMaxCharge_D;
1814 : : }
1815 : : }
1816 : :
1817 [ # # ]: 0 : if (pnStcap)
1818 : : {
1819 [ # # ]: 0 : *pnStcap = bNeedsFlower ? nStflow : nStcap; /* initially, metal atoms are not radicals */
1820 : : }
1821 [ # # ]: 0 : if (pnStflow)
1822 : : {
1823 : 0 : *pnStflow = nStflow;
1824 : : }
1825 [ # # ]: 0 : if (pnMGroupEdgeFlow)
1826 : : {
1827 : 0 : *pnMGroupEdgeFlow = nMGroupEdgeCap - nMGroupEdgeFlow;
1828 : : }
1829 [ # # ]: 0 : if (pnMGroupEdgeCap)
1830 : : {
1831 : 0 : *pnMGroupEdgeCap = nMGroupEdgeCap;
1832 : : }
1833 : :
1834 : 0 : return bNeedsFlower; /* number of variable bonds to metal */
1835 : : }
1836 : :
1837 : :
1838 : : /**************************************************************************************
1839 : : int nCountBnsSizes( inp_ATOM *at, int num_at, int nAddEdges2eachAtom, int nAddVertices,
1840 : : T_GROUP_INFO *ti, VAL_AT *pVA, ALL_TC_GROUPS *pTCGroups )
1841 : :
1842 : : fills out totals:
1843 : :
1844 : : pTCGroups->num_atoms = number of atoms
1845 : : pTCGroups->num_bonds = number of bonds between atoms
1846 : : pTCGroups->num_tgroups = number of tautomeric groups
1847 : : pTCGroups->num_tgroup_edges = number of edges to tautomeric groups
1848 : : pTCGroups->tgroup_charge = total charge on thautomeric atoms (negative)
1849 : : pTCGroups->num_tc_groups = total number of all groups
1850 : : pTCGroups->nVertices = total number of vertices excluding groups interconnections
1851 : : pTCGroups->nEdges = total number of edges excluding groups interconnections
1852 : :
1853 : : creates entries for the groups and adds to each group:
1854 : :
1855 : : TC_GROUP::type = BNS_VERT_TYPE_TGROUP, BNS_VT_C_POS, BNS_VT_C_NEG, BNS_VT_C_POS_C, BNS_VT_C_NEG_C
1856 : : TC_GROUP::ord_num = ordering number within the type, e.g. t-group number
1857 : : TC_GROUP::st_cap = all from the atoms in ChargeStruct or tautomeric group info.
1858 : : TC_GROUP::st_flow = all from the atoms in ChargeStruct (0 for t-groups).
1859 : : TC_GROUP::num_edges = number of edges to the atoms or ChargeStruct vertices.
1860 : : TC_GROUP::edges_cap = sum of all incoming edge caps; see also nTautEndpointEdgeCap(..).
1861 : : TC_GROUP::edges_flow = sum of all incoming edge flows; 0 for t-groups.
1862 : :
1863 : : TC_GROUP::nVertexNumber - NO FILLED WITH ANYTHING
1864 : :
1865 : : Note: the nDelta = st_cap - st_flow needs to be preserved when adding more vertices
1866 : :
1867 : : Return value: =0 => success
1868 : : <0 => error
1869 : : **************************************************************************************/
1870 : 0 : int nCountBnsSizes( inp_ATOM *at, int num_at, int nAddEdges2eachAtom, int nAddVertices,
1871 : : T_GROUP_INFO *ti, VAL_AT *pVA, ICHICONST SRM *pSrm, ALL_TC_GROUPS *pTCGroups )
1872 : : {
1873 : 0 : int i, j, n, k, ret = 0, nBonds, nOtherEdges, nVertices, bMetalAtoms, bNeedsFlower;
1874 : : int nTgroupEdges, nTgroupEdgesFromTg, nTotNegChargInTgroups, cap, flow;
1875 : 0 : MY_CONST C_NODE *pCN = NULL;
1876 : 0 : nVertices = nBonds = nOtherEdges = nTgroupEdges = nTgroupEdgesFromTg = nTotNegChargInTgroups = 0;
1877 : :
1878 : : /* count metal atoms and electrons */
1879 [ # # ]: 0 : for (i = 0; i < num_at; i++)
1880 : : {
1881 : 0 : pTCGroups->num_metal_atoms += ( pVA[i].cMetal != 0 );
1882 : 0 : pTCGroups->num_metal_bonds += pVA[i].cNumBondsToMetal;
1883 : 0 : pTCGroups->total_electrons += at[i].el_number;
1884 [ # # ]: 0 : pTCGroups->total_electrons_metals += pVA[i].cMetal ? at[i].el_number : 0;
1885 : : }
1886 : 0 : pTCGroups->total_electrons -= pTCGroups->total_charge;
1887 : 0 : pTCGroups->num_metal_bonds /= 2;
1888 : :
1889 : : /* register tautomeric groups */
1890 [ # # ]: 0 : for (i = 0; i < ti->num_t_groups; i++)
1891 : : {
1892 : 0 : ret = RegisterTCGroup( pTCGroups,
1893 : : BNS_VERT_TYPE_TGROUP,
1894 : 0 : ti->t_group[i].nGroupNumber,
1895 : 0 : ti->t_group[i].num[0] /* st_cap */,
1896 : : 0 /* st_flow */,
1897 : : 0 /* edge cap */,
1898 : : 0 /* edge flow */,
1899 : 0 : ti->t_group[i].nNumEndpoints /* num Edges */
1900 : : );
1901 [ # # ]: 0 : if (ret < 0)
1902 : : {
1903 : 0 : goto exit_function;
1904 : : }
1905 : :
1906 : : /* edges to tautomeric groups */
1907 : 0 : nOtherEdges += ti->t_group[i].nNumEndpoints;
1908 : 0 : nTgroupEdgesFromTg += ti->t_group[i].nNumEndpoints;
1909 : : /* total negative charge in t-groups */
1910 : 0 : nTotNegChargInTgroups += ti->t_group[i].num[1];
1911 [ # # ]: 0 : if (ret > 0)
1912 : : {
1913 : : /* should always happen since this is the first time this t-group is added */
1914 : 0 : j = ret - 1;
1915 : 0 : pTCGroups->pTCG[j].tg_num_H = ti->t_group[i].num[0] - ti->t_group[i].num[1];
1916 : 0 : pTCGroups->pTCG[j].tg_num_Minus = ti->t_group[i].num[1];
1917 : : }
1918 : : }
1919 : :
1920 : 0 : bMetalAtoms = 0;
1921 : :
1922 : 0 : repeat_for_metals:
1923 : :
1924 : : /* count vertices and register ChargeValence groups */
1925 : : /* for now an atom may belong either to a t-group or to a ChargeValence group, but not to both */
1926 [ # # ]: 0 : for (i = 0; i < num_at; i++)
1927 : : {
1928 : : /* number of bonds */
1929 : 0 : nBonds += at[i].valence;
1930 : : /* Process ChargeStruct vertices and edges */
1931 [ # # ]: 0 : if (pVA[i].cnListIndex)
1932 : : {
1933 : : /* count vertices & edges in the ChargeValence Substructure attached to an atom */
1934 : : /* Important: unlike inp_ATOM, each edge e appears in pCN[*].e[*] only ONE time */
1935 : 0 : int len = cnList[j = pVA[i].cnListIndex - 1].len;
1936 : 0 : int bits = cnList[j].bits;
1937 : : int type, neigh_type; /* djb-rwth: removing redundant variables */
1938 : 0 : pCN = cnList[j].pCN;
1939 : :
1940 : : /* first process all non-metals, after that -- all metals */
1941 [ # # ]: 0 : if (( bits != cn_bits_Me ) != !bMetalAtoms)
1942 : : {
1943 : 0 : continue;
1944 : : }
1945 : : /* djb-rwth: removing redundant code */
1946 [ # # ]: 0 : for (j = 0; j < len; j++)
1947 : : {
1948 : 0 : type = pCN[j].v.type; /* ChargeStruct vertex type: atom is the first, c-groups are last */
1949 : :
1950 : : /* process all pCN[j] neighbors */
1951 [ # # # # ]: 0 : for (k = 0; k < MAX_CN_VAL && ( n = pCN[j].e[k].neigh ); k++)
1952 : : {
1953 : 0 : nOtherEdges++; /* edges inside ChargeStruct */
1954 : 0 : n--; /* neighbor vertex position inside cnList[j].pCN */
1955 : 0 : neigh_type = pCN[n].v.type; /* type of the neighboring atom */
1956 : :
1957 [ # # ]: 0 : if (IS_BNS_VT_C_GR( neigh_type ))
1958 : : {
1959 : : /* register this edge to a CN-group vertex */
1960 [ # # # # ]: 0 : cap = !bMetalAtoms ? pCN[j].e[k].cap : pCN[j].e[k].cap ? pSrm->nMetalMaxCharge_D : 0;
1961 [ # # # # ]: 0 : flow = !bMetalAtoms ? pCN[j].e[k].flow : pCN[j].e[k].flow ? pSrm->nMetalMaxCharge_D : 0;
1962 : :
1963 : 0 : ret = RegisterTCGroup( pTCGroups,
1964 : : neigh_type,
1965 : : 0 /* ord_num*/,
1966 : : 0 /* st_cap */,
1967 : : 0 /* st_flow */,
1968 : : cap /* edge cap*/,
1969 : : flow /* edge flow */,
1970 : : 1 /* nNumEdges*/ );
1971 [ # # ]: 0 : if (ret < 0)
1972 : : {
1973 : 0 : goto exit_function;
1974 : : }
1975 [ # # ]: 0 : if (ret > 0)
1976 : : {
1977 : : /* the group has just been created; add one more edge to (+/-) or supergroup */
1978 : 0 : ret = RegisterTCGroup( pTCGroups,
1979 : : neigh_type,
1980 : : 0 /* ord_num*/,
1981 : : 0 /* st_cap */,
1982 : : 0 /* st_flow */,
1983 : : 0 /* edge cap*/,
1984 : : 0/* edge flow*/,
1985 : : 1 /* nNumEdges*/ );
1986 [ # # ]: 0 : if (ret < 0)
1987 : : {
1988 : 0 : goto exit_function;
1989 : : }
1990 : 0 : nOtherEdges++;
1991 : : }
1992 : : }
1993 : :
1994 [ # # ]: 0 : if (IS_BNS_VT_C_GR( type ))
1995 : : {
1996 : : /* register this edge to a CN-group vertex; normally this does not happen */
1997 : :
1998 [ # # # # ]: 0 : cap = !bMetalAtoms ? pCN[j].e[k].cap : pCN[j].e[k].cap ? pSrm->nMetalMaxCharge_D : 0;
1999 [ # # # # ]: 0 : flow = !bMetalAtoms ? pCN[j].e[k].flow : pCN[j].e[k].flow ? pSrm->nMetalMaxCharge_D : 0;
2000 : :
2001 : 0 : ret = RegisterTCGroup( pTCGroups, type, 0 /* ord_num*/,
2002 : : 0 /* st_cap */, 0 /* st_flow */,
2003 : : cap /* edge cap*/, flow /* edge flow */, 1 /* nNumEdges*/ );
2004 [ # # ]: 0 : if (ret < 0)
2005 : : {
2006 : 0 : goto exit_function;
2007 : : }
2008 [ # # ]: 0 : if (ret > 0)
2009 : : {
2010 : : /* the group has just been created; add one more edge to (+/-) or supergroup */
2011 : 0 : ret = RegisterTCGroup( pTCGroups, type, 0 /* ord_num*/,
2012 : : 0 /* st_cap */, 0 /* st_flow */,
2013 : : 0 /* edge cap*/, 0/* edge flow*/, 1 /* nNumEdges*/ );
2014 [ # # ]: 0 : if (ret < 0)
2015 : : {
2016 : 0 : goto exit_function;
2017 : : }
2018 : 0 : nOtherEdges++;
2019 : : }
2020 : : }
2021 : : } /* end of the current vertex pCN[j] neighbors */
2022 : :
2023 : : /* process pCN[j] vertex */
2024 : :
2025 [ # # ]: 0 : if (type & BNS_VERT_TYPE_ATOM)
2026 : : {
2027 : 0 : continue; /* do not count regular atoms here */
2028 : : }
2029 [ # # # # ]: 0 : if (IS_BNS_VT_CHRG_STRUCT( type ))
2030 : : {
2031 : 0 : nVertices++;
2032 : 0 : continue;
2033 : : }
2034 : :
2035 [ # # # # ]: 0 : if (pSrm->bMetalAddFlower && IS_BNS_VT_M_GR( type ))
2036 : 0 : {
2037 : : /* special treatment: flow and cap are known as well as structure */
2038 : : /* initial bond valence to metal is either 0 or 1 */
2039 : : EdgeFlow nEdgeFlow, nEdgeCap;
2040 : :
2041 : 0 : bNeedsFlower = AtomStcapStflow( at, pVA, pSrm, i, NULL /*pnStcap*/, NULL /*pnStflow*/,
2042 : : &nEdgeCap, &nEdgeFlow );
2043 [ # # ]: 0 : if (!bNeedsFlower)
2044 : : {
2045 : 0 : ret = RI_ERR_PROGR;
2046 : 0 : goto exit_function;
2047 : : }
2048 : : /*
2049 : : GetAtomToMCGroupInitEdgeCapFlow( &nEdgeCap, &nEdgeFlow, pSrm, at, pVA, i );
2050 : : GetAtomToMCGroupInitEdgeCapFlow( &nEdgeCap, &nEdgeFlow, pSrm );
2051 : : */
2052 : : /* the 1st is the flower base */
2053 : : /* atom - G0 edge and G0 vertex */
2054 : 0 : ret = RegisterTCGroup( pTCGroups,
2055 : : type,
2056 : : 0 /* ord_num*/,
2057 : : /*pVA[i].cInitFreeValences*/
2058 : : 0 /* st_cap */,
2059 : : 0 /* st_flow */,
2060 : : (int) nEdgeCap,
2061 : : (int) nEdgeFlow,
2062 : : 1 /* nNumEdges*/ );
2063 [ # # ]: 0 : if (ret < 0)
2064 : : {
2065 : 0 : goto exit_function;
2066 : : }
2067 : : /* count edge atom-G0 */
2068 : 0 : nOtherEdges++;
2069 [ # # ]: 0 : if (ret > 0)
2070 : : {
2071 : : /* first time registration: add G0-G1 and G0-G2 edges to G0 */
2072 : :
2073 : 0 : ret = RegisterTCGroup( pTCGroups,
2074 : : type,
2075 : : 0 /* ord_num*/,
2076 : : 0 /* st_cap */,
2077 : : 0 /* st_flow */,
2078 : : 0,/* edge cap*/
2079 : : 0 /*edge flow*/,
2080 : : 2 /* nNumEdges*/ );
2081 : :
2082 [ # # ]: 0 : if (ret < 0)
2083 : : {
2084 : 0 : goto exit_function;
2085 : : }
2086 : :
2087 : : /* first time registration: add G1; it has 3 edges */
2088 : :
2089 : 0 : ret = RegisterTCGroup( pTCGroups,
2090 : : type,
2091 : : 1 /* ord_num*/,
2092 : : 0 /* st_cap */,
2093 : : 0 /* st_flow */,
2094 : : 0,/* edge cap*/
2095 : : 0 /*edge flow*/,
2096 : : 3 /* nNumEdges*/ );
2097 : :
2098 [ # # ]: 0 : if (ret <= 0)
2099 : : {
2100 [ # # ]: 0 : ret = !ret ? RI_ERR_PROGR : ret;
2101 : 0 : goto exit_function;
2102 : : }
2103 : :
2104 : : /* first time registration: add G2; it has 3 edges */
2105 : :
2106 : 0 : ret = RegisterTCGroup( pTCGroups,
2107 : : type,
2108 : : 2 /* ord_num*/,
2109 : : 0 /* st_cap */,
2110 : : 0 /* st_flow */,
2111 : : 0,/* edge cap*/
2112 : : 0 /*edge flow*/,
2113 : : 3 /* nNumEdges*/ );
2114 : :
2115 [ # # ]: 0 : if (ret <= 0)
2116 : : {
2117 [ # # ]: 0 : ret = !ret ? RI_ERR_PROGR : ret;
2118 : 0 : goto exit_function;
2119 : : }
2120 : :
2121 : : /* first time registration: add G3; it has 2 edges */
2122 : :
2123 : 0 : ret = RegisterTCGroup( pTCGroups,
2124 : : type,
2125 : : 3 /* ord_num*/,
2126 : : 0 /* st_cap */,
2127 : : 0 /* st_flow */,
2128 : : 0,/* edge cap*/
2129 : : 0 /*edge flow*/,
2130 : : 2 /* nNumEdges*/ );
2131 : :
2132 [ # # ]: 0 : if (ret <= 0)
2133 : : {
2134 [ # # ]: 0 : ret = !ret ? RI_ERR_PROGR : ret;
2135 : 0 : goto exit_function;
2136 : : }
2137 : : /* count added metal flower vertices: G0, G1, G2, G3 */
2138 : 0 : nVertices += 4;
2139 : : /* count added metal flower edges: C0-C1, C0-C2, C1-C2, C1-C3, C2-C3 */
2140 : 0 : nOtherEdges += 5;
2141 : : /* add connections of G0 to G1 and G2 */
2142 : : }
2143 : 0 : continue;
2144 : : }
2145 : :
2146 : 0 : nVertices++; /* count BNS_VT_C_POS* types; all contain BNS_VERT_TYPE_C_GROUP bit */
2147 [ # # ]: 0 : if (!IS_BNS_VT_C_GR( type ))
2148 : : { /* check */
2149 : 0 : ret = RI_ERR_PROGR;
2150 : 0 : goto exit_function;
2151 : : }
2152 : : /* add st_cap and st_flow for a charge group */
2153 [ # # # # ]: 0 : cap = !bMetalAtoms ? pCN[j].v.cap : pCN[j].v.cap ? pSrm->nMetalMaxCharge_D : 0;
2154 [ # # # # ]: 0 : flow = !bMetalAtoms ? pCN[j].v.flow : pCN[j].v.flow ? pSrm->nMetalMaxCharge_D : 0;
2155 : :
2156 : 0 : ret = RegisterTCGroup( pTCGroups, type, 0 /* ord_num*/,
2157 : : cap /* st-cap*/, flow /* st-flow */,
2158 : : 0 /* edge cap */, 0 /* edge flow */, 0 /* edges already counted */ );
2159 [ # # ]: 0 : if (ret < 0)
2160 : : {
2161 : 0 : goto exit_function;
2162 : : }
2163 : : }
2164 : : }
2165 : : else
2166 : : {
2167 : 0 : pCN = NULL;
2168 : : }
2169 : :
2170 : : /* count edge caps to t-groups */
2171 [ # # ]: 0 : if (at[i].endpoint)
2172 : : {
2173 : 0 : int nEdgeCap = nTautEndpointEdgeCap( at, pVA, i );
2174 : 0 : nTgroupEdges++;
2175 [ # # ]: 0 : if (nEdgeCap < 0)
2176 : : {
2177 : 0 : ret = nEdgeCap;
2178 : 0 : goto exit_function;
2179 : : }
2180 : :
2181 : : /* add number of unsatisfied valences for a t-group; the unknown flow = 0 */
2182 : 0 : ret = RegisterTCGroup( pTCGroups,
2183 : : BNS_VERT_TYPE_TGROUP,
2184 : 0 : at[i].endpoint,
2185 : : 0 /* st_cap */,
2186 : : 0 /* st_flow */,
2187 : : nEdgeCap /* edge cap */,
2188 : : 0 /* edge flow */,
2189 : : 0 /* t-group edges have already been counted */ );
2190 [ # # ]: 0 : if (ret < 0)
2191 : : {
2192 : 0 : goto exit_function;
2193 : : }
2194 : : }
2195 : : }
2196 : :
2197 [ # # # # ]: 0 : if (!bMetalAtoms && pTCGroups->num_metal_atoms)
2198 : : {
2199 : 0 : bMetalAtoms = 1;
2200 : 0 : nBonds = 0; /* added 2006-05-15 */
2201 : 0 : goto repeat_for_metals;
2202 : : }
2203 : :
2204 : : /* count real atoms and bonds */
2205 : 0 : nBonds /= 2;
2206 : 0 : pTCGroups->num_atoms = num_at;
2207 : 0 : pTCGroups->num_bonds = nBonds;
2208 : :
2209 : 0 : pTCGroups->num_tgroups = ti->num_t_groups;
2210 : 0 : pTCGroups->num_tgroup_edges = nTgroupEdges;
2211 : 0 : pTCGroups->tgroup_charge = -nTotNegChargInTgroups;
2212 : :
2213 [ # # # # ]: 0 : if (0 <= ret && nTgroupEdgesFromTg != nTgroupEdges)
2214 : : {
2215 : 0 : ret = BNS_PROGRAM_ERR;
2216 : : }
2217 : :
2218 : 0 : nVertices += num_at;
2219 : :
2220 : :
2221 : : /* count other vertices */
2222 : 0 : nVertices += ti->num_t_groups;
2223 : 0 : nBonds += nOtherEdges;
2224 : :
2225 : : /* return edges and vertices */
2226 : 0 : pTCGroups->nVertices = nVertices;
2227 : 0 : pTCGroups->nEdges = nBonds;
2228 : :
2229 : :
2230 : 0 : exit_function:
2231 : 0 : return ret;
2232 : : }
2233 : :
2234 : :
2235 : : /****************************************************************
2236 : : int nAddSuperCGroups( ALL_TC_GROUPS *pTCGroups )
2237 : :
2238 : : 1. adds BNS_VT_C_POS_ALL and BNS_VT_C_NEG_ALL ONLY if both
2239 : : {TCG_Plus0 and TCG_Plus_C0} and/or
2240 : : {TCG_Minus0 and TCG_Minus_C0} are present, respectively
2241 : :
2242 : : 2. fills pTCGroups->nGroup[]:
2243 : :
2244 : : pTCGroups->nGroup[k] < 0 => does not exist
2245 : : pTCGroups->nGroup[k] = i => the group is pTCGroups->pTCG[i]
2246 : :
2247 : : where group group
2248 : : k = type number
2249 : : TCG_Plus0 BNS_VT_C_POS 0
2250 : : TCG_Plus1, BNS_VT_C_POS 1
2251 : : TCG_Minus0, BNS_VT_C_NEG 0
2252 : : TCG_Minus1, BNS_VT_C_NEG 1
2253 : : TCG_Plus_C0, BNS_VT_C_POS_C 0
2254 : : TCG_Plus_C1, BNS_VT_C_POS_C 1
2255 : : TCG_Minus_C0, BNS_VT_C_NEG_C 0
2256 : : TCG_Minus_C1, BNS_VT_C_NEG_C 1
2257 : : TCG_Plus, BNS_VT_C_POS_ALL 0
2258 : : TCG_Minus, BNS_VT_C_NEG_ALL 0
2259 : :
2260 : : only groups with number 0 are processed
2261 : :
2262 : : 3. If only one of the groups in pairs mentioned in (1) above
2263 : : is present then
2264 : :
2265 : : pTCGroups->nGroup[TCG_Plus] := pTCGroups->nGroup[TCG_Plus0] or
2266 : : pTCGroups->nGroup[TCG_Plus] := pTCGroups->nGroup[TCG_Plus_C0];
2267 : : an additional BNS_VT_C_POS_ALL vertex is not created
2268 : :
2269 : : same for pTCGroups->nGroup[TCG_Minus] and BNS_VT_C_NEG_ALL
2270 : :
2271 : : 4. Adds to these new "supergroups" (TCG_Plus, TCG_Minus)
2272 : : descriptions in pTCGroups->pTCG[k]
2273 : : st_cap, st_flow, edges cap and flow from the corresponding
2274 : : groups {TCG_Plus0 and TCG_Plus_C0}. Same for the Minus groups.
2275 : : Stores indexes k in
2276 : : pTCGroups->nGroup[TCG_Plus], pTCGroups->nGroup[TCG_Minus]
2277 : :
2278 : : ****************************************************************/
2279 : 0 : int nAddSuperCGroups( ALL_TC_GROUPS *pTCGroups )
2280 : : {
2281 : 0 : int i, k, n, n1, n2, n3, ret = 0, nNumToConnect; /* djb-rwth: removing redundant variables */
2282 : :
2283 [ # # ]: 0 : for (i = 0; i < pTCGroups->num_tc_groups; i++)
2284 : : {
2285 [ # # ]: 0 : if (pTCGroups->pTCG[i].type & BNS_VERT_TYPE_TGROUP)
2286 : : {
2287 : : /* djb-rwth: removing redundant code */
2288 : 0 : continue; /* t-group */
2289 : : }
2290 [ # # ]: 0 : if (IS_BNS_VT_C_GR( pTCGroups->pTCG[i].type ) ||
2291 [ # # ]: 0 : IS_BNS_VT_M_GR( pTCGroups->pTCG[i].type ))
2292 : : {
2293 : : /* ChargeValence (cn) group */
2294 [ # # # # : 0 : switch (pTCGroups->pTCG[i].type)
# # # # ]
2295 : : {
2296 : 0 : case BNS_VT_C_POS:
2297 : 0 : k = TCG_Plus0;
2298 : 0 : break;
2299 : 0 : case BNS_VT_C_NEG:
2300 : 0 : k = TCG_Minus0;
2301 : 0 : break;
2302 : 0 : case BNS_VT_C_POS_C:
2303 : 0 : k = TCG_Plus_C0;
2304 : 0 : break;
2305 : 0 : case BNS_VT_C_NEG_C:
2306 : 0 : k = TCG_Minus_C0;
2307 : 0 : break;
2308 : 0 : case BNS_VT_C_POS_M:
2309 : 0 : k = TCG_Plus_M0;
2310 : 0 : break;
2311 : 0 : case BNS_VT_C_NEG_M:
2312 : 0 : k = TCG_Minus_M0;
2313 : 0 : break;
2314 : 0 : case BNS_VT_M_GROUP:
2315 [ # # # # : 0 : switch (pTCGroups->pTCG[i].ord_num)
# ]
2316 : : {
2317 : 0 : case 0:
2318 : 0 : k = TCG_MeFlower0;
2319 : 0 : break;
2320 : 0 : case 1:
2321 : 0 : k = TCG_MeFlower1;
2322 : 0 : break;
2323 : 0 : case 2:
2324 : 0 : k = TCG_MeFlower2;
2325 : 0 : break;
2326 : 0 : case 3:
2327 : 0 : k = TCG_MeFlower3;
2328 : 0 : break;
2329 : 0 : default:
2330 : 0 : ret = RI_ERR_PROGR; /* unexpected group type */
2331 : 0 : goto exit_function;
2332 : : }
2333 : 0 : break;
2334 : :
2335 : 0 : default:
2336 : 0 : ret = RI_ERR_PROGR; /* unexpected group type */
2337 : 0 : goto exit_function;
2338 : : }
2339 : :
2340 [ # # # # : 0 : if (pTCGroups->nGroup[k] >= 0 || (pTCGroups->pTCG[i].ord_num && !IS_BNS_VT_M_GR( pTCGroups->pTCG[i].type ))) /* djb-rwth: addressing LLVM warning */
# # ]
2341 : : {
2342 : 0 : ret = RI_ERR_PROGR;
2343 : 0 : goto exit_function;
2344 : : }
2345 : 0 : pTCGroups->nGroup[k] = i; /* ordering number of the Charge group, starting from 0 */
2346 : : }
2347 : : }
2348 : :
2349 : : /* add (+) supergroup */
2350 : 0 : n1 = pTCGroups->nGroup[TCG_Plus0];
2351 : 0 : n2 = pTCGroups->nGroup[TCG_Plus_C0];
2352 : 0 : n3 = pTCGroups->nGroup[TCG_Plus_M0];
2353 : 0 : nNumToConnect = ( n1 >= 0 ) + ( n2 >= 0 ) + ( n3 >= 0 );
2354 : :
2355 [ # # ]: 0 : if (nNumToConnect)
2356 : : {
2357 : : /* if both groups are present then add a supergroup */
2358 : 0 : ret = RegisterTCGroup( pTCGroups,
2359 : : BNS_VT_C_POS_ALL,
2360 : : 0,
2361 : : 0 /* st_cap */,
2362 : : 0 /* st_flow */,
2363 : : 0 /* edge cap */,
2364 : : 0 /* edge flow */,
2365 : : 1 + nNumToConnect
2366 : : /* one more edge to connect to */
2367 : : /* an additional (+/-) vertex */ );
2368 : :
2369 [ # # ]: 0 : if (ret <= 0)
2370 : : {
2371 [ # # ]: 0 : ret = !ret ? RI_ERR_PROGR : ret;
2372 : 0 : goto exit_function;
2373 : : }
2374 : :
2375 : 0 : pTCGroups->nGroup[TCG_Plus] = ret - 1; /* newly added group number */
2376 : 0 : pTCGroups->nVertices += 2; /* two vertices including itself */
2377 : 0 : pTCGroups->nEdges += 1 + nNumToConnect; /* one more edge to connect to an additional (+/-) vertex */
2378 : : }
2379 : :
2380 : : /* add (-) supergroup */
2381 : 0 : n1 = pTCGroups->nGroup[TCG_Minus0];
2382 : 0 : n2 = pTCGroups->nGroup[TCG_Minus_C0];
2383 : 0 : n3 = pTCGroups->nGroup[TCG_Minus_M0];
2384 : 0 : nNumToConnect = ( n1 >= 0 ) + ( n2 >= 0 ) + ( n3 >= 0 );
2385 [ # # ]: 0 : if (nNumToConnect)
2386 : : {
2387 : : /* if both groups are present then add a supergroup */
2388 : :
2389 : 0 : ret = RegisterTCGroup( pTCGroups,
2390 : : BNS_VT_C_NEG_ALL,
2391 : : 0,
2392 : : 0 /* st_cap */,
2393 : : 0 /* st_flow */,
2394 : : 0 /* edge cap */,
2395 : : 0 /* edge flow */,
2396 : : 1 + nNumToConnect /* one more edge to connect to an additional (+/-) vertex */ );
2397 : :
2398 [ # # ]: 0 : if (ret < 0)
2399 : : {
2400 : 0 : goto exit_function;
2401 : : }
2402 : 0 : pTCGroups->nGroup[TCG_Minus] = ret - 1; /* newly added group number */
2403 : 0 : pTCGroups->nVertices += 2; /* needs two vertices including itself */
2404 : 0 : pTCGroups->nEdges += 1 + nNumToConnect; /* one more edge to connect to an additional (+/-) vertex */
2405 : : }
2406 : :
2407 : : /* add neutralization vertex: (+)-()=(-) connection */
2408 : 0 : k = pTCGroups->nGroup[TCG_Minus];
2409 : 0 : n = pTCGroups->nGroup[TCG_Plus];
2410 : 0 : nNumToConnect = ( k >= 0 ) + ( n >= 0 );
2411 [ # # ]: 0 : if (nNumToConnect)
2412 : : {
2413 : 0 : pTCGroups->nVertices += 1;
2414 : 0 : pTCGroups->nEdges += nNumToConnect; /* one edge per super-c-group */
2415 : : }
2416 : :
2417 : 0 : ret = 0;
2418 : :
2419 : 0 : exit_function:
2420 : 0 : return ret;
2421 : : }
2422 : :
2423 : :
2424 : : /*********************************************************************************/
2425 : 0 : int AddTGroups2TCGBnStruct( BN_STRUCT *pBNS,
2426 : : StrFromINChI *pStruct,
2427 : : VAL_AT *pVA,
2428 : : ALL_TC_GROUPS *pTCGroups,
2429 : : int nMaxAddEdges )
2430 : : {
2431 : 0 : int ret = 0;
2432 : 0 : inp_ATOM *at = pStruct->at;
2433 : 0 : int num_atoms = pStruct->num_atoms;
2434 : : int tot_st_cap, tot_st_flow;
2435 : : /* ret = ReInitBnStruct( pBNS ); */
2436 : :
2437 [ # # ]: 0 : if (pTCGroups->num_tgroups /* tgi && tgi->num_t_groups && tgi->t_group*/)
2438 : : {
2439 : : int i, k, endpoint, /*centerpoint,*/ fictpoint;
2440 : 0 : int num_tg = pTCGroups->num_tgroups;
2441 : 0 : int num_edges = pBNS->num_edges;
2442 : 0 : int num_vertices = pBNS->num_vertices;
2443 : : BNS_VERTEX *vert_ficpoint, *vert_ficpoint_prev; /* fictitious vertex describing t-group */
2444 : : BNS_VERTEX *vert_endpoint;
2445 : : BNS_EDGE *edge; /* edge between that vertex and the tautomeric endpoint */
2446 : 0 : int nMaxTGroupNumber = 0;
2447 : : /*ENDPOINT_INFO eif;*/
2448 : :
2449 : : /* Debug: check overflow */
2450 [ # # ]: 0 : if (num_vertices + num_tg >= pBNS->max_vertices)
2451 : : {
2452 : 0 : return BNS_VERT_EDGE_OVFL;
2453 : : }
2454 [ # # ]: 0 : if (num_edges + pTCGroups->num_tgroup_edges >= pBNS->max_edges)
2455 : : {
2456 : 0 : return BNS_VERT_EDGE_OVFL;
2457 : : }
2458 : :
2459 : : /* find the largest t-group ID */
2460 [ # # ]: 0 : for (i = 0; i < pTCGroups->num_tc_groups; i++)
2461 : : {
2462 [ # # ]: 0 : if (pTCGroups->pTCG[i].type & BNS_VERT_TYPE_TGROUP)
2463 : : {
2464 : 0 : k = pTCGroups->pTCG[i].ord_num;
2465 [ # # ]: 0 : if (k <= 0)
2466 : : {
2467 : 0 : return BNS_CPOINT_ERR; /* t-group does not have a number or has a wrong number */
2468 : : }
2469 [ # # ]: 0 : if (k > pTCGroups->num_tc_groups)
2470 : : {
2471 : 0 : return BNS_CPOINT_ERR; /* t-group has a wrong number */
2472 : : }
2473 [ # # ]: 0 : if (k != nMaxTGroupNumber + 1)
2474 : : {
2475 : 0 : return BNS_CPOINT_ERR; /* t-group numbers are not contiguously ascending */
2476 : : }
2477 : 0 : nMaxTGroupNumber = k;
2478 : : }
2479 : : else
2480 : : {
2481 : 0 : break; /* t-groups are contiguous and first in the list */
2482 : : }
2483 : : }
2484 : :
2485 [ # # ]: 0 : if (i != num_tg)
2486 : : {
2487 : 0 : return BNS_CPOINT_ERR; /* number of t-groups is wrong */
2488 : : }
2489 : :
2490 : : /* since t-group IDs may be not contiguous, clear all vertices that will be added.
2491 : : all-zeroes-vertex will be ignored by the BNS
2492 : : */
2493 : 0 : memset( pBNS->vert + num_vertices, 0, nMaxTGroupNumber * sizeof( pBNS->vert[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
2494 : :
2495 : : /* initialize new fictitious vertices */
2496 : 0 : vert_ficpoint_prev = pBNS->vert + num_vertices - 1;
2497 : :
2498 : 0 : tot_st_cap = tot_st_flow = 0;
2499 : :
2500 [ # # ]: 0 : for (i = 0; i < num_tg; i++, vert_ficpoint_prev = vert_ficpoint)
2501 : : {
2502 : : /*
2503 : : vert_ficpoint-1 is the last vertex;
2504 : : vert_ficpoint is the vertex that is being added
2505 : : Note: nGroupNumber are not contiguous
2506 : : */
2507 : 0 : vert_ficpoint = pBNS->vert + num_vertices + pTCGroups->pTCG[i].ord_num - 1;
2508 : 0 : vert_ficpoint->iedge = vert_ficpoint_prev->iedge + vert_ficpoint_prev->max_adj_edges;
2509 : 0 : vert_ficpoint->max_adj_edges = pTCGroups->pTCG[i].num_edges + nMaxAddEdges + BNS_ADD_SUPER_TGROUP;
2510 : 0 : vert_ficpoint->num_adj_edges = 0;
2511 : 0 : vert_ficpoint->st_edge.flow = vert_ficpoint->st_edge.flow0 = 0;
2512 : 0 : vert_ficpoint->st_edge.cap = vert_ficpoint->st_edge.cap0 = pTCGroups->pTCG[i].st_cap;
2513 : 0 : tot_st_cap += pTCGroups->pTCG[i].st_cap;
2514 : 0 : vert_ficpoint->type = pTCGroups->pTCG[i].type;
2515 : 0 : pTCGroups->pTCG[i].nVertexNumber = (int) ( vert_ficpoint - pBNS->vert );
2516 : : }
2517 : :
2518 [ # # ]: 0 : for (endpoint = 0; endpoint < num_atoms; endpoint++)
2519 : : {
2520 [ # # ]: 0 : if (!at[endpoint].endpoint)
2521 : 0 : continue;
2522 : 0 : fictpoint = at[endpoint].endpoint + num_vertices - 1;
2523 : 0 : vert_ficpoint = pBNS->vert + fictpoint; /* t-group vertex */
2524 : 0 : vert_endpoint = pBNS->vert + endpoint; /* endpoint vertex */
2525 : : /* Debug: check overflow */
2526 [ # # ]: 0 : if (fictpoint >= pBNS->max_vertices ||
2527 [ # # ]: 0 : num_edges >= pBNS->max_edges ||
2528 [ # # ]: 0 : vert_ficpoint->num_adj_edges >= vert_ficpoint->max_adj_edges ||
2529 [ # # ]: 0 : vert_endpoint->num_adj_edges >= vert_endpoint->max_adj_edges)
2530 : : {
2531 : 0 : ret = BNS_VERT_EDGE_OVFL;
2532 : 0 : break;
2533 : : }
2534 : :
2535 : : #ifdef NEVER
2536 : : /* obtain donor/acceptor info */
2537 : : if (!nGetEndpointInfo( at, endpoint, &eif ))
2538 : : {
2539 : : ret = BNS_BOND_ERR;
2540 : : break;
2541 : : }
2542 : : #endif
2543 : :
2544 : 0 : vert_endpoint->type |= BNS_VERT_TYPE_ENDPOINT;
2545 : :
2546 : : #ifdef NEVER
2547 : : /* set capacity = 1 to the edges from the endpoint to the centerpoint(s) */
2548 : : for (k = 0; k < vert_endpoint->num_adj_edges; k++)
2549 : : {
2550 : : int iedge = vert_endpoint->iedge[k];
2551 : : if (!pBNS->edge[iedge].cap)
2552 : : {
2553 : : /* single bond, possibly between endpoint and centerpoint */
2554 : : centerpoint = ( pBNS->edge[iedge].neighbor12 ^ endpoint );
2555 : : if (centerpoint < pBNS->num_atoms &&
2556 : : pBNS->vert[centerpoint].st_edge.cap >= 1)
2557 : : {
2558 : : int bond_type = ( at[endpoint].bond_type[k] & BOND_TYPE_MASK );
2559 : : if (bond_type == BOND_TAUTOM ||
2560 : : bond_type == BOND_ALTERN ||
2561 : : bond_type == BOND_ALT12NS ||
2562 : : bond_type == BOND_SINGLE)
2563 : : {
2564 : : pBNS->edge[iedge].cap = 1;
2565 : : }
2566 : : }
2567 : : }
2568 : : }
2569 : : #endif
2570 : :
2571 : : /* create a new edge connecting endpoint to the new fictitious t-group vertex vert_ficpoint */
2572 : 0 : edge = pBNS->edge + num_edges;
2573 : 0 : edge->cap = vert_endpoint->st_edge.cap - vert_endpoint->st_edge.flow;
2574 : 0 : edge->cap = inchi_min( edge->cap, MAX_TGROUP_EDGE_CAP );
2575 : 0 : edge->cap = inchi_max( edge->cap, 0 );
2576 : 0 : edge->flow = 0;
2577 : 0 : edge->pass = 0;
2578 : :
2579 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 1 )
2580 : : edge->forbidden &= pBNS->edge_forbidden_mask;
2581 : : #endif
2582 : :
2583 : : #ifdef NEVER
2584 : : /* later include case when the charge change allows the endpoint to become tautomeric */
2585 : : /* mark endoint having moveable H atom with flow=1 */
2586 : :
2587 : : /* -- old "no charges" version -- */
2588 : : /* if (at[endpoint].chem_bonds_valence == at[endpoint].valence) */
2589 : : /* -- the following line takes charges into account -- */
2590 : : if (eif.cDonor) /* means the endpoint has an H-atom to donate */
2591 : : {
2592 : : /* increment edge flow */
2593 : : edge->flow++;
2594 : : /* increment one vertex st-flow & cap */
2595 : : vert_ficpoint->st_edge.flow++;
2596 : : vert_ficpoint->st_edge.cap++;
2597 : : /* increment another vertex st-flow & cap */
2598 : : vert_endpoint->st_edge.flow++;
2599 : : vert_endpoint->st_edge.cap++;
2600 : : }
2601 : : #endif
2602 : :
2603 : : /* connect edge to endpoint and fictpoint and increment the counters of neighbors and edges */
2604 : 0 : ret = ConnectTwoVertices( vert_endpoint, vert_ficpoint, edge, pBNS, 0 );
2605 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
2606 : : {
2607 : 0 : break;
2608 : : }
2609 : 0 : num_edges++;
2610 : 0 : edge->cap0 = edge->cap;
2611 : 0 : edge->flow0 = edge->flow;
2612 : 0 : pVA[endpoint].nTautGroupEdge = num_edges; /* edge index + 1 */
2613 : : }
2614 : :
2615 : 0 : pBNS->num_edges = num_edges;
2616 : 0 : pBNS->num_vertices += nMaxTGroupNumber;
2617 : 0 : pBNS->num_t_groups = num_tg;
2618 : 0 : pBNS->tot_st_cap += tot_st_cap;
2619 : 0 : pBNS->tot_st_flow += tot_st_flow;
2620 : : }
2621 : :
2622 : 0 : return ret;
2623 : : }
2624 : :
2625 : :
2626 : : /*****************************************************************************************************/
2627 : 0 : int ConnectTwoVertices( BNS_VERTEX *p1, BNS_VERTEX *p2, BNS_EDGE *e, BN_STRUCT *pBNS, int bClearEdge )
2628 : : {
2629 : 0 : int ip1 = (int) ( p1 - pBNS->vert );
2630 : 0 : int ip2 = (int) ( p2 - pBNS->vert );
2631 : 0 : int ie = (int) ( e - pBNS->edge );
2632 : :
2633 : : /* debug: check bounds */
2634 [ # # # # ]: 0 : if (ip1 >= pBNS->max_vertices || ip1 < 0 ||
2635 [ # # # # ]: 0 : ip2 >= pBNS->max_vertices || ip2 < 0 ||
2636 [ # # # # ]: 0 : ie >= pBNS->max_edges || ie < 0 ||
2637 [ # # ]: 0 : ( p1->iedge - pBNS->iedge ) < 0 ||
2638 [ # # ]: 0 : ( p1->iedge - pBNS->iedge ) + p1->max_adj_edges > pBNS->max_iedges ||
2639 [ # # ]: 0 : ( p2->iedge - pBNS->iedge ) < 0 ||
2640 [ # # ]: 0 : ( p2->iedge - pBNS->iedge ) + p2->max_adj_edges > pBNS->max_iedges ||
2641 [ # # ]: 0 : p1->num_adj_edges >= p1->max_adj_edges ||
2642 [ # # ]: 0 : p2->num_adj_edges >= p2->max_adj_edges)
2643 : : {
2644 : 0 : return BNS_VERT_EDGE_OVFL;
2645 : : }
2646 : : /* clear the edge */
2647 [ # # ]: 0 : if (bClearEdge)
2648 : : {
2649 : 0 : memset( e, 0, sizeof( *e ) ); /* djb-rwth: memset_s C11/Annex K variant? */
2650 : : }
2651 : : else
2652 [ # # # # ]: 0 : if (e->neighbor1 || e->neighbor12)
2653 : : {
2654 : 0 : return BNS_PROGRAM_ERR;
2655 : : }
2656 : :
2657 : : /* connect */
2658 : 0 : e->neighbor1 = inchi_min( ip1, ip2 );
2659 : 0 : e->neighbor12 = ip1 ^ ip2;
2660 : 0 : p1->iedge[p1->num_adj_edges] = ie;
2661 : 0 : p2->iedge[p2->num_adj_edges] = ie;
2662 : 0 : e->neigh_ord[ip1 > ip2] = p1->num_adj_edges++;
2663 : :
2664 : 0 : e->neigh_ord[ip1 < ip2] = p2->num_adj_edges++;
2665 : 0 : return 0;
2666 : : }
2667 : :
2668 : :
2669 : : /***********************************************************************************************************
2670 : : METAL ATOMS' FLOWER - Provides a source/sink of "free valences"
2671 : : ***********************************************************************************************************
2672 : :
2673 : : c1+...+cn = 2c+dc - total cap and flow of edges to the flower base from metal atoms
2674 : : f1+...+fn = 2f+df they should allow changing bonds to metals from 0-order to triple
2675 : : dc,df = 0 or 1 hence c=3*n, f=0 (initial zero bond order) or n
2676 : : Gi=vertex(M-group)
2677 : : Ci=its st_cap [C3,F3] C0 = F0 = 2c + 2D + dc (st_cap & st_flow)
2678 : : Fi=its st_flow G3 C2 = F2 = c + 2D
2679 : : / \ C1 = F1 = c + 2D + dc-df
2680 : : ci=cap of edge i cx,fx/ \cy,fy C3 = F3 = 0
2681 : : fi=edge flow / \ Constraints
2682 : : [C2,F2]/ cd,fd \[C1,F1] -----------------
2683 : : G2--------G1 fa+fb+2f+df=F0=C0
2684 : : \ / ca = c + 2D (edge cap) fa+fd =F2=C2
2685 : : ca,fa \ / cb,fb fa = c + D - f (edge flow) fb+fd =C1=F1
2686 : : \ / fi <= ci
2687 : : G0 [C0,F0] cb = c + 2D + dc -----------------
2688 : : /\ fb = c + D + dc - (f + df)
2689 : : ci=3, fi=0 or 1 c1,f1 /... \ cn,fn ------------------------------------
2690 : : / \ cd = c + 2D D is an arbitrary integer > 0
2691 : : all n Metal atoms: M1 ... Mn fd = f + D it allows to apply
2692 : : C3++ (add st_flow to cancel radicals)
2693 : : For each Mi add cap and flow=cap cx = cy = D D times.
2694 : : to M-charge group fx = fy = 0
2695 : : --------------------------------------------------------------------------------------
2696 : : | f=0 | f=c, dc>=df | 0 <= 2f+df <= 2c+dc
2697 : : edge +------------------------+-----------+----------+-------------+-------------
2698 : : | flow | rescap | flow | rescap | flow | rescap
2699 : : ----------+------------+-----------+-----------+----------+-------------+-------------
2700 : : f1+..+fn | df | 2c+dc-df | 2c+df | dc-df | 2f+df | 2c-2f+dc-df
2701 : : fa | c+D | D | D | c+D | c+D-f | c+D
2702 : : fb | c+D+dc-df | D+df | D+dc-df | c+D+df | c+D+dc-f-df| c+D+df
2703 : : fd | D | c+D | c+D | D | f+D | D
2704 : : --------------------------------------------------------------------------------------
2705 : : ***********************************************************************************************************/
2706 : 0 : int AddRadicalToMetal(int* tot_st_cap, int* tot_st_flow, ICHICONST SRM* pSrm, BN_STRUCT* pBNS, ALL_TC_GROUPS* pTCGroups)
2707 : : {
2708 : 0 : int iG0 = pTCGroups->nGroup[TCG_MeFlower0]; /* index in pTCGroups->pTCG[] */
2709 : 0 : int iG1 = pTCGroups->nGroup[TCG_MeFlower1];
2710 : 0 : int iG2 = pTCGroups->nGroup[TCG_MeFlower2];
2711 : 0 : int iG3 = pTCGroups->nGroup[TCG_MeFlower3];
2712 : 0 : int n = (iG0 >= 0) + (iG1 >= 0) + (iG2 >= 0) + (iG3 >= 0);
2713 : : int vG0, vG1, vG2, vG3; /* M-vertex number */
2714 : 0 : BNS_VERTEX* pG0 = NULL, * pG1 = NULL, * pG2 = NULL, * pG3 = NULL;
2715 : :
2716 [ # # ]: 0 : if (pTCGroups->num_metal_atoms &&
2717 [ # # ]: 0 : pSrm->bMetalAddFlower &&
2718 [ # # # # ]: 0 : *tot_st_cap % 2 &&
2719 : : n == 4)
2720 : : {
2721 : 0 : vG0 = pTCGroups->pTCG[iG0].nVertexNumber;
2722 : 0 : vG1 = pTCGroups->pTCG[iG1].nVertexNumber;
2723 : 0 : vG2 = pTCGroups->pTCG[iG2].nVertexNumber;
2724 : 0 : vG3 = pTCGroups->pTCG[iG3].nVertexNumber;
2725 : :
2726 : 0 : pG0 = pBNS->vert + vG0;
2727 : 0 : pG1 = pBNS->vert + vG1;
2728 : 0 : pG2 = pBNS->vert + vG2;
2729 : 0 : pG3 = pBNS->vert + vG3;
2730 : :
2731 : : /* add 1 unit to metal flower st_cap */
2732 : 0 : pG3->st_edge.cap++;
2733 : 0 : pG3->st_edge.cap0++;
2734 : 0 : (*tot_st_cap)++;
2735 : 0 : return 1;
2736 : : }
2737 : :
2738 : 0 : return 0;
2739 : : }
2740 : :
2741 : :
2742 : : /***********************************************************************************************************/
2743 : 0 : int ConnectMetalFlower( int *pcur_num_vertices, int *pcur_num_edges,
2744 : : int *tot_st_cap, int *tot_st_flow, ICHICONST SRM *pSrm,
2745 : : BN_STRUCT *pBNS, ALL_TC_GROUPS *pTCGroups )
2746 : : {
2747 : 0 : int iG0 = pTCGroups->nGroup[TCG_MeFlower0]; /* index in pTCGroups->pTCG[] */
2748 : 0 : int iG1 = pTCGroups->nGroup[TCG_MeFlower1];
2749 : 0 : int iG2 = pTCGroups->nGroup[TCG_MeFlower2];
2750 : 0 : int iG3 = pTCGroups->nGroup[TCG_MeFlower3];
2751 : 0 : int n = ( iG0 >= 0 ) + ( iG1 >= 0 ) + ( iG2 >= 0 ) + ( iG3 >= 0 );
2752 : : int vG0, vG1, vG2, vG3; /* M-vertex number */
2753 : 0 : int cur_num_edges = *pcur_num_edges;
2754 : 0 : int cur_num_vertices = *pcur_num_vertices;
2755 : 0 : BNS_VERTEX *pG0 = NULL, *pG1 = NULL, *pG2 = NULL, *pG3 = NULL;
2756 : 0 : BNS_EDGE *ea = NULL, *eb = NULL, *ed = NULL, *ex = NULL, *ey = NULL, *e;
2757 : : int ia, ib, id, ix, iy;
2758 : : int c, f, dc, df, ca, fa, cb, fb, cd, fd, cx, fx, cy, fy;
2759 : : int C0, F0, C1, F1, C2, F2, C3, F3, D;
2760 : 0 : int ret = 0, i;
2761 : :
2762 [ # # ]: 0 : if (0 == n)
2763 : : {
2764 : 0 : goto exit_function;
2765 : : }
2766 : :
2767 [ # # ]: 0 : if (4 != n)
2768 : : {
2769 : 0 : ret = RI_ERR_PROGR;
2770 : 0 : goto exit_function;
2771 : : }
2772 : :
2773 : 0 : vG0 = pTCGroups->pTCG[iG0].nVertexNumber;
2774 : 0 : vG1 = pTCGroups->pTCG[iG1].nVertexNumber;
2775 : 0 : vG2 = pTCGroups->pTCG[iG2].nVertexNumber;
2776 : 0 : vG3 = pTCGroups->pTCG[iG3].nVertexNumber;
2777 : :
2778 : 0 : pG0 = pBNS->vert + vG0;
2779 : 0 : pG1 = pBNS->vert + vG1;
2780 : 0 : pG2 = pBNS->vert + vG2;
2781 : 0 : pG3 = pBNS->vert + vG3;
2782 : :
2783 : : /* count G0 edges cap and flow (currently only atoms are connected to G0) */
2784 [ # # ]: 0 : for (i = 0, c = 0, f = 0; i < pG0->num_adj_edges; i++)
2785 : : {
2786 : 0 : e = pBNS->edge + pG0->iedge[i];
2787 : 0 : c += e->cap;
2788 : 0 : f += e->flow;
2789 : : }
2790 : :
2791 : : /* consistency checks */
2792 [ # # ]: 0 : if (!IS_BNS_VT_M_GR( pTCGroups->pTCG[iG0].type ) &&
2793 [ # # ]: 0 : ( pTCGroups->pTCG[iG0].edges_cap != pG0->st_edge.cap ||
2794 [ # # ]: 0 : pTCGroups->pTCG[iG0].edges_flow != pG0->st_edge.flow ))
2795 : : {
2796 : 0 : ret = RI_ERR_PROGR;
2797 : 0 : goto exit_function;
2798 : : }
2799 : :
2800 [ # # ]: 0 : if (pTCGroups->pTCG[iG0].edges_cap != c ||
2801 [ # # ]: 0 : pTCGroups->pTCG[iG0].edges_flow != f)
2802 : : {
2803 : 0 : ret = RI_ERR_PROGR;
2804 : 0 : goto exit_function;
2805 : : }
2806 : :
2807 : : /* get new edges */
2808 : :
2809 : 0 : ea = pBNS->edge + (ia = cur_num_edges++);
2810 : 0 : eb = pBNS->edge + (ib = cur_num_edges++);
2811 : 0 : ed = pBNS->edge + (id = cur_num_edges++);
2812 : 0 : ex = pBNS->edge + (ix = cur_num_edges++);
2813 : 0 : ey = pBNS->edge + (iy = cur_num_edges++);
2814 : :
2815 : : /* connect vertices with edges */
2816 : 0 : ret = ConnectTwoVertices( pG0, pG1, eb, pBNS, 1 );
2817 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
2818 : : {
2819 : 0 : goto exit_function;
2820 : : }
2821 : :
2822 : 0 : ret = ConnectTwoVertices( pG0, pG2, ea, pBNS, 1 );
2823 : :
2824 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
2825 : : {
2826 : 0 : goto exit_function;
2827 : : }
2828 : :
2829 : 0 : ret = ConnectTwoVertices( pG1, pG2, ed, pBNS, 1 );
2830 : :
2831 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
2832 : : {
2833 : 0 : goto exit_function;
2834 : : }
2835 : :
2836 : 0 : ret = ConnectTwoVertices( pG1, pG3, ey, pBNS, 1 );
2837 : :
2838 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
2839 : : {
2840 : 0 : goto exit_function;
2841 : : }
2842 : :
2843 : 0 : ret = ConnectTwoVertices( pG2, pG3, ex, pBNS, 1 );
2844 : :
2845 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
2846 : : {
2847 : 0 : goto exit_function;
2848 : : }
2849 : :
2850 : : /* calculate caps and flows */
2851 : :
2852 : 0 : dc = c % 2;
2853 : 0 : c /= 2;
2854 : 0 : df = f % 2;
2855 : 0 : f /= 2;
2856 : :
2857 : 0 : D = pSrm->nMetalFlowerParam_D;
2858 : :
2859 : 0 : C0 = F0 = 2 * c + 2 * D + dc;
2860 : 0 : C1 = F1 = c + 2 * D + dc - df;
2861 : 0 : C2 = F2 = c + 2 * D;
2862 : 0 : C3 = F3 = 0;
2863 : :
2864 : 0 : ca = c + 2 * D;
2865 : 0 : fa = c + D - f;
2866 : :
2867 : 0 : cb = c + 2 * D + dc;
2868 : 0 : fb = c + D + dc - ( f + df );
2869 : :
2870 : 0 : cd = c + 2 * D;
2871 : 0 : fd = f + D;
2872 : :
2873 : 0 : cx = cy = D;
2874 : 0 : fx = fy = 0;
2875 : :
2876 : : /* check overflow */
2877 [ # # # # : 0 : if (C0 >= EDGE_FLOW_ST_MASK || F0 >= EDGE_FLOW_ST_MASK ||
# # ]
2878 [ # # # # ]: 0 : C1 >= EDGE_FLOW_ST_MASK || F1 >= EDGE_FLOW_ST_MASK ||
2879 [ # # # # ]: 0 : C2 >= EDGE_FLOW_ST_MASK || F2 >= EDGE_FLOW_ST_MASK ||
2880 [ # # ]: 0 : C3 >= EDGE_FLOW_ST_MASK || F3 >= EDGE_FLOW_ST_MASK)
2881 : : {
2882 : 0 : return BNS_PROGRAM_ERR; /* cannot handle too large st-cap or st-flow */
2883 : : }
2884 : :
2885 : : /* set st caps and flows */
2886 : :
2887 : 0 : SetStCapFlow( pG0, tot_st_flow, tot_st_cap, C0, F0 );
2888 : 0 : SetStCapFlow( pG1, tot_st_flow, tot_st_cap, C1, F1 );
2889 : 0 : SetStCapFlow( pG2, tot_st_flow, tot_st_cap, C2, F2 );
2890 : 0 : SetStCapFlow( pG3, tot_st_flow, tot_st_cap, C3, F3 );
2891 : :
2892 : 0 : SetEdgeCapFlow( ea, ca, fa );
2893 : 0 : SetEdgeCapFlow( eb, cb, fb );
2894 : 0 : SetEdgeCapFlow( ed, cd, fd );
2895 : 0 : SetEdgeCapFlow( ex, cx, fx );
2896 : 0 : SetEdgeCapFlow( ey, cy, fy );
2897 : :
2898 : :
2899 : 0 : *pcur_num_edges = cur_num_edges;
2900 : 0 : *pcur_num_vertices = cur_num_vertices;
2901 : :
2902 : 0 : ret = 0;
2903 : :
2904 : 0 : exit_function:
2905 : :
2906 : 0 : return ret;
2907 : : }
2908 : :
2909 : :
2910 : : /********************************************************************************/
2911 : 0 : void SetEdgeCapFlow( BNS_EDGE *e, int edge_cap, int edge_flow )
2912 : : {
2913 : 0 : e->cap = e->cap0 = edge_cap;
2914 : 0 : e->flow = e->flow0 = edge_flow;
2915 : 0 : }
2916 : :
2917 : :
2918 : : /*********************************************************************************
2919 : : Add cap and flow to an edge
2920 : : Add edge flow to the source vertex st_flow
2921 : : Add edge cap & flow to the destination vertex cap and flow
2922 : : *********************************************************************************/
2923 : 0 : int AddEdgeFlow( int edge_cap, int edge_flow, BNS_EDGE *e01, BNS_VERTEX *pSrc /*src*/,
2924 : : BNS_VERTEX *pDst/*dest*/, int *tot_st_cap, int *tot_st_flow )
2925 : : {
2926 : :
2927 : : /* overflow check */
2928 [ # # # # : 0 : if (e01->cap < 0 || edge_cap < 0 || (int) e01->cap + edge_cap >= EDGE_FLOW_MASK)
# # ]
2929 : : {
2930 : 0 : return BNS_PROGRAM_ERR;
2931 : : }
2932 : :
2933 [ # # # # ]: 0 : if (pDst->st_edge.cap < 0 || (int) pDst->st_edge.cap + edge_cap >= EDGE_FLOW_ST_MASK ||
2934 [ # # # # ]: 0 : pDst->st_edge.flow < 0 || (int) pDst->st_edge.flow + edge_flow >= EDGE_FLOW_ST_MASK ||
2935 [ # # # # ]: 0 : pSrc->st_edge.cap < 0 || pSrc->st_edge.flow < 0 ||
2936 [ # # ]: 0 : (int) pSrc->st_edge.flow + edge_flow >= EDGE_FLOW_ST_MASK)
2937 : : {
2938 : 0 : return BNS_PROGRAM_ERR;
2939 : : }
2940 : :
2941 : : /* add flow */
2942 : 0 : e01->cap += edge_cap;
2943 : 0 : e01->flow += edge_flow;
2944 : 0 : e01->cap0 = e01->cap;
2945 : 0 : e01->flow0 = e01->flow;
2946 : :
2947 : 0 : pDst->st_edge.cap += edge_cap;
2948 : 0 : pDst->st_edge.cap0 = pDst->st_edge.cap;
2949 : 0 : *tot_st_cap += edge_cap;
2950 : :
2951 : 0 : pDst->st_edge.flow += edge_flow;
2952 : 0 : pDst->st_edge.flow0 = pDst->st_edge.flow;
2953 : 0 : *tot_st_flow += edge_flow;
2954 : :
2955 : 0 : pSrc->st_edge.flow += edge_flow;
2956 : 0 : pSrc->st_edge.flow0 = pSrc->st_edge.flow;
2957 : 0 : *tot_st_flow += edge_flow;
2958 : :
2959 : : /*
2960 : : pDst->st_edge.cap += e01->cap;
2961 : : pDst->st_edge.cap0 = pDst->st_edge.cap;
2962 : : *tot_st_cap += e01->cap;
2963 : :
2964 : : pDst->st_edge.flow += e01->flow;
2965 : : pDst->st_edge.flow0 = pDst->st_edge.flow;
2966 : : *tot_st_flow += e01->flow;
2967 : :
2968 : : pSrc->st_edge.flow += e01->flow;
2969 : : pSrc->st_edge.flow0 = pSrc->st_edge.flow;
2970 : : *tot_st_flow += e01->flow;
2971 : : */
2972 : 0 : return 0;
2973 : : }
2974 : :
2975 : :
2976 : : /**************************************************************
2977 : : (+) and (-) group V - connection
2978 : : ================================
2979 : :
2980 : : BNS_VERT_TYPE__AUX (+/-)-connection
2981 : : (v) st_cap =
2982 : : / \ st_flow = (cap0 - Delta0 - flow0) + (cap1 - Delta1 -flow1)
2983 : : / \
2984 : : / \ cap = cap1
2985 : : / \ flow = (cap1 - Delta1 - flow1)
2986 : : / \
2987 : : (-) (+) st_cap = cap1
2988 : : / \ / \ st_flow = cap1 - Delta1
2989 : : /cap0 \ /cap1 \
2990 : : flow0 flow1
2991 : :
2992 : : ***************************************************************
2993 : :
2994 : : (+) supergroup Y - connection
2995 : : ==============================
2996 : :
2997 : : (+) BNS_VT_C_POS_ALL (+) supergroup
2998 : : Delta0 | ==============
2999 : : not shown | cap = cap0+cap1
3000 : : | flow = flow0+flow1-Delta0-Delta1
3001 : : BNS_VERT_TYPE__AUX (y) <------------------ additional vertex: st_cap = cap0+cap1
3002 : : / \ st_flow = cap0+cap1
3003 : : cap=cap0 / \ cap = cap1
3004 : : flow=cap0-flow0 / \ flow = cap1 - flow1 - Delta1
3005 : : -Delta0 / \
3006 : : not-C (+) (+) Carbons st_cap = cap1
3007 : : BNS_VT_C_POS / \ / \ BNS_VT_C_POS_C st_flow = cap1 - Delta1
3008 : : / \ / \
3009 : : totals cap0 cap1 = sum of all cap going up into (+) from atoms or ChargeStruct
3010 : : to (+): flow0 flow1= sum of all flow going up into (+)
3011 : : Delta0 Delta1 = st_cap(+)-st_flow(+) before connection
3012 : : Observations
3013 : : ============
3014 : : A. Any Delta > 0 on (+) or (-) group decreases total (signed) charge by Delta
3015 : :
3016 : : B. Any alt path from an atom through ChargeStruct to an atom
3017 : : does not change the total charge
3018 : :
3019 : : C. st_flow(+/-) = cap(+)-flow(+)-Delta(+) + cap(-)-flow(-)-Delta(-) =
3020 : : = charge(+) + |max (-) charge| + charge(-) = const
3021 : : (charge conservation)
3022 : :
3023 : : D. To decrease total charge: increase st_cap on (+) or (-) group, including supergroup
3024 : : E. To increase total charge: increase st_cap on any (y) or (v)-connecting vertex
3025 : :
3026 : : F. To cancel charges:
3027 : : 1. Forbid (+/-)-(+) or (+/-)-(-) edge
3028 : : 2. Add delta>0 to (+/-) st_cap
3029 : : 3. Add same delta to (+) or (-) st_cap
3030 : :
3031 : :
3032 : : ****************************************************************/
3033 : :
3034 : : /************************************************************************************
3035 : : j2,j3 < j1 < j0
3036 : :
3037 : : (+/-) <---- next step; if does not exist then
3038 : : / \ st_cap1' := st_flow1'
3039 : : / \
3040 : : / \ st_cap1' := cap01'
3041 : : pv1 (+)super st_flow1':= cap01'-flow01' = flow02'+flow03'
3042 : : j1 |
3043 : : | cap01' := st_cap0'
3044 : : | flow01':= st_cap0'-flow02'-flow03'
3045 : : |
3046 : : | st_cap0' :=
3047 : : ( ) pv0,j0 st_flow0':= cap2+st_cap3
3048 : : / \
3049 : : / \ cap03' = cap3
3050 : : / \ flow03' = cap3 - flow3 - Delta3
3051 : : / \
3052 : : st_cap2, st_flow2 (+) (+C) st_cap3' := cap3
3053 : : pv2,j2 pv3,j3 st_flow3' := cap3-Delta3
3054 : : / \ / \ Delta3 := st_cap3 - st_flow3
3055 : : cap2, flow2 cap3, flow3 = sums of incoming
3056 : : **************************************************************************************/
3057 : :
3058 : 0 : int ConnectSuperCGroup( int nSuperCGroup, int nAddGroups[], int num_add,
3059 : : int *pcur_num_vertices, int *pcur_num_edges,
3060 : : int *tot_st_cap, int *tot_st_flow,
3061 : : BN_STRUCT *pBNS, ALL_TC_GROUPS *pTCGroups )
3062 : : {
3063 : 0 : BNS_EDGE **e0X = NULL, *e;
3064 : 0 : BNS_VERTEX **pvX = NULL, *pv0 = NULL, *pv1 = NULL, *pv = NULL;
3065 : 0 : int *jX = NULL, *iX = NULL;
3066 : 0 : int i, j, num_groups, j0, i1, j1, iXX, ret = 0, fst = 0;
3067 : 0 : int cur_num_vertices = *pcur_num_vertices;
3068 : 0 : int cur_num_edges = *pcur_num_edges;
3069 : :
3070 [ # # ]: 0 : if (nSuperCGroup >= 0)
3071 : : {
3072 : 0 : i1 = pTCGroups->nGroup[nSuperCGroup]; /* the supergroup */
3073 [ # # ]: 0 : if (i1 < 0)
3074 : 0 : return 0;
3075 : : }
3076 : : else
3077 : : {
3078 : 0 : i1 = -1;
3079 : 0 : fst = 1;
3080 : : }
3081 : :
3082 [ # # ]: 0 : for (i = num_groups = 0; i < num_add; i++)
3083 : : {
3084 : 0 : iXX = pTCGroups->nGroup[nAddGroups[i]];
3085 [ # # # # ]: 0 : num_groups += ( iXX >= 0 && iXX != i1 );
3086 : : }
3087 [ # # ]: 0 : if (num_groups < 1)
3088 : : { /* Y connect only 2 or more groups; V connects even 1 group */
3089 : 0 : return 0;
3090 : : }
3091 : :
3092 : 0 : e0X = (BNS_EDGE **) inchi_calloc( (long long)num_groups + 1, sizeof( e0X[0] ) ); /* djb-rwth: cast operator added */
3093 : 0 : pvX = (BNS_VERTEX **) inchi_calloc( (long long)num_groups + 1, sizeof( pvX[0] ) ); /* djb-rwth: cast operator added */
3094 : 0 : jX = (int *) inchi_calloc( (long long)num_groups + 1, sizeof( jX[0] ) ); /* djb-rwth: cast operator added */
3095 : 0 : iX = (int *) inchi_calloc( (long long)num_groups + 1, sizeof( iX[0] ) ); /* djb-rwth: cast operator added */
3096 : :
3097 [ # # # # : 0 : if (!e0X || !pvX || !jX || !iX)
# # # # ]
3098 : : {
3099 : 0 : ret = RI_ERR_ALLOC;
3100 : 0 : goto exit_function;
3101 : : }
3102 : :
3103 : : /* create vert_ficpoint -- central Y-connection vertex */
3104 : :
3105 : 0 : j0 = cur_num_vertices;
3106 : 0 : pv0 = pBNS->vert + j0; /* center of the Y-connection; has number j0 */
3107 : 0 : pv0->iedge = ( pv0 - 1 )->iedge + ( pv0 - 1 )->max_adj_edges;
3108 : 0 : pv0->max_adj_edges = num_groups + 1 + BNS_ADD_EDGES; /* Y-connection num. edges */
3109 : 0 : pv0->num_adj_edges = 0; /* nothing connected yet */
3110 : 0 : pv0->type = BNS_VT_YVCONNECTOR;
3111 : 0 : cur_num_vertices++;
3112 : :
3113 [ # # ]: 0 : if (fst == 0)
3114 : : {
3115 : : /* find super c-group vertex pv1, number j1 */
3116 : 0 : jX[0] = j1 = pTCGroups->pTCG[i1].nVertexNumber;
3117 : 0 : iX[0] = i1;
3118 : 0 : pvX[0] = pv1 = pBNS->vert + j1;
3119 : : }
3120 : :
3121 : : /* find other c-group vertices */
3122 [ # # ]: 0 : for (i = 0, j = 1; i < num_add; i++)
3123 : : {
3124 : 0 : iXX = pTCGroups->nGroup[nAddGroups[i]];
3125 [ # # # # ]: 0 : if (( iXX >= 0 ) && ( iXX != i1 ))
3126 : : {
3127 : 0 : iX[j] = iXX;
3128 : 0 : jX[j] = pTCGroups->pTCG[iXX].nVertexNumber;
3129 : 0 : pvX[j] = pBNS->vert + jX[j];
3130 : 0 : j++;
3131 : : }
3132 : : }
3133 : :
3134 : : /* grab (num_groups+1) free edges */
3135 [ # # ]: 0 : for (i = fst; i <= num_groups; i++)
3136 : : {
3137 : 0 : e = e0X[i] = pBNS->edge + cur_num_edges;
3138 : 0 : pv = pvX[i];
3139 : 0 : j = jX[i];
3140 : 0 : iXX = iX[i];
3141 : : /* connect all to pv0 */
3142 : 0 : ret = ConnectTwoVertices( pv0, pv, e, pBNS, 1 );
3143 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
3144 : : {
3145 : 0 : goto exit_function;
3146 : : }
3147 [ # # ]: 0 : if (i)
3148 : : {
3149 : : /* from c-group to central Y-connecting vertex of from supergroup to (+/-) vertex */
3150 : 0 : pTCGroups->pTCG[iX[i]].nForwardEdge = cur_num_edges;
3151 : : }
3152 : : else
3153 : : {
3154 : : /* from central Y-connecting vertex to supergroup */
3155 : 0 : pTCGroups->pTCG[iX[i]].nBackwardEdge = cur_num_edges;
3156 : : }
3157 : 0 : cur_num_edges++;
3158 : : }
3159 : :
3160 : : /* set flow and cap for incoming into pv0 edges */
3161 [ # # ]: 0 : for (i = 1; i <= num_groups; i++)
3162 : : {
3163 : 0 : int nDelta = pTCGroups->pTCG[iX[i]].st_cap - pTCGroups->pTCG[iX[i]].edges_cap;
3164 : 0 : int edge_cap = pTCGroups->pTCG[iX[i]].edges_cap + nDelta; /* added nDelta */
3165 : 0 : int edge_flow = pTCGroups->pTCG[iX[i]].edges_cap - pTCGroups->pTCG[iX[i]].edges_flow /*-nDelta*/;
3166 : :
3167 : 0 : ret = AddEdgeFlow( edge_cap, edge_flow,
3168 : 0 : e0X[i], pvX[i]/*src*/, pv0 /* dest*/, tot_st_cap, tot_st_flow );
3169 : :
3170 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
3171 : : {
3172 : 0 : goto exit_function;
3173 : : }
3174 : : }
3175 : :
3176 [ # # ]: 0 : if (fst == 0)
3177 : : {
3178 : : /* set flow and cap for going out of pv0 and into pv1 edge */
3179 : 0 : int edge_cap = pv0->st_edge.cap;
3180 : 0 : int edge_flow = pv0->st_edge.cap - pv0->st_edge.flow;
3181 : :
3182 : 0 : ret = AddEdgeFlow( pv0->st_edge.cap, pv0->st_edge.cap - pv0->st_edge.flow,
3183 : : e0X[0], pv0/*src*/, pv1 /* dest*/, tot_st_cap, tot_st_flow );
3184 : :
3185 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
3186 : : {
3187 : 0 : goto exit_function;
3188 : : }
3189 : :
3190 : 0 : pTCGroups->pTCG[iX[0]].edges_cap += edge_cap;
3191 : 0 : pTCGroups->pTCG[iX[0]].edges_flow += edge_flow;
3192 : 0 : pTCGroups->pTCG[iX[0]].st_cap += edge_cap;
3193 : 0 : pTCGroups->pTCG[iX[0]].st_flow += edge_flow;
3194 : : }
3195 : : else
3196 : : {
3197 : : /* no supergroup => change cap to flow */
3198 : 0 : *tot_st_cap += pv0->st_edge.flow - pv0->st_edge.cap;
3199 : 0 : pv0->st_edge.cap += pv0->st_edge.flow - pv0->st_edge.cap;
3200 : 0 : pv0->st_edge.cap0 = pv0->st_edge.cap;
3201 : : }
3202 : :
3203 : 0 : *pcur_num_vertices = cur_num_vertices;
3204 : 0 : *pcur_num_edges = cur_num_edges;
3205 : 0 : ret = num_groups;
3206 : :
3207 : 0 : exit_function:
3208 [ # # # # ]: 0 : if (e0X) inchi_free( e0X );
3209 [ # # # # ]: 0 : if (pvX) inchi_free( pvX );
3210 [ # # # # ]: 0 : if (jX) inchi_free( jX );
3211 [ # # # # ]: 0 : if (iX) inchi_free( iX );
3212 : :
3213 : 0 : return ret;
3214 : : }
3215 : :
3216 : :
3217 : : /*********************************************************************************/
3218 : 0 : void AddStCapFlow( BNS_VERTEX *vert_ficpoint, int *tot_st_flow, int *tot_st_cap, int cap, int flow )
3219 : : {
3220 : 0 : vert_ficpoint->st_edge.flow += flow;
3221 : 0 : *tot_st_flow += flow;
3222 : 0 : vert_ficpoint->st_edge.cap += cap;
3223 : 0 : *tot_st_cap += cap;
3224 : :
3225 : 0 : vert_ficpoint->st_edge.flow0 = vert_ficpoint->st_edge.flow;
3226 : 0 : vert_ficpoint->st_edge.cap0 = vert_ficpoint->st_edge.cap;
3227 : 0 : }
3228 : :
3229 : :
3230 : : /*********************************************************************************/
3231 : 0 : void SetStCapFlow( BNS_VERTEX *vert_ficpoint, int *tot_st_flow, int *tot_st_cap, int cap, int flow )
3232 : : {
3233 : 0 : *tot_st_flow += flow - vert_ficpoint->st_edge.flow;
3234 : 0 : vert_ficpoint->st_edge.flow = flow;
3235 : 0 : *tot_st_cap += cap - vert_ficpoint->st_edge.cap;
3236 : 0 : vert_ficpoint->st_edge.cap = cap;
3237 : :
3238 : 0 : vert_ficpoint->st_edge.flow0 = vert_ficpoint->st_edge.flow;
3239 : 0 : vert_ficpoint->st_edge.cap0 = vert_ficpoint->st_edge.cap;
3240 : 0 : }
3241 : :
3242 : :
3243 : : /*********************************************************************************
3244 : : int AddCGroups2TCGBnStruct( BN_STRUCT *pBNS, StrFromINChI *pStruct,
3245 : : VAL_AT *pVA, ALL_TC_GROUPS *pTCGroups )
3246 : :
3247 : :
3248 : : *********************************************************************************/
3249 : 0 : int AddCGroups2TCGBnStruct( BN_STRUCT *pBNS, StrFromINChI *pStruct, VAL_AT *pVA,
3250 : : ALL_TC_GROUPS *pTCGroups, int nMaxAddEdges )
3251 : : {
3252 : 0 : int ret = 0, ret1, ret2, ret3, bNeedsFlower; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
3253 : 0 : inp_ATOM *at = pStruct->at;
3254 : 0 : int num_atoms = pStruct->num_atoms;
3255 : : /*int num_tg = pTCGroups->num_tgroups;*/
3256 : 0 : int num_cg = pTCGroups->num_tc_groups - pTCGroups->num_tgroups;
3257 : 0 : int fst_cg_vertex = pBNS->num_vertices;
3258 : 0 : int fst_cg_group = pTCGroups->num_tgroups;
3259 : 0 : int num_vertices = pBNS->num_vertices;
3260 : 0 : int num_edges = pBNS->num_edges;
3261 : 0 : int cg_charge = 0;
3262 : 0 : ICHICONST SRM *pSrm = pStruct->pSrm;
3263 : :
3264 : : /* ret = ReInitBnStruct( pBNS ); */
3265 : :
3266 [ # # ]: 0 : if (num_cg > 0)
3267 : : {
3268 : : /* if ( cgi && cgi->num_c_groups && cgi->c_group ) */
3269 : : int i, i1, i2, j, j1, j2, k, k1, k2, n, c_point, c_neigh, cap, flow;
3270 : : int cur_num_vertices, cur_num_edges;
3271 : : BNS_VERTEX *vert_ficpoint, *vert_ficpoint_prev, *vert_ficpoint_base; /* fictitious vertex describing charge c-group */
3272 : : BNS_VERTEX *pv1, *pv2;
3273 : : BNS_EDGE *edge; /* edge between that vertex and the tautomeric c_point */
3274 : 0 : int nMaxCGroupNumber = 0;
3275 : : MY_CONST C_NODE *pCN;
3276 : : int cn_len, cn_bits, bMetalAtoms;
3277 : : int type;
3278 : : int tot_st_cap, tot_st_flow;
3279 : : int nAddGroups[16];
3280 : :
3281 : :
3282 : : /* Debug: check overflow */
3283 [ # # ]: 0 : if (num_vertices >= pBNS->max_vertices)
3284 : : {
3285 : 0 : return BNS_VERT_EDGE_OVFL;
3286 : : }
3287 : :
3288 : 0 : nMaxCGroupNumber = num_cg;
3289 : : /* clear all vertices not used until now */
3290 : 0 : memset( pBNS->vert + num_vertices, 0, ( (long long)pBNS->max_vertices - num_vertices ) * sizeof( pBNS->vert[0] ) ); /* djb-rwth: cast operator added; memset_s C11/Annex K variant? */
3291 : 0 : tot_st_cap = pBNS->tot_st_cap;
3292 : 0 : tot_st_flow = pBNS->tot_st_flow;
3293 : :
3294 : : /*****************************************/
3295 : : /* initialize new fictitious vertices */
3296 : : /* representing c-point groups, c-groups */
3297 : : /*****************************************/
3298 : 0 : vert_ficpoint_prev = pBNS->vert + fst_cg_vertex - 1;
3299 : :
3300 [ # # ]: 0 : for (i = 0; i < num_cg; i++)
3301 : : {
3302 : : /*
3303 : : vert_ficpoint-1 is the last vertex;
3304 : : vert_ficpoint is the being added vertex
3305 : : Note: nGroupNumber are not contiguous
3306 : : */
3307 : 0 : vert_ficpoint = vert_ficpoint_prev + 1;
3308 : 0 : vert_ficpoint->iedge = vert_ficpoint_prev->iedge + vert_ficpoint_prev->max_adj_edges;
3309 : 0 : vert_ficpoint->max_adj_edges = pTCGroups->pTCG[i + fst_cg_group].num_edges + nMaxAddEdges;
3310 : 0 : vert_ficpoint->num_adj_edges = 0;
3311 : :
3312 : 0 : vert_ficpoint->st_edge.flow += pTCGroups->pTCG[i + fst_cg_group].st_flow;
3313 : 0 : tot_st_flow += pTCGroups->pTCG[i + fst_cg_group].st_flow;
3314 : 0 : vert_ficpoint->st_edge.cap += pTCGroups->pTCG[i + fst_cg_group].st_cap;
3315 : 0 : tot_st_cap += pTCGroups->pTCG[i + fst_cg_group].st_cap;
3316 : :
3317 : 0 : vert_ficpoint->st_edge.flow0 = vert_ficpoint->st_edge.flow;
3318 : 0 : vert_ficpoint->st_edge.cap0 = vert_ficpoint->st_edge.cap;
3319 : :
3320 : 0 : vert_ficpoint->type = pTCGroups->pTCG[i + fst_cg_group].type;
3321 : : /* save the vertex number */
3322 : 0 : pTCGroups->pTCG[i + fst_cg_group].nVertexNumber = (int) ( vert_ficpoint - pBNS->vert );
3323 : :
3324 : 0 : vert_ficpoint_prev = vert_ficpoint; /* keep track of iedges */
3325 : : }
3326 : :
3327 : 0 : cur_num_vertices = (int) ( vert_ficpoint_prev - pBNS->vert ) + 1;
3328 : 0 : cur_num_edges = num_edges;
3329 : :
3330 : : /*************************************************************/
3331 : : /* pass 1: */
3332 : : /* create ChargeStruct for c-points and connect them to */
3333 : : /* the vertices representing c-point groups; */
3334 : : /* set final atom st_cap, st_flow */
3335 : : /*************************************************************/
3336 [ # # ]: 0 : for (c_point = 0; c_point < num_atoms; c_point++)
3337 : : {
3338 [ # # ]: 0 : if (!( k = pVA[c_point].cnListIndex ))
3339 : 0 : continue; /* not a c-point */
3340 : :
3341 : 0 : k--;
3342 : 0 : pCN = cnList[k].pCN; /* pointer to the ChargeStruct */
3343 : 0 : cn_len = cnList[k].len; /* length of the ChargeStruct */
3344 : 0 : cn_bits = cnList[k].bits; /* bits: for M-recognition */
3345 : : /* cn_bits = cnList[k].bits; */ /* ChargeStruct type */
3346 : 0 : bMetalAtoms = ( cn_bits == cn_bits_Me );
3347 : 0 : vert_ficpoint_base = vert_ficpoint_prev; /* add aux vertices after this */
3348 : :
3349 : : /* create disconnected auxiliary vertices of the at[c_point] ChargeStruct; add to them st_flow & st_cap */
3350 [ # # ]: 0 : for (i1 = 0; i1 < cn_len; i1++)
3351 : : {
3352 [ # # # # ]: 0 : if (!IS_BNS_VT_CHRG_STRUCT( pCN[i1].v.type ))
3353 : : {
3354 : 0 : continue;
3355 : : }
3356 : : /* the atom is always the first; the attached c-points are always the last */
3357 : 0 : vert_ficpoint = vert_ficpoint_base + i1; /* i1 = 1, 2,.. less number of attached c-points */
3358 : 0 : vert_ficpoint->iedge = vert_ficpoint_prev->iedge + vert_ficpoint_prev->max_adj_edges;
3359 : 0 : vert_ficpoint->max_adj_edges = pCN[i1].v.valence; /* do not add additional edges to aux vertices */
3360 : 0 : vert_ficpoint->num_adj_edges = 0;
3361 : :
3362 [ # # # # ]: 0 : cap = !bMetalAtoms ? pCN[i1].v.cap : pCN[i1].v.cap ? pSrm->nMetalMaxCharge_D : 0;
3363 [ # # # # ]: 0 : flow = !bMetalAtoms ? pCN[i1].v.flow : pCN[i1].v.flow ? pSrm->nMetalMaxCharge_D : 0;
3364 : :
3365 : 0 : AddStCapFlow( vert_ficpoint, &tot_st_flow, &tot_st_cap, cap, flow );
3366 : 0 : vert_ficpoint->type = pCN[i1].v.type; /* =BNS_VERT_TYPE__AUX */
3367 : :
3368 : 0 : vert_ficpoint_prev = vert_ficpoint; /* the last one will be vert_ficpoint for the next c-point */
3369 : 0 : cur_num_vertices = (int) ( vert_ficpoint - pBNS->vert ) + 1;
3370 : :
3371 [ # # ]: 0 : if (vert_ficpoint->iedge + vert_ficpoint->max_adj_edges - pBNS->iedge >= pBNS->max_iedges)
3372 : : {
3373 : 0 : return BNS_VERT_EDGE_OVFL;
3374 : : }
3375 [ # # ]: 0 : if (cur_num_vertices >= pBNS->max_vertices)
3376 : : {
3377 : 0 : return BNS_VERT_EDGE_OVFL;
3378 : : }
3379 : : }
3380 : :
3381 : : /* connect the vertices with new edges, add edge flow and cap */
3382 [ # # ]: 0 : for (i1 = 0; i1 < cn_len; i1++)
3383 : : {
3384 : 0 : pv1 = NULL;
3385 : 0 : k1 = -1;
3386 : :
3387 : : /* find vertex corresponding to i1 */
3388 : :
3389 [ # # ]: 0 : if (pCN[i1].v.type & BNS_VERT_TYPE_ATOM)
3390 : : {
3391 : 0 : pv1 = pBNS->vert + c_point; /* may be only one atom -- the current c_point at i1==0 */
3392 : : /* add atom vertex st_cap and st_flow */
3393 [ # # # # ]: 0 : cap = !bMetalAtoms ? pCN[i1].v.cap : pCN[i1].v.cap ? pSrm->nMetalMaxCharge_D : 0;
3394 [ # # # # ]: 0 : flow = !bMetalAtoms ? pCN[i1].v.flow : pCN[i1].v.flow ? pSrm->nMetalMaxCharge_D : 0;
3395 : 0 : AddStCapFlow( pv1, &tot_st_flow, &tot_st_cap, cap, flow );
3396 : : }
3397 : :
3398 [ # # ]: 0 : else if (IS_BNS_VT_C_GR( pCN[i1].v.type ))
3399 : : {
3400 : : /* find c-group vertex by looking for its type */
3401 [ # # ]: 0 : for (j = 0; j < num_cg; j++)
3402 : : {
3403 [ # # ]: 0 : if (pCN[i1].v.type == pBNS->vert[fst_cg_vertex + j].type)
3404 : : {
3405 : 0 : pv1 = pBNS->vert + fst_cg_vertex + j;
3406 : 0 : break;
3407 : : }
3408 : : }
3409 : : /* index of the pTCGroups->pTCG[] */
3410 [ # # ]: 0 : if (pv1)
3411 : : {
3412 : 0 : k1 = j + fst_cg_group;
3413 [ # # ]: 0 : if (pTCGroups->pTCG[k1].type != pCN[i1].v.type ||
3414 [ # # ]: 0 : pTCGroups->pTCG[k1].ord_num)
3415 : : {
3416 : 0 : return RI_ERR_PROGR;
3417 : : }
3418 : : }
3419 : : }
3420 : :
3421 [ # # ]: 0 : else if (IS_BNS_VT_M_GR( pCN[i1].v.type ))
3422 : : {
3423 : 0 : k1 = pTCGroups->nGroup[TCG_MeFlower0];
3424 [ # # ]: 0 : if (k1 < 0 ||
3425 [ # # ]: 0 : pTCGroups->pTCG[k1].type != pCN[i1].v.type ||
3426 [ # # ]: 0 : pTCGroups->pTCG[k1].ord_num ||
3427 [ # # ]: 0 : !pSrm->bMetalAddFlower)
3428 : : {
3429 : 0 : return RI_ERR_PROGR;
3430 : : }
3431 : 0 : pv1 = pBNS->vert + pTCGroups->pTCG[k1].nVertexNumber;
3432 : : }
3433 : :
3434 [ # # # # ]: 0 : else if (IS_BNS_VT_CHRG_STRUCT( pCN[i1].v.type ))
3435 : : {
3436 : : /* aux vertex */
3437 : 0 : pv1 = vert_ficpoint_base + i1;
3438 : : }
3439 : :
3440 [ # # ]: 0 : if (!pv1)
3441 : : {
3442 : 0 : return BNS_BOND_ERR;
3443 : : }
3444 : :
3445 : : /* connect pairs of vertices with new edges */
3446 [ # # # # ]: 0 : for (k = 0; k < MAX_CN_VAL && ( i2 = pCN[i1].e[k].neigh ); k++)
3447 : : {
3448 : 0 : pv2 = NULL;
3449 : 0 : k2 = -1;
3450 : 0 : i2--; /* neighbor */
3451 : :
3452 : : /* find vertex corresponding to i2 */
3453 : :
3454 [ # # ]: 0 : if (pCN[i2].v.type & BNS_VERT_TYPE_ATOM)
3455 : : {
3456 : 0 : pv2 = pBNS->vert + c_point;
3457 [ # # # # ]: 0 : cap = !bMetalAtoms ? pCN[i2].v.cap : pCN[i2].v.cap ? pSrm->nMetalMaxCharge_D : 0;
3458 [ # # # # ]: 0 : flow = !bMetalAtoms ? pCN[i2].v.flow : pCN[i2].v.flow ? pSrm->nMetalMaxCharge_D : 0;
3459 : : /* add atom vertex st_cap and st_flow; this normally should not happen */
3460 : 0 : AddStCapFlow( pv2, &tot_st_flow, &tot_st_cap, cap, flow );
3461 : : }
3462 : :
3463 [ # # ]: 0 : else if (IS_BNS_VT_C_GR( pCN[i2].v.type ))
3464 : : {
3465 : : /* find c-group vertex by looking for its type */
3466 [ # # ]: 0 : for (j = 0; j < num_cg; j++)
3467 : : {
3468 [ # # ]: 0 : if (pCN[i2].v.type == pBNS->vert[fst_cg_vertex + j].type)
3469 : : {
3470 : 0 : pv2 = pBNS->vert + fst_cg_vertex + j;
3471 : 0 : break;
3472 : : }
3473 : : }
3474 [ # # ]: 0 : if (pv2)
3475 : : {
3476 : 0 : k2 = j + fst_cg_group;
3477 [ # # ]: 0 : if (pTCGroups->pTCG[k2].type != pCN[i2].v.type ||
3478 [ # # ]: 0 : pTCGroups->pTCG[k2].ord_num)
3479 : : {
3480 : 0 : return RI_ERR_PROGR;
3481 : : }
3482 : : }
3483 : : }
3484 : :
3485 [ # # ]: 0 : else if (IS_BNS_VT_M_GR( pCN[i2].v.type ))
3486 : : {
3487 : 0 : k2 = pTCGroups->nGroup[TCG_MeFlower0];
3488 [ # # ]: 0 : if (k2 < 0 ||
3489 [ # # ]: 0 : pTCGroups->pTCG[k2].type != pCN[i2].v.type ||
3490 [ # # ]: 0 : pTCGroups->pTCG[k2].ord_num ||
3491 [ # # ]: 0 : !pSrm->bMetalAddFlower)
3492 : : {
3493 : 0 : return RI_ERR_PROGR;
3494 : : }
3495 : 0 : pv2 = pBNS->vert + pTCGroups->pTCG[k2].nVertexNumber;
3496 : : }
3497 : :
3498 [ # # # # ]: 0 : else if (IS_BNS_VT_CHRG_STRUCT( pCN[i2].v.type ))
3499 : : {
3500 : 0 : pv2 = vert_ficpoint_base + i2;
3501 : : }
3502 : :
3503 : : /* connect pv1 and pv2 */
3504 [ # # # # : 0 : if (!pv1 || !pv2 || pv1 == pv2)
# # ]
3505 : : {
3506 : 0 : return BNS_BOND_ERR;
3507 : : }
3508 : :
3509 : 0 : j1 = (int)(pv1 - pBNS->vert);
3510 : 0 : j2 = (int)(pv2 - pBNS->vert);
3511 : :
3512 : : /* create a new edge connecting pv1 and pv2 */
3513 : 0 : edge = pBNS->edge + cur_num_edges;
3514 [ # # # # ]: 0 : if ((IS_BNS_VT_M_GR( pCN[i1].v.type ) && IS_BNS_VT_ATOM( pCN[i2].v.type )) ||
3515 [ # # # # ]: 0 : (IS_BNS_VT_M_GR( pCN[i2].v.type ) && IS_BNS_VT_ATOM( pCN[i1].v.type ))) /* djb-rwth: addressing LLVM warnings */
3516 : 0 : {
3517 : : /* at[c_point] is a metal or is treated as a metal; connect it to M-group */
3518 : : /* metal - M-group (i.e. Metal-Flower) edge */
3519 : : int nStCap, nStFlow;
3520 : 0 : bNeedsFlower = AtomStcapStflow( at, pVA, pSrm, c_point, &nStCap, &nStFlow, &edge->cap, &edge->flow );
3521 : : /* GetAtomToMCGroupInitEdgeCapFlow( &edge->cap, &edge->flow, pSrm, at, pVA, c_point ); */
3522 [ # # ]: 0 : if (!bNeedsFlower)
3523 : : {
3524 : 0 : return RI_ERR_PROGR;
3525 : : }
3526 : 0 : pVA[c_point].nMetalGroupEdge = cur_num_edges + 1;
3527 : : /* pBNS->vert[c_point].st_edge.cap += edge->flow;*/ /* where was this done ???*/
3528 : 0 : pBNS->vert[c_point].st_edge.flow += edge->flow;
3529 : 0 : pBNS->vert[c_point].st_edge.cap += edge->flow + pVA[c_point].cInitFreeValences;
3530 : 0 : pBNS->vert[c_point].st_edge.flow0 = pBNS->vert[c_point].st_edge.flow;
3531 : 0 : pBNS->vert[c_point].st_edge.cap0 = pBNS->vert[c_point].st_edge.cap;
3532 : 0 : tot_st_flow += edge->flow;
3533 : 0 : tot_st_cap += edge->flow + pVA[c_point].cInitFreeValences;
3534 : : }
3535 : : else
3536 : : {
3537 [ # # # # ]: 0 : edge->cap = !bMetalAtoms ? pCN[i1].e[k].cap : pCN[i1].e[k].cap ? pSrm->nMetalMaxCharge_D : 0;
3538 [ # # # # ]: 0 : edge->flow = !bMetalAtoms ? pCN[i1].e[k].flow : pCN[i1].e[k].flow ? pSrm->nMetalMaxCharge_D : 0;
3539 : : }
3540 : :
3541 : 0 : edge->forbidden = pCN[i1].e[k].bForbiddenEdge ? BNS_EDGE_FORBIDDEN_MASK : 0;
3542 : :
3543 : : /* c-group incoming edges cap and flow needed in ConnectSuperCGroup() */
3544 : : /*
3545 : : if ( k1 >= 0 ) {
3546 : : pTCGroups->pTCG[k1].edges_cap += pCN[i1].e[k].cap;
3547 : : pTCGroups->pTCG[k1].edges_flow += pCN[i1].e[k].flow;
3548 : : }
3549 : : if ( k2 >= 0 ) {
3550 : : pTCGroups->pTCG[k2].edges_cap += pCN[i1].e[k].cap;
3551 : : pTCGroups->pTCG[k2].edges_flow += pCN[i1].e[k].flow;
3552 : : }
3553 : : */
3554 : :
3555 : 0 : edge->pass = 0;
3556 : :
3557 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 1 )
3558 : : edge->forbidden &= pBNS->edge_forbidden_mask;
3559 : : #endif
3560 : :
3561 : : /* check edge overflow */
3562 [ # # ]: 0 : if (pv1->num_adj_edges >= pv1->max_adj_edges ||
3563 [ # # ]: 0 : pv2->num_adj_edges >= pv2->max_adj_edges ||
3564 [ # # ]: 0 : cur_num_edges >= pBNS->max_edges)
3565 : : {
3566 : 0 : return BNS_VERT_EDGE_OVFL;
3567 : : }
3568 : :
3569 : : /* connect edge to the incident vertices and increment the counters of neighbors and edges */
3570 : :
3571 : 0 : ret = ConnectTwoVertices( pv1, pv2, edge, pBNS, 0 );
3572 : :
3573 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
3574 : : {
3575 : 0 : return ret;
3576 : : }
3577 : :
3578 : 0 : edge->cap0 = edge->cap;
3579 : 0 : edge->flow0 = edge->flow;
3580 : :
3581 : : /* save the edge index */
3582 [ # # ]: 0 : type = IS_BNS_VT_C_GR( pv1->type ) ? pv1->type :
3583 [ # # ]: 0 : IS_BNS_VT_C_GR( pv2->type ) ? pv2->type : 0;
3584 [ # # ]: 0 : if (type)
3585 : : {
3586 : : /* the edge connects to a c-group */
3587 [ # # ]: 0 : if (type & BNS_VERT_TYPE_C_NEGATIVE)
3588 : : {
3589 : 0 : pVA[c_point].nCMinusGroupEdge = cur_num_edges + 1;
3590 : : }
3591 : : else
3592 : : {
3593 : 0 : pVA[c_point].nCPlusGroupEdge = cur_num_edges + 1;
3594 : : }
3595 : : }
3596 : 0 : cur_num_edges++; /* end of new edge creation */
3597 : : }
3598 : : }
3599 : : }
3600 : :
3601 : :
3602 : : /*************************************************************/
3603 : : /* pass 2: */
3604 : : /* adjust bond cap, flow from the final atom st_cap, st_flow */
3605 : : /*************************************************************/
3606 [ # # ]: 0 : for (c_point = 0; c_point < num_atoms; c_point++)
3607 : : {
3608 : : int st_cap, st_cap2, max_edge_flow;
3609 : 0 : pv1 = pBNS->vert + c_point; /* atom vertex */
3610 : 0 : st_cap = pv1->st_edge.cap;
3611 [ # # ]: 0 : for (k = 0; k < pv1->num_adj_edges; k++)
3612 : : {
3613 : 0 : edge = pBNS->edge + pv1->iedge[k]; /* incident edge */
3614 : 0 : c_neigh = edge->neighbor12 ^ c_point; /* adjacent vertex */
3615 : 0 : pv2 = pBNS->vert + c_neigh;
3616 [ # # # # ]: 0 : if (c_neigh > c_point || !( pv2->type & BNS_VERT_TYPE_ATOM ))
3617 : : {
3618 : 0 : continue;
3619 : : }
3620 : : /* adjacent vertex is an atom; the edge is a bond; process each bond only once */
3621 : 0 : st_cap2 = pv2->st_edge.cap;
3622 : : /* the edge flow <= min( incident atom st_caps) */
3623 : 0 : max_edge_flow = inchi_min( st_cap, st_cap2 );
3624 : : /* bond order <= triple bond (flow=2) */
3625 [ # # # # ]: 0 : if (((pSrm->bMetalAddFlower && !pSrm->nMetalMinBondOrder &&
3626 [ # # # # ]: 0 : ( pVA[c_point].cMetal && pVA[c_point].cNumBondsToMetal)) ||
3627 [ # # # # ]: 0 : (pVA[c_neigh].cMetal && pVA[c_neigh].cNumBondsToMetal) )) /* djb-rwth: addressing LLVM warnings */
3628 : : {
3629 : 0 : max_edge_flow = inchi_min( max_edge_flow, MAX_BOND_EDGE_CAP + 1 );
3630 : : }
3631 : : else
3632 : : {
3633 : 0 : max_edge_flow = inchi_min( max_edge_flow, MAX_BOND_EDGE_CAP );
3634 : : }
3635 [ # # ]: 0 : if (at[c_point].bond_type[k] == BOND_TYPE_SINGLE)
3636 : : {
3637 : : /* the bond has not been changed due to stereo */
3638 : 0 : edge->cap = edge->cap0 = max_edge_flow;
3639 : : }
3640 : : }
3641 : : }
3642 : :
3643 : : /***********************************************************/
3644 : : /************** ************/
3645 : : /************** connect M-flower with new edges ************/
3646 : : /************** ************/
3647 : : /***********************************************************/
3648 : :
3649 : 0 : ret = ConnectMetalFlower( &cur_num_vertices, &cur_num_edges, &tot_st_cap, &tot_st_flow, pSrm, pBNS, pTCGroups );
3650 : :
3651 [ # # ]: 0 : if (ret < 0)
3652 : : {
3653 : 0 : goto exit_function;
3654 : : }
3655 : :
3656 : : /***********************************************************/
3657 : : /************** ************/
3658 : : /************** add additional vertices & edges ************/
3659 : : /************** to connect c-groups ************/
3660 : : /************** ************/
3661 : : /***********************************************************/
3662 : :
3663 : : /* (+) supergroup, Y-connection */
3664 : :
3665 : 0 : k = 0;
3666 : 0 : nAddGroups[k++] = TCG_Plus0;
3667 : 0 : nAddGroups[k++] = TCG_Plus_C0;
3668 : 0 : nAddGroups[k++] = TCG_Plus_M0;
3669 : :
3670 : 0 : ret1 = ConnectSuperCGroup( TCG_Plus,
3671 : : nAddGroups,
3672 : : k,
3673 : : &cur_num_vertices,
3674 : : &cur_num_edges,
3675 : : &tot_st_cap,
3676 : : &tot_st_flow,
3677 : : pBNS,
3678 : : pTCGroups ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
3679 : :
3680 : : /* (-) supergroup, Y-connection */
3681 : :
3682 : 0 : k = 0;
3683 : 0 : nAddGroups[k++] = TCG_Minus0;
3684 : 0 : nAddGroups[k++] = TCG_Minus_C0;
3685 : 0 : nAddGroups[k++] = TCG_Minus_M0;
3686 : :
3687 : 0 : ret2 = ConnectSuperCGroup( TCG_Minus,
3688 : : nAddGroups,
3689 : : k,
3690 : : &cur_num_vertices,
3691 : : &cur_num_edges,
3692 : : &tot_st_cap,
3693 : : &tot_st_flow,
3694 : : pBNS,
3695 : : pTCGroups ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
3696 : :
3697 : : /******** connect (+) and (-) ***************/
3698 : :
3699 : 0 : k = 0;
3700 : 0 : nAddGroups[k++] = TCG_Plus;
3701 : 0 : nAddGroups[k++] = TCG_Minus;
3702 : :
3703 : 0 : ret3 = ConnectSuperCGroup( -1,
3704 : : nAddGroups,
3705 : : k,
3706 : : &cur_num_vertices,
3707 : : &cur_num_edges,
3708 : : &tot_st_cap,
3709 : : &tot_st_flow,
3710 : : pBNS,
3711 : : pTCGroups );
3712 : :
3713 : : /* Take care of the full charge */
3714 : :
3715 : 0 : cg_charge = pTCGroups->total_charge - pTCGroups->tgroup_charge - pTCGroups->charge_on_atoms;
3716 : 0 : ret = 1;
3717 [ # # ]: 0 : if (ret3 > 0)
3718 : : {
3719 : : /* (+) and (-) or at least one of them have been connected */
3720 : 0 : int nVertPlusMinus = cur_num_vertices - 1;
3721 : 0 : BNS_VERTEX *pVertPlusMinus = pBNS->vert + nVertPlusMinus;
3722 : 0 : BNS_VERTEX *pVertPlus = NULL, *pVertMinus = NULL, *pVert = NULL;
3723 : 0 : BNS_EDGE *pEdgePlus = NULL, *pEdgeMinus = NULL, *pEdge = NULL;
3724 : 0 : n = pTCGroups->nGroup[TCG_Plus] >= 0; /* (+)-supergroup exists */
3725 : 0 : k = pTCGroups->nGroup[TCG_Minus] >= 0; /* (-)-supergroup exists */
3726 : :
3727 [ # # # # ]: 0 : if (pVertPlusMinus->num_adj_edges == 2 && k + n == 2)
3728 : : {
3729 : 0 : pEdgePlus = pBNS->edge + pVertPlusMinus->iedge[0]; /* TCG_Plus was the 1st */
3730 : 0 : pEdgeMinus = pBNS->edge + pVertPlusMinus->iedge[1]; /* TCG_Minus was the 2nd */
3731 : : }
3732 : :
3733 [ # # # # ]: 0 : else if (pVertPlusMinus->num_adj_edges == 1 && k + n == 1)
3734 : : {
3735 [ # # ]: 0 : if (pTCGroups->nGroup[TCG_Plus] >= 0)
3736 : : {
3737 : 0 : pEdgePlus = pBNS->edge + pVertPlusMinus->iedge[0];
3738 : : }
3739 [ # # ]: 0 : else if (pTCGroups->nGroup[TCG_Minus] >= 0)
3740 : : {
3741 : 0 : pEdgeMinus = pBNS->edge + pVertPlusMinus->iedge[0];
3742 : : }
3743 : : }
3744 : :
3745 [ # # ]: 0 : else if (k + n)
3746 : : {
3747 : : /* program error check */
3748 : 0 : ret = BNS_BOND_ERR;
3749 : 0 : goto exit_function;
3750 : : }
3751 : :
3752 [ # # ]: 0 : if (pEdgePlus)
3753 : : {
3754 : 0 : pVertPlus = pBNS->vert + ( pEdgePlus->neighbor12 ^ nVertPlusMinus );
3755 : : }
3756 [ # # ]: 0 : if (pEdgeMinus)
3757 : : {
3758 : 0 : pVertMinus = pBNS->vert + ( pEdgeMinus->neighbor12 ^ nVertPlusMinus );
3759 : : }
3760 : :
3761 [ # # ]: 0 : pVert = pVertPlus ? pVertPlus : pVertMinus ? pVertMinus : NULL;
3762 [ # # ]: 0 : pEdge = pEdgePlus ? pEdgePlus : pEdgeMinus ? pEdgeMinus : NULL;
3763 [ # # ]: 0 : if (pEdgeMinus)
3764 : : {
3765 : 0 : pTCGroups->nEdgeMinus = (int) ( pEdgeMinus - pBNS->edge );
3766 : : }
3767 [ # # ]: 0 : if (pEdgePlus)
3768 : : {
3769 : 0 : pTCGroups->nEdgePlus = (int) ( pEdgePlus - pBNS->edge );
3770 : : }
3771 [ # # ]: 0 : if (pEdge)
3772 : : {
3773 : 0 : pTCGroups->nEdge4charge = (int) ( pEdge - pBNS->edge );
3774 : : }
3775 : :
3776 : : /* set total charge */
3777 : :
3778 [ # # # # ]: 0 : if (pVert && pEdge)
3779 : : {
3780 : : /* do not check rescaps for now */
3781 [ # # ]: 0 : if (cg_charge > 0)
3782 : : {
3783 : 0 : pVertPlusMinus->st_edge.cap += cg_charge;
3784 : 0 : tot_st_cap += cg_charge;
3785 : 0 : pVertPlusMinus->st_edge.cap0 = pVertPlusMinus->st_edge.cap;
3786 : : }
3787 : :
3788 [ # # ]: 0 : if (cg_charge < 0)
3789 : : {
3790 : 0 : pVert->st_edge.cap -= cg_charge;
3791 : 0 : tot_st_cap -= cg_charge;
3792 : 0 : pVert->st_edge.cap0 = pVert->st_edge.cap;
3793 : :
3794 [ # # ]: 0 : if (pEdge->cap - pEdge->flow + cg_charge < 0)
3795 : : {
3796 : : /* 2006-02-06: increase edge capacity to avoid clogging */
3797 : 0 : pEdge->cap = pEdge->flow - cg_charge;
3798 : : }
3799 : : }
3800 : 0 : pTCGroups->added_charge = cg_charge;
3801 : : }
3802 [ # # # # : 0 : if (!cg_charge || ( pVert && pEdge ))
# # ]
3803 : : {
3804 : 0 : ret = 2;
3805 : : }
3806 : : }
3807 : :
3808 : 0 : AddRadicalToMetal( &tot_st_cap, &tot_st_flow, pSrm, pBNS, pTCGroups );
3809 : :
3810 : :
3811 : 0 : pBNS->num_edges = cur_num_edges;
3812 : 0 : pBNS->num_vertices = cur_num_vertices;
3813 : 0 : pBNS->num_c_groups = num_cg;
3814 : 0 : pBNS->tot_st_cap = tot_st_cap;
3815 : 0 : pBNS->tot_st_flow = tot_st_flow;
3816 : : }
3817 : :
3818 : 0 : exit_function:
3819 : 0 : return ret;
3820 : : }
3821 : :
3822 : :
3823 : : /********************************************************************************/
3824 : 0 : int nNumEdgesToCnVertex( MY_CONST C_NODE *pCN, int len, int v )
3825 : : {
3826 : 0 : int i, j, n, num_edges, v1 = v + 1;
3827 [ # # ]: 0 : for (i = 0, num_edges = 0; i < len; i++)
3828 : : {
3829 [ # # # # ]: 0 : for (j = 0; j < MAX_CN_VAL && ( n = pCN[i].e[j].neigh ); j++)
3830 : : {
3831 [ # # # # ]: 0 : num_edges += ( i == v || n == v1 );
3832 : : }
3833 : : }
3834 : 0 : return num_edges;
3835 : : }
3836 : :
3837 : :
3838 : : /*********************************************************************************
3839 : : BN_STRUCT* AllocateAndInitTCGBnStruct( StrFromINChI *pStruct, VAL_AT *pVA,
3840 : : ALL_TC_GROUPS *pTCGroups,
3841 : : int nMaxAddAtoms, int nMaxAddEdges,
3842 : : int max_altp, int *pNum_changed_bonds )
3843 : : allocate BN_STRUCT that has:
3844 : :
3845 : : pBNS->max_vertices = pTCGroups->nVertices + nMaxAddAtoms
3846 : : pBNS->max_edges = pTCGroups->nEdges +
3847 : : pBNS->max_vertices * (nMaxAddEdges + NUM_KINDS_OF_GROUPS)
3848 : : pBNS->max_iedges = 2*pBNS->max_edges + pTCGroups->nAddIedges
3849 : :
3850 : : pBNS->len_alt_path = pBNS->max_vertices + iALTP_HDR_LEN + 1 +
3851 : : max( pBNS->max_vertices/2, 16 )
3852 : : pBNS->max_altp = max_altp
3853 : :
3854 : : other members:
3855 : :
3856 : : pBNS->num_atoms = num_atoms;
3857 : : pBNS->num_bonds = num_bonds;
3858 : : pBNS->num_added_atoms = 0;
3859 : : pBNS->num_t_groups = 0;
3860 : : pBNS->num_c_groups = 0;
3861 : : pBNS->nMaxAddAtoms = nMaxAddAtoms;
3862 : : pBNS->nMaxAddEdges = nMaxAddEdges;
3863 : :
3864 : : atom vertices and bond edges:
3865 : : --- vertex(atom) ---
3866 : : st_cap = (at[].chem_bonds_valence - at[].valence) + pVA[].cInitFreeValences
3867 : : st_flow = SUM{bond_orders; ALT_BOND counted as SINGLE} - at[].valence
3868 : : --- edge(bond) ---
3869 : : flow = bond_order - 1; for ALT_BOND flow = 0
3870 : : cap = min(min(st_cap of neighbors),2); for ALT_BOND cap = 1
3871 : : max number of edges per atom = number of bonds +
3872 : : number of edges to ChargeStruct +
3873 : : 1 (if atom is a tautomeric endpoint) +
3874 : : nMaxAddEdges
3875 : : --- NOTE ---
3876 : : Here are not included nDelta(dots) from ChargeStruct and flow to ChargeStruct
3877 : :
3878 : : *********************************************************************************/
3879 : 0 : BN_STRUCT* AllocateAndInitTCGBnStruct( StrFromINChI *pStruct, VAL_AT *pVA,
3880 : : ALL_TC_GROUPS *pTCGroups,
3881 : : int nMaxAddAtoms, int nMaxAddEdges,
3882 : : int max_altp, int *pNum_changed_bonds )
3883 : : {
3884 : 0 : inp_ATOM *at = pStruct->at;
3885 : 0 : int num_atoms = pStruct->num_atoms;
3886 : 0 : ICHICONST SRM *pSrm = pStruct->pSrm;
3887 : :
3888 : 0 : BN_STRUCT *pBNS = NULL;
3889 : : BNS_VERTEX *vert;
3890 : : BNS_IEDGE *iedge;
3891 : :
3892 : 0 : int neigh, num_changed_bonds = 0;
3893 : : U_CHAR bond_type, bond_mark;
3894 : : int bNeedsFlower1, bNeedsFlower2, min_order;
3895 : :
3896 : : int i, j, k, m, n_edges, num_bonds, num_edges;
3897 : : int f1, f2, c1, c2, edge_cap, edge_flow, st_cap, st_flow, flag_alt_bond;
3898 : : int tot_st_cap, tot_st_flow;
3899 : : int max_tg, max_edges, max_vertices, len_alt_path, max_iedges, num_iedges, num_altp;
3900 : :
3901 : : /* count vertices */
3902 : 0 : max_tg = pTCGroups->num_tgroups;
3903 : : /* +1 for a super-tautomeric group */
3904 : : /* max_vertices = num_atoms + nMaxAddAtoms + max_tg + 1; */
3905 : 0 : max_vertices = pTCGroups->nVertices + nMaxAddAtoms;
3906 : :
3907 : : /* count edges */
3908 : 0 : num_changed_bonds = 0;
3909 : 0 : num_bonds = pTCGroups->num_bonds;
3910 : :
3911 : : /* each atom has enough edges to belong to a tautomeric group + nMaxAddEdges */
3912 : : /* number of atoms is large enough to accommodate max. possible number of t-groups + nMaxAddAtoms */
3913 : : /* max_altp cannot be larger than BN_MAX_ALTP = 16 */
3914 : 0 : num_edges = pTCGroups->nEdges;
3915 : :
3916 : : /* +max_tg for edges between t-groups and super-tautomeric group */
3917 : 0 : max_edges = num_edges + ( nMaxAddEdges + NUM_KINDS_OF_GROUPS )*max_vertices;
3918 : 0 : max_iedges = 2 * max_edges + pTCGroups->nAddIedges;
3919 : 0 : len_alt_path = max_vertices + iALTP_HDR_LEN + 1; /* may overflow if an edge is traversed in 2 directions */
3920 [ # # ]: 0 : len_alt_path += inchi_max( max_vertices / 2, 16 ); /* to avoid the overflow */
3921 : :
3922 [ # # ]: 0 : if (!(pBNS = (BN_STRUCT*)inchi_calloc(1, sizeof(BN_STRUCT))) ||
3923 [ # # ]: 0 : !(pBNS->edge = (BNS_EDGE*)inchi_calloc(max_edges, sizeof(BNS_EDGE))) ||
3924 [ # # ]: 0 : !(pBNS->vert = (BNS_VERTEX*)inchi_calloc(max_vertices, sizeof(BNS_VERTEX))) ||
3925 [ # # ]: 0 : !(pBNS->iedge = (BNS_IEDGE*)inchi_calloc(max_iedges, sizeof(BNS_IEDGE))))
3926 : : {
3927 : 0 : return DeAllocateBnStruct( pBNS );
3928 : : }
3929 : :
3930 : : /* alt path init (standard spell) */
3931 [ # # # # ]: 0 : for (num_altp = 0; num_altp < max_altp && num_altp < BN_MAX_ALTP; num_altp++)
3932 : : {
3933 [ # # ]: 0 : if (!( pBNS->altp[num_altp] = (BNS_ALT_PATH*) inchi_calloc( len_alt_path, sizeof( BNS_ALT_PATH ) ) ))
3934 : : {
3935 : 0 : return DeAllocateBnStruct( pBNS );
3936 : : }
3937 : 0 : ALTP_ALLOCATED_LEN( pBNS->altp[num_altp] ) = len_alt_path;
3938 : 0 : pBNS->len_alt_path = len_alt_path; /* ??? duplication ??? */
3939 : : /* re-init */
3940 : 0 : ALTP_DELTA( pBNS->altp[num_altp] ) = 0;
3941 : 0 : ALTP_START_ATOM( pBNS->altp[num_altp] ) = NO_VERTEX;
3942 : 0 : ALTP_END_ATOM( pBNS->altp[num_altp] ) = NO_VERTEX;
3943 : 0 : ALTP_PATH_LEN( pBNS->altp[num_altp] ) = 0;
3944 : : }
3945 : 0 : pBNS->alt_path = NULL;
3946 : 0 : pBNS->num_altp = 0;
3947 : 0 : pBNS->max_altp = num_altp;
3948 : :
3949 : :
3950 : : /* fill vertices (no connectivity) */
3951 : 0 : iedge = pBNS->iedge;
3952 : 0 : num_iedges = 0;
3953 : 0 : tot_st_cap = tot_st_flow = 0;
3954 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
3955 : : {
3956 : : /* count edges incident to pBNS->vert[i] */
3957 : 0 : k = at[i].valence + ( at[i].endpoint != 0 ) + ( nMaxAddEdges /*+ NUM_KINDS_OF_GROUPS*/ );
3958 [ # # ]: 0 : if (( j = pVA[i].cnListIndex - 1 ) >= 0)
3959 : : {
3960 : : /* add number of neighbors in the ChargeStruct */
3961 : 0 : k += nNumEdgesToCnVertex( cnList[j].pCN, cnList[j].len, 0 );
3962 : : }
3963 : : /* set max number of edges for the vertex */
3964 : 0 : pBNS->vert[i].max_adj_edges = k;
3965 : 0 : pBNS->vert[i].iedge = iedge;
3966 : 0 : iedge += k;
3967 : : /* add atom vertex cap */
3968 : 0 : st_cap = 0;
3969 : 0 : st_flow = 0;
3970 : 0 : bNeedsFlower1 = AtomStcapStflow( at, pVA, pSrm, i, &c1, &f1, NULL, NULL );
3971 : : /* pVA[i].cNumBondsToMetal = bNeedsFlower1; */
3972 : : /* GetAtomStCapFlow( at, pVA, pSrm, i, &c1, &f1 ); */
3973 : 0 : st_cap += c1;
3974 [ # # ]: 0 : st_cap += bNeedsFlower1 ? 0 : pVA[i].cInitFreeValences;
3975 : 0 : pBNS->vert[i].st_edge.cap = st_cap; /* the 1st time st_cap is set */
3976 : 0 : pBNS->vert[i].st_edge.cap0 = pBNS->vert[i].st_edge.cap;
3977 : 0 : tot_st_cap += st_cap;
3978 : : }
3979 : :
3980 : 0 : num_iedges = (int) ( iedge - pBNS->iedge );
3981 [ # # ]: 0 : if (max_iedges - num_iedges < ( nMaxAddEdges + NUM_KINDS_OF_GROUPS )*max_vertices)
3982 : : {
3983 : 0 : return DeAllocateBnStruct( pBNS );
3984 : : }
3985 : :
3986 : 0 : pBNS->num_atoms = num_atoms; /* number of real atoms */
3987 : 0 : pBNS->num_added_atoms = 0;
3988 : 0 : pBNS->num_t_groups = 0; /* number of added t-groups */
3989 : 0 : pBNS->num_c_groups = 0;
3990 : 0 : pBNS->nMaxAddAtoms = nMaxAddAtoms;
3991 : 0 : pBNS->nMaxAddEdges = nMaxAddEdges;
3992 : :
3993 : 0 : pBNS->num_vertices = num_atoms; /* current number of vertices, in general a sum of
3994 : : pBNS->num_atoms
3995 : : pBNS->num_t_groups
3996 : : number of c-groups
3997 : : number of auxiliary vertices
3998 : : pBNS->num_added_atoms
3999 : : */
4000 : 0 : pBNS->max_vertices = max_vertices;
4001 : :
4002 : :
4003 : 0 : pBNS->num_bonds = num_bonds; /* number of real edges (bonds) */
4004 : 0 : pBNS->max_edges = max_edges;
4005 : 0 : pBNS->max_iedges = max_iedges;
4006 : :
4007 : :
4008 : : /*
4009 : : To remove t-groups and added atoms:
4010 : :
4011 : : for ( i = 0; i < pBNS->num_atoms; i ++ )
4012 : : {
4013 : : for ( j = pBNS->vert[i].num_adj_edges-1; 0 <= j; j -- )
4014 : : {
4015 : : k = pBNS->edge[pBNS->vert[i].iedge[j]].neighbor12 ^ i;
4016 : : if ( pBNS->vert[k].type & BNS_VERT_TYPE_ATOM )
4017 : : {
4018 : : pBNS->vert[i].num_adj_edges = j+1;
4019 : : break;
4020 : : }
4021 : : }
4022 : : }
4023 : :
4024 : : pBNS->num_vertices = pBNS->num_atoms;
4025 : : pBNS->num_edges = pBNS->num_bonds;
4026 : : pBNS->num_added_atoms = 0;
4027 : : pBNS->num_t_groups = 0;
4028 : : pBNS->num_added_edges = 0;
4029 : :
4030 : : ALTP_DELTA(pBNS->alt_path) = 0;
4031 : : ALTP_START_ATOM(pBNS->alt_path) = NO_VERTEX;
4032 : : ALTP_END_ATOM(pBNS->alt_path) = NO_VERTEX;
4033 : : ALTP_PATH_LEN(pBNS->alt_path) = 0;
4034 : :
4035 : : */
4036 : :
4037 : :
4038 : : /* add and fill edges and connectivity */
4039 [ # # ]: 0 : for (i = 0, n_edges = 0; i < num_atoms; i++)
4040 : : {
4041 : 0 : vert = pBNS->vert + i; /* pointer to the ith vertex */
4042 : 0 : st_cap = 0;
4043 : 0 : st_flow = 0;
4044 : 0 : flag_alt_bond = 0;
4045 [ # # ]: 0 : for (j = 0; j < at[i].valence; j++)
4046 : : {
4047 : 0 : neigh = at[i].neighbor[j];
4048 : : /* find this bond at the neighbor */
4049 [ # # ]: 0 : for (k = 0; k < at[neigh].valence; k++)
4050 : : {
4051 [ # # ]: 0 : if (at[neigh].neighbor[k] == i)
4052 : : {
4053 : 0 : break;
4054 : : }
4055 : : }
4056 : 0 : bond_type = ( at[i].bond_type[j] & BOND_TYPE_MASK );
4057 : 0 : bond_mark = ( at[i].bond_type[j] & ~BOND_TYPE_MASK );
4058 [ # # # # : 0 : if (bond_type != BOND_SINGLE && bond_type != BOND_DOUBLE && bond_type != BOND_TRIPLE)
# # ]
4059 : : {
4060 : : /* make unknown bonds single */
4061 : 0 : bond_type = BOND_SINGLE;
4062 : 0 : at[i].bond_type[j] = bond_mark | bond_type;
4063 : 0 : num_changed_bonds++;
4064 : : }
4065 [ # # ]: 0 : if (neigh > i)
4066 : : {
4067 : : /* this is the first time we encounter this bond */
4068 : 0 : bNeedsFlower1 = AtomStcapStflow( at, pVA, pSrm, i, &c1, &f1, NULL, NULL );
4069 : : /* GetAtomStCapFlow( at, pVA, pSrm, i, &c1, &f1 ); */
4070 [ # # ]: 0 : c1 += bNeedsFlower1 ? 0 : pVA[i].cInitFreeValences; /* elevate cap to the lowest valence in ChargeStruct */
4071 : 0 : bNeedsFlower2 = AtomStcapStflow( at, pVA, pSrm, neigh, &c2, &f2, NULL, NULL );
4072 : : /* GetAtomStCapFlow( at, pVA, pSrm, neigh, &c2, &f2 ); */
4073 [ # # ]: 0 : c2 += bNeedsFlower2 ? 0 : pVA[neigh].cInitFreeValences; /* elevate cap to the lowest valence in ChargeStruct */
4074 : :
4075 : : /* at this point -O would have st_cap=st_flow=0 because the lowest valence=1 for charge=-1 */
4076 : : /* however, if -O belongs to a t-group its cap would be 1, flow = 0 */
4077 : : /*f1 = MAX_AT_FLOW(at[i]);*/
4078 : : /*f2 = MAX_AT_FLOW(at[neigh]);*/
4079 : :
4080 : 0 : edge_flow = BondFlowMaxcapMinorder( at, pVA, pSrm, i, j, &edge_cap, &min_order, NULL );
4081 : :
4082 : 0 : pBNS->edge[n_edges].neighbor1 = (AT_NUMB) i;
4083 : 0 : pBNS->edge[n_edges].neighbor12 = (AT_NUMB) ( i ^ neigh );
4084 : 0 : pBNS->edge[n_edges].flow =
4085 : 0 : pBNS->edge[n_edges].flow0 = edge_flow;
4086 : 0 : pBNS->edge[n_edges].cap =
4087 : 0 : pBNS->edge[n_edges].cap0 = edge_cap;
4088 : 0 : pBNS->edge[n_edges].neigh_ord[0] = j; /* iedge to neigh index at vertex[i], i < neigh */
4089 : 0 : pBNS->edge[n_edges].neigh_ord[1] = k; /* iedge to i index at vertex[neigh], i < neigh */
4090 : 0 : pBNS->edge[n_edges].pass = 0;
4091 : 0 : pBNS->edge[n_edges].forbidden = 0; /* may be forbidden if edge_flow = 1: stereogenic fixed double bond */
4092 [ # # ]: 0 : if (bond_type == BOND_TYPE_DOUBLE)
4093 : : {
4094 : : /* forbid changing stereogenic double bonds */
4095 [ # # # # ]: 0 : for (m = 0; m < MAX_NUM_STEREO_BONDS && at[i].sb_parity[m]; m++)
4096 : : {
4097 [ # # ]: 0 : if (at[i].sb_ord[m] == j)
4098 : : {
4099 : 0 : pBNS->edge[n_edges].forbidden |= BNS_EDGE_FORBIDDEN_MASK;
4100 : 0 : break;
4101 : : }
4102 : : }
4103 : : }
4104 [ # # ]: 0 : if (pBNS->vert[neigh].iedge) /* djb-rwth: fixing a NULL pointer dereference */
4105 : : {
4106 : 0 : vert->iedge[j] = pBNS->vert[neigh].iedge[k] = n_edges++; /* same iedge index as neighbor index in at[] */
4107 : : }
4108 : : }
4109 : : else
4110 : : {
4111 : : /* this is the second time we encounter this bond. It was stored at */
4112 : 0 : int iedge2 = pBNS->vert[neigh].iedge[k];
4113 : 0 : edge_cap = pBNS->edge[iedge2].cap;
4114 : 0 : edge_flow = pBNS->edge[iedge2].flow;
4115 : : }
4116 : 0 : st_flow += edge_flow;
4117 : : /*
4118 : : st_cap += edge_cap;
4119 : : */
4120 : : }
4121 : :
4122 : 0 : vert->num_adj_edges = j;
4123 : : /*
4124 : : vert->st_edge.cap =
4125 : : vert->st_edge.cap0 = st_cap;
4126 : : */
4127 : 0 : vert->st_edge.flow =
4128 : 0 : vert->st_edge.flow0 = st_flow;
4129 : 0 : vert->type = BNS_VERT_TYPE_ATOM;
4130 : : /*
4131 : : tot_st_cap += vert->st_edge.cap;
4132 : : */
4133 : 0 : tot_st_flow += vert->st_edge.flow;
4134 : : }
4135 : :
4136 : 0 : *pNum_changed_bonds = num_changed_bonds / 2;
4137 : :
4138 : 0 : pBNS->num_edges = n_edges; /* number of edges */
4139 : 0 : pBNS->num_iedges = num_iedges;
4140 : 0 : pBNS->num_added_edges = 0;
4141 : :
4142 : 0 : pBNS->tot_st_cap = tot_st_cap;
4143 : 0 : pBNS->tot_st_flow = tot_st_flow;
4144 : :
4145 : : /* exit_function: */
4146 : :
4147 : 0 : return pBNS;
4148 : : }
4149 : :
4150 : :
4151 : : /****************************************************************************/
4152 : 0 : void IncrZeroBondsAndClearEndpts( inp_ATOM *at, int num_at, int iComponent )
4153 : : {
4154 : : int i, j;
4155 [ # # ]: 0 : for (i = 0; i < num_at; i++)
4156 : : {
4157 : 0 : at[i].endpoint = 0;
4158 : 0 : at[i].component = iComponent;
4159 [ # # ]: 0 : for (j = 0; j < at[i].valence; j++)
4160 : : {
4161 [ # # ]: 0 : if (!at[i].bond_type[j])
4162 : : {
4163 : 0 : at[i].bond_type[j] = BOND_TYPE_SINGLE;
4164 : 0 : at[i].chem_bonds_valence += BOND_TYPE_SINGLE;
4165 : : }
4166 : : }
4167 : : }
4168 : 0 : }
4169 : :
4170 : :
4171 : : /****************************************************************************/
4172 : 0 : void IncrZeroBonds( inp_ATOM *at, int num_at, int iComponent )
4173 : : {
4174 : : int i, j;
4175 [ # # ]: 0 : for (i = 0; i < num_at; i++)
4176 : : {
4177 : 0 : at[i].component = iComponent;
4178 [ # # ]: 0 : for (j = 0; j < at[i].valence; j++)
4179 : : {
4180 [ # # ]: 0 : if (!at[i].bond_type[j])
4181 : : {
4182 : 0 : at[i].bond_type[j] = BOND_TYPE_SINGLE;
4183 : 0 : at[i].chem_bonds_valence += BOND_TYPE_SINGLE;
4184 : : }
4185 : : }
4186 : : }
4187 : 0 : }
4188 : :
4189 : :
4190 : : /****************************************************************************/
4191 : 0 : void ClearEndpts( inp_ATOM *at, int num_at )
4192 : : {
4193 : : int i;
4194 [ # # ]: 0 : for (i = 0; i < num_at; i++)
4195 : : {
4196 : 0 : at[i].endpoint = 0;
4197 : : }
4198 : 0 : }
4199 : :
4200 : :
4201 : : /****************************************************************************/
4202 : : #define ANY_VERT_TYPE(X) (((X) & (BNS_VERT_TYPE_ATOM | BNS_VERT_TYPE_TGROUP | BNS_VERT_TYPE_C_GROUP)) && \
4203 : : !((X) & (BNS_VERT_TYPE_SUPER_TGROUP)))
4204 : : #define GRP_VERT_TYPE(X) (((X) & (BNS_VERT_TYPE_TGROUP | BNS_VERT_TYPE_C_GROUP)) && \
4205 : : !((X) & (BNS_VERT_TYPE_SUPER_TGROUP)))
4206 : :
4207 : : typedef struct tagVertexFlow
4208 : : {
4209 : : int type;
4210 : : Vertex v;
4211 : : EdgeIndex e_In;
4212 : : EdgeIndex e_Out;
4213 : : EdgeFlow delta_In;
4214 : : EdgeFlow delta_Out;
4215 : : Vertex bUsed; /* indicates the charge edge belongs to already processed atom */
4216 : : } VF;
4217 : : #define NUM_VF 3
4218 : : #define VF_USED_IN 1
4219 : : #define VF_USED_OUT 2
4220 : : #define VF_USED_ALL (VF_USED_IN | VF_USED_OUT)
4221 : :
4222 : :
4223 : :
4224 : : int GetDeltaChargeFromVF( BN_STRUCT *pBNS, VAL_AT *pVA, VF *vf );
4225 : :
4226 : :
4227 : :
4228 : : /****************************************************************************/
4229 : 0 : int GetDeltaChargeFromVF( BN_STRUCT *pBNS, VAL_AT *pVA, VF *vf )
4230 : : {
4231 : 0 : int i, v = NO_VERTEX;
4232 [ # # # # : 0 : int ieIn1 = ( !( vf->bUsed & VF_USED_IN ) && vf->e_In >= 0 && vf->delta_In ) ? vf->e_In + 1 : NO_VERTEX;
# # ]
4233 [ # # # # : 0 : int ieOut1 = ( !( vf->bUsed & VF_USED_OUT ) && vf->e_Out >= 0 && vf->delta_Out ) ? vf->e_Out + 1 : NO_VERTEX;
# # ]
4234 : : int nInitCharge, nPlusFlow, nMinusFlow, nDeltaCharge, nNumDeltaCharge, eCPlus, eCMinus;
4235 : :
4236 [ # # ]: 0 : if (!( vf->type & BNS_VERT_TYPE_C_GROUP ) ||
4237 [ # # # # ]: 0 : ( vf->type & BNS_VERT_TYPE_SUPER_TGROUP ) ||
4238 [ # # ]: 0 : ( ieIn1 == NO_VERTEX && ieOut1 == NO_VERTEX ))
4239 : : {
4240 : 0 : return 0;
4241 : : }
4242 [ # # ]: 0 : if (vf->type & BNS_VERT_TYPE_C_NEGATIVE)
4243 : : {
4244 : : /* negative charge edge */
4245 [ # # ]: 0 : for (i = 0; i < pBNS->num_atoms; i++)
4246 : : {
4247 [ # # # # ]: 0 : if (pVA[i].nCMinusGroupEdge == ieIn1 || pVA[i].nCMinusGroupEdge == ieOut1)
4248 : : {
4249 : 0 : v = i;
4250 : 0 : break;
4251 : : }
4252 : : }
4253 : : }
4254 : : else
4255 : : {
4256 : : /* positive charge edge */
4257 [ # # ]: 0 : for (i = 0; i < pBNS->num_atoms; i++)
4258 : : {
4259 [ # # # # ]: 0 : if (pVA[i].nCPlusGroupEdge == ieIn1 || pVA[i].nCPlusGroupEdge == ieOut1)
4260 : : {
4261 : 0 : v = i;
4262 : 0 : break;
4263 : : }
4264 : : }
4265 : : }
4266 : :
4267 [ # # ]: 0 : if (v == NO_VERTEX)
4268 : 0 : return 0;
4269 : :
4270 : 0 : nInitCharge = pVA[v].cInitCharge;
4271 : 0 : nPlusFlow = nMinusFlow = 0;
4272 : 0 : nNumDeltaCharge = 0;
4273 : :
4274 [ # # ]: 0 : if (( eCPlus = pVA[v].nCPlusGroupEdge - 1 ) >= 0)
4275 : : {
4276 : 0 : nPlusFlow = pBNS->edge[eCPlus].cap
4277 : 0 : - pBNS->edge[eCPlus].flow;
4278 : : }
4279 : :
4280 [ # # ]: 0 : if (( eCMinus = pVA[v].nCMinusGroupEdge - 1 ) >= 0)
4281 : : {
4282 : 0 : nMinusFlow = -pBNS->edge[eCMinus].flow;
4283 : : }
4284 : 0 : nInitCharge += nPlusFlow + nMinusFlow;
4285 : :
4286 : 0 : nDeltaCharge = 0;
4287 : :
4288 [ # # ]: 0 : if (!( vf[0].bUsed & VF_USED_OUT ))
4289 : : {
4290 [ # # # # ]: 0 : if (vf[0].e_Out == eCPlus || vf[0].e_Out == eCMinus)
4291 : : {
4292 : 0 : nDeltaCharge -= vf[0].delta_Out;
4293 : 0 : vf[0].bUsed |= VF_USED_OUT;
4294 : : }
4295 : : }
4296 : :
4297 [ # # ]: 0 : if (!( vf[0].bUsed & VF_USED_IN ))
4298 : : {
4299 [ # # # # ]: 0 : if (vf[0].e_In == eCPlus || vf[0].e_In == eCMinus)
4300 : : {
4301 : 0 : nDeltaCharge -= vf[0].delta_In;
4302 : 0 : vf[0].bUsed |= VF_USED_IN;
4303 : : }
4304 : : }
4305 : :
4306 [ # # # # ]: 0 : if (!nInitCharge && nDeltaCharge)
4307 : : {
4308 : 0 : nNumDeltaCharge++;
4309 : : }
4310 [ # # # # ]: 0 : else if (nInitCharge && 0 == nInitCharge + nDeltaCharge)
4311 : : {
4312 : 0 : nNumDeltaCharge--;
4313 : : }
4314 : :
4315 : 0 : return nNumDeltaCharge;
4316 : : }
4317 : :
4318 : :
4319 : : /****************************************************************************/
4320 : 0 : int EvaluateChargeChanges( BN_STRUCT *pBNS, VAL_AT *pVA, int *pnDeltaH, int *pnDeltaCharge, int *pnNumVisitedAtoms )
4321 : : {
4322 : 0 : int pass, i, j, v0, v1, v2, v, ineigh1, /*ineigh2,*/ vLast, n, delta, ret, ie, err = 0;
4323 : : BNS_EDGE *edge;
4324 : : int nDeltaH, nDeltaCharge, iPrev, nInitCharge, nPlusFlow, nMinusFlow;
4325 : 0 : int nNumDeltaH = 0;
4326 : 0 : int nNumDeltaCharge = 0;
4327 : 0 : int nNumVisitedAtoms = 0;
4328 : : VF vf[NUM_VF + 1];
4329 : :
4330 : 0 : *pnDeltaH = 0;
4331 : 0 : *pnDeltaCharge = 0;
4332 : 0 : *pnNumVisitedAtoms = 0;
4333 : :
4334 [ # # ]: 0 : for (pass = pBNS->num_altp - 1, ret = 0; 0 <= pass; pass--)
4335 : : {
4336 : :
4337 : 0 : pBNS->alt_path = pBNS->altp[pass];
4338 : 0 : v1 = ALTP_START_ATOM( pBNS->alt_path );
4339 : 0 : n = ALTP_PATH_LEN( pBNS->alt_path );
4340 : 0 : delta = ALTP_DELTA( pBNS->alt_path );
4341 : 0 : vLast = ALTP_END_ATOM( pBNS->alt_path );
4342 : 0 : v0 = v2 = NO_VERTEX;
4343 : :
4344 : 0 : memset( vf, 0, sizeof( vf ) ); /* djb-rwth: memset_s C11/Annex K variant? */
4345 [ # # ]: 0 : for (i = 0; i < (int) ( sizeof( vf ) / sizeof( vf[0] ) ); i++)
4346 : : {
4347 : 0 : vf[i].v = NO_VERTEX; /* = -2 */
4348 : 0 : vf[i].e_In = NO_VERTEX;
4349 : 0 : vf[i].e_Out = NO_VERTEX;
4350 : : }
4351 : 0 : iPrev = 0;
4352 : : /* add to the queue */
4353 [ # # # # ]: 0 : if (ANY_VERT_TYPE( pBNS->vert[v1].type ))
4354 : : {
4355 [ # # ]: 0 : if (pBNS->vert[v1].type & BNS_VERT_TYPE_ATOM)
4356 : : {
4357 : 0 : nNumVisitedAtoms++;
4358 : : }
4359 : 0 : vf[2].type = pBNS->vert[v1].type;
4360 : 0 : vf[2].v = v1;
4361 : 0 : iPrev = 2;
4362 : : }
4363 : :
4364 : 0 : nNumDeltaH = 0;
4365 : 0 : nNumDeltaCharge = 0;
4366 : 0 : nNumVisitedAtoms = 0;
4367 : :
4368 [ # # ]: 0 : for (i = 0; i < n; i++, delta = -delta, v0 = v1, v1 = v2) /* djb-rwth: removing redundant code */
4369 : : {
4370 : 0 : ineigh1 = ALTP_THIS_ATOM_NEIGHBOR( pBNS->alt_path, i ); /* v1->v2 neighbor */
4371 : : /*ineigh2 = ALTP_NEXT_ATOM_NEIGHBOR(pBNS->alt_path, i);*/ /* v2->v1 neighbor */
4372 : 0 : edge = pBNS->edge + ( ie = pBNS->vert[v1].iedge[ineigh1] );
4373 : : /* follow the BN Structure, not the inp_ATOM, to take care of swithching to
4374 : : t-groups, c-groups or other fictitious edges/vertices
4375 : : */
4376 : :
4377 [ # # ]: 0 : if (iPrev)
4378 : : {
4379 : : /* add exit delta and edge */
4380 : 0 : vf[2].e_Out = ie;
4381 : 0 : vf[2].delta_Out = delta;
4382 : : }
4383 : :
4384 : 0 : v2 = edge->neighbor12 ^ v1; /* next vertex */
4385 [ # # ]: 0 : if (pBNS->vert[v2].type & BNS_VERT_TYPE_ATOM)
4386 : : {
4387 : 0 : nNumVisitedAtoms++;
4388 : : }
4389 : :
4390 [ # # # # : 0 : if (( ANY_VERT_TYPE( pBNS->vert[v2].type ) || i == n - 1 ) &&
# # ]
4391 [ # # # # ]: 0 : ( vf[0].type & BNS_VERT_TYPE_C_GROUP ) && vf[0].bUsed != VF_USED_ALL)
4392 : : {
4393 : : /* unused vertex is about to be discarded */
4394 : 0 : nNumDeltaCharge += GetDeltaChargeFromVF( pBNS, pVA, &vf[0] );
4395 : : }
4396 : :
4397 [ # # # # ]: 0 : if (ANY_VERT_TYPE( pBNS->vert[v2].type ))
4398 : : {
4399 : : /* shift the queue */
4400 : 0 : vf[0] = vf[1];
4401 : 0 : vf[1] = vf[2];
4402 : 0 : vf[2] = vf[3]; /* make vf[2] empty */
4403 : : /* add next vertex */
4404 : 0 : vf[2].v = v2;
4405 : 0 : vf[2].type = pBNS->vert[v2].type;
4406 : 0 : vf[2].e_In = ie;
4407 : 0 : vf[2].delta_In = delta;
4408 : 0 : iPrev = 2; /* indicates a newly added vertex */
4409 : : }
4410 [ # # ]: 0 : else if (i == n - 1)
4411 : : {
4412 : : /* shift the queue */
4413 : 0 : vf[0] = vf[1];
4414 : 0 : vf[1] = vf[2];
4415 : 0 : vf[2] = vf[3]; /* make vf[2] empty */
4416 : 0 : iPrev = 1; /* indicates the last vertex */
4417 : : }
4418 : : else
4419 : : {
4420 : 0 : iPrev = 0; /* no new vertex has been added */
4421 : : }
4422 : :
4423 [ # # # # ]: 0 : if (iPrev && ( vf[1].type & BNS_VERT_TYPE_ATOM ))
4424 : : {
4425 : : /* a new vertex has just been added and */
4426 : : /* an atom is in the middle of the queue */
4427 : : EdgeIndex eCPlus, eCMinus;
4428 : 0 : v = vf[1].v;
4429 : 0 : nInitCharge = pVA[v].cInitCharge;
4430 : 0 : nPlusFlow = nMinusFlow = 0;
4431 [ # # ]: 0 : if (( eCPlus = pVA[v].nCPlusGroupEdge - 1 ) >= 0)
4432 : : {
4433 : 0 : nPlusFlow = pBNS->edge[eCPlus].cap
4434 : 0 : - pBNS->edge[eCPlus].flow;
4435 : : }
4436 [ # # ]: 0 : if (( eCMinus = pVA[v].nCMinusGroupEdge - 1 ) >= 0)
4437 : : {
4438 : 0 : nMinusFlow = -pBNS->edge[eCMinus].flow;
4439 : : }
4440 : 0 : nInitCharge += nPlusFlow + nMinusFlow;
4441 : :
4442 : 0 : nDeltaH = nDeltaCharge = 0;
4443 : :
4444 [ # # ]: 0 : if (vf[0].type & BNS_VERT_TYPE_TGROUP)
4445 : : {
4446 : 0 : nDeltaH -= delta;
4447 : : }
4448 [ # # ]: 0 : else if (( vf[0].type & BNS_VERT_TYPE_C_GROUP ) &&
4449 [ # # ]: 0 : !( vf[0].bUsed & VF_USED_OUT ))
4450 : : {
4451 [ # # # # ]: 0 : if (vf[0].e_Out == eCPlus || vf[0].e_Out == eCMinus)
4452 : : {
4453 : 0 : nDeltaCharge -= vf[0].delta_Out;
4454 : 0 : vf[0].bUsed |= VF_USED_OUT;
4455 : : }
4456 : : }
4457 : :
4458 [ # # ]: 0 : if (vf[2].type & BNS_VERT_TYPE_TGROUP)
4459 : : {
4460 : 0 : nDeltaH += delta;
4461 : : }
4462 [ # # ]: 0 : else if (( vf[2].type & BNS_VERT_TYPE_C_GROUP ) &&
4463 [ # # ]: 0 : !( vf[2].bUsed & VF_USED_IN ))
4464 : : {
4465 [ # # # # ]: 0 : if (vf[2].e_In == eCPlus || vf[2].e_In == eCMinus)
4466 : : {
4467 : 0 : nDeltaCharge -= vf[2].delta_In;
4468 : 0 : vf[2].bUsed |= VF_USED_IN;
4469 : : }
4470 : : }
4471 : :
4472 [ # # # # ]: 0 : if (!nInitCharge && nDeltaCharge)
4473 : : {
4474 : 0 : nNumDeltaCharge++;
4475 : : }
4476 [ # # # # ]: 0 : else if (nInitCharge && 0 == nInitCharge + nDeltaCharge)
4477 : : {
4478 : 0 : nNumDeltaCharge--;
4479 : : }
4480 : :
4481 : 0 : nNumDeltaH += abs( nDeltaH );
4482 : : /* nNumDeltaCharge += abs(nDeltaCharge); */
4483 : 0 : vf[1].bUsed = VF_USED_ALL;
4484 : : }
4485 : : }
4486 : :
4487 [ # # ]: 0 : for (j = 0; j < 3; j++)
4488 : : {
4489 : 0 : nNumDeltaCharge += GetDeltaChargeFromVF( pBNS, pVA, &vf[j] );
4490 : : }
4491 : :
4492 : 0 : *pnDeltaH += nNumDeltaH;
4493 : 0 : *pnDeltaCharge += nNumDeltaCharge;
4494 : 0 : *pnNumVisitedAtoms += nNumVisitedAtoms;
4495 : :
4496 : :
4497 [ # # ]: 0 : if (v2 != vLast)
4498 : : {
4499 : 0 : err = BNS_PROGRAM_ERR;
4500 : : }
4501 : : }
4502 [ # # ]: 0 : return err ? err : ret;
4503 : : }
4504 : :
4505 : :
4506 : : /****************************************************************************/
4507 : 0 : int RunBnsTestOnce( BN_STRUCT *pBNS, BN_DATA *pBD, VAL_AT *pVA, Vertex *pvFirst, Vertex *pvLast,
4508 : : int *pPathLen, int *pnDeltaH, int *pnDeltaCharge, int *pnNumVisitedAtoms )
4509 : : {
4510 : 0 : int bChangeFlow = 0; /* do not change flow */
4511 : : int delta, ret, ret2, pass; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
4512 : :
4513 : 0 : ReInitBnStructAltPaths( pBNS );
4514 : 0 : pass = 0;
4515 : 0 : pBNS->alt_path = pBNS->altp[pass];
4516 : 0 : pBNS->num_altp = 0;
4517 : 0 : pBNS->bChangeFlow = 0;
4518 : 0 : delta = BalancedNetworkSearch( pBNS, pBD, bChangeFlow );
4519 [ # # ]: 0 : if (delta > 0)
4520 : : {
4521 : 0 : pBNS->alt_path = pBNS->altp[pass];
4522 : 0 : *pvFirst = ALTP_START_ATOM( pBNS->alt_path );
4523 : 0 : *pPathLen = ALTP_PATH_LEN( pBNS->alt_path );
4524 : 0 : *pvLast = ALTP_END_ATOM( pBNS->alt_path );
4525 : 0 : pBNS->num_altp++;
4526 : 0 : ret2 = EvaluateChargeChanges( pBNS, pVA, pnDeltaH, pnDeltaCharge, pnNumVisitedAtoms ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
4527 : : }
4528 : : else
4529 : : {
4530 : 0 : *pvFirst = NO_VERTEX;
4531 : 0 : *pPathLen = 0;
4532 : 0 : *pvLast = NO_VERTEX;
4533 : 0 : ret2 = 0;
4534 : : }
4535 : :
4536 : 0 : ReInitBnStructAltPaths( pBNS );
4537 : :
4538 : 0 : ret = ReInitBnData( pBD );
4539 : :
4540 [ # # ]: 0 : return ( delta >= 0 && ret > 0 ) ? -ret
4541 [ # # ]: 0 : : delta;
4542 : : }
4543 : :
4544 : :
4545 : : /****************************************************************************/
4546 : 0 : int RunBnsRestoreOnce( BN_STRUCT *pBNS, BN_DATA *pBD, VAL_AT *pVA, ALL_TC_GROUPS *pTCGroups )
4547 : : {
4548 : : /* run BNS for the first time */
4549 : 0 : int nTotalDelta = 0, ret = 0;
4550 : : int nDelta;
4551 : :
4552 : 0 : ReInitBnStructAltPaths( pBNS );
4553 : :
4554 : : do
4555 : : {
4556 : 0 : nDelta = RunBalancedNetworkSearch( pBNS, pBD, BNS_EF_CHNG_FLOW );
4557 [ # # # # ]: 0 : if (IS_BNS_ERROR( nDelta ))
4558 : : {
4559 : 0 : ret = nDelta;
4560 : 0 : goto exit_function;
4561 : : }
4562 : 0 : nTotalDelta += nDelta;
4563 : 0 : ReInitBnStructAltPaths( pBNS );
4564 : 0 : ret = ReInitBnData( pBD );
4565 [ # # ]: 0 : if (ret > 0)
4566 : : {
4567 : 0 : ret = -ret;
4568 : 0 : goto exit_function;
4569 : : }
4570 : : }
4571 [ # # # # ]: 0 : while (nDelta > 0 && ret == 0);
4572 : :
4573 : 0 : pBNS->tot_st_flow += 2 * nTotalDelta;
4574 : :
4575 : 0 : ret = nTotalDelta;
4576 : :
4577 : 0 : exit_function:
4578 : 0 : return ret;
4579 : : }
4580 : :
4581 : :
4582 : : /****************************************************************************/
4583 : : /* djb-rwth: this function is completely senseless -- discussion required */
4584 : 0 : int comp_cc_cand( const void *a1, const void *a2 )
4585 : : {
4586 : 0 : const CC_CAND *p1 = (const CC_CAND *) a1;
4587 : 0 : const CC_CAND *p2 = (const CC_CAND *) a2;
4588 : : int ret;
4589 : :
4590 [ # # ]: 0 : if ((ret = (int) p2->cMetal - (int) p1->cMetal)) /* djb-rwth: addressing LLVM warning */
4591 : 0 : return ret; /* metal first */
4592 [ # # ]: 0 : if ((ret = (int) p2->cNumBondsToMetal - (int) p1->cNumBondsToMetal)) /* djb-rwth: addressing LLVM warning */
4593 : 0 : return ret; /* connected to metal first */
4594 [ # # ]: 0 : if ((ret = (int) p2->cPeriodicRowNumber - (int) p1->cPeriodicRowNumber)) /* djb-rwth: addressing LLVM warning */
4595 : 0 : return ret; /* heaviest first */
4596 [ # # ]: 0 : if ((ret = (int) p2->num_bonds - (int) p1->num_bonds)) /* djb-rwth: addressing LLVM warning */
4597 : 0 : return ret; /* more bonds first */
4598 [ # # ]: 0 : if ((ret = (int) p1->chem_valence - (int) p2->chem_valence)) /* djb-rwth: addressing LLVM warning */
4599 : 0 : return ret; /* less bond order first */
4600 [ # # # # ]: 0 : if ((!p1->cNumValenceElectrons && p2->cNumValenceElectrons)) /* djb-rwth: addressing LLVM warning */
4601 : 0 : return -1; /* no valence electrons first */
4602 [ # # # # ]: 0 : if ((!p2->cNumValenceElectrons && p1->cNumValenceElectrons)) /* djb-rwth: addressing LLVM warning */
4603 : 0 : return -1; /* no valence electrons first */
4604 [ # # ]: 0 : if (((int) p2->cNumValenceElectrons - (int) p1->cNumValenceElectrons)) /* djb-rwth: addressing LLVM warning */
4605 : 0 : return ret; /* more valence electrons first */
4606 : 0 : ret = (int) p2->iat - (int) p1->iat; /* greater canon number first */
4607 : :
4608 : 0 : return ret;
4609 : : }
4610 : :
4611 : :
4612 : : /*****************************************************************************************************
4613 : : Locate E1=C-E2 where
4614 : : e ev are the edges
4615 : :
4616 : : E1 and E2 are atoms that belong to the same t-group
4617 : : C is an atom that does not belong to any t-group
4618 : : e is a forbidden edge
4619 : : ev is not a forbidden edge
4620 : :
4621 : : Make changes so that:
4622 : : E1(d)-C(d)-E2
4623 : :
4624 : : where (d) means doublet radical
4625 : :
4626 : : */
4627 : : /**************************************************************************************************/
4628 : 0 : int get_pVA_atom_type( VAL_AT *pVA, inp_ATOM *at, int iat, int bond_type )
4629 : : {
4630 : 0 : int type = 0, val;
4631 [ # # ]: 0 : if (pVA[iat].cNumValenceElectrons == 4)
4632 : : {
4633 [ # # ]: 0 : if (pVA[iat].cPeriodicRowNumber == 1)
4634 : : {
4635 : 0 : type |= EL_TYPE_C;
4636 : : }
4637 : : }
4638 : :
4639 [ # # ]: 0 : else if (pVA[iat].cNumValenceElectrons == 6)
4640 : : {
4641 [ # # ]: 0 : if (pVA[iat].cPeriodicRowNumber == 1)
4642 : : {
4643 : 0 : type |= EL_TYPE_O;
4644 : : }
4645 [ # # ]: 0 : else if (pVA[iat].cPeriodicRowNumber < 5)
4646 : : {
4647 : 0 : type |= EL_TYPE_S;
4648 : : }
4649 [ # # ]: 0 : if (bond_type == BOND_TYPE_SINGLE &&
4650 [ # # # # ]: 0 : ( type & ( EL_TYPE_O | EL_TYPE_S ) ) &&
4651 [ # # ]: 0 : 1 == nNoMetalBondsValence( at, iat ) &&
4652 : 0 : 1 == nNoMetalNumBonds( at, iat ))
4653 : : {
4654 : 0 : type |= EL_TYPE_OSt;
4655 : : }
4656 : : }
4657 : :
4658 [ # # ]: 0 : else if (pVA[iat].cNumValenceElectrons == 5)
4659 : : {
4660 [ # # ]: 0 : if (pVA[iat].cPeriodicRowNumber == 1)
4661 : : {
4662 : 0 : type |= EL_TYPE_N;
4663 : : }
4664 : : else
4665 : : {
4666 : 0 : type |= EL_TYPE_P;
4667 : : }
4668 : : }
4669 : :
4670 [ # # ]: 0 : else if (!is_el_a_metal( pVA[iat].cPeriodicNumber ))
4671 : : {
4672 : 0 : type |= EL_TYPE_X;
4673 : : }
4674 : :
4675 : : /* check for possibility to be a tautomeric endpoint (that is, be a Mobile H site) */
4676 : 0 : val = get_endpoint_valence( at[iat].el_number );
4677 : :
4678 [ # # # # : 0 : if (val && val > at[iat].valence && !at[iat].radical &&
# # ]
4679 [ # # # # ]: 0 : -1 <= at[iat].charge && at[iat].charge <= 0 &&
4680 [ # # ]: 0 : val == at[iat].chem_bonds_valence - at[iat].charge + at[iat].num_H)
4681 : : {
4682 : 0 : type |= EL_TYPE_PT;
4683 : : }
4684 : :
4685 : 0 : return type;
4686 : : }
4687 : :
4688 : :
4689 : : /*************************************************************************************/
4690 : 0 : int AllocEdgeList( EDGE_LIST *pEdges, int nLen )
4691 : : {
4692 [ # # # ]: 0 : switch (nLen)
4693 : : {
4694 : 0 : case EDGE_LIST_FREE:
4695 [ # # ]: 0 : if (NULL != pEdges->pnEdges)
4696 : : {
4697 [ # # ]: 0 : inchi_free( pEdges->pnEdges );
4698 : : }
4699 : : /* fall through */
4700 : : case EDGE_LIST_CLEAR:
4701 : 0 : memset( pEdges, 0, sizeof( *pEdges ) ); /* djb-rwth: memset_s C11/Annex K variant? */
4702 : 0 : break;
4703 : 0 : default:
4704 [ # # # # ]: 0 : if (nLen > 0 && nLen != pEdges->num_alloc)
4705 : : {
4706 : 0 : EdgeIndex *tmp_edges = pEdges->pnEdges;
4707 : 0 : int tmp_num = pEdges->num_edges;
4708 : 0 : pEdges->pnEdges = (EdgeIndex *) inchi_calloc( nLen, sizeof( pEdges->pnEdges[0] ) );
4709 [ # # ]: 0 : if (!pEdges->pnEdges)
4710 : : {
4711 : 0 : return RI_ERR_ALLOC;
4712 : : }
4713 : 0 : tmp_num = inchi_min( tmp_num, nLen );
4714 [ # # # # ]: 0 : if (tmp_edges && tmp_num > 0)
4715 : : {
4716 : 0 : memcpy(pEdges->pnEdges, tmp_edges, tmp_num * sizeof(pEdges->pnEdges[0]));
4717 : 0 : pEdges->num_edges = tmp_num;
4718 : : }
4719 : : else
4720 : : {
4721 : 0 : pEdges->num_edges = 0;
4722 : : }
4723 [ # # ]: 0 : if (tmp_edges)
4724 : : {
4725 [ # # ]: 0 : inchi_free( tmp_edges );
4726 : : }
4727 : 0 : pEdges->num_alloc = nLen;
4728 : 0 : return 0;
4729 : : }
4730 : 0 : break;
4731 : : }
4732 : :
4733 : 0 : return 0;
4734 : : }
4735 : :
4736 : :
4737 : : /********************************************************************/
4738 : 0 : int AddToEdgeList( EDGE_LIST *pEdges, int iedge, int nAddLen )
4739 : : {
4740 [ # # ]: 0 : if (pEdges->num_alloc == pEdges->num_edges)
4741 : : {
4742 : : int ret;
4743 [ # # ]: 0 : if (nAddLen <= 0)
4744 : : {
4745 : 0 : return RI_ERR_PROGR;
4746 : : }
4747 [ # # ]: 0 : if ((ret = AllocEdgeList( pEdges, pEdges->num_alloc + nAddLen ))) /* djb-rwth: addressing LLVM warning */
4748 : : {
4749 : 0 : return ret;
4750 : : }
4751 : : }
4752 : :
4753 : 0 : pEdges->pnEdges[pEdges->num_edges++] = (EdgeIndex) iedge;
4754 : 0 : return 0;
4755 : : }
4756 : :
4757 : :
4758 : : /********************************************************************/
4759 : 0 : int RemoveFromEdgeListByIndex( EDGE_LIST *pEdges, int index )
4760 : : {
4761 : : int len;
4762 [ # # ]: 0 : if (0 <= ( len = pEdges->num_edges - index - 1 ))
4763 : : {
4764 [ # # ]: 0 : if (len)
4765 : : {
4766 : 0 : memmove(pEdges->pnEdges + index, pEdges->pnEdges + index + 1, len * sizeof(pEdges->pnEdges[0]));
4767 : : }
4768 : 0 : pEdges->num_edges--;
4769 : 0 : pEdges->pnEdges[pEdges->num_edges] = 0;
4770 : 0 : return 0;
4771 : : }
4772 : 0 : return -1;
4773 : : }
4774 : :
4775 : :
4776 : : /********************************************************************/
4777 : 0 : int FindInEdgeList( EDGE_LIST *pEdges, int iedge )
4778 : : {
4779 : : int i;
4780 : 0 : EdgeIndex ie = iedge;
4781 [ # # ]: 0 : for (i = pEdges->num_edges - 1; 0 <= i; i--)
4782 : : {
4783 [ # # ]: 0 : if (ie == pEdges->pnEdges[i])
4784 : : {
4785 : 0 : return i;
4786 : : }
4787 : : }
4788 : :
4789 : 0 : return -1;
4790 : : }
4791 : :
4792 : :
4793 : : /********************************************************************/
4794 : 0 : int RemoveFromEdgeListByValue( EDGE_LIST *pEdges, int iedge )
4795 : : {
4796 : 0 : int i, ret, n = 0;
4797 : 0 : EdgeIndex ie = iedge;
4798 [ # # ]: 0 : for (i = pEdges->num_edges - 1; 0 <= i; i--)
4799 : : {
4800 [ # # ]: 0 : if (ie == pEdges->pnEdges[i])
4801 : : {
4802 [ # # ]: 0 : if ((ret = RemoveFromEdgeListByIndex( pEdges, i ))) /* djb-rwth: addressing LLVM warning */
4803 : : {
4804 : 0 : return ret;
4805 : : }
4806 : 0 : n++;
4807 : : }
4808 : : }
4809 : :
4810 : 0 : return n;
4811 : : }
4812 : :
4813 : :
4814 : : /********************************************************************/
4815 : 0 : int AllocBfsQueue( BFS_Q *pQ, int num_at, int min_ring_size )
4816 : : {
4817 : 0 : int ret = 0;
4818 [ # # # ]: 0 : switch (num_at)
4819 : : {
4820 : 0 : case BFS_Q_FREE:
4821 [ # # ]: 0 : if (pQ->q)
4822 : : {
4823 : 0 : pQ->q = QueueDelete( pQ->q );
4824 : : }
4825 [ # # ]: 0 : if (pQ->nAtomLevel)
4826 : : {
4827 [ # # ]: 0 : inchi_free( pQ->nAtomLevel );
4828 : : }
4829 [ # # ]: 0 : if (pQ->cSource)
4830 : : {
4831 [ # # ]: 0 : inchi_free( pQ->cSource );
4832 : : }
4833 : : /* fall through */
4834 : : case BFS_Q_CLEAR:
4835 : 0 : memset( pQ, 0, sizeof( *pQ ) ); /* djb-rwth: memset_s C11/Annex K variant? */
4836 : 0 : return 0;
4837 : :
4838 : 0 : default:
4839 [ # # ]: 0 : if (num_at <= 0)
4840 : : {
4841 : 0 : ret = RI_ERR_PROGR;
4842 : 0 : goto exit_function;
4843 : : }
4844 [ # # ]: 0 : if (num_at > pQ->num_at)
4845 : : {
4846 [ # # ]: 0 : if (pQ->num_at)
4847 : : {
4848 : 0 : AllocBfsQueue( pQ, BFS_Q_FREE, 0 );
4849 : : }
4850 : 0 : pQ->q = QueueCreate( num_at + 1, sizeof( qInt ) );
4851 : 0 : pQ->nAtomLevel = (AT_RANK*) inchi_calloc( num_at, sizeof( pQ->nAtomLevel[0] ) );
4852 : 0 : pQ->cSource = (S_CHAR *) inchi_calloc( num_at, sizeof( pQ->cSource[0] ) );
4853 [ # # # # : 0 : if (!pQ->q || !pQ->cSource || !pQ->nAtomLevel)
# # ]
4854 : : {
4855 : 0 : ret = RI_ERR_ALLOC;
4856 : 0 : goto exit_function;
4857 : : }
4858 : 0 : pQ->num_at = num_at;
4859 : : }
4860 : 0 : pQ->min_ring_size = min_ring_size;
4861 : : }
4862 : :
4863 : 0 : exit_function:
4864 : 0 : return ret;
4865 : : }
4866 : :
4867 : :
4868 : : /*************************************************************************************/
4869 : 0 : void RemoveForbiddenEdgeMask( BN_STRUCT *pBNS, EDGE_LIST *pEdges, int forbidden_edge_mask )
4870 : : {
4871 : 0 : int i, mask = ~forbidden_edge_mask;
4872 [ # # ]: 0 : for (i = 0; i < pEdges->num_edges; i++)
4873 : : {
4874 : 0 : pBNS->edge[pEdges->pnEdges[i]].forbidden &= mask;
4875 : : }
4876 : 0 : }
4877 : :
4878 : :
4879 : : /*************************************************************************************/
4880 : 0 : void SetForbiddenEdgeMask( BN_STRUCT *pBNS, EDGE_LIST *pEdges, int forbidden_edge_mask )
4881 : : {
4882 : : int i;
4883 [ # # ]: 0 : for (i = 0; i < pEdges->num_edges; i++)
4884 : : {
4885 : 0 : pBNS->edge[pEdges->pnEdges[i]].forbidden |= forbidden_edge_mask;
4886 : : }
4887 : 0 : }
4888 : :
4889 : :
4890 : : /****************************************************************************/
4891 : 0 : void RemoveForbiddenBondFlowBits( BN_STRUCT *pBNS, int forbidden_edge_mask_int )
4892 : : {
4893 : : BNS_EDGE *e;
4894 : : int i;
4895 : 0 : int inv_forbidden_edge_mask = ~forbidden_edge_mask_int;
4896 [ # # ]: 0 : for (i = 0, e = pBNS->edge; i < pBNS->num_bonds; i++, e++)
4897 : : {
4898 : 0 : e->forbidden &= inv_forbidden_edge_mask;
4899 : : }
4900 : 0 : }
4901 : :
4902 : :
4903 : : /******************************************************************************************************
4904 : : upper vc
4905 : : edge /
4906 : : v1[i0]---v0
4907 : : \ /
4908 : : \ /
4909 : : \ /
4910 : : v1[i1]
4911 : : |
4912 : : |
4913 : : atom
4914 : : */
4915 : 0 : int GetChargeFlowerUpperEdge( BN_STRUCT *pBNS, VAL_AT *pVA, int nChargeEdge )
4916 : : {
4917 : 0 : int ret = NO_VERTEX, i, j, k, i0, i1;
4918 : : Vertex v0, v1[3], vc, v_t, v;
4919 : : BNS_EDGE *pe, *pe1[3], *pe_t;
4920 : : BNS_VERTEX *pv0, *pv1[3], *pv_t;
4921 : :
4922 [ # # ]: 0 : if (nChargeEdge < 0)
4923 : : {
4924 : 0 : goto exit_function;
4925 : : }
4926 : :
4927 : 0 : pe = pBNS->edge + nChargeEdge;
4928 : 0 : vc = pe->neighbor1; /* charge vertex */
4929 [ # # ]: 0 : if (!IS_BNS_VT_C_GR( pBNS->vert[vc].type ))
4930 : : {
4931 : 0 : vc = vc ^ pe->neighbor12;
4932 : : }
4933 : :
4934 : 0 : v0 = vc ^ pe->neighbor12; /* ChargeStruct vertex ? */
4935 : 0 : pv0 = pBNS->vert + v0;
4936 [ # # ]: 0 : if (IS_BNS_VT_ATOM( pv0->type ))
4937 : : {
4938 : 0 : goto exit_function; /* no charge flower exists */
4939 : : }
4940 : :
4941 : : /* 2 edges from v0 */
4942 [ # # # # ]: 0 : for (i = j = 0; i < pv0->num_adj_edges && j < 3; i++)
4943 : : {
4944 : 0 : pe1[j] = pBNS->edge + pv0->iedge[i];
4945 [ # # # # ]: 0 : if (vc != ( v1[j] = pe1[j]->neighbor12 ^ v0 ) &&
4946 : 0 : ( pv1[j] = pBNS->vert + v1[j],
4947 [ # # # # ]: 0 : !IS_BNS_VT_ATOM( pv1[j]->type ) && !IS_BNS_VT_C_GR( pv1[j]->type ) ))
4948 : : {
4949 : 0 : j++;
4950 : : }
4951 : : }
4952 : :
4953 [ # # # # ]: 0 : if (j != 2 || i != pv0->num_adj_edges)
4954 : : {
4955 : 0 : goto exit_function;
4956 : : }
4957 : :
4958 [ # # ]: 0 : if (pv1[1]->num_adj_edges == 2 &&
4959 [ # # ]: 0 : pv1[0]->num_adj_edges == 3)
4960 : : {
4961 : 0 : i0 = 1;
4962 : 0 : i1 = 0;
4963 : : }
4964 [ # # ]: 0 : else if (pv1[0]->num_adj_edges == 2 &&
4965 [ # # ]: 0 : pv1[1]->num_adj_edges == 3)
4966 : : {
4967 : 0 : i0 = 0;
4968 : 0 : i1 = 1;
4969 : : }
4970 : : else
4971 : : {
4972 : 0 : goto exit_function;
4973 : : }
4974 : :
4975 : : /* additional check: traverse edges around v1[i1] */
4976 : 0 : pv_t = pv1[i1];
4977 : 0 : v_t = v1[i1];
4978 [ # # ]: 0 : for (i = k = 0; i < pv_t->num_adj_edges; i++)
4979 : : {
4980 : 0 : pe_t = pBNS->edge + pv_t->iedge[i];
4981 : 0 : v = pe_t->neighbor12 ^ v_t; /* v1[i1] neighbor */
4982 [ # # ]: 0 : if (v == v0)
4983 : : {
4984 : 0 : k += 1;
4985 : : }
4986 [ # # ]: 0 : if (v == v1[i0])
4987 : : {
4988 : 0 : k += 2;
4989 : : }
4990 [ # # ]: 0 : if (IS_BNS_VT_ATOM( pBNS->vert[v].type ))
4991 : : {
4992 : 0 : k += 4;
4993 : : }
4994 : : }
4995 [ # # ]: 0 : if (k != 7)
4996 : : {
4997 : 0 : goto exit_function;
4998 : : }
4999 : :
5000 : 0 : ret = (int) ( pe1[i0] - pBNS->edge );
5001 : :
5002 : 0 : exit_function:
5003 : 0 : return ret;
5004 : : }
5005 : :
5006 : :
5007 : :
5008 : : #if (INCLUDE_NORMALIZATION_ENTRY_POINT == 1 )
5009 : : /********************************************************************************************
5010 : : input: allocate (num_at+num_deleted_H) atoms in inp_ATOM *at_norm, *at_fixed_bonds_out
5011 : : allocate t_group_info
5012 : : *********************************************************************************************/
5013 : : int NormalizeStructure( ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd, BN_STRUCT *pBNS,
5014 : : StrFromINChI *pStruct, inp_ATOM *at, inp_ATOM *at2,
5015 : : VAL_AT *pVA, ALL_TC_GROUPS *pTCGroups,
5016 : : inp_ATOM *at_norm, inp_ATOM *at_fixed_bonds_out, T_GROUP_INFO *t_group_info )
5017 : : {
5018 : : int i, ret, num_endpoints, nLenTaut;
5019 : : int num_at = pStruct->num_atoms;
5020 : : int num_deleted_H = pStruct->num_deleted_H;
5021 : : int len_at = num_at + num_deleted_H;
5022 : : /*
5023 : : T_GROUP_INFO tgi;
5024 : : T_GROUP_INFO *t_group_info = &tgi;
5025 : : inp_ATOM *at_fixed_bonds_out = NULL;
5026 : : inp_ATOM *at_norm = NULL;
5027 : :
5028 : : at_norm = (inp_ATOM *)inchi_calloc( len_at, sizeof(at_norm[0]) );
5029 : : at_fixed_bonds_out = (inp_ATOM *)inchi_calloc( len_at, sizeof(at_fixed_bonds_out[0]) );
5030 : : if ( !at_norm || !at_fixed_bonds_out ) {
5031 : : if ( at_norm ) inchi_free( at_norm );
5032 : : if ( at_fixed_bonds_out ) inchi_free( at_fixed_bonds_out );
5033 : : ret = RI_ERR_ALLOC;
5034 : : goto exit_function;
5035 : : }
5036 : : */
5037 : : /* call normalization only */
5038 : : memset( t_group_info, 0, sizeof( t_group_info[0] ) );
5039 : : t_group_info->tni.nNumRemovedExplicitH = pStruct->num_deleted_H;
5040 : : t_group_info->bTautFlags = ip->bTautFlags;
5041 : : t_group_info->bTautFlagsDone = 0; /* (ip->bTautFlagsDone | sd->bTautFlagsDone[INCHI_BAS]);*/
5042 : :
5043 : : memcpy( at2, at, len_at * sizeof( at2[0] ) );
5044 : : pStruct->at = at2;
5045 : : ret = CopyBnsToAtom( pStruct, pBNS, pVA, pTCGroups, 1 );
5046 : : pStruct->at = at;
5047 : : if (ret < 0)
5048 : : {
5049 : : goto exit_function;
5050 : : }
5051 : : #if ( FIND_RING_SYSTEMS == 1 )
5052 : : ret = MarkRingSystemsInp( at2, num_at, 0 );
5053 : : if (ret < 0)
5054 : : {
5055 : : goto exit_function;
5056 : : }
5057 : : #endif
5058 : : memcpy( at_norm, at2, len_at * sizeof( at_norm[0] ) );
5059 : : for (i = 0, num_endpoints = 0; i < num_at; i++)
5060 : : {
5061 : : num_endpoints += ( 0 != at_norm[i].endpoint );
5062 : : at_norm[i].endpoint = 0;
5063 : : }
5064 : :
5065 : : ret = mark_alt_bonds_and_taut_groups( ic, pCG, at_norm, at_fixed_bonds_out, num_at, t_group_info,
5066 : : NULL /* &inpbTautFlags*/, NULL /*inpbTautFlagsDone*/ );
5067 : : if (ret < 0)
5068 : : {
5069 : : goto exit_function;/* out of RAM or other normalization problem */
5070 : : }
5071 : : /* after normalization, t_group_info->t_group[i].num[0] = number of H + number of (-) */
5072 : : /* t_group_info->t_group[i].num[1] = number of (-) */
5073 : :
5074 : : /* --- count t-groups, remove (-)-only t-groups, replace -------------------------------*/
5075 : : /* t_group_info->t_group[i].num[0] with */
5076 : : /* t_group_info->t_group[i].num[0]-t_group_info->t_group[i].num[1] */
5077 : : nLenTaut = CountTautomerGroupsInpAt( at_norm, num_at, t_group_info );
5078 : : ret = nLenTaut;
5079 : : exit_function:
5080 : : return ret;
5081 : : }
5082 : : #endif
5083 : :
5084 : :
5085 : :
5086 : : /****************************************************************************/
5087 : 0 : int MakeOneInChIOutOfStrFromINChI2( struct tagCANON_GLOBALS *pCG,
5088 : : INCHI_CLOCK *ic,
5089 : : ICHICONST INPUT_PARMS *ip_inp,
5090 : : STRUCT_DATA *sd_inp,
5091 : : BN_STRUCT *pBNS, StrFromINChI *pStruct,
5092 : : inp_ATOM *at, inp_ATOM *at2, inp_ATOM *at3,
5093 : : VAL_AT *pVA, ALL_TC_GROUPS *pTCGroups,
5094 : : T_GROUP_INFO **t_group_info,
5095 : : inp_ATOM **at_norm, inp_ATOM **at_prep )
5096 : : {
5097 : : int ret;
5098 : : INPUT_PARMS ip_loc, *ip;
5099 : : STRUCT_DATA sd_loc, *sd;
5100 : :
5101 : 0 : ip_loc = *ip_inp;
5102 : 0 : sd_loc = *sd_inp;
5103 : 0 : ip = &ip_loc;
5104 : 0 : sd = &sd_loc;
5105 : :
5106 : 0 : memset( sd, 0, sizeof( *sd ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5107 : :
5108 : : /* create structure out of BNS */
5109 : 0 : memcpy(at2, at, ((long long)pStruct->num_atoms + (long long)pStruct->num_deleted_H) * sizeof(at2[0])); /* djb-rwth: cast operator added */
5110 : 0 : pStruct->at = at2;
5111 : 0 : ret = CopyBnsToAtom( pStruct, pBNS, pVA, pTCGroups, 1 );
5112 : 0 : pStruct->at = at;
5113 [ # # ]: 0 : if (ret < 0)
5114 : : {
5115 : 0 : goto exit_function;/* out of RAM or other normalization problem */
5116 : : }
5117 : :
5118 : 0 : pStruct->at = at;
5119 : :
5120 : 0 : ret = MakeOneInChIOutOfStrFromINChI( pCG, ic, ip, sd, pStruct,
5121 : : at2, at3, pTCGroups );
5122 : :
5123 [ # # ]: 0 : if (ret < 0)
5124 : : {
5125 : 0 : goto exit_function;/* out of RAM or other normalization problem */
5126 : : }
5127 [ # # ]: 0 : if (at_norm)
5128 : : {
5129 : 0 : *at_norm = pStruct->pOne_norm_data[0]->at;
5130 : : }
5131 [ # # ]: 0 : if (at_prep)
5132 : : {
5133 [ # # # # ]: 0 : if (pStruct->pOne_norm_data[0]->bTautPreprocessed && pStruct->pOne_norm_data[0]->at_fixed_bonds)
5134 : : {
5135 : 0 : *at_prep = pStruct->pOne_norm_data[0]->at_fixed_bonds;
5136 : : }
5137 : : else
5138 : : /* get preprocessed structure in case of Fixed-H */
5139 [ # # # # : 0 : if (pStruct->iMobileH == TAUT_NON && pStruct->pOne_norm_data[1] && pStruct->pOne_norm_data[1]->bTautPreprocessed)
# # ]
5140 : : {
5141 : 0 : *at_prep = pStruct->pOne_norm_data[1]->at_fixed_bonds;
5142 : : }
5143 : : else
5144 : : {
5145 : 0 : *at_prep = NULL;
5146 : : }
5147 : : }
5148 [ # # ]: 0 : if (t_group_info)
5149 : : {
5150 [ # # ]: 0 : if (pStruct->iMobileH == TAUT_YES &&
5151 [ # # ]: 0 : pStruct->One_ti.num_t_groups &&
5152 [ # # # # ]: 0 : pStruct->One_ti.t_group && pStruct->One_ti.nEndpointAtomNumber)
5153 : : {
5154 : 0 : *t_group_info = &pStruct->One_ti;
5155 : : }
5156 : : else
5157 : : {
5158 : 0 : *t_group_info = NULL;
5159 : : }
5160 : : }
5161 : :
5162 : 0 : exit_function:
5163 : 0 : return ret;
5164 : : }
5165 : :
5166 : :
5167 : : /****************************************************************************/
5168 : 0 : int MakeOneInChIOutOfStrFromINChI( struct tagCANON_GLOBALS *pCG,
5169 : : INCHI_CLOCK *ic,
5170 : : ICHICONST INPUT_PARMS *ip,
5171 : : STRUCT_DATA *sd,
5172 : : StrFromINChI *pStruct,
5173 : : inp_ATOM *at2,
5174 : : inp_ATOM *at3,
5175 : : ALL_TC_GROUPS *pTCGroups )
5176 : : {
5177 : :
5178 : 0 : INCHI_MODE bTautFlags = ip->bTautFlags | TG_FLAG_H_ALREADY_REMOVED;
5179 : 0 : INCHI_MODE bTautFlagsDone = 0; /*(ip->bTautFlagsDone | sd->bTautFlagsDone[INCHI_BAS]);*/
5180 : : INChI *cur_INChI[TAUT_NUM];
5181 : : INChI_Aux *cur_INChI_Aux[TAUT_NUM];
5182 : : int i, j, k;
5183 : 0 : int iComponent = pTCGroups->iComponent;
5184 : 0 : int len_at = pStruct->num_atoms + pStruct->num_deleted_H;
5185 : 0 : int num_atoms = pStruct->num_atoms;
5186 : : long ulStructTime;
5187 : :
5188 : : INP_ATOM_DATA InpCurAtData;
5189 : : INP_ATOM_DATA *inp_cur_data;
5190 : :
5191 : : INP_ATOM_DATA InpNormAtData, InpNormTautData;
5192 : : INP_ATOM_DATA *inp_norm_data[TAUT_NUM]; /* = { &InpNormAtData, &InpNormTautData }; */
5193 : :
5194 : 0 : int bOrigCoord = 0;
5195 : 0 : int num_at, ret = RI_ERR_PROGR;
5196 : : struct tagInchiTime ulMaxTime;
5197 : :
5198 : 0 : T_GROUP_INFO *t_group_info = NULL;
5199 : : /* initialization */
5200 : 0 : inp_cur_data = &InpCurAtData;
5201 : 0 : inp_norm_data[TAUT_NON] = &InpNormAtData;
5202 : 0 : inp_norm_data[TAUT_YES] = &InpNormTautData;
5203 : :
5204 : 0 : memset( inp_cur_data, 0, sizeof( *inp_cur_data ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5205 : 0 : memset( inp_norm_data[TAUT_NON], 0, sizeof( *inp_norm_data[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5206 : 0 : memset( inp_norm_data[TAUT_YES], 0, sizeof( *inp_norm_data[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5207 : 0 : ulStructTime = sd->ulStructTime;
5208 : 0 : memset( sd, 0, sizeof( *sd ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5209 : :
5210 : : /* deallocate old results */
5211 : 0 : free_t_group_info( &pStruct->One_ti );
5212 [ # # ]: 0 : for (k = 0; k < TAUT_NUM; k++)
5213 : : {
5214 : 0 : Free_INChI( &pStruct->pOneINChI[k] );
5215 : 0 : Free_INChI_Aux( &pStruct->pOneINChI_Aux[k] );
5216 [ # # ]: 0 : if (pStruct->pOne_norm_data[k])
5217 : : {
5218 : 0 : FreeInpAtomData( pStruct->pOne_norm_data[k] );
5219 [ # # ]: 0 : inchi_free( pStruct->pOne_norm_data[k] );
5220 : 0 : pStruct->pOne_norm_data[k] = NULL;
5221 : : }
5222 : 0 : cur_INChI[k] = NULL;
5223 : 0 : cur_INChI_Aux[k] = NULL;
5224 : : }
5225 : :
5226 : 0 : memcpy(at3, at2, sizeof(at3[0]) * len_at);
5227 : :
5228 : : /* prepare the structure */
5229 : 0 : IncrZeroBondsAndClearEndpts( at3, num_atoms, iComponent + 1 );
5230 : :
5231 : 0 : CopySt2At( at3, pStruct->st, pStruct->num_atoms );
5232 : :
5233 : 0 : FixUnkn0DStereoBonds( at3, pStruct->num_atoms );
5234 : :
5235 : 0 : ret = ReconcileAllCmlBondParities( at3, pStruct->num_atoms, 0 );
5236 : :
5237 [ # # ]: 0 : if (ret < 0)
5238 : : {
5239 : 0 : goto exit_function;
5240 : : }
5241 : :
5242 [ # # ]: 0 : if (0 < fix_odd_things( num_atoms, at3, 1, ip->bFixNonUniformDraw ))
5243 : : {
5244 [ # # ]: 0 : if (sd->nErrorType < _IS_WARNING)
5245 : : {
5246 : 0 : sd->nErrorType = _IS_WARNING;
5247 : : }
5248 : 0 : sd->bTautFlagsDone[INCHI_BAS] |= TG_FLAG_FIX_ODD_THINGS_DONE;
5249 : : }
5250 : :
5251 : : /* allocate and set parameters */
5252 : 0 : inp_cur_data->at = at3;
5253 : 0 : inp_cur_data->num_at = num_atoms;
5254 : 0 : inp_cur_data->num_removed_H = pStruct->num_deleted_H;
5255 : :
5256 : 0 : bTautFlagsDone &= ~( TG_FLAG_FOUND_ISOTOPIC_H_DONE | TG_FLAG_FOUND_ISOTOPIC_ATOM_DONE );
5257 : :
5258 [ # # ]: 0 : if ((i = bNumHeterAtomHasIsotopicH( at3, num_atoms ))) /* djb-rwth: addressing LLVM warning */
5259 : : {
5260 [ # # ]: 0 : if (i & 1)
5261 : : {
5262 : 0 : bTautFlagsDone |= TG_FLAG_FOUND_ISOTOPIC_H_DONE;
5263 : : }
5264 [ # # ]: 0 : if (i & 2)
5265 : : {
5266 : 0 : bTautFlagsDone |= TG_FLAG_FOUND_ISOTOPIC_ATOM_DONE;
5267 : : }
5268 : : }
5269 : :
5270 : 0 : memset( &ulMaxTime, 0, sizeof( ulMaxTime ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5271 : :
5272 : : /* allocate memory for non-tautimeric (k=0) and tautomeric (k=1) results */
5273 [ # # ]: 0 : for (k = 0; k < TAUT_NUM; k++)
5274 : : {
5275 : :
5276 [ # # # # ]: 0 : if (!pStruct->bMobileH || k == pStruct->bMobileH)
5277 : 0 : {
5278 : : /* pStruct->bMobileH=0: k = 0, 1 => allow allocation of both Fixed-H and Mobile-H InChI
5279 : : pStruct->bMobileH=1: k = 1 only => allow allocation of only Mobile-H InChI */
5280 : :
5281 : : /* djb-rwth: introducing variables for correct nAllocMode expression */
5282 : 0 : int nAM1 = 0, nAM2 = 0;
5283 : 0 : int nAllocMode = 0; /* copied from below 2024-09-01 DT */
5284 : :
5285 [ # # ]: 0 : if (k == TAUT_YES)
5286 : 0 : nAM1 = REQ_MODE_TAUT;
5287 : :
5288 [ # # ]: 0 : if (bTautFlagsDone & (TG_FLAG_FOUND_ISOTOPIC_H_DONE | TG_FLAG_FOUND_ISOTOPIC_ATOM_DONE))
5289 : 0 : nAM2 = ip->nMode & REQ_MODE_ISO;
5290 : :
5291 : 0 : nAllocMode = nAM1 | nAM2; /* djb-rwth: original sequence of bit-wise operations had to be rewritten */
5292 : :
5293 [ # # # # : 0 : if ((k == TAUT_NON && ( ip->nMode & REQ_MODE_BASIC )) ||
# # ]
5294 [ # # ]: 0 : (k == TAUT_YES && ( ip->nMode & REQ_MODE_TAUT ))) /* djb-rwth: addressing LLVM warnings */
5295 : : {
5296 : : /* alloc INChI and INChI_Aux only if ip->nMode allows this */
5297 : 0 : cur_INChI[k] = Alloc_INChI( inp_cur_data->at, inp_cur_data->num_at, &inp_cur_data->num_bonds,
5298 : : &inp_cur_data->num_isotopic, nAllocMode );
5299 : 0 : cur_INChI_Aux[k] = Alloc_INChI_Aux( inp_cur_data->num_at,
5300 : : inp_cur_data->num_isotopic, nAllocMode, bOrigCoord );
5301 [ # # ]: 0 : if (cur_INChI_Aux[k])
5302 : : {
5303 : 0 : cur_INChI_Aux[k]->bIsIsotopic = inp_cur_data->num_isotopic;
5304 : : }
5305 : :
5306 : : /* alloc memory for the output structure: non-tautomeric and tautomeric (for displaying) */
5307 : 0 : CreateInpAtomData( inp_norm_data[k], inp_cur_data->num_at + inp_cur_data->num_removed_H, k );
5308 : :
5309 : 0 : inp_norm_data[k]->num_removed_H = inp_cur_data->num_removed_H;
5310 : : }
5311 : : else
5312 : : {
5313 : 0 : FreeInpAtomData( inp_norm_data[k] );
5314 : : }
5315 : : }
5316 : : else
5317 : : {
5318 : 0 : FreeInpAtomData( inp_norm_data[k] );
5319 : : }
5320 : : }
5321 : :
5322 : 0 : k = pStruct->bMobileH;
5323 : :
5324 : : /* In case of Fixed-H we have to create InChI for both Fixed-H and Mobile-H */
5325 : :
5326 : 0 : num_at = Create_INChI( pCG,
5327 : : ic,
5328 : : (INPUT_PARMS *) ip,
5329 : : cur_INChI,
5330 : : cur_INChI_Aux,
5331 : : NULL,
5332 : : inp_cur_data->at,
5333 : : inp_norm_data,
5334 : 0 : inp_cur_data->num_at + inp_cur_data->num_removed_H,
5335 : 0 : ip->nMode,
5336 : : &bTautFlags,
5337 : : &bTautFlagsDone,
5338 : : NULL /* &ulMaxTime*/,
5339 : 0 : &pStruct->One_ti,
5340 : 0 : sd->pStrErrStruct );
5341 : :
5342 : 0 : SetConnectedComponentNumber( inp_cur_data->at, inp_cur_data->num_at, iComponent + 1 ); /* normalization alters structure component number */
5343 : :
5344 : : /* Detect InChI errors */
5345 : :
5346 [ # # ]: 0 : if (num_at < 0)
5347 : : {
5348 : 0 : ret = num_at;
5349 : : }
5350 [ # # # # ]: 0 : else if (cur_INChI[k] && cur_INChI[k]->nErrorCode)
5351 : : {
5352 : 0 : ret = cur_INChI[k]->nErrorCode;
5353 : : }
5354 [ # # # # ]: 0 : else if (cur_INChI_Aux[k] && cur_INChI_Aux[k]->nErrorCode)
5355 : : {
5356 : 0 : ret = cur_INChI_Aux[k]->nErrorCode;
5357 : : }
5358 : : else
5359 : : {
5360 : 0 : ret = 0;
5361 : : }
5362 : :
5363 : : /* Fill out the output */
5364 : :
5365 [ # # ]: 0 : if (!ret) /* djb-rwth: fixing a NULL pointer dereference */
5366 : : {
5367 : 0 : int bMobileH = pStruct->bMobileH;
5368 [ # # ]: 0 : if (bMobileH == TAUT_NON &&
5369 [ # # ]: 0 : 0 == cur_INChI[TAUT_NON]->nNumberOfAtoms &&
5370 [ # # ]: 0 : 0 < cur_INChI[TAUT_YES]->nNumberOfAtoms)
5371 : : {
5372 : : /* tautomerism or H(+) removal/addition was not discovered */
5373 : 0 : bMobileH = TAUT_YES;
5374 : : }
5375 : :
5376 [ # # ]: 0 : if (cur_INChI[1])
5377 : 0 : pStruct->nChargeRevrs = cur_INChI[TAUT_YES]->nTotalCharge; /* djb-rwth: fixing a NULL pointer dereference */
5378 : :
5379 : 0 : pStruct->pOneINChI[0] = cur_INChI[bMobileH];
5380 : 0 : pStruct->pOneINChI_Aux[0] = cur_INChI_Aux[bMobileH];
5381 : 0 : pStruct->nOneINChI_bMobileH = bMobileH;
5382 : 0 : cur_INChI[bMobileH] = NULL; /* remove pointer to avoid deallocation at exit_function */
5383 : 0 : cur_INChI_Aux[bMobileH] = NULL; /* remove pointer to avoid deallocation at exit_function */
5384 : :
5385 [ # # ]: 0 : pStruct->nNumRemovedProtons = ( pStruct->iMobileH == TAUT_YES ) ? pStruct->One_ti.tni.nNumRemovedProtons : 0;
5386 : :
5387 : :
5388 : : /* set correct t-group numbers to endpoints */
5389 : :
5390 : 0 : t_group_info = &pStruct->One_ti;
5391 : :
5392 [ # # # # : 0 : if (t_group_info->num_t_groups && t_group_info->t_group && t_group_info->nEndpointAtomNumber)
# # ]
5393 : : {
5394 : 0 : inp_ATOM *at_norm = inp_norm_data[TAUT_YES]->at;
5395 : 0 : int num_at_norm = inp_norm_data[TAUT_YES]->num_at;
5396 [ # # ]: 0 : for (i = 0; i < num_at_norm; i++)
5397 : : {
5398 : 0 : at_norm[i].endpoint = 0;
5399 : : }
5400 [ # # ]: 0 : for (i = 0; i < t_group_info->num_t_groups; i++)
5401 : : {
5402 : 0 : k = t_group_info->t_group[i].nFirstEndpointAtNoPos;
5403 : : /* add number of mobile (-) to the number of mobile H */
5404 : 0 : t_group_info->t_group[i].num[0] += t_group_info->t_group[i].num[1];
5405 [ # # ]: 0 : for (j = 0; j < t_group_info->t_group[i].nNumEndpoints; j++, k++)
5406 : : {
5407 : 0 : at_norm[t_group_info->nEndpointAtomNumber[k]].endpoint = t_group_info->t_group[i].nGroupNumber;
5408 : : }
5409 : : }
5410 : : }
5411 : :
5412 : 0 : pStruct->pOne_norm_data[0] = (INP_ATOM_DATA *) inchi_malloc( sizeof( pStruct->pOne_norm_data[0][0] ) );
5413 : :
5414 [ # # ]: 0 : if (pStruct->pOne_norm_data[0])
5415 : : {
5416 : 0 : memcpy(pStruct->pOne_norm_data[0], inp_norm_data[bMobileH], sizeof(pStruct->pOne_norm_data[0][0]));
5417 : 0 : memset( inp_norm_data[bMobileH], 0, sizeof( *inp_norm_data[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5418 : : }
5419 : : else
5420 : : {
5421 : 0 : ret = RI_ERR_ALLOC;
5422 : : }
5423 : :
5424 [ # # # # ]: 0 : if (bMobileH == TAUT_NON && cur_INChI[TAUT_YES]->nNumberOfAtoms > 0)
5425 : : {
5426 [ # # ]: 0 : int bMobileHalt = ALT_TAUT( bMobileH ); /* = TAUT_YES */
5427 : 0 : pStruct->pOneINChI[1] = cur_INChI[bMobileHalt];
5428 : 0 : pStruct->pOneINChI_Aux[1] = cur_INChI_Aux[bMobileHalt];
5429 : 0 : cur_INChI[bMobileHalt] = NULL;
5430 : 0 : cur_INChI_Aux[bMobileHalt] = NULL;
5431 : 0 : pStruct->pOne_norm_data[1] = (INP_ATOM_DATA *) inchi_malloc( sizeof( pStruct->pOne_norm_data[0][0] ) );
5432 [ # # ]: 0 : if (pStruct->pOne_norm_data[1])
5433 : : {
5434 : 0 : memcpy(pStruct->pOne_norm_data[1], inp_norm_data[bMobileHalt], sizeof(pStruct->pOne_norm_data[0][0]));
5435 : 0 : memset( inp_norm_data[bMobileHalt], 0, sizeof( *inp_norm_data[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5436 : : }
5437 : : else
5438 : : {
5439 : 0 : ret = RI_ERR_ALLOC;
5440 : : }
5441 : : }
5442 : : }
5443 : : else
5444 : : {
5445 : : #if ( bRELEASE_VERSION != 1 )
5446 : : #ifndef TARGET_API_LIB
5447 : : fprintf( stdout, "ERROR: Create_INChI returned %d\n", ret );
5448 : : #endif
5449 : : #endif
5450 : : }
5451 : :
5452 : 0 : exit_function:
5453 : : /* deallocate unused */
5454 [ # # ]: 0 : for (k = 0; k < TAUT_NUM; k++)
5455 : : {
5456 : 0 : Free_INChI( &cur_INChI[k] );
5457 : 0 : Free_INChI_Aux( &cur_INChI_Aux[k] );
5458 : 0 : FreeInpAtomData( inp_norm_data[k] );
5459 : : }
5460 : 0 : sd->ulStructTime = ulStructTime;
5461 : :
5462 : 0 : return ret;
5463 : : }
5464 : :
5465 : :
5466 : : /****************************************************************************
5467 : : Input:
5468 : : at[].num_H = total number of all terminal H connected to the atom
5469 : : at[].num_iso_H[] = numbers of isotopic H among at[].num_H
5470 : : Explicit H are disconnected
5471 : : Calculate InChI with normalization only in MakeOneInChIOutOfStrFromINChI()
5472 : : with (TG_FLAG_H_ALREADY_REMOVED & bTautFlags) != 0
5473 : : Output:
5474 : : at[].num_H = number of implicit non-isotopic H connected to the atom
5475 : : at[].num_iso_H[] = numbers of implicit isotopic H (not included in at[].num_H)
5476 : : Explicit H are connected
5477 : : Calculate InChI with full preprocessing MakeInChIOutOfStrFromINChI2()
5478 : : with (TG_FLAG_H_ALREADY_REMOVED & bTautFlags) == 0
5479 : : ****************************************************************************/
5480 : 0 : int ConnectDisconnectedH( inp_ATOM *at, int num_atoms, int num_deleted_H )
5481 : : {
5482 : : int i, j, k, n, m, num_H;
5483 : 0 : int tot_atoms = num_atoms + num_deleted_H;
5484 : :
5485 [ # # ]: 0 : for (i = num_atoms; i < tot_atoms; i = j)
5486 : : {
5487 : 0 : k = at[i].neighbor[0]; /* a[k] is the atom connected to the explicit hydrogen at[i] */
5488 : :
5489 [ # # # # ]: 0 : for (j = i; j < tot_atoms && at[j].neighbor[0] == k; j++)
5490 : : {
5491 : : ;
5492 : : }
5493 : :
5494 : 0 : num_H = j - i; /* number of explicit H for at[k] */
5495 [ # # ]: 0 : if (num_H > at[k].num_H)
5496 : : {
5497 : 0 : return RI_ERR_PROGR;
5498 : : }
5499 [ # # ]: 0 : if (num_H + at[k].valence > MAXVAL)
5500 : : {
5501 : 0 : return RI_ERR_SYNTAX;
5502 : : }
5503 : :
5504 : : /* insert links to explicit H before all other links in the connection list */
5505 : 0 : n = at[k].valence;
5506 : 0 : memmove(at[k].neighbor + num_H, at[k].neighbor, sizeof(at[k].neighbor[0]) * n);
5507 : 0 : memmove(at[k].bond_stereo + num_H, at[k].bond_stereo, sizeof(at[k].bond_stereo[0]) * n);
5508 : 0 : memmove(at[k].bond_type + num_H, at[k].bond_type, sizeof(at[k].bond_type[0]) * n);
5509 [ # # ]: 0 : for (n = 0; n < num_H; n++)
5510 : : {
5511 : 0 : at[k].neighbor[n] = i + n;
5512 : 0 : at[k].bond_stereo[n] = 0;
5513 : 0 : at[k].bond_type[n] = BOND_TYPE_SINGLE;
5514 : : }
5515 : :
5516 [ # # # # ]: 0 : for (m = 0; m < MAX_NUM_STEREO_BONDS && at[k].sb_parity[m]; m++)
5517 : : {
5518 : 0 : at[k].sb_ord[m] += num_H;
5519 [ # # ]: 0 : if (at[k].sn_ord[m] < 0)
5520 : : {
5521 [ # # ]: 0 : for (n = i; n < j; n++)
5522 : : {
5523 [ # # ]: 0 : if (at[n].orig_at_number == at[k].sn_orig_at_num[m])
5524 : : {
5525 : 0 : at[k].sn_ord[m] = n - i;
5526 : 0 : break;
5527 : : }
5528 : : }
5529 : :
5530 [ # # ]: 0 : if (n == j)
5531 : : {
5532 : 0 : return RI_ERR_PROGR;
5533 : : }
5534 : : }
5535 : : else
5536 : : {
5537 : 0 : at[k].sn_ord[m] += num_H;
5538 : : }
5539 : : }
5540 : :
5541 : 0 : at[k].valence += num_H;
5542 : 0 : at[k].chem_bonds_valence += num_H;
5543 : 0 : at[k].num_H -= num_H; /* cannot be negative */
5544 : :
5545 : : /*memset( at[k].num_iso_H, 0, sizeof(at[0].num_iso_H) );*/ /* attached H must carry all isotopic shifts */
5546 [ # # ]: 0 : for (n = i; n < j; n++)
5547 : : {
5548 : 0 : at[n].chem_bonds_valence = BOND_TYPE_SINGLE;
5549 : : }
5550 : :
5551 : : /* isotopic H */
5552 [ # # # # ]: 0 : for (m = j - 1; i <= m && at[m].iso_atw_diff > 0; m--)
5553 : : {
5554 [ # # ]: 0 : if (at[m].iso_atw_diff > NUM_H_ISOTOPES)
5555 : : {
5556 : 0 : return RI_ERR_PROGR;
5557 : : }
5558 [ # # ]: 0 : if (0 >= at[k].num_iso_H[(int) at[m].iso_atw_diff - 1] --)
5559 : : {
5560 : 0 : return RI_ERR_PROGR;
5561 : : }
5562 : : }
5563 : : }
5564 : :
5565 : : /* subtract isotopic H */
5566 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
5567 : : {
5568 [ # # ]: 0 : for (m = 0; m < NUM_H_ISOTOPES; m++)
5569 : : {
5570 : 0 : at[i].num_H -= at[i].num_iso_H[m];
5571 : : }
5572 [ # # ]: 0 : if (0 > at[i].num_H)
5573 : : {
5574 : 0 : return RI_ERR_PROGR;
5575 : : }
5576 : : }
5577 : :
5578 : 0 : return tot_atoms;
5579 : : }
5580 : :
5581 : :
5582 : : /******************************************************************************************************
5583 : : Input:
5584 : : at[].num_H = number of implicit non-isotopic H connected to the atom
5585 : : at[].num_iso_H[] = numbers of implicit isotopic H (not included in at[].num_H)
5586 : : Explicit H are connected
5587 : : Calculate InChI with (TG_FLAG_H_ALREADY_REMOVED & bTautFlags) == 0
5588 : : Output:
5589 : : at[].num_H = total number of all terminal H connected to the atom
5590 : : at[].num_iso_H[] = numbers of isotopic H among at[].num_H
5591 : : Explicit H are disconnected
5592 : : Calculate InChI with (TG_FLAG_H_ALREADY_REMOVED & bTautFlags) != 0
5593 : : *******************************************************************************************************/
5594 : 0 : int DisconnectedConnectedH( inp_ATOM *at, int num_atoms, int num_deleted_H )
5595 : : {
5596 : : int i, j, k, n, m, num_H, num_iso_H;
5597 : 0 : int tot_atoms = num_atoms + num_deleted_H;
5598 : 0 : S_CHAR ctmp = '0';
5599 : :
5600 : : /* add implicit isotopic H to total implicit H */
5601 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
5602 : : {
5603 [ # # ]: 0 : for (m = 0; m < NUM_H_ISOTOPES; m++)
5604 : : {
5605 : 0 : at[i].num_H += at[i].num_iso_H[m];
5606 : : }
5607 : : }
5608 : :
5609 [ # # ]: 0 : for (i = num_atoms; i < tot_atoms; i = j)
5610 : : {
5611 : 0 : k = at[i].neighbor[0]; /* a[k] is the atom connected to the explicit hydrogen at[i] */
5612 : :
5613 [ # # # # ]: 0 : for (j = i; j < tot_atoms && at[j].neighbor[0] == k; j++)
5614 : : {
5615 : 0 : at[j].chem_bonds_valence = 0;
5616 : : }
5617 : 0 : num_H = j - i; /* number of explicit H for at[k] */
5618 : :
5619 : : /* verify correct number of explicit H */
5620 [ # # # # ]: 0 : for (n = 0; n < at[k].valence && at[k].neighbor[n] >= num_atoms; n++)
5621 : : {
5622 : : ;
5623 : : }
5624 [ # # ]: 0 : if (n != num_H)
5625 : : {
5626 : 0 : return RI_ERR_PROGR;
5627 : : }
5628 : :
5629 : : /* remove bonds to explicit H located in front of all other bonds in the connection list */
5630 : 0 : at[k].valence -= num_H; /* djb-rwth: use of cast operators avoided */
5631 : 0 : n = at[k].valence; /* new number of bonds */
5632 : 0 : at[k].chem_bonds_valence -= num_H; /* new no-H valence */
5633 [ # # ]: 0 : if (n)
5634 : : {
5635 : 0 : memmove(at[k].neighbor, at[k].neighbor + num_H, sizeof(at[k].neighbor[0]) * n);
5636 : 0 : memmove(at[k].bond_stereo, at[k].bond_stereo + num_H, sizeof(at[k].bond_stereo[0]) * n);
5637 : 0 : memmove(at[k].bond_type, at[k].bond_type + num_H, sizeof(at[k].bond_type[0]) * n);
5638 : : }
5639 : : /* clear the 'tails' */
5640 : 0 : memset( at[k].neighbor + n, 0, sizeof( at[k].neighbor[0] ) * num_H ); /* djb-rwth: memset_s C11/Annex K variant? */
5641 : 0 : memset( at[k].bond_stereo + n, 0, sizeof( at[k].bond_stereo[0] ) * num_H ); /* djb-rwth: memset_s C11/Annex K variant? */
5642 : 0 : memset( at[k].bond_type + n, 0, sizeof( at[k].bond_type[0] ) * num_H ); /* djb-rwth: memset_s C11/Annex K variant? */
5643 : :
5644 [ # # # # ]: 0 : for (m = 0; m < MAX_NUM_STEREO_BONDS && at[k].sb_parity[m]; m++)
5645 : : {
5646 : 0 : at[k].sb_ord[m] -= num_H;
5647 [ # # # # ]: 0 : if (0 <= at[k].sn_ord[m] && at[k].sn_ord[m] < num_H)
5648 : : {
5649 : 0 : at[k].sn_ord[m] = -1; /* disconnected explicit H */
5650 : : }
5651 : : }
5652 : : /* add explicit isotopic H (already included in num_H) */
5653 [ # # # # ]: 0 : for (num_iso_H = 0, m = j - 1; i <= m && at[m].iso_atw_diff > 0; m--)
5654 : : {
5655 [ # # ]: 0 : if (at[m].iso_atw_diff > NUM_H_ISOTOPES)
5656 : : {
5657 : 0 : return RI_ERR_PROGR;
5658 : : }
5659 : 0 : at[k].num_iso_H[(int) at[m].iso_atw_diff - 1] ++;
5660 : : }
5661 : 0 : at[k].num_H += num_H; /* add all explicit H including isotopic */
5662 : : }
5663 : :
5664 : 0 : return tot_atoms;
5665 : : }
5666 : :
5667 : :
5668 : : /****************************************************************************/
5669 : 0 : int MakeInChIOutOfStrFromINChI2( INCHI_CLOCK *ic,
5670 : : CANON_GLOBALS *pCG,
5671 : : ICHICONST INPUT_PARMS *ip_inp,
5672 : : STRUCT_DATA *sd_inp,
5673 : : StrFromINChI *pStruct,
5674 : : int iComponent,
5675 : : int iAtNoOffset,
5676 : : long num_inp )
5677 : : {
5678 : : char szTitle[MAX_SDF_HEADER + MAX_SDF_VALUE + 256];
5679 : :
5680 : : int len, ret;
5681 : : /*
5682 : : PINChI2 *pINChI[INCHI_NUM];
5683 : : PINChI_Aux2 *pINChI_Aux[INCHI_NUM];
5684 : : */
5685 : : INPUT_PARMS local_ip;
5686 : : STRUCT_DATA local_sd;
5687 : 0 : INPUT_PARMS *ip = &local_ip;
5688 : 0 : STRUCT_DATA *sd = &local_sd;
5689 : :
5690 : : ORIG_ATOM_DATA OrigAtData; /* 0=> disconnected, 1=> original */
5691 : 0 : ORIG_ATOM_DATA *orig_inp_data = &OrigAtData;
5692 : : ORIG_ATOM_DATA PrepAtData[2]; /* 0=> disconnected, 1=> original */
5693 : 0 : ORIG_ATOM_DATA *prep_inp_data = PrepAtData;
5694 : :
5695 : : INCHI_IOS_STRING temp_string_container;
5696 : 0 : INCHI_IOS_STRING *strbuf = &temp_string_container;
5697 : 0 : memset( strbuf, 0, sizeof( *strbuf ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5698 : :
5699 [ # # ]: 0 : if (0 >= inchi_strbuf_init(strbuf, INCHI_STRBUF_INITIAL_SIZE, INCHI_STRBUF_SIZE_INCREMENT))
5700 : : {
5701 : 0 : ret = RI_ERR_ALLOC;
5702 : 0 : goto early_exit_error; /* djb-rwth: avoiding garbage value */
5703 : : }
5704 : :
5705 : : /* djb-rwth: fixing oss-fuzz issue #70552 */
5706 [ # # # # : 0 : if (!ip_inp || !sd_inp || !pStruct)
# # ]
5707 : : {
5708 : 0 : ret = RI_ERR_ALLOC;
5709 : 0 : goto early_exit_error; /* djb-rwth: avoiding garbage value */
5710 : : }
5711 : :
5712 : 0 : *ip = *ip_inp;
5713 : 0 : ip->bDisplay = 0;
5714 : 0 : ip->bDisplayCompositeResults = 0;
5715 : 0 : ip->bDisplayEachComponentINChI = 0;
5716 : 0 : ip->bDisplayIfRestoreWarnings = 0;
5717 : 0 : ip->bINChIOutputOptions = INCHI_OUT_NO_AUX_INFO;
5718 : :
5719 : : /*
5720 : : if ( pStruct->bMobileH ) {
5721 : : ip->nMode &= ~REQ_MODE_BASIC;
5722 : : ip->nMode |= REQ_MODE_TAUT;
5723 : : } else {
5724 : : ip->nMode |= (REQ_MODE_TAUT | REQ_MODE_BASIC);
5725 : : }
5726 : : */
5727 : :
5728 : 0 : memset( sd, 0, sizeof( *sd ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5729 : 0 : sd->fPtrStart = -1;
5730 : 0 : sd->fPtrEnd = -1;
5731 : :
5732 : : /*
5733 : : if ( ip->nMode & REQ_MODE_STEREO ) {
5734 : : if ( ip->nMode & (REQ_MODE_RELATIVE_STEREO | REQ_MODE_RACEMIC_STEREO) ) {
5735 : : sd->bChiralFlag |= FLAG_INP_AT_NONCHIRAL;
5736 : : } else {
5737 : : sd->bChiralFlag |= FLAG_INP_AT_CHIRAL;
5738 : : }
5739 : : }
5740 : : */
5741 : :
5742 : 0 : memset( orig_inp_data, 0, sizeof( *orig_inp_data ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5743 : 0 : memset( prep_inp_data, 0, 2 * sizeof( *prep_inp_data ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5744 : 0 : memset( pStruct->RevInChI.pINChI, 0, sizeof( pStruct->RevInChI.pINChI ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5745 : 0 : memset( pStruct->RevInChI.pINChI_Aux, 0, sizeof( pStruct->RevInChI.pINChI_Aux ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5746 : 0 : memset( szTitle, 0, sizeof( szTitle ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5747 : :
5748 : 0 : len = sizeof( orig_inp_data->at[0] )*( (long long)pStruct->num_atoms + (long long)pStruct->num_deleted_H ); /* djb-rwth: cast operators added */
5749 : :
5750 : 0 : orig_inp_data->at = (inp_ATOM *) inchi_malloc( len );
5751 : :
5752 [ # # ]: 0 : if (orig_inp_data->at)
5753 : : {
5754 : : /*memcpy( orig_inp_data->at, pStruct->at2, len );*/
5755 : : /*ret = ConnectDisconnectedH( orig_inp_data->at, pStruct->num_atoms, pStruct->num_deleted_H );*/
5756 : :
5757 : 0 : CopySt2At( pStruct->at2, pStruct->st, pStruct->num_atoms );
5758 : :
5759 : 0 : ret = ConnectDisconnectedH( pStruct->at2, pStruct->num_atoms, pStruct->num_deleted_H );
5760 [ # # ]: 0 : if (ret < 0)
5761 : : {
5762 : 0 : goto exit_error;
5763 : : }
5764 : :
5765 : 0 : orig_inp_data->num_inp_atoms = ret;
5766 : : /* connections changed => reconcile parities even if they were reconciled before */
5767 : : /* remove t-group markings and increment zero-order bonds,
5768 : : otherwise MakeInChIOutOfStrFromINChI2() woild fail */
5769 : : /*
5770 : : IncrZeroBondsAndClearEndpts(pStruct->at2, pStruct->num_atoms, iComponent+1);
5771 : : */
5772 : :
5773 : 0 : IncrZeroBonds( pStruct->at2, pStruct->num_atoms, iComponent + 1 );
5774 : :
5775 : : /* CopySt2At() moved to the position before ConnectDisconnectedH() because
5776 : : in case stereo exists only in Mobile-H layer and the processd here
5777 : : component is restored in Fixed-H layer the parities needed by
5778 : : ConnectDisconnectedH() must be there before calling
5779 : : ConnectDisconnectedH()
5780 : : */
5781 : : /*CopySt2At( pStruct->at2, pStruct->st, pStruct->num_atoms );*/
5782 : :
5783 : 0 : ret = ReconcileAllCmlBondParities( pStruct->at2, orig_inp_data->num_inp_atoms, 0 );
5784 [ # # ]: 0 : if (ret < 0)
5785 : : {
5786 : 0 : goto exit_error;
5787 : : }
5788 : :
5789 : : #if USE_BCF
5790 : : memcpy_s( orig_inp_data->at, (long long)len, pStruct->at2, len ); /* djb-rwth: function replaced with its safe C11 variant */
5791 : : #else
5792 : 0 : memcpy(orig_inp_data->at, pStruct->at2, len);
5793 : : #endif
5794 : :
5795 : 0 : ClearEndpts( orig_inp_data->at, pStruct->num_atoms );
5796 : :
5797 [ # # ]: 0 : if (FixUnkn0DStereoBonds( orig_inp_data->at, pStruct->num_atoms ))
5798 : : {
5799 : 0 : ret = ReconcileAllCmlBondParities( pStruct->at2, orig_inp_data->num_inp_atoms, 0 );
5800 [ # # ]: 0 : if (ret < 0)
5801 : : {
5802 : 0 : goto exit_error;
5803 : : }
5804 : : }
5805 : : /* keep endpoint[] markings in at2[] for subsequent add/remove protons */
5806 : : }
5807 : : else
5808 : : {
5809 : 0 : ret = RI_ERR_ALLOC;
5810 : 0 : goto exit_error;
5811 : : }
5812 : :
5813 : 0 : memset( sd->num_components, 0, sizeof( sd->num_components ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5814 : 0 : memset( sd->num_taut, 0, sizeof( sd->num_taut ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5815 : 0 : memset( sd->num_non_taut, 0, sizeof( sd->num_non_taut ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5816 : 0 : memset( sd->bTautFlagsDone, 0, sizeof( sd->bTautFlagsDone ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5817 : 0 : memset( sd->bTautFlags, 0, sizeof( sd->bTautFlags ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5818 : :
5819 : :
5820 : 0 : ret = ProcessOneStructure( ic, pCG, sd, ip, szTitle,
5821 : 0 : pStruct->RevInChI.pINChI,
5822 : 0 : pStruct->RevInChI.pINChI_Aux,
5823 : : NULL /*inp_file*/,
5824 : : NULL /*log_file*/,
5825 : : NULL /*out_file*/,
5826 : : NULL /*prb_file*/,
5827 : : orig_inp_data, prep_inp_data,
5828 : : num_inp, strbuf,
5829 : : 0 /* save_opt_bits */ );
5830 : :
5831 : 0 : memcpy(pStruct->RevInChI.num_components, sd->num_components, sizeof(pStruct->RevInChI.num_components));
5832 : 0 : memcpy(sd_inp->pStrErrStruct, sd->pStrErrStruct, sizeof(sd_inp->pStrErrStruct));
5833 : 0 : pStruct->RevInChI.nRetVal = ret;
5834 : :
5835 : : /* translate returned value */
5836 [ # # # # : 0 : if (ret == _IS_ERROR || ret == _IS_FATAL || ret == _IS_UNKNOWN)
# # ]
5837 : : {
5838 : 0 : ret = RI_ERR_PROGR;
5839 : : }
5840 [ # # ]: 0 : else if (ret == _IS_OKAY)
5841 : : {
5842 : 0 : ret = 0;
5843 : : }
5844 [ # # ]: 0 : else if (ret == _IS_WARNING)
5845 : : {
5846 : 0 : ret = 1;
5847 : : }
5848 : : else
5849 : : {
5850 : 0 : ret = RI_ERR_PROGR;
5851 : : }
5852 : :
5853 : : /* save total charge from Mobile-H layer */
5854 : :
5855 : 0 : pStruct->nChargeRevrs = 0;
5856 [ # # ]: 0 : if (ret >= 0)
5857 : : {
5858 [ # # ]: 0 : if (bRevInchiComponentExists( pStruct, INCHI_REC, TAUT_YES, 0 ))
5859 : : {
5860 : 0 : pStruct->nChargeRevrs = pStruct->RevInChI.pINChI[INCHI_REC][0][TAUT_YES]->nTotalCharge;
5861 : : }
5862 [ # # ]: 0 : else if (bRevInchiComponentExists( pStruct, INCHI_BAS, TAUT_YES, 0 ))
5863 : : {
5864 : 0 : pStruct->nChargeRevrs = pStruct->RevInChI.pINChI[INCHI_BAS][0][TAUT_YES]->nTotalCharge;
5865 : : }
5866 : : }
5867 : :
5868 : : /* free structure data */
5869 : 0 : FreeOrigAtData( orig_inp_data );
5870 : 0 : FreeOrigAtData( prep_inp_data );
5871 : 0 : FreeOrigAtData( prep_inp_data + 1 );
5872 : :
5873 : 0 : exit_error:
5874 : : #if ( FIX_GAF_2019_2==1 )
5875 [ # # ]: 0 : if (orig_inp_data->at)
5876 : : {
5877 : 0 : FreeInpAtom(&orig_inp_data->at);
5878 : : }
5879 : : #endif
5880 : 0 : early_exit_error:
5881 : 0 : inchi_strbuf_close( strbuf );
5882 : :
5883 : 0 : return ret;
5884 : : }
5885 : :
5886 : :
5887 : : /****************************************************************************/
5888 : 0 : int OutputInChIOutOfStrFromINChI( struct tagINCHI_CLOCK *ic,
5889 : : struct tagCANON_GLOBALS *pCG,
5890 : : ICHICONST INPUT_PARMS *ip_inp,
5891 : : STRUCT_DATA *sd_inp,
5892 : : long num_inp,
5893 : : int bINChIOutputOptions,
5894 : : INCHI_IOSTREAM *pout,
5895 : : INCHI_IOSTREAM *plog,
5896 : : InpInChI *pOneInput,
5897 : : int bHasSomeFixedH,
5898 : : unsigned char save_opt_bits )
5899 : : {
5900 : : char szTitle[MAX_SDF_HEADER + MAX_SDF_VALUE + 256];
5901 : :
5902 : : int len, ret;
5903 : : /*
5904 : : PINChI2 *pINChI[INCHI_NUM];
5905 : : PINChI_Aux2 *pINChI_Aux[INCHI_NUM];
5906 : : */
5907 : : REV_INCHI RevInChI;
5908 : :
5909 : : INPUT_PARMS local_ip;
5910 : : STRUCT_DATA local_sd;
5911 : 0 : INPUT_PARMS *ip = &local_ip;
5912 : 0 : STRUCT_DATA *sd = &local_sd;
5913 : :
5914 : : ORIG_ATOM_DATA OrigAtData; /* 0=> disconnected, 1=> original */
5915 : 0 : ORIG_ATOM_DATA *orig_inp_data = &OrigAtData;
5916 : : ORIG_ATOM_DATA PrepAtData[2]; /* 0=> disconnected, 1=> original */
5917 : 0 : ORIG_ATOM_DATA *prep_inp_data = PrepAtData;
5918 : :
5919 : : INCHI_IOS_STRING temp_string_container;
5920 : 0 : INCHI_IOS_STRING *strbuf = &temp_string_container;
5921 : 0 : memset( strbuf, 0, sizeof( *strbuf ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5922 : :
5923 [ # # ]: 0 : if (0 >= inchi_strbuf_init( strbuf, INCHI_STRBUF_INITIAL_SIZE, INCHI_STRBUF_SIZE_INCREMENT ))
5924 : : {
5925 : 0 : ret = RI_ERR_ALLOC;
5926 : 0 : goto exit_error;
5927 : : }
5928 : :
5929 : 0 : *ip = *ip_inp;
5930 : 0 : ip->bNoStructLabels = 1;
5931 : 0 : ip->bDisplay = 0;
5932 : 0 : ip->bDisplayCompositeResults = 0;
5933 : 0 : ip->bDisplayEachComponentINChI = 0;
5934 : 0 : ip->bDisplayIfRestoreWarnings = 0;
5935 : :
5936 : : #if ( I2S_MODIFY_OUTPUT == 1 )
5937 : : if (bINChIOutputOptions & INCHI_OUT_SDFILE_ONLY)
5938 : : {
5939 : : ip->bINChIOutputOptions = bINChIOutputOptions & ~( INCHI_OUT_PLAIN_TEXT | INCHI_OUT_PLAIN_TEXT_COMMENTS );
5940 : : }
5941 : : else
5942 : : {
5943 : : if (bINChIOutputOptions & INCHI_OUT_PLAIN_TEXT)
5944 : : {
5945 : : ip->bINChIOutputOptions = (bINChIOutputOptions & ~INCHI_OUT_SDFILE_ONLY) | INCHI_OUT_EMBED_REC; /* djb-rwth: addressing LLVM warning */
5946 : : }
5947 : : else
5948 : : {
5949 : : if (bINChIOutputOptions & ( INCHI_OUT_NO_AUX_INFO | INCHI_OUT_SHORT_AUX_INFO | INCHI_OUT_ONLY_AUX_INFO | INCHI_OUT_TABBED_OUTPUT ))
5950 : : {
5951 : : ip->bINChIOutputOptions = ( INCHI_OUT_PLAIN_TEXT | INCHI_OUT_EMBED_REC | bINChIOutputOptions );
5952 : : }
5953 : : else
5954 : : {
5955 : : ip->bINChIOutputOptions = ( INCHI_OUT_PLAIN_TEXT | INCHI_OUT_EMBED_REC );
5956 : : }
5957 : : }
5958 : : }
5959 : : #else
5960 : 0 : ip->bINChIOutputOptions = ( INCHI_OUT_PLAIN_TEXT | INCHI_OUT_EMBED_REC );
5961 : : #endif
5962 : :
5963 [ # # ]: 0 : if (bHasSomeFixedH)
5964 : : {
5965 : 0 : ip->nMode |= ( REQ_MODE_TAUT | REQ_MODE_BASIC );
5966 : : }
5967 : : else
5968 : : {
5969 : 0 : ip->nMode &= ~REQ_MODE_BASIC;
5970 : 0 : ip->nMode |= REQ_MODE_TAUT;
5971 : : }
5972 : :
5973 : 0 : memset( sd, 0, sizeof( *sd ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5974 : 0 : sd->fPtrStart = -1;
5975 : 0 : sd->fPtrEnd = -1;
5976 : : /*
5977 : : if ( ip->nMode & REQ_MODE_STEREO ) {
5978 : : if ( ip->nMode & (REQ_MODE_RELATIVE_STEREO | REQ_MODE_RACEMIC_STEREO) ) {
5979 : : sd->bChiralFlag |= FLAG_INP_AT_NONCHIRAL;
5980 : : } else {
5981 : : sd->bChiralFlag |= FLAG_INP_AT_CHIRAL;
5982 : : }
5983 : : }
5984 : : */
5985 : 0 : memset( orig_inp_data, 0, sizeof( *orig_inp_data ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5986 : 0 : memset( prep_inp_data, 0, 2 * sizeof( *prep_inp_data ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5987 : 0 : memset( RevInChI.pINChI, 0, sizeof( RevInChI.pINChI ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5988 : 0 : memset( RevInChI.pINChI_Aux, 0, sizeof( RevInChI.pINChI_Aux ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5989 : :
5990 : 0 : len = sizeof( orig_inp_data->at[0] ) * pOneInput->num_atoms;
5991 : 0 : orig_inp_data->at = (inp_ATOM *) inchi_malloc( len );
5992 : 0 : orig_inp_data->szCoord = (MOL_COORD *) inchi_calloc( pOneInput->num_atoms, sizeof( orig_inp_data->szCoord[0] ) );
5993 : :
5994 : 0 : orig_inp_data->polymer = pOneInput->polymer;
5995 : 0 : orig_inp_data->v3000 = pOneInput->v3000;
5996 : 0 : pOneInput->polymer = NULL;
5997 : 0 : pOneInput->v3000 = NULL;
5998 : 0 : orig_inp_data->valid_polymer = pOneInput->valid_polymer;
5999 : :
6000 [ # # # # ]: 0 : if (orig_inp_data->at && orig_inp_data->szCoord)
6001 : 0 : {
6002 : : int i, k;
6003 : 0 : memcpy(orig_inp_data->at, pOneInput->atom, len);
6004 : 0 : orig_inp_data->num_inp_atoms = pOneInput->num_atoms;
6005 : 0 : ClearEndpts( orig_inp_data->at, orig_inp_data->num_inp_atoms );
6006 : : /* otherwise fails on CID=450438 */
6007 [ # # ]: 0 : if (FixUnkn0DStereoBonds( orig_inp_data->at, orig_inp_data->num_inp_atoms ))
6008 : : {
6009 : 0 : ret = ReconcileAllCmlBondParities( orig_inp_data->at, orig_inp_data->num_inp_atoms, 0 );
6010 [ # # ]: 0 : if (ret < 0)
6011 : : {
6012 : : /* djb-rwth: fixing a NULL pointer dereference */
6013 : 0 : free(orig_inp_data->at);
6014 : 0 : free(orig_inp_data->szCoord);
6015 : 0 : goto exit_error;
6016 : : }
6017 : : }
6018 : :
6019 : : /* To obtain rA,rB,rC in AuxInfo we have to emulate input coordinates; make all of them zeroes */
6020 [ # # ]: 0 : for (i = 0; i < pOneInput->num_atoms; i++)
6021 : : {
6022 [ # # ]: 0 : for (k = 0; k < NUM_COORD*LEN_COORD; k += LEN_COORD)
6023 : : {
6024 : 0 : orig_inp_data->szCoord[i][k] = '0';
6025 : : }
6026 : : }
6027 : : }
6028 : : else
6029 : : {
6030 : : /* djb-rwth: fixing a NULL pointer dereference */
6031 : 0 : ret = RI_ERR_ALLOC;
6032 : 0 : free(orig_inp_data->at);
6033 : 0 : free(orig_inp_data->szCoord);
6034 : 0 : goto exit_error;
6035 : : }
6036 : :
6037 : 0 : memset( sd->num_components, 0, sizeof( sd->num_components ) ); /* djb-rwth: memset_s C11/Annex K variant? */
6038 : 0 : memset( sd->num_taut, 0, sizeof( sd->num_taut ) ); /* djb-rwth: memset_s C11/Annex K variant? */
6039 : 0 : memset( sd->num_non_taut, 0, sizeof( sd->num_non_taut ) ); /* djb-rwth: memset_s C11/Annex K variant? */
6040 : 0 : memset( sd->bTautFlagsDone, 0, sizeof( sd->bTautFlagsDone ) ); /* djb-rwth: memset_s C11/Annex K variant? */
6041 : 0 : memset( sd->bTautFlags, 0, sizeof( sd->bTautFlags ) ); /* djb-rwth: memset_s C11/Annex K variant? */
6042 : 0 : memset( szTitle, 0, sizeof( szTitle ) ); /* djb-rwth: memset_s C11/Annex K variant? */
6043 : :
6044 : :
6045 : :
6046 : 0 : ret = ProcessOneStructure( ic, pCG, sd, ip, szTitle,
6047 : : RevInChI.pINChI,
6048 : : RevInChI.pINChI_Aux,
6049 : : NULL /*inp_file*/,
6050 : : plog /*log_file*/,
6051 : : pout /*out_file*/,
6052 : : NULL /*prb_file*/,
6053 : : orig_inp_data, prep_inp_data,
6054 : : num_inp, strbuf, save_opt_bits );
6055 : :
6056 : 0 : memcpy(RevInChI.num_components, sd->num_components, sizeof(RevInChI.num_components));
6057 : : /*
6058 : : memcpy(sd_inp->pStrErrStruct, sd->pStrErrStruct, sizeof(sd_inp->pStrErrStruct) );
6059 : : */
6060 : :
6061 : 0 : RevInChI.nRetVal = ret;
6062 : :
6063 : : /* translate returned value */
6064 [ # # # # : 0 : if (ret == _IS_ERROR || ret == _IS_FATAL || ret == _IS_UNKNOWN)
# # ]
6065 : : {
6066 : 0 : ret = RI_ERR_PROGR;
6067 : : }
6068 [ # # ]: 0 : else if (ret == _IS_OKAY)
6069 : : {
6070 : 0 : ret = 0;
6071 : : }
6072 [ # # ]: 0 : else if (ret == _IS_WARNING)
6073 : : {
6074 : 0 : ret = 1;
6075 : : }
6076 : : else
6077 : : {
6078 : 0 : ret = RI_ERR_PROGR;
6079 : : }
6080 : :
6081 : : /* free structure data */
6082 : 0 : FreeOrigAtData( orig_inp_data );
6083 : 0 : FreeOrigAtData( prep_inp_data );
6084 : 0 : FreeOrigAtData( prep_inp_data + 1 );
6085 : 0 : FreeAllINChIArrays( RevInChI.pINChI,
6086 : : RevInChI.pINChI_Aux,
6087 : : RevInChI.num_components );
6088 : :
6089 : :
6090 : 0 : exit_error:
6091 : 0 : inchi_strbuf_close( strbuf );
6092 : :
6093 : 0 : return ret;
6094 : : }
6095 : : #endif
|