rino 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +44 -0
- data/Rakefile +123 -0
- data/ext/extconf.rb +26 -0
- data/ext/ruby_inchi_main.so +0 -0
- data/ext/src/aux2atom.h +2786 -0
- data/ext/src/comdef.h +148 -0
- data/ext/src/e_0dstereo.c +3014 -0
- data/ext/src/e_0dstereo.h +31 -0
- data/ext/src/e_comdef.h +57 -0
- data/ext/src/e_ctl_data.h +147 -0
- data/ext/src/e_ichi_io.c +498 -0
- data/ext/src/e_ichi_io.h +40 -0
- data/ext/src/e_ichi_parms.c +37 -0
- data/ext/src/e_ichi_parms.h +41 -0
- data/ext/src/e_ichicomp.h +50 -0
- data/ext/src/e_ichierr.h +40 -0
- data/ext/src/e_ichimain.c +593 -0
- data/ext/src/e_ichisize.h +43 -0
- data/ext/src/e_inchi_atom.c +75 -0
- data/ext/src/e_inchi_atom.h +33 -0
- data/ext/src/e_inpdef.h +41 -0
- data/ext/src/e_mode.h +706 -0
- data/ext/src/e_mol2atom.c +649 -0
- data/ext/src/e_readinch.c +58 -0
- data/ext/src/e_readmol.c +54 -0
- data/ext/src/e_readmol.h +180 -0
- data/ext/src/e_readstru.c +251 -0
- data/ext/src/e_readstru.h +33 -0
- data/ext/src/e_util.c +284 -0
- data/ext/src/e_util.h +61 -0
- data/ext/src/extr_ct.h +251 -0
- data/ext/src/ichi.h +206 -0
- data/ext/src/ichi_bns.c +7999 -0
- data/ext/src/ichi_bns.h +231 -0
- data/ext/src/ichican2.c +5000 -0
- data/ext/src/ichicano.c +2195 -0
- data/ext/src/ichicano.h +49 -0
- data/ext/src/ichicans.c +1625 -0
- data/ext/src/ichicant.h +379 -0
- data/ext/src/ichicomn.h +260 -0
- data/ext/src/ichicomp.h +50 -0
- data/ext/src/ichidrp.h +119 -0
- data/ext/src/ichierr.h +124 -0
- data/ext/src/ichiisot.c +101 -0
- data/ext/src/ichilnct.c +286 -0
- data/ext/src/ichimain.h +132 -0
- data/ext/src/ichimak2.c +1189 -0
- data/ext/src/ichimake.c +3812 -0
- data/ext/src/ichimake.h +205 -0
- data/ext/src/ichimap1.c +851 -0
- data/ext/src/ichimap2.c +2856 -0
- data/ext/src/ichimap4.c +1609 -0
- data/ext/src/ichinorm.c +741 -0
- data/ext/src/ichinorm.h +67 -0
- data/ext/src/ichiparm.c +45 -0
- data/ext/src/ichiparm.h +1441 -0
- data/ext/src/ichiprt1.c +3612 -0
- data/ext/src/ichiprt2.c +1511 -0
- data/ext/src/ichiprt3.c +3011 -0
- data/ext/src/ichiqueu.c +1003 -0
- data/ext/src/ichiring.c +326 -0
- data/ext/src/ichiring.h +49 -0
- data/ext/src/ichisize.h +35 -0
- data/ext/src/ichisort.c +539 -0
- data/ext/src/ichister.c +3538 -0
- data/ext/src/ichister.h +35 -0
- data/ext/src/ichitaut.c +3843 -0
- data/ext/src/ichitaut.h +387 -0
- data/ext/src/ichitime.h +74 -0
- data/ext/src/inchi_api.h +670 -0
- data/ext/src/inchi_dll.c +1480 -0
- data/ext/src/inchi_dll.h +34 -0
- data/ext/src/inchi_dll_main.c +23 -0
- data/ext/src/inchi_dll_main.h +31 -0
- data/ext/src/inpdef.h +328 -0
- data/ext/src/lreadmol.h +1246 -0
- data/ext/src/mode.h +706 -0
- data/ext/src/ruby_inchi_main.c +558 -0
- data/ext/src/runichi.c +4179 -0
- data/ext/src/strutil.c +3861 -0
- data/ext/src/strutil.h +182 -0
- data/ext/src/util.c +1130 -0
- data/ext/src/util.h +85 -0
- data/lib/clean_tempfile.rb +220 -0
- data/lib/rino.rb +111 -0
- data/test/test.rb +386 -0
- metadata +130 -0
data/ext/src/ichinorm.c
ADDED
@@ -0,0 +1,741 @@
|
|
1
|
+
/*
|
2
|
+
* International Union of Pure and Applied Chemistry (IUPAC)
|
3
|
+
* International Chemical Identifier (InChI)
|
4
|
+
* Version 1
|
5
|
+
* Software version 1.00
|
6
|
+
* April 13, 2005
|
7
|
+
* Developed at NIST
|
8
|
+
*/
|
9
|
+
|
10
|
+
#include <stdio.h>
|
11
|
+
#include <stdlib.h>
|
12
|
+
#include <string.h>
|
13
|
+
|
14
|
+
#include "mode.h"
|
15
|
+
|
16
|
+
#include "inpdef.h"
|
17
|
+
#include "extr_ct.h"
|
18
|
+
#include "ichitaut.h"
|
19
|
+
#include "ichinorm.h"
|
20
|
+
#include "ichierr.h"
|
21
|
+
#include "util.h"
|
22
|
+
|
23
|
+
#include "ichicomp.h"
|
24
|
+
|
25
|
+
#ifndef INCHI_ALL_CPP
|
26
|
+
#ifdef __cplusplus
|
27
|
+
extern "C" {
|
28
|
+
#endif
|
29
|
+
#endif
|
30
|
+
|
31
|
+
/* defined in ichisort.c, prototype in ichicomn.h */
|
32
|
+
int insertions_sort_AT_RANK( AT_RANK *base, int num );
|
33
|
+
|
34
|
+
#ifndef INCHI_ALL_CPP
|
35
|
+
#ifdef __cplusplus
|
36
|
+
}
|
37
|
+
#endif
|
38
|
+
#endif
|
39
|
+
|
40
|
+
|
41
|
+
/* local prototypes */
|
42
|
+
int cmp_iso_atw_diff_component_no( const void *a1, const void *a2 );
|
43
|
+
|
44
|
+
/********************************************************************************/
|
45
|
+
int cmp_iso_atw_diff_component_no( const void *a1, const void *a2 )
|
46
|
+
{
|
47
|
+
int ret = (int)((const inp_ATOM*)a1)->iso_atw_diff - (int)((const inp_ATOM*)a2)->iso_atw_diff;
|
48
|
+
if ( !ret ) /* make the sort stable */
|
49
|
+
ret = (int)((const inp_ATOM*)a1)->component - (int)((const inp_ATOM*)a2)->component;
|
50
|
+
return ret;
|
51
|
+
}
|
52
|
+
typedef struct tagTreeAtom {
|
53
|
+
AT_NUMB neighbor[MAXVAL]; /* positions (from 0) of the neighbors in the inp_ATOM array */
|
54
|
+
S_CHAR valence; /* number of bonds = number of neighbors */
|
55
|
+
AT_NUMB nRingSystem;
|
56
|
+
AT_NUMB nBlockSystem;
|
57
|
+
S_CHAR bCutVertex;
|
58
|
+
} tre_ATOM;
|
59
|
+
|
60
|
+
#if( FIND_RING_SYSTEMS == 1 ) /* { */
|
61
|
+
/********************************************************************************/
|
62
|
+
int MarkRingSystemsInp( inp_ATOM *at, int num_atoms )
|
63
|
+
{
|
64
|
+
AT_NUMB *nStackAtom = NULL;
|
65
|
+
int nTopStackAtom=-1;
|
66
|
+
AT_NUMB *nRingStack = NULL;
|
67
|
+
int nTopRingStack=-1; /* was AT_NUMB */
|
68
|
+
AT_NUMB *nDfsNumber = NULL;
|
69
|
+
AT_NUMB *nLowNumber = NULL;
|
70
|
+
S_CHAR *cNeighNumb = NULL;
|
71
|
+
AT_NUMB nDfs;
|
72
|
+
#if( FIND_RINS_SYSTEMS_DISTANCES == 1 )
|
73
|
+
AT_NUMB nRs, *nRsConnect = NULL;
|
74
|
+
int k;
|
75
|
+
AT_NUMB *tree = NULL;
|
76
|
+
int nNumConnect, nMaxNumConnect, nLenConnect;
|
77
|
+
#endif
|
78
|
+
AT_NUMB nNumAtInRingSystem;
|
79
|
+
int i, j, u, start, nNumRingSystems, nNumStartChildren;
|
80
|
+
|
81
|
+
/* allocate arrays */
|
82
|
+
nStackAtom = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nStackAtom[0]));
|
83
|
+
nRingStack = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nRingStack[0]));
|
84
|
+
nDfsNumber = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nDfsNumber[0]));
|
85
|
+
nLowNumber = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nLowNumber[0]));
|
86
|
+
cNeighNumb = (S_CHAR *)inchi_malloc(num_atoms*sizeof(cNeighNumb[0]));
|
87
|
+
#if( FIND_RINS_SYSTEMS_DISTANCES == 1 )
|
88
|
+
nRsConnect = (AT_NUMB *)inchi_calloc(3*num_atoms+3,sizeof(nRsConnect[0]));
|
89
|
+
#endif
|
90
|
+
/* check allocation */
|
91
|
+
if ( !nStackAtom || !nRingStack || !nDfsNumber || !nLowNumber || !cNeighNumb
|
92
|
+
#if( FIND_RINS_SYSTEMS_DISTANCES == 1 )
|
93
|
+
|| !nRsConnect
|
94
|
+
#endif
|
95
|
+
) {
|
96
|
+
nNumRingSystems = CT_OUT_OF_RAM; /* program error */ /* <BRKPT> */
|
97
|
+
goto exit_function;
|
98
|
+
}
|
99
|
+
|
100
|
+
/********************************************
|
101
|
+
*
|
102
|
+
* Find Cut-vertices & Blocks
|
103
|
+
*
|
104
|
+
********************************************/
|
105
|
+
|
106
|
+
/* initiation */
|
107
|
+
start = 0;
|
108
|
+
nNumRingSystems = 0;
|
109
|
+
u = start; /* start atom */
|
110
|
+
nDfs = 0;
|
111
|
+
nTopStackAtom =-1;
|
112
|
+
nTopRingStack =-1;
|
113
|
+
memset( nDfsNumber, 0, num_atoms*sizeof(nDfsNumber[0]));
|
114
|
+
memset( cNeighNumb, 0, num_atoms*sizeof(cNeighNumb[0]));
|
115
|
+
/* push the start atom on the stack */
|
116
|
+
nLowNumber[u] = nDfsNumber[u] = ++nDfs;
|
117
|
+
nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
|
118
|
+
nRingStack[++nTopRingStack] = (AT_NUMB)u;
|
119
|
+
|
120
|
+
nNumStartChildren = 0;
|
121
|
+
|
122
|
+
do {
|
123
|
+
/* advance */
|
124
|
+
advance_block:
|
125
|
+
if ( (int)at[i=nStackAtom[nTopStackAtom]].valence > (j = (int)cNeighNumb[i]) ) {
|
126
|
+
cNeighNumb[i] ++;
|
127
|
+
u = (int)at[i].neighbor[j];
|
128
|
+
if ( !nDfsNumber[u] ) {
|
129
|
+
/* tree edge, 1st visit -- advance */
|
130
|
+
nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
|
131
|
+
nRingStack[++nTopRingStack] = (AT_NUMB)u;
|
132
|
+
nLowNumber[u] = nDfsNumber[u] = ++nDfs;
|
133
|
+
nNumStartChildren += (i == start);
|
134
|
+
} else
|
135
|
+
if ( !nTopStackAtom || u != (int)nStackAtom[nTopStackAtom-1] ) { /* may comment out ? */
|
136
|
+
/* back edge: u is not a predecessor of i */
|
137
|
+
if ( nDfsNumber[u] < nDfsNumber[i] ) {
|
138
|
+
/* Back edge, 1st visit: u is an ancestor of i. Compare */
|
139
|
+
if ( nLowNumber[i] > nDfsNumber[u] ) {
|
140
|
+
nLowNumber[i] = nDfsNumber[u];
|
141
|
+
}
|
142
|
+
}
|
143
|
+
} /* may comment out ? */
|
144
|
+
goto advance_block;
|
145
|
+
} else {
|
146
|
+
cNeighNumb[i] = 0;
|
147
|
+
}
|
148
|
+
|
149
|
+
/* back up */
|
150
|
+
if ( i != start ) {
|
151
|
+
u = (int)nStackAtom[nTopStackAtom-1]; /* predecessor of i */
|
152
|
+
if ( nLowNumber[i] >= nDfsNumber[u] ) {
|
153
|
+
/* output the block */
|
154
|
+
nNumRingSystems ++;
|
155
|
+
at[u].nBlockSystem = nNumRingSystems;
|
156
|
+
if ( u != start || nNumStartChildren > 1 ) {
|
157
|
+
at[u].bCutVertex += 1;
|
158
|
+
}
|
159
|
+
while ( nTopRingStack >= 0 ) {
|
160
|
+
j = nRingStack[nTopRingStack--];
|
161
|
+
at[j].nBlockSystem = nNumRingSystems; /* mark the atom */
|
162
|
+
if ( i == j ) {
|
163
|
+
break;
|
164
|
+
}
|
165
|
+
}
|
166
|
+
} else
|
167
|
+
if ( nLowNumber[u] > nLowNumber[i] ) {
|
168
|
+
/* inherit */
|
169
|
+
nLowNumber[u] = nLowNumber[i];
|
170
|
+
}
|
171
|
+
}
|
172
|
+
} while ( --nTopStackAtom >= 0 );
|
173
|
+
|
174
|
+
|
175
|
+
/********************************************
|
176
|
+
*
|
177
|
+
* Find Ring Systems
|
178
|
+
* Including chain atoms X: A-X-B, where the bonds (of any kind) are bridges.
|
179
|
+
*
|
180
|
+
********************************************/
|
181
|
+
|
182
|
+
/* initiation */
|
183
|
+
start = 0;
|
184
|
+
nNumRingSystems = 0;
|
185
|
+
u = start; /* start atom */
|
186
|
+
nDfs = 0;
|
187
|
+
nTopStackAtom =-1;
|
188
|
+
nTopRingStack =-1;
|
189
|
+
memset( nDfsNumber, 0, num_atoms*sizeof(nDfsNumber[0]));
|
190
|
+
memset( cNeighNumb, 0, num_atoms*sizeof(cNeighNumb[0]));
|
191
|
+
/* push the start atom on the stack */
|
192
|
+
nLowNumber[u] = nDfsNumber[u] = ++nDfs;
|
193
|
+
nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
|
194
|
+
nRingStack[++nTopRingStack] = (AT_NUMB)u;
|
195
|
+
#if( FIND_RINS_SYSTEMS_DISTANCES == 1 )
|
196
|
+
nNumConnect = nLenConnect = nMaxNumConnect = 0;
|
197
|
+
#endif
|
198
|
+
|
199
|
+
do {
|
200
|
+
/* advance */
|
201
|
+
advance_ring:
|
202
|
+
if ( (int)at[i=nStackAtom[nTopStackAtom]].valence > (j = (int)cNeighNumb[i]) ) {
|
203
|
+
cNeighNumb[i] ++;
|
204
|
+
u = (int)at[i].neighbor[j];
|
205
|
+
if ( !nDfsNumber[u] ) {
|
206
|
+
/* tree edge, 1st visit -- advance */
|
207
|
+
nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
|
208
|
+
nRingStack[++nTopRingStack] = (AT_NUMB)u;
|
209
|
+
nLowNumber[u] = nDfsNumber[u] = ++nDfs;
|
210
|
+
} else
|
211
|
+
if ( !nTopStackAtom || u != (int)nStackAtom[nTopStackAtom-1] ) {
|
212
|
+
/* back edge: u is not a predecessor of i */
|
213
|
+
if ( nDfsNumber[u] < nDfsNumber[i] ) {
|
214
|
+
/* Back edge, 1st visit: u is ancestor of i. Compare */
|
215
|
+
if ( nLowNumber[i] > nDfsNumber[u] ) {
|
216
|
+
nLowNumber[i] = nDfsNumber[u];
|
217
|
+
}
|
218
|
+
}
|
219
|
+
}
|
220
|
+
goto advance_ring;
|
221
|
+
} else {
|
222
|
+
cNeighNumb[i] = 0;
|
223
|
+
}
|
224
|
+
|
225
|
+
/* back up */
|
226
|
+
if ( nDfsNumber[i] == nLowNumber[i] ) {
|
227
|
+
/* found a ring system */
|
228
|
+
nNumRingSystems ++;
|
229
|
+
/* unwind nRingStack[] down to i */
|
230
|
+
#if( FIND_RINS_SYSTEMS_DISTANCES == 1 )
|
231
|
+
nNumConnect = 2;
|
232
|
+
/* data structure: for each ring system nRsConnect[] contains:
|
233
|
+
* 1) nNumConnect+1 = (number of already discovered neighboring "ring systems" + 1)+1
|
234
|
+
* 2) nNumAtInRingSystem
|
235
|
+
* 3) (nNumConnect-1) numbers (IDs) of neighboring ring systems.
|
236
|
+
* BFS guarantees that each neighboring ring system is encountered only one time
|
237
|
+
* Number of all neighboring ring systems = (nNumConnect-1)+1 = nNumConnect
|
238
|
+
* (One additional ring system is where the BFS retracts from the vertex #i,
|
239
|
+
* except when i=DFS root node. In the latter case there is/are only (nNumConnect-1)
|
240
|
+
* neighboring ring system(s).
|
241
|
+
*/
|
242
|
+
#endif
|
243
|
+
/* count atoms in a ring system */
|
244
|
+
for ( nNumAtInRingSystem = 0, j = nTopRingStack; 0 <= j; j -- ) {
|
245
|
+
nNumAtInRingSystem ++;
|
246
|
+
if ( i == (int)nRingStack[j] ) {
|
247
|
+
break;
|
248
|
+
}
|
249
|
+
}
|
250
|
+
while ( nTopRingStack >= 0 ) {
|
251
|
+
j = (int)nRingStack[nTopRingStack--];
|
252
|
+
at[j].nRingSystem = (AT_NUMB)nNumRingSystems; /* ring system id */
|
253
|
+
at[j].nNumAtInRingSystem = nNumAtInRingSystem;
|
254
|
+
#if( FIND_RINS_SYSTEMS_DISTANCES == 1 )
|
255
|
+
for ( k = 0; k < at[j].valence; k ++ ) {
|
256
|
+
if ( (nRs = at[at[j].neighbor[k]].nRingSystem) && (int)nRs != nNumRingSystems ) {
|
257
|
+
nRsConnect[nLenConnect + (nNumConnect++)] = nRs; /* adjacent ring system id */
|
258
|
+
}
|
259
|
+
}
|
260
|
+
#endif
|
261
|
+
if ( i == j ) {
|
262
|
+
/* reached atom on the top of nStackAtom[] stack */
|
263
|
+
break;
|
264
|
+
}
|
265
|
+
}
|
266
|
+
#if( FIND_RINS_SYSTEMS_DISTANCES == 1 )
|
267
|
+
nRsConnect[nLenConnect] = nNumConnect;
|
268
|
+
nRsConnect[nLenConnect+1] = nNumAtInRingSystem;
|
269
|
+
nLenConnect += nNumConnect;
|
270
|
+
if ( nMaxNumConnect < nNumConnect ) {
|
271
|
+
/* max number of neighboring ring systems */
|
272
|
+
nMaxNumConnect = nNumConnect;
|
273
|
+
}
|
274
|
+
#endif
|
275
|
+
} else
|
276
|
+
if ( nTopStackAtom > 0 ) {
|
277
|
+
j = (int)nStackAtom[nTopStackAtom-1];
|
278
|
+
/* inherit nLowNumber */
|
279
|
+
if ( nLowNumber[j] > nLowNumber[i] ) {
|
280
|
+
nLowNumber[j] = nLowNumber[i];
|
281
|
+
}
|
282
|
+
}
|
283
|
+
} while ( --nTopStackAtom >= 0 );
|
284
|
+
|
285
|
+
#if( FIND_RINS_SYSTEMS_DISTANCES == 1 ) /* normally disabled */
|
286
|
+
nMaxNumConnect ++;
|
287
|
+
if ( nNumRingSystems > 1 ) {
|
288
|
+
int nCol = nMaxNumConnect+1;
|
289
|
+
int nNumInSyst= nMaxNumConnect;
|
290
|
+
int nMaxNeigh = nMaxNumConnect-1;
|
291
|
+
#define T(a,b) tree[(a)*nCol+b]
|
292
|
+
if ( tree = (AT_NUMB *)inchi_calloc( nCol * (nNumRingSystems+1), sizeof(tree[0])) ) {
|
293
|
+
int len, neigh;
|
294
|
+
/* reuse previous allocations */
|
295
|
+
AT_NUMB *nNumVisitedNeighbors = nStackAtom;
|
296
|
+
AT_NUMB *nDistanceFromTerminal = nRingStack;
|
297
|
+
AT_NUMB *nCurrActiveRingSystem = nDfsNumber;
|
298
|
+
AT_NUMB *nNextActiveRingSystem = nLowNumber;
|
299
|
+
int nNumCurrActiveRingSystems, nNumNextActiveRingSystems, pass;
|
300
|
+
/* build a "condensation graph (actually, a tree)" in which
|
301
|
+
* each vertex corresponds to a ring system T(row, col) = T(ring syst, neighbors)
|
302
|
+
* Number of rows = column length = max. number of ring system neighbors + 2
|
303
|
+
* Number of cols = row length = number of ring systems + 1
|
304
|
+
* Neighboring ring systems are contiguously stored in a row
|
305
|
+
* T(i,0) = number of neighbors, 1 <= i <= nNumRingSystems;
|
306
|
+
* T(i,k) = number of a neighboring ring system, 1 <= k <= T(i,0)
|
307
|
+
* T(i,nCol-1) = number of atoms in the system #i
|
308
|
+
*/
|
309
|
+
for ( i = 1, j = 0; len=nRsConnect[j]; i ++ ) {
|
310
|
+
T(i, nNumInSyst) = nRsConnect[j+1];
|
311
|
+
for ( k = 2; k < len; k ++ ) {
|
312
|
+
neigh = nRsConnect[j+k];
|
313
|
+
if ( T(i,0) < nMaxNeigh && T(neigh,0) < nMaxNeigh ) {
|
314
|
+
T(i,0) ++;
|
315
|
+
T(neigh,0) ++;
|
316
|
+
T(i,T(i,0)) = neigh;
|
317
|
+
T(neigh,T(neigh,0)) = i;
|
318
|
+
} else {
|
319
|
+
nNumRingSystems = CT_OVERFLOW; /* program error */ /* <BRKPT> */
|
320
|
+
goto exit_function;
|
321
|
+
}
|
322
|
+
}
|
323
|
+
j += len;
|
324
|
+
}
|
325
|
+
/* clear memory */
|
326
|
+
memset( nNumVisitedNeighbors, 0, nNumRingSystems*sizeof(nNumVisitedNeighbors[0]) );
|
327
|
+
memset( nDistanceFromTerminal, 0, nNumRingSystems*sizeof(nDistanceFromTerminal[0]) );
|
328
|
+
memset( nCurrActiveRingSystem, 0, nNumRingSystems*sizeof(nCurrActiveRingSystem[0]) );
|
329
|
+
memset( nNextActiveRingSystem, 0, nNumRingSystems*sizeof(nNextActiveRingSystem[0]) );
|
330
|
+
nNumNextActiveRingSystems = 0;
|
331
|
+
for ( i = 0; i < nNumRingSystems; i ++ ) {
|
332
|
+
if ( 1 == T(i+1,0) ) {
|
333
|
+
nNextActiveRingSystem[i] = 1; /* number of traversed neighbors + 1 */
|
334
|
+
nDistanceFromTerminal[i] = 1;
|
335
|
+
nNumNextActiveRingSystems ++;
|
336
|
+
} else {
|
337
|
+
nNextActiveRingSystem[i] = 0;
|
338
|
+
nDistanceFromTerminal[i] = 0;
|
339
|
+
}
|
340
|
+
nNumVisitedNeighbors[i] = 0;
|
341
|
+
}
|
342
|
+
|
343
|
+
/* nCurrActiveRingSystem[i] = a sum of:
|
344
|
+
* 1) +1 if it is or was active
|
345
|
+
* 2) +(number of neighbors from which it was reached)
|
346
|
+
* 3) +1 if it was left and not active anymore
|
347
|
+
*/
|
348
|
+
pass = 0;
|
349
|
+
do {
|
350
|
+
nNumCurrActiveRingSystems = nNumNextActiveRingSystems;
|
351
|
+
nNumNextActiveRingSystems = 0;
|
352
|
+
memcpy( nCurrActiveRingSystem, nNextActiveRingSystem,
|
353
|
+
nNumRingSystems*sizeof(nNextActiveRingSystem[0]));
|
354
|
+
for ( i = 0; i < nNumRingSystems; i ++ ) {
|
355
|
+
if ( T(i+1,0) == nCurrActiveRingSystem[i] ) {
|
356
|
+
/* on the previous pass currently active ring system i+1 bas been reached
|
357
|
+
* from all neighbors except one;
|
358
|
+
* the neighbors from which it was reached have
|
359
|
+
* T(neigh,0)+1 == nCurrActiveRingSystem[i]
|
360
|
+
* this ring system has not been left yet
|
361
|
+
*/
|
362
|
+
for ( k = 1, len=T(i+1,0); k <= len; k ++ ) {
|
363
|
+
neigh = (int)T(i+1,k);
|
364
|
+
if ( T(neigh,0) >= nCurrActiveRingSystem[neigh-1] ) {
|
365
|
+
if ( 0 == pass ) {
|
366
|
+
nDistanceFromTerminal[i] = 1;
|
367
|
+
}
|
368
|
+
break;
|
369
|
+
}
|
370
|
+
}
|
371
|
+
if ( k <= len ) {
|
372
|
+
/* neigh was not reached from at least 2 neighbors
|
373
|
+
* walk along -R- chain (T(neigh,0)==2) up to
|
374
|
+
* 1) a terminal system, not including it or
|
375
|
+
* 2) a branching point.
|
376
|
+
*
|
377
|
+
* pass = 0: started from terminal systems:
|
378
|
+
* reach the branching point.
|
379
|
+
* If chain system next to a terminal system has already been reached
|
380
|
+
* then walk along it according to Note below
|
381
|
+
*
|
382
|
+
* pass > 0: started from branching points
|
383
|
+
* 2a) If the branching point has not been reached from 2 or more neighbors,
|
384
|
+
* then include it
|
385
|
+
* 2b) If the branching point has not been reached from 1 neighbor only,
|
386
|
+
* then do not include it: it will be a starting point later
|
387
|
+
* Note: if a chain atom already has nDistanceFromTerminal[i] > 0, then
|
388
|
+
* the last atom should be the one such that
|
389
|
+
* its nDistanceFromTerminal[]+1>= nDistanceFromTerminal[] of the
|
390
|
+
* next in the chain
|
391
|
+
*/
|
392
|
+
int bOk = 0;
|
393
|
+
k = i+1; /* starting point */
|
394
|
+
if ( 0 == pass && T(k,nNumInSyst) > 1 ) {
|
395
|
+
nNumNextActiveRingSystems ++; /* request next pass */
|
396
|
+
continue; /* stop a the terminal ring system */
|
397
|
+
}
|
398
|
+
while( 2 == T(neigh,0) ) {
|
399
|
+
/* walk along a chain */
|
400
|
+
if ( !nNextActiveRingSystem[neigh-1] ) {
|
401
|
+
nNextActiveRingSystem[neigh-1] = 1; /* make neighbor active */
|
402
|
+
} else
|
403
|
+
if ( nDistanceFromTerminal[k-1]+1 <= nDistanceFromTerminal[neigh-1] ) {
|
404
|
+
/* walking along the chain; already have had a walk */
|
405
|
+
/* in the opposite direction at this pass */
|
406
|
+
} else {
|
407
|
+
/* k is the last; neigh (it is a bridge -X-) has not been reached */
|
408
|
+
bOk = 1;
|
409
|
+
break;
|
410
|
+
}
|
411
|
+
nNextActiveRingSystem[k-1] ++; /* leave system k */
|
412
|
+
if ( nNextActiveRingSystem[neigh-1] < T(neigh,0) ) {
|
413
|
+
nNextActiveRingSystem[neigh-1] ++; /* add one connection to neigh */
|
414
|
+
}
|
415
|
+
nDistanceFromTerminal[neigh-1] = nDistanceFromTerminal[k-1]+1;
|
416
|
+
j = (T(neigh,1)==k)? 2:1;
|
417
|
+
k = neigh;
|
418
|
+
neigh = T(k,j); /* next in the chain */
|
419
|
+
nNumNextActiveRingSystems ++;
|
420
|
+
if ( T(k,nNumInSyst) > 1 ) {
|
421
|
+
bOk = 1;
|
422
|
+
break; /* stop on a ring system */
|
423
|
+
}
|
424
|
+
}
|
425
|
+
/* neigh is a terminal or a bridge or a branching point */
|
426
|
+
if ( 2 > T(neigh,0) ) {
|
427
|
+
/* neighbor is a terminal atom */
|
428
|
+
if ( 1 < pass ) {
|
429
|
+
nNumRingSystems = CT_UNKNOWN_ERR; /* error (debug only) */ /* <BRKPT> */
|
430
|
+
goto exit_function;
|
431
|
+
}
|
432
|
+
continue;
|
433
|
+
}
|
434
|
+
if ( 2 == T(neigh,0) ) {
|
435
|
+
/* neighbor is a bridge */
|
436
|
+
continue;
|
437
|
+
}
|
438
|
+
/* neighbor is a branching point */
|
439
|
+
if ( T(neigh,0) > nCurrActiveRingSystem[neigh-1] ) {
|
440
|
+
/* move to the neigh (make neigh active): on previous pass it */
|
441
|
+
/* has not been reached from 2 or more neighbors */
|
442
|
+
if ( !nNextActiveRingSystem[neigh-1] ) {
|
443
|
+
nNextActiveRingSystem[neigh-1] = 1;
|
444
|
+
}
|
445
|
+
if ( nDistanceFromTerminal[neigh-1] < nDistanceFromTerminal[k-1]+1 ) {
|
446
|
+
nDistanceFromTerminal[neigh-1] = nDistanceFromTerminal[k-1]+1;
|
447
|
+
}
|
448
|
+
nNextActiveRingSystem[k-1] ++; /* leave system k */
|
449
|
+
if ( nNextActiveRingSystem[neigh-1] < T(neigh,0) ) {
|
450
|
+
nNextActiveRingSystem[neigh-1] ++; /* add one connection to neigh */
|
451
|
+
}
|
452
|
+
nNumNextActiveRingSystems ++;
|
453
|
+
}
|
454
|
+
}
|
455
|
+
}
|
456
|
+
}
|
457
|
+
pass ++;
|
458
|
+
} while ( nNumNextActiveRingSystems );
|
459
|
+
|
460
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
461
|
+
at[i].nDistanceFromTerminal = nDistanceFromTerminal[(int)at[i].nRingSystem-1];
|
462
|
+
}
|
463
|
+
|
464
|
+
inchi_free( tree );
|
465
|
+
tree = NULL;
|
466
|
+
#undef T
|
467
|
+
} else {
|
468
|
+
nNumRingSystems = CT_OUT_OF_RAM; /* error */ /* <BRKPT> */
|
469
|
+
goto exit_function;
|
470
|
+
}
|
471
|
+
}
|
472
|
+
#endif
|
473
|
+
|
474
|
+
|
475
|
+
exit_function:
|
476
|
+
if ( nStackAtom )
|
477
|
+
inchi_free( nStackAtom );
|
478
|
+
if ( nRingStack )
|
479
|
+
inchi_free( nRingStack );
|
480
|
+
if ( nDfsNumber )
|
481
|
+
inchi_free( nDfsNumber );
|
482
|
+
if ( nLowNumber )
|
483
|
+
inchi_free( nLowNumber );
|
484
|
+
if ( cNeighNumb )
|
485
|
+
inchi_free( cNeighNumb );
|
486
|
+
#if( FIND_RINS_SYSTEMS_DISTANCES == 1 )
|
487
|
+
if ( nRsConnect )
|
488
|
+
inchi_free( nRsConnect );
|
489
|
+
if ( tree )
|
490
|
+
inchi_free( tree );
|
491
|
+
#endif
|
492
|
+
return nNumRingSystems;
|
493
|
+
}
|
494
|
+
|
495
|
+
|
496
|
+
#endif /* } FIND_RING_SYSTEMS */
|
497
|
+
|
498
|
+
/********************************************************************************/
|
499
|
+
/* Return value: new number of atoms > 0 or -1=out of RAM */
|
500
|
+
int remove_terminal_HDT( int num_atoms, inp_ATOM *at )
|
501
|
+
{
|
502
|
+
AT_NUMB *new_ord;
|
503
|
+
inp_ATOM *new_at;
|
504
|
+
char *p;
|
505
|
+
const static char szHDT[]="HDT";
|
506
|
+
const static int kMax = sizeof(szHDT); /* = 4 */
|
507
|
+
int ret = -1;
|
508
|
+
int num_hydrogens=0, num_H = 0; /* number of terminal H, D, T */
|
509
|
+
int i, j, k, n, m;
|
510
|
+
int val;
|
511
|
+
AT_RANK new_HydrogenAt_order[NUM_H_ISOTOPES+1];
|
512
|
+
AT_RANK new_OtherNeigh_order[MAXVAL];
|
513
|
+
S_CHAR old_trans[MAX_NUM_STEREO_BONDS];
|
514
|
+
|
515
|
+
int num_OtherNeigh, num_HydrogenAt;
|
516
|
+
|
517
|
+
new_ord=(AT_NUMB *)inchi_calloc(num_atoms, sizeof(new_ord[0])); /* changed malloc to calloc 9-11-2003 */
|
518
|
+
new_at =(inp_ATOM *)inchi_malloc(sizeof(new_at[0]) *num_atoms);
|
519
|
+
if (!new_ord || !new_at)
|
520
|
+
goto exit_function;
|
521
|
+
/* move H. D, T to the end of the list of atoms */
|
522
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
523
|
+
at[i].component = i; /* temporarily save original numbering */
|
524
|
+
/* get k = temp. hydrogen isotope/non-hydrogen atom type: */
|
525
|
+
/* k=0:H, k=2:D, k=3:T, k=4=kMax: not a hydrogen */
|
526
|
+
k = at[i].elname[1]? kMax : (p=strchr(szHDT, at[i].elname[0]))? p-szHDT : kMax;
|
527
|
+
/* set hydrogen isotope atw differences */
|
528
|
+
/* Notes: k-value of isotopic H is incremented to correct iso_atw_diff value later. */
|
529
|
+
/* 1H isotope cannot be detected here. */
|
530
|
+
if ( k == ATW_H || k == ATW_H+1 ) { /* D or T, k = 1 or 2 */
|
531
|
+
at[i].elname[0] = 'H'; /* hydrogen isotope */
|
532
|
+
at[i].iso_atw_diff = ++k; /* increment k to make k = iso_atw_diff ( 2 for D, 3 for T ) */
|
533
|
+
}
|
534
|
+
num_H += (k != kMax && at[i].valence == 1 && at[i].chem_bonds_valence == 1 && !NUMH(at,i) );
|
535
|
+
}
|
536
|
+
|
537
|
+
/* special case: HD, HT, DT, HH: the only non-isotopic H or
|
538
|
+
* the lightest isotopic H out of two is removed
|
539
|
+
* to become implicit (make the heavier H the "central atom").
|
540
|
+
* Note: This must be consistent with mol_to_atom()
|
541
|
+
* treatment of isotopic Hn aliases.
|
542
|
+
*/
|
543
|
+
if ( 2 == num_H && 2 == num_atoms && !NUMH(at,0) && !NUMH(at,1) ) {
|
544
|
+
|
545
|
+
if ( at[0].iso_atw_diff >= at[1].iso_atw_diff ) {
|
546
|
+
new_ord[0] = 0;
|
547
|
+
new_ord[1] = 1;
|
548
|
+
} else {
|
549
|
+
new_ord[0] = 1;
|
550
|
+
new_ord[1] = 0;
|
551
|
+
}
|
552
|
+
if ( at[new_ord[1]].charge ) {
|
553
|
+
at[new_ord[0]].charge += at[new_ord[1]].charge;
|
554
|
+
at[new_ord[1]].charge = 0;
|
555
|
+
}
|
556
|
+
new_at[new_ord[0]] = at[0];
|
557
|
+
new_at[new_ord[1]] = at[1];
|
558
|
+
num_hydrogens = 1;
|
559
|
+
|
560
|
+
} else {
|
561
|
+
/* general case except H-H */
|
562
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
563
|
+
k = (at[i].elname[1] || NUMH(at,i))? kMax : (at[i].elname[0]=='H')? at[i].iso_atw_diff : kMax;
|
564
|
+
if ( k < kMax && at[i].valence == 1 && at[i].chem_bonds_valence == 1 &&
|
565
|
+
/* the order of comparison is important */
|
566
|
+
((n=(int)at[i].neighbor[0]) > i /* at[n] has not been encountered yet*/ ||
|
567
|
+
(int)new_ord[n] < num_atoms - num_hydrogens) /* at[n] might have been encountered; it has not been moved */ ) {
|
568
|
+
/* found an explicit terminal hydrogen */
|
569
|
+
num_hydrogens ++;
|
570
|
+
if ( k==0 && ATW_H <= at[i].iso_atw_diff && at[i].iso_atw_diff < ATW_H+NUM_H_ISOTOPES ) {
|
571
|
+
k = at[i].iso_atw_diff; /* H isotope has already been marked above or elsewhere */
|
572
|
+
}
|
573
|
+
if ( at[i].charge ) { /* transfer charge from the hydrogen */
|
574
|
+
at[n].charge += at[i].charge;
|
575
|
+
at[i].charge = 0;
|
576
|
+
}
|
577
|
+
new_ord[i] = num_atoms - num_hydrogens; /* move hydrogens to the end of the list */
|
578
|
+
} else {
|
579
|
+
new_ord[i] = i - num_hydrogens; /* adjust non-hydrogens positions */
|
580
|
+
}
|
581
|
+
new_at[new_ord[i]] = at[i]; /* copy atoms to their new positions */
|
582
|
+
}
|
583
|
+
}
|
584
|
+
|
585
|
+
if ( num_hydrogens ) {
|
586
|
+
int num_others = num_atoms-num_hydrogens; /* atoms which are not terminal H, D, T */
|
587
|
+
if ( num_hydrogens > 1 ) {
|
588
|
+
/* sort hydrogen isotopes in ascending order, */
|
589
|
+
/* orig, numbers being the secondary sorting key */
|
590
|
+
qsort( new_at+num_others, num_hydrogens, sizeof(new_at[0]), cmp_iso_atw_diff_component_no );
|
591
|
+
}
|
592
|
+
/* save new numbering of hydrogen atoms using temporarily saved orig numbering */
|
593
|
+
for ( i = num_others; i < num_atoms; i ++ ) {
|
594
|
+
new_ord[(int)new_at[i].component] = i;
|
595
|
+
}
|
596
|
+
|
597
|
+
/* renumber neighbors according to new_ord[] and detach terminal hydrogens */
|
598
|
+
for ( i = 0; i < num_others; i++ ) {
|
599
|
+
memset( new_HydrogenAt_order, 0, sizeof(new_HydrogenAt_order) );
|
600
|
+
memset( new_OtherNeigh_order, 0, sizeof(new_OtherNeigh_order) );
|
601
|
+
num_OtherNeigh = 0;
|
602
|
+
num_HydrogenAt = 0;
|
603
|
+
num_H = 0;
|
604
|
+
|
605
|
+
for ( m = 0; m < MAX_NUM_STEREO_BONDS && new_at[i].sb_parity[m]; m ++ ) {
|
606
|
+
old_trans[m] = 2 - (new_at[i].sn_ord[m] + new_at[i].sb_ord[m] + (new_at[i].sn_ord[m] > new_at[i].sb_ord[m]))%2;
|
607
|
+
}
|
608
|
+
|
609
|
+
for ( k = j = val = 0; k < new_at[i].valence; k++ ) {
|
610
|
+
if ( num_others <= ( n = new_ord[new_at[i].neighbor[k]] ) ) {
|
611
|
+
/* discovered neighbor = disconnected explicit hydrogen
|
612
|
+
* i = new atom new_at[i] ordering number
|
613
|
+
* n = new number of the explicit H
|
614
|
+
* k = ordering number of the explicit H in new_at[i] adjacency list
|
615
|
+
*/
|
616
|
+
if ( 0 < new_at[n].iso_atw_diff && new_at[n].iso_atw_diff < ATW_H+NUM_H_ISOTOPES ) {
|
617
|
+
/* make explicit isotopic H implicit */
|
618
|
+
new_at[i].num_iso_H[new_at[n].iso_atw_diff-1] ++; /* isotopic H */
|
619
|
+
num_HydrogenAt += !new_HydrogenAt_order[new_at[n].iso_atw_diff];
|
620
|
+
new_HydrogenAt_order[new_at[n].iso_atw_diff] = k+1;
|
621
|
+
} else {
|
622
|
+
/* make explicit non-isotopic H implicit */
|
623
|
+
new_at[i].num_H ++; /* non-isotopic H */
|
624
|
+
num_HydrogenAt += !num_H;
|
625
|
+
num_H ++;
|
626
|
+
new_HydrogenAt_order[0] = k+1;
|
627
|
+
}
|
628
|
+
/* decrement chem. bonds valence because one bond is removed */
|
629
|
+
new_at[i].chem_bonds_valence = inchi_max( 0, new_at[i].chem_bonds_valence-1 );
|
630
|
+
new_at[n].neighbor[0] = i; /* update removed hydrogen neighbor number */
|
631
|
+
if ( new_at[i].sb_parity[0] ) {
|
632
|
+
/* if the removed H is an SB neighbor then mark it as removed */
|
633
|
+
for ( m = 0; m < MAX_NUM_STEREO_BONDS && new_at[i].sb_parity[m]; m ++ ) {
|
634
|
+
if ( k == (int)new_at[i].sn_ord[m] ) {
|
635
|
+
new_at[i].sn_ord[m] = -(new_at[n].iso_atw_diff+1);
|
636
|
+
/* means the SB neighbor has been removed; (-4)=H, (-3)=1H, (-2)=D, (-1)=T */
|
637
|
+
}
|
638
|
+
}
|
639
|
+
}
|
640
|
+
} else {
|
641
|
+
/* discovered a regular (not an explicit H) neighbor */
|
642
|
+
if ( new_at[i].sb_parity[0] ) {
|
643
|
+
if ( num_OtherNeigh < MAX_NUM_STEREO_BONDS ) {
|
644
|
+
new_OtherNeigh_order[num_OtherNeigh] = k+1;
|
645
|
+
}
|
646
|
+
num_OtherNeigh ++; /* increment outside of if() to detect overflow */
|
647
|
+
if ( val != k ) {
|
648
|
+
/* store new stereobond and sb-neighbor ordering numbers */
|
649
|
+
for ( m = 0; m < MAX_NUM_STEREO_BONDS && new_at[i].sb_parity[m]; m ++ ) {
|
650
|
+
if ( k == (int)new_at[i].sb_ord[m] )
|
651
|
+
new_at[i].sb_ord[m] = val;
|
652
|
+
else
|
653
|
+
if ( k == (int)new_at[i].sn_ord[m] )
|
654
|
+
new_at[i].sn_ord[m] = val;
|
655
|
+
}
|
656
|
+
}
|
657
|
+
}
|
658
|
+
new_at[i].neighbor[val] = new_ord[new_at[i].neighbor[k]];
|
659
|
+
new_at[i].bond_type[val] = new_at[i].bond_type[k];
|
660
|
+
new_at[i].bond_stereo[val] = new_at[i].bond_stereo[k];
|
661
|
+
val ++;
|
662
|
+
}
|
663
|
+
}
|
664
|
+
if ( new_at[i].valence > val && new_at[i].sb_parity[0] ) {
|
665
|
+
if ( num_HydrogenAt == new_at[i].valence - val && num_HydrogenAt + num_OtherNeigh <= MAXVAL ) {
|
666
|
+
/* recalculate parity so that it would describe neighbor sequence H,1H,D,T,neigh[0],neigh[1]... */
|
667
|
+
memmove( new_OtherNeigh_order + num_HydrogenAt, new_OtherNeigh_order, num_OtherNeigh*sizeof(new_OtherNeigh_order[0]));
|
668
|
+
for ( k = 0, j = 1; k <= NUM_H_ISOTOPES; k ++ ) {
|
669
|
+
if ( new_HydrogenAt_order[k] ) {
|
670
|
+
new_OtherNeigh_order[num_HydrogenAt - j] = new_HydrogenAt_order[k];
|
671
|
+
for ( m = 0; m < MAX_NUM_STEREO_BONDS && new_at[i].sb_parity[m]; m ++ ) {
|
672
|
+
if ( (int)new_at[i].sn_ord[m] == -(k+1) ) {
|
673
|
+
new_at[i].sn_ord[m] = -j;
|
674
|
+
/* negative means explicit H isotope ord are
|
675
|
+
(contiguously) in front of the adjacency list */
|
676
|
+
}
|
677
|
+
}
|
678
|
+
j ++;
|
679
|
+
}
|
680
|
+
}
|
681
|
+
/* at this point new_OtherNeigh_order[] contains
|
682
|
+
incremented old ordering numbers in new order */
|
683
|
+
k = insertions_sort_AT_RANK( new_OtherNeigh_order, num_HydrogenAt + num_OtherNeigh );
|
684
|
+
k = k%2; /* seems to be of no use */
|
685
|
+
/*if ( k ) {*/
|
686
|
+
/*
|
687
|
+
for ( m = 0; m < MAX_NUM_STEREO_BONDS && new_at[i].sb_parity[m]; m ++ ) {
|
688
|
+
if ( PARITY_WELL_DEF(new_at[i].sb_parity[m]) ) {
|
689
|
+
if ( old_trans[m] != 2 - (4 + new_at[i].sn_ord[m] + new_at[i].sb_ord[m] + (new_at[i].sn_ord[m] > new_at[i].sb_ord[m]))%2 ) {
|
690
|
+
new_at[i].sb_parity[m] = 3 - new_at[i].sb_parity[m];
|
691
|
+
}
|
692
|
+
}
|
693
|
+
}
|
694
|
+
*/
|
695
|
+
/*}*/
|
696
|
+
}
|
697
|
+
#ifdef _DEBUG
|
698
|
+
else {
|
699
|
+
/* error */
|
700
|
+
int stop = 1;
|
701
|
+
}
|
702
|
+
#endif
|
703
|
+
}
|
704
|
+
new_at[i].valence = val;
|
705
|
+
}
|
706
|
+
memcpy( at, new_at, sizeof(at[0])*num_atoms );
|
707
|
+
ret = num_others;
|
708
|
+
} else {
|
709
|
+
ret = num_atoms;
|
710
|
+
}
|
711
|
+
exit_function:
|
712
|
+
if ( new_ord )
|
713
|
+
inchi_free ( new_ord );
|
714
|
+
if ( new_at )
|
715
|
+
inchi_free ( new_at );
|
716
|
+
return ret;
|
717
|
+
}
|
718
|
+
/************************************************************************/
|
719
|
+
int add_DT_to_num_H( int num_atoms, inp_ATOM *at )
|
720
|
+
/* assume num_1H, num_D and num_T are not included in num_H */
|
721
|
+
{
|
722
|
+
int i, j;
|
723
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
724
|
+
for ( j = 0; j < NUM_H_ISOTOPES; j ++ )
|
725
|
+
at[i].num_H += at[i].num_iso_H[j];
|
726
|
+
}
|
727
|
+
return 0;
|
728
|
+
}
|
729
|
+
/***************************************************************/
|
730
|
+
/* not used ---
|
731
|
+
int FixAromaticOxygenAndSulfur( inp_ATOM *atom )
|
732
|
+
{
|
733
|
+
if ( !atom->elname[1] && (atom->elname[0]=='O' || atom->elname[0]=='S') &&
|
734
|
+
atom->valence==2 && !atom->charge && !atom->radical &&
|
735
|
+
atom->bond_type[0] + atom->bond_type[1] == 3 ) {
|
736
|
+
atom->charge = 1;
|
737
|
+
return 1; // fixed
|
738
|
+
}
|
739
|
+
return 0;
|
740
|
+
}
|
741
|
+
*/
|