rino 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/README +44 -0
  2. data/Rakefile +123 -0
  3. data/ext/extconf.rb +26 -0
  4. data/ext/ruby_inchi_main.so +0 -0
  5. data/ext/src/aux2atom.h +2786 -0
  6. data/ext/src/comdef.h +148 -0
  7. data/ext/src/e_0dstereo.c +3014 -0
  8. data/ext/src/e_0dstereo.h +31 -0
  9. data/ext/src/e_comdef.h +57 -0
  10. data/ext/src/e_ctl_data.h +147 -0
  11. data/ext/src/e_ichi_io.c +498 -0
  12. data/ext/src/e_ichi_io.h +40 -0
  13. data/ext/src/e_ichi_parms.c +37 -0
  14. data/ext/src/e_ichi_parms.h +41 -0
  15. data/ext/src/e_ichicomp.h +50 -0
  16. data/ext/src/e_ichierr.h +40 -0
  17. data/ext/src/e_ichimain.c +593 -0
  18. data/ext/src/e_ichisize.h +43 -0
  19. data/ext/src/e_inchi_atom.c +75 -0
  20. data/ext/src/e_inchi_atom.h +33 -0
  21. data/ext/src/e_inpdef.h +41 -0
  22. data/ext/src/e_mode.h +706 -0
  23. data/ext/src/e_mol2atom.c +649 -0
  24. data/ext/src/e_readinch.c +58 -0
  25. data/ext/src/e_readmol.c +54 -0
  26. data/ext/src/e_readmol.h +180 -0
  27. data/ext/src/e_readstru.c +251 -0
  28. data/ext/src/e_readstru.h +33 -0
  29. data/ext/src/e_util.c +284 -0
  30. data/ext/src/e_util.h +61 -0
  31. data/ext/src/extr_ct.h +251 -0
  32. data/ext/src/ichi.h +206 -0
  33. data/ext/src/ichi_bns.c +7999 -0
  34. data/ext/src/ichi_bns.h +231 -0
  35. data/ext/src/ichican2.c +5000 -0
  36. data/ext/src/ichicano.c +2195 -0
  37. data/ext/src/ichicano.h +49 -0
  38. data/ext/src/ichicans.c +1625 -0
  39. data/ext/src/ichicant.h +379 -0
  40. data/ext/src/ichicomn.h +260 -0
  41. data/ext/src/ichicomp.h +50 -0
  42. data/ext/src/ichidrp.h +119 -0
  43. data/ext/src/ichierr.h +124 -0
  44. data/ext/src/ichiisot.c +101 -0
  45. data/ext/src/ichilnct.c +286 -0
  46. data/ext/src/ichimain.h +132 -0
  47. data/ext/src/ichimak2.c +1189 -0
  48. data/ext/src/ichimake.c +3812 -0
  49. data/ext/src/ichimake.h +205 -0
  50. data/ext/src/ichimap1.c +851 -0
  51. data/ext/src/ichimap2.c +2856 -0
  52. data/ext/src/ichimap4.c +1609 -0
  53. data/ext/src/ichinorm.c +741 -0
  54. data/ext/src/ichinorm.h +67 -0
  55. data/ext/src/ichiparm.c +45 -0
  56. data/ext/src/ichiparm.h +1441 -0
  57. data/ext/src/ichiprt1.c +3612 -0
  58. data/ext/src/ichiprt2.c +1511 -0
  59. data/ext/src/ichiprt3.c +3011 -0
  60. data/ext/src/ichiqueu.c +1003 -0
  61. data/ext/src/ichiring.c +326 -0
  62. data/ext/src/ichiring.h +49 -0
  63. data/ext/src/ichisize.h +35 -0
  64. data/ext/src/ichisort.c +539 -0
  65. data/ext/src/ichister.c +3538 -0
  66. data/ext/src/ichister.h +35 -0
  67. data/ext/src/ichitaut.c +3843 -0
  68. data/ext/src/ichitaut.h +387 -0
  69. data/ext/src/ichitime.h +74 -0
  70. data/ext/src/inchi_api.h +670 -0
  71. data/ext/src/inchi_dll.c +1480 -0
  72. data/ext/src/inchi_dll.h +34 -0
  73. data/ext/src/inchi_dll_main.c +23 -0
  74. data/ext/src/inchi_dll_main.h +31 -0
  75. data/ext/src/inpdef.h +328 -0
  76. data/ext/src/lreadmol.h +1246 -0
  77. data/ext/src/mode.h +706 -0
  78. data/ext/src/ruby_inchi_main.c +558 -0
  79. data/ext/src/runichi.c +4179 -0
  80. data/ext/src/strutil.c +3861 -0
  81. data/ext/src/strutil.h +182 -0
  82. data/ext/src/util.c +1130 -0
  83. data/ext/src/util.h +85 -0
  84. data/lib/clean_tempfile.rb +220 -0
  85. data/lib/rino.rb +111 -0
  86. data/test/test.rb +386 -0
  87. metadata +130 -0
data/ext/src/strutil.c ADDED
@@ -0,0 +1,3861 @@
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
+ #include <ctype.h>
14
+ #include <math.h>
15
+
16
+ #include "mode.h"
17
+
18
+ #include "inpdef.h"
19
+ #include "util.h"
20
+ #include "ichi.h"
21
+ #include "strutil.h"
22
+ #include "ichierr.h"
23
+
24
+ #include "ichicomp.h"
25
+ #include "extr_ct.h"
26
+ #include "ichister.h"
27
+
28
+ /* local prototypes */
29
+ int cmp_components( const void *a1, const void *a2 );
30
+ int mark_one_struct_component( inp_ATOM* at, int j, AT_NUMB *mark, AT_NUMB num_disconnected_components );
31
+ int Free_INChI_Stereo( INChI_Stereo *pINChI_Stereo );
32
+ INChI_Stereo *Alloc_INChI_Stereo(int num_at, int num_bonds);
33
+ int RemoveInpAtBond( inp_ATOM *at, int iat, int k );
34
+ int DisconnectInpAtBond( inp_ATOM *at, AT_NUMB *nOldCompNumber, int iat, int neigh_ord );
35
+ int move_explicit_Hcation(inp_ATOM *at, int num_at, int iat, int iat_H, int bInAllComponents);
36
+ int DisconnectOneLigand( inp_ATOM *at, AT_NUMB *nOldCompNumber, S_CHAR *bMetal, char *elnumber_Heteroat,
37
+ int num_halogens, int num_atoms, int iMetal, int jLigand, INCHI_MODE *bTautFlagsDone );
38
+ int bIsAmmoniumSalt( inp_ATOM *at, int i, int *piO, int *pk, S_CHAR *num_explicit_H );
39
+ int DisconnectAmmoniumSalt ( inp_ATOM *at, int i, int iO, int k, S_CHAR *num_explicit_H );
40
+ int bIsMetalSalt( inp_ATOM *at, int i );
41
+ int DisconnectMetalSalt( inp_ATOM *at, int i );
42
+ int bIsMetalToDisconnect(inp_ATOM *at, int i, int bCheckMetalValence);
43
+
44
+ int get_iat_number( int el_number, const int el_num[], int el_num_len );
45
+ int tot_unsat( int unsat[] );
46
+ int max_unsat( int unsat[] );
47
+
48
+ double dist3D( inp_ATOM *at1, inp_ATOM *at2 );
49
+ double dist2D( inp_ATOM *at1, inp_ATOM *at2 );
50
+ double dist_from_segm( double x, double y, double x1, double y1, double x2, double y2);
51
+ int segments_intersect( double x11, double y11, double x12, double y12, /* segment #1 */
52
+ double x21, double y21, double x22, double y22 );
53
+ double GetMinDistDistribution( inp_ATOM *at, int num_at, int iat, int iat_H,
54
+ int bInAllComponents, double min_dist[], int num_segm );
55
+
56
+ int nFindOneOM(inp_ATOM *at, int at_no, int ord_OM[], int num_OM);
57
+ int the_only_doublet_neigh(inp_ATOM *at, int i1, int *ineigh1, int *ineigh2);
58
+
59
+
60
+ #ifndef NUMH
61
+ #define NUM_ISO_H(AT,N) (AT[N].num_iso_H[0]+AT[N].num_iso_H[1]+AT[N].num_iso_H[2])
62
+ #define NUMH(AT,N) (AT[N].num_H+NUM_ISO_H(AT,N))
63
+ #endif
64
+
65
+ /************************************************************************/
66
+ int the_only_doublet_neigh(inp_ATOM *at, int i1, int *ineigh1, int *ineigh2)
67
+ {
68
+ int i, neigh1, num_rad1=0, num_rad2=0;
69
+ inp_ATOM *a = at+i1, *b;
70
+ if ( RADICAL_DOUBLET != a->radical )
71
+ return -1;
72
+ for ( i = 0; i < a->valence; i ++ ) {
73
+ b = at + (neigh1 = (int)a->neighbor[i]);
74
+ if ( RADICAL_DOUBLET == b->radical ) {
75
+ num_rad1 ++;
76
+ *ineigh1 = i;
77
+ }
78
+ }
79
+ if ( 1 == num_rad1 ) {
80
+ a = at + (neigh1 = (int)a->neighbor[*ineigh1]);
81
+ for ( i = 0; i < a->valence; i ++ ) {
82
+ b = at +(int)a->neighbor[i];
83
+ if ( RADICAL_DOUBLET == b->radical ) {
84
+ num_rad2 ++;
85
+ *ineigh2 = i;
86
+ }
87
+ }
88
+ if ( 1 == num_rad2 ) {
89
+ return neigh1;
90
+ }
91
+ }
92
+ return -1;
93
+ }
94
+
95
+ /************************************************************************/
96
+ int fix_odd_things( int num_atoms, inp_ATOM *at )
97
+ { /* 0 1 2 3 4 5 6 7 8 9 */
98
+ static const char el[] = "N;P;As;Sb;O;S;Se;Te;"; /* 8 elements + C, Si */
99
+ static U_CHAR en[10]; /* same number: 8 elements */
100
+ static int ne=0, ne2; /* will be 8 and 10 */
101
+ static int el_number_P;
102
+ static int el_number_H;
103
+ static int el_number_C;
104
+ static int el_number_O;
105
+ static int el_number_Si;
106
+
107
+ #define FIRST_NEIGHB2 4
108
+ #define FIRST_CENTER2 5
109
+ #define NUM_CENTERS_N 4
110
+
111
+ int i1, i2, k1, k2, c, num_changes = 0;
112
+ char elname[ATOM_EL_LEN];
113
+ if ( !ne ) { /* one time initialization */
114
+ const char *b, *e;
115
+ int len;
116
+ for ( b = el; e = strchr( b, ';'); b = e+1 ) {
117
+ len = e-b;
118
+ memcpy( elname, b, len );
119
+ elname[len] = '\0';
120
+ en[ne++] = get_periodic_table_number( elname );
121
+ }
122
+ ne2 = ne;
123
+ el_number_P = get_periodic_table_number( "P" );
124
+ el_number_H = get_periodic_table_number( "H" );
125
+ el_number_O = get_periodic_table_number( "O" );
126
+ en[ne2++] = el_number_C = get_periodic_table_number( "C" );
127
+ en[ne2++] = el_number_Si = get_periodic_table_number( "Si" );
128
+ }
129
+
130
+ /* H(-)-X -> H-X(-); H(+)-X -> H-X(+) */
131
+ for ( i1 = 0; i1 < num_atoms; i1 ++ ) {
132
+ if ( 1 == at[i1].valence &&
133
+ 1 == abs(at[i1].charge) &&
134
+ (0 == at[i1].radical || RADICAL_SINGLET == at[i1].radical) &&
135
+ BOND_TYPE_SINGLE == at[i1].bond_type[0] &&
136
+ el_number_H == at[i1].el_number &&
137
+ el_number_H != at[i2=(int)at[i1].neighbor[0]].el_number &&
138
+ !NUMH(at,i1) &&
139
+ !NUMH(at,i2)
140
+ ) {
141
+ at[i2].charge += at[i1].charge;
142
+ at[i1].charge = 0;
143
+ }
144
+ }
145
+
146
+ /* replace XHm(-)--Y==XHn(+) with XHm==Y--XHn, (n>=0 ,m>=0, X=N,P,As,Sb,O,S,Se,Te) */
147
+
148
+ for ( i1 = 0; i1 < num_atoms; i1 ++ ) {
149
+ if ( 1 != at[i1].charge ||
150
+ at[i1].radical && RADICAL_SINGLET != at[i1].radical ||
151
+ at[i1].chem_bonds_valence == at[i1].valence ||
152
+ !memchr(en, at[i1].el_number, ne) ||
153
+ get_el_valence( at[i1].el_number, at[i1].charge, 0 ) != at[i1].chem_bonds_valence+NUMH(at,i1) ) {
154
+ continue;
155
+ }
156
+
157
+ /* found a candidate at[i1] for X in XHn(+) */
158
+
159
+ if ( 1 == at[i1].valence &&
160
+ BOND_TYPE_DOUBLE == at[i1].bond_type[0] ) {
161
+ c = (int)at[i1].neighbor[0];
162
+ for ( k2 = 0; k2 < at[c].valence; k2 ++ ) {
163
+ i2 = at[c].neighbor[k2];
164
+ if ( 1 == at[i2].valence &&
165
+ -1 == at[i2].charge &&
166
+ at[i2].el_number == at[i1].el_number && /* exact match */
167
+ (0 == at[i2].radical || RADICAL_SINGLET == at[i2].radical) &&
168
+ BOND_TYPE_SINGLE == at[i2].bond_type[0] &&
169
+ /*memchr(en, at[i2].el_number, ne) &&*/
170
+ get_el_valence( at[i2].el_number, at[i2].charge, 0 ) == at[i2].chem_bonds_valence+NUMH(at,i2) ) {
171
+ /* found both X(-) and X(+); change bonds and remove charges */
172
+ for ( k1 = 0; k1 < at[c].valence && i1 != at[c].neighbor[k1]; k1 ++ )
173
+ ;
174
+ at[i1].charge = at[i2].charge = 0;
175
+ at[i1].bond_type[0] = at[c].bond_type[k1] = BOND_TYPE_SINGLE;
176
+ at[i1].chem_bonds_valence --;
177
+ at[i2].bond_type[0] = at[c].bond_type[k2] = BOND_TYPE_DOUBLE;
178
+ at[i2].chem_bonds_valence ++;
179
+ num_changes ++;
180
+ break;
181
+ }
182
+ }
183
+ }
184
+ else {
185
+ /* explicit H case: detect H-neighbors and Y */
186
+ int ineigh, neigh, i1_c, i2_c, num_H_i1, num_H_i2;
187
+ for ( ineigh = 0, num_H_i1 = 0, i1_c = -1; ineigh < at[i1].valence; ineigh ++ ) {
188
+ neigh = at[i1].neighbor[ineigh];
189
+ if ( at[neigh].el_number == el_number_H ) {
190
+ if ( at[neigh].chem_bonds_valence == 1 &&
191
+ (0 == at[neigh].radical || RADICAL_SINGLET == at[neigh].radical)
192
+ ) {
193
+ num_H_i1 ++; /* found H-neighbor */
194
+ } else {
195
+ break; /* wrong neighbor */
196
+ }
197
+ } else
198
+ if ( at[i1].bond_type[ineigh] == BOND_TYPE_DOUBLE ) {
199
+ /* found a candidate for Y; bond must bedouble */
200
+ i1_c = ineigh;
201
+ c = neigh;
202
+ }
203
+ }
204
+ if ( i1_c < 0 || num_H_i1 + 1 != at[i1].valence ) {
205
+ continue;
206
+ }
207
+ for ( k2 = 0; k2 < at[c].valence; k2 ++ ) {
208
+ i2 = at[c].neighbor[k2];
209
+ if (-1 == at[i2].charge &&
210
+ at[i2].el_number == at[i1].el_number && /* exact match */
211
+ (0 == at[i2].radical || RADICAL_SINGLET == at[i2].radical) &&
212
+ get_el_valence( at[i2].el_number, at[i2].charge, 0 ) == at[i2].chem_bonds_valence+NUMH(at,i2) ) {
213
+ for ( ineigh = 0, num_H_i2 = 0, i2_c = -1; ineigh < at[i2].valence; ineigh ++ ) {
214
+ neigh = at[i2].neighbor[ineigh];
215
+ if ( at[neigh].el_number == el_number_H ) {
216
+ if ( at[neigh].chem_bonds_valence == 1 &&
217
+ (0 == at[neigh].radical || RADICAL_SINGLET == at[neigh].radical)
218
+ ) {
219
+ num_H_i2 ++; /* found H-neighbor */
220
+ } else {
221
+ break; /* wrong neighbor */
222
+ }
223
+ } else
224
+ if ( c == neigh && at[i2].bond_type[ineigh] == BOND_TYPE_SINGLE ) {
225
+ i2_c = ineigh; /* position of Y neighbor; bond must be single */
226
+ } else {
227
+ break;
228
+ }
229
+ }
230
+ if ( num_H_i2 + (i2_c >= 0) != at[i2].valence ) {
231
+ continue;
232
+ }
233
+ /* found both X(-) and X(+); change bonds and remove charges */
234
+ for ( k1 = 0; k1 < at[c].valence && i1 != at[c].neighbor[k1]; k1 ++ )
235
+ ;
236
+ at[i1].charge = at[i2].charge = 0;
237
+ at[i1].bond_type[i1_c] = at[c].bond_type[k1] = BOND_TYPE_SINGLE;
238
+ at[i1].chem_bonds_valence --;
239
+ at[i2].bond_type[i2_c] = at[c].bond_type[k2] = BOND_TYPE_DOUBLE;
240
+ at[i2].chem_bonds_valence ++;
241
+ num_changes ++;
242
+ break;
243
+ }
244
+ }
245
+ }
246
+ }
247
+
248
+ /* Replace
249
+
250
+ X- X X=O,S,Se,Te -- terminal atoms (NEIGHB2)
251
+ \ | \ ||
252
+ >Y++ with >Y Y=S,Se,Te -- central cation (CENTER2)
253
+ / | / ||
254
+ X- X Y valence=4, original Y bond valence = 4
255
+
256
+
257
+
258
+
259
+ X- X X=O,S,Se,Te -- terminal atoms (NEIGHB2)
260
+ \ | \ ||
261
+ >P+ with >P
262
+ / | / |
263
+ X- X- Y valence=4, original Y bond valence = 4
264
+
265
+ */
266
+
267
+ for ( i1 = 0; i1 < num_atoms; i1 ++ ) {
268
+ if ( 1 == at[i1].valence &&
269
+ -1 == at[i1].charge &&
270
+ (0 == at[i1].radical || RADICAL_SINGLET == at[i1].radical) &&
271
+ !NUMH(at,i1) &&
272
+ BOND_TYPE_SINGLE == at[i1].bond_type[0] &&
273
+ memchr( en+FIRST_NEIGHB2, at[i1].el_number, ne-FIRST_NEIGHB2 )) {
274
+ int charge, i;
275
+ /* found a candidate for X */
276
+ c = (int)at[i1].neighbor[0]; /* candidate for Y */
277
+ if ( ((charge=2) == at[c].charge && memchr( en+FIRST_CENTER2, at[c].el_number, ne-FIRST_CENTER2) ||
278
+ (charge=1) == at[c].charge && el_number_P==at[c].el_number ) &&
279
+ 4 == at[c].valence &&
280
+ (0 == at[c].radical || RADICAL_SINGLET == at[c].radical ) &&
281
+ at[c].valence == at[c].chem_bonds_valence &&
282
+ !NUMH(at,c) ) {
283
+ ; /* accept */
284
+ } else {
285
+ continue; /* ignore at[i1] */
286
+ }
287
+ for ( k2 = 0; k2 < at[c].valence; k2 ++ ) {
288
+ i2 = at[c].neighbor[k2];
289
+ if ( i2 == i1 ) {
290
+ continue;
291
+ }
292
+ if ( 1 == at[i2].valence &&
293
+ -1 == at[i2].charge &&
294
+ memchr( en+FIRST_NEIGHB2, at[i2].el_number, ne-FIRST_NEIGHB2 ) &&
295
+ /*at[i2].el_number == at[i1].el_number &&*/ /* exact match */
296
+ (0 == at[i2].radical || RADICAL_SINGLET == at[i2].radical) &&
297
+ !NUMH(at,i2) &&
298
+ BOND_TYPE_SINGLE == at[i2].bond_type[0] ) {
299
+ /* found both X(-) and X(-); change bonds and remove charges */
300
+ for ( k1 = 0; k1 < at[c].valence && i1 != at[c].neighbor[k1]; k1 ++ )
301
+ ;
302
+ for ( i = 0; i < charge; i ++ ) {
303
+ /* in case of P it does not matter which X atom is neutralized
304
+ because of tautomerism. However, neutral central atom is important
305
+ for the neutralization of the components */
306
+ switch( i ) {
307
+ case 0:
308
+ at[i1].charge = 0;
309
+ at[i1].bond_type[0] = at[c].bond_type[k1] = BOND_TYPE_DOUBLE;
310
+ at[i1].bond_stereo[0] = at[c].bond_stereo[k1] = 0;
311
+ at[i1].chem_bonds_valence ++;
312
+ at[c].chem_bonds_valence ++;
313
+ num_changes ++;
314
+ break;
315
+ case 1:
316
+ at[i2].charge = 0;
317
+ at[i2].bond_type[0] = at[c].bond_type[k2] = BOND_TYPE_DOUBLE;
318
+ at[i2].bond_stereo[0] = at[c].bond_stereo[k2] = 0;
319
+ at[i2].chem_bonds_valence ++;
320
+ at[c].chem_bonds_valence ++;
321
+ num_changes ++;
322
+ break;
323
+ }
324
+ }
325
+ break;
326
+ }
327
+ }
328
+ }
329
+ }
330
+
331
+ /* A(doublet)-B(doublet) -> A=B (A and B have no other doublet neighbors) */
332
+ /* A(doublet)=B(doublet) -> A#B (A and B have no other doublet neighbors) */
333
+ for( i1 = 0; i1 < num_atoms; i1 ++ ) {
334
+ if ( RADICAL_DOUBLET == at[i1].radical &&
335
+ 0 <= (i2=the_only_doublet_neigh(at, i1, &k1, &k2)) ) {
336
+ if ( at[i1].bond_type[k1] <= BOND_TYPE_DOUBLE ) {
337
+ at[i1].bond_type[k1] ++;
338
+ at[i1].chem_bonds_valence ++;
339
+ at[i2].bond_type[k2] ++;
340
+ at[i2].chem_bonds_valence ++;
341
+ at[i1].radical = 0;
342
+ at[i2].radical = 0;
343
+ }
344
+ }
345
+ }
346
+
347
+ #if( REMOVE_ION_PAIRS_EARLY == 1 )
348
+
349
+ num_changes += remove_ion_pairs( num_atoms, at );
350
+ #endif
351
+
352
+ return num_changes;
353
+ }
354
+ /************************************************************************/
355
+ int post_fix_odd_things( int num_atoms, inp_ATOM *at )
356
+ {
357
+ int num_changes = 0;
358
+ /* currently does nothing */
359
+ return num_changes;
360
+ }
361
+ /************************************************************************/
362
+ int nFindOneOM(inp_ATOM *at, int at_no, int ord_OM[], int num_OM)
363
+ {
364
+ int i, n_OM, n_OM_best, best_value, cur_value, diff;
365
+ int num_best;
366
+
367
+ if ( 1 == num_OM ) {
368
+ return ord_OM[0];
369
+ }
370
+ if ( 1 > num_OM ) {
371
+ return -1;
372
+ }
373
+
374
+ /* select neighbors with min. number of bonds */
375
+ num_best = 1;
376
+ n_OM = (int)at[at_no].neighbor[ord_OM[0]];
377
+ best_value = (int)at[n_OM].valence;
378
+ /* compare number of bonds; move indexes of the best neighbors to the first elements of ord_OM[] */
379
+ for ( i = 1; i < num_OM; i ++ ) {
380
+ n_OM = at[at_no].neighbor[ord_OM[i]];
381
+ cur_value = (int)at[n_OM].valence;
382
+ diff = cur_value - best_value;
383
+ if ( diff < 0 ) {
384
+ n_OM_best = n_OM;
385
+ best_value = cur_value;
386
+ ord_OM[0] = ord_OM[i];
387
+ num_best = 1;
388
+ } else
389
+ if ( diff == 0 ) { /* was '=', pointed by WDI */
390
+ ord_OM[num_best ++] = ord_OM[i];
391
+ }
392
+ }
393
+ num_OM = num_best;
394
+ if ( 1 == num_OM ) {
395
+ return ord_OM[0];
396
+ }
397
+ /* select neighbors with min. periodic numbers */
398
+ num_best = 1;
399
+ n_OM = (int)at[at_no].neighbor[ord_OM[0]];
400
+ best_value = (int)at[n_OM].el_number;
401
+ /* compare periodic numbers; move indexes of the best neighbors to the first elements of ord_OM[] */
402
+ for ( i = 1; i < num_OM; i ++ ) {
403
+ n_OM = at[at_no].neighbor[ord_OM[i]];
404
+ cur_value = (int)at[n_OM].el_number;
405
+ diff = cur_value - best_value;
406
+ if ( diff < 0 ) {
407
+ n_OM_best = n_OM;
408
+ best_value = cur_value;
409
+ ord_OM[0] = ord_OM[i];
410
+ num_best = 1;
411
+ } else
412
+ if ( diff == 0 ) { /* was '=', pointed by WDI */
413
+ ord_OM[num_best ++] = ord_OM[i];
414
+ }
415
+ }
416
+ num_OM = num_best;
417
+ if ( 1 == num_OM ) {
418
+ return ord_OM[0];
419
+ }
420
+ /* if neighbors are not terminal atoms then reject */
421
+ if ( 1 < at[n_OM].valence ) {
422
+ return -1;
423
+ }
424
+ /* if neighbors are terminal atoms then the one without isotope or with lightest isotope */
425
+ num_best = 1;
426
+ n_OM = (int)at[at_no].neighbor[ord_OM[0]];
427
+ best_value = (int)at[n_OM].iso_atw_diff;
428
+ /* compare periodic numbers; move indexes of the best neighbors to the first elements of ord_OM[] */
429
+ for ( i = 1; i < num_OM; i ++ ) {
430
+ n_OM = at[at_no].neighbor[ord_OM[i]];
431
+ cur_value = (int)at[n_OM].el_number;
432
+ diff = cur_value - best_value;
433
+ if ( (!cur_value && best_value) || diff < 0 ) {
434
+ n_OM_best = n_OM;
435
+ best_value = cur_value;
436
+ ord_OM[0] = ord_OM[i];
437
+ num_best = 1;
438
+ } else
439
+ if ( diff == 0 ) { /* was '=', pointed by WDI */
440
+ ord_OM[num_best ++] = ord_OM[i];
441
+ }
442
+ }
443
+ num_OM = num_best;
444
+ if ( 1 == num_OM ) {
445
+ return ord_OM[0];
446
+ }
447
+ /* return any */
448
+ return ord_OM[0];
449
+ }
450
+ /************************************************************************/
451
+ /* the bonds are fixed in fix_special_bonds() */
452
+ int remove_ion_pairs( int num_atoms, inp_ATOM *at )
453
+ {
454
+ int num_changes = 0;
455
+
456
+ /* 0 1 2 3 4 5 6 7 8 9 8 9 */
457
+ static const char el[] = "N;P;As;Sb;O;S;Se;Te;C;Si"; /* 8 elements + C, Si */
458
+ static char en[12]; /* same number: 8 elements */
459
+ static int ne=0; /* will be 8 and 10 */
460
+
461
+ #define ELEM_N_FST 0
462
+ #define ELEM_N_LEN 4
463
+ #define ELEM_O_FST 4
464
+ #define ELEM_O_LEN 4
465
+ #define ELEM_C_FST 8
466
+ #define ELEM_C_LEN 2
467
+
468
+ #define MAX_NEIGH 6
469
+
470
+ int i, n, n2, i1, i2, i3, i4, type, chrg;
471
+ int num_C_II=0, num_C_plus=0, num_C_minus=0, num_N_plus=0, num_N_minus=0, num_O_plus=0, num_O_minus=0, num_All;
472
+ inp_ATOM *a;
473
+ char elname[ATOM_EL_LEN], *p;
474
+ if ( !ne ) { /* one time initialization */
475
+ const char *b, *e;
476
+ int len;
477
+ for ( b = el; e = strchr( b, ';'); b = e+1 ) {
478
+ len = e-b;
479
+ memcpy( elname, b, len );
480
+ elname[len] = '\0';
481
+ en[ne++] = get_periodic_table_number( elname );
482
+ }
483
+ en[ne] = '\0';
484
+ }
485
+
486
+ /****** count candidates ********/
487
+ for ( i = 0, a = at; i < num_atoms; i ++, a++ ) {
488
+ if ( 1 == (chrg=a->charge) || -1 == chrg ) {
489
+ if ( p = (char*)memchr( en, a->el_number, ne) ) {
490
+ n = p - en;
491
+ if ( n >= ELEM_C_FST ) {
492
+ if ( chrg > 0 )
493
+ num_C_plus ++;
494
+ else
495
+ num_C_minus ++;
496
+ } else
497
+ if ( n >= ELEM_O_FST ) {
498
+ if ( chrg > 0 )
499
+ num_O_plus ++;
500
+ else
501
+ num_O_minus ++;
502
+ } else {
503
+ if ( chrg > 0 )
504
+ num_N_plus ++;
505
+ else
506
+ num_N_minus ++;
507
+ }
508
+ }
509
+ } else
510
+ if ( !chrg && a->chem_bonds_valence + NUMH(a, 0) == 2 &&
511
+ get_el_valence( a->el_number, 0, 0 ) == 4 &&
512
+ NULL != memchr( en+ELEM_C_FST, a->el_number, ELEM_C_LEN) ) {
513
+ num_C_II ++;
514
+ }
515
+ }
516
+ num_All = num_C_II + num_C_plus + num_C_minus + num_N_plus + num_N_minus + num_O_plus + num_O_minus;
517
+ if ( !num_All ) {
518
+ return 0;
519
+ }
520
+
521
+ /**************************************************************************/
522
+ /*************************** Terminal ion pairs ***************************/
523
+ /**************************************************************************/
524
+
525
+ /*-------------------------------------------------------------------------
526
+ Pair type 1 N=N,P,As,Sb; O=O,S,Se,Te
527
+ ===========
528
+
529
+ X X if X is another -O(-) then neutralize O(-)
530
+ | | that has a higher periodic table number
531
+ O=N(+)-O(-) => O=N=O
532
+ i n
533
+ --------------------------------------------------------------------------*/
534
+ for ( type = 1; type <= 18; type ++ ) {
535
+ if ( (!type || 1 == type) ) {
536
+ for ( i = 0; i < num_atoms && 0 < num_N_plus && 0 < num_O_minus; i ++ ) {
537
+ if ( 1 == at[i].charge && 3 == nNoMetalNumBonds(at, i) &&
538
+ 4 == nNoMetalBondsValence(at, i) &&
539
+ NULL != memchr( en+ELEM_N_FST, at[i].el_number, ELEM_N_LEN) ) {
540
+ int num_OM = 0, ord_OM[3]; /* -O(-) */
541
+ int num_O = 0; /* =O */
542
+ int num_O_other = 0;
543
+ for ( i1 = 0; i1 < at[i].valence; i1 ++ ) {
544
+ n = at[i].neighbor[i1];
545
+ if ( 1 == nNoMetalNumBonds(at, n) && 0 == num_of_H( at, n ) &&
546
+ NULL != (p = (char*)memchr( en+ELEM_O_FST, at[n].el_number, ELEM_O_LEN)) ) {
547
+ if ( BOND_TYPE_SINGLE == at[i].bond_type[i1] &&
548
+ -1 == at[n].charge ) {
549
+ ord_OM[num_OM ++] = i1;
550
+ } else
551
+ if ( BOND_TYPE_DOUBLE == at[n].bond_type[0] &&
552
+ 0 == at[n].charge ) {
553
+ num_O ++;
554
+ } else {
555
+ num_O_other ++;
556
+ }
557
+ }
558
+ }
559
+ if ( num_OM > 0 && num_O > 0 && !num_O_other &&
560
+ 0 <= (i1=nFindOneOM(at, i, ord_OM, num_OM)) ) {
561
+ /* remove charges and increase bond order */
562
+ n = at[i].neighbor[i1];
563
+ i2 = is_in_the_list( at[n].neighbor, (AT_NUMB)i, at[n].valence ) - at[n].neighbor;
564
+ at[i].bond_type[i1] ++;
565
+ at[n].bond_type[i2] ++;
566
+ at[i].chem_bonds_valence ++;
567
+ at[n].chem_bonds_valence ++;
568
+ at[i].charge --;
569
+ at[n].charge ++;
570
+ at[i].radical = 0;
571
+ at[n].radical = 0;
572
+ num_changes ++;
573
+ num_N_plus --;
574
+ num_O_minus --;
575
+ num_All -= 2;
576
+ }
577
+ }
578
+ }
579
+ }
580
+ /*-------------------------------------------------------------------------
581
+ Terminal pair types: 2,3,4,5,6,7,8,9 N=N,P,As,Sb; O=O,S,Se,Te; C=C,Si
582
+ ====================================
583
+ type #
584
+ 2 2: O=N-C(II)- => O=N#C- N=N,P,As,Sb; O=O,S,Se,Te; C=C,Si
585
+ 3 9: O=O(+)-C(-)(III) => O=O=C(IV)
586
+ 4 3: O(-)-N(+)(IV) => O=N(V) (input structure has at least 1 double bond)
587
+ 5 4: O(-)-O(+)(III) => O=O(IV)
588
+ 6 8: O(-)-O-C(+)(III) => O=O=C(IV)
589
+ 7 5: N(-)=N(+)(IV) => N#N(V) allow terminal H on N(-)
590
+ 8 6: N(-)=O(+)(III) => N#O-
591
+ 9 7: N(-)=C(+)(III) => N#C-
592
+ --------------------------------------------------------------------------*/
593
+ if ( !type || 2 <= type && type <= 9 ) {
594
+ for ( i = 0; i < num_atoms && 0 < num_All; i ++ ) {
595
+ if ( 0 == at[i].charge && 1 == nNoMetalNumBonds(at, i) && 2 == nNoMetalBondsValence(at, i) &&
596
+ 0 == num_of_H( at, i ) &&
597
+ NULL != memchr( en+ELEM_O_FST, at[i].el_number, ELEM_O_LEN) &&
598
+ 0 <= ( i1 = nNoMetalNeighIndex(at, i)) &&
599
+ at[i].bond_type[i1] <= BOND_TYPE_TRIPLE ) {
600
+ /* terminal O= */
601
+ n = at[i].neighbor[i1];
602
+ if ( (!type || type == 2) && 0 < num_C_II ) { /* avoid alternating bonds */
603
+ if ( 0 == at[n].charge &&
604
+ 2 == nNoMetalNumBonds(at, n) && 3 == nNoMetalBondsValence(at, n) &&
605
+ 0 == num_of_H( at, n ) &&
606
+ NULL != memchr( en+ELEM_N_FST, at[n].el_number, ELEM_N_LEN) &&
607
+ 0 <= (i2 = nNoMetalOtherNeighIndex( at, n, i ) ) &&
608
+ at[n].bond_type[i2] <= BOND_TYPE_TRIPLE ) {
609
+ /* i2 = index of opposite to at[i] neighbor of at[n] */
610
+ /*i2 = (at[n].neighbor[0] == i);*/
611
+ n2 = at[n].neighbor[i2];
612
+ if ( 0 == at[n2].charge &&
613
+ 2 == at[n2].valence && 2 == at[n2].chem_bonds_valence &&
614
+ 0 == num_of_H( at, n2 ) &&
615
+ NULL != memchr( en+ELEM_C_FST, at[n2].el_number, ELEM_C_LEN) ) {
616
+ /* i n n2 */
617
+ /* found O=N-C(II)- */
618
+ /* convert O=N-C(II)- => O=N#C- */
619
+ i3 = (at[n2].neighbor[0] != n); /* index of at[n] neighbor of n2 */
620
+ at[ n].chem_bonds_valence = 5; /* N */
621
+ at[n2].chem_bonds_valence = 4; /* C */
622
+ at[ n].bond_type[i2] = BOND_TYPE_TRIPLE;
623
+ at[n2].bond_type[i3] = BOND_TYPE_TRIPLE;
624
+ at[n2].radical = 0;
625
+ num_changes ++;
626
+ num_C_II --;
627
+ num_All --;
628
+ continue;
629
+ }
630
+ }
631
+ }
632
+ if ( (!type || type == 3) && 0 < num_O_plus && 0 < num_C_minus ) {
633
+ if ( 1 == at[n].charge && 2 == nNoMetalNumBonds(at, n) && 3 == nNoMetalBondsValence(at, n) &&
634
+ 0 == num_of_H( at, n ) &&
635
+ NULL != memchr( en+ELEM_O_FST, at[n].el_number, ELEM_O_LEN) &&
636
+ 0 <= (i2 = nNoMetalOtherNeighIndex( at, n, i ) ) &&
637
+ at[n].bond_type[i2] <= BOND_TYPE_TRIPLE ) {
638
+ /* found O=O(+)- */
639
+ /* i2 = index of opposite to at[i] neighbor of at[n] */
640
+ /*i2 = (at[n].neighbor[0] == i);*/
641
+ n2 = at[n].neighbor[i2];
642
+ if ( -1 == at[n2].charge && 3 >= nNoMetalNumBonds(at, n2) && 3 == nNoMetalBondsValence(at, n2)+NUMH(at,n2) &&
643
+ NULL != memchr( en+ELEM_C_FST, at[n2].el_number, ELEM_C_LEN) ) {
644
+ /* i n n2 */
645
+ /* found found O=O(+)-C(-)(III) */
646
+ /* convert O=O(+)-C(-)(III) => O=O=C(IV) */
647
+ i3 = (at[n2].neighbor[0] != n); /* index of at[n] neighbor of n2 */
648
+ at[ n].charge --;
649
+ at[n2].charge ++;
650
+ at[ n].chem_bonds_valence += 1; /* =O- => =O= */
651
+ at[n2].chem_bonds_valence += 1; /* -C => =C */
652
+ at[ n].bond_type[i2] = BOND_TYPE_DOUBLE;
653
+ at[n2].bond_type[i3] = BOND_TYPE_DOUBLE;
654
+ num_changes ++;
655
+ num_O_plus --;
656
+ num_C_minus --;
657
+ num_All -= 2;
658
+ continue;
659
+ }
660
+ }
661
+ }
662
+ } else
663
+ if ( -1 == at[i].charge &&
664
+ 0 < num_O_minus + num_N_minus &&
665
+ 0 < num_N_plus + num_O_plus + num_C_plus &&
666
+ 1 == nNoMetalNumBonds(at, i) && 1 == nNoMetalBondsValence(at, i) &&
667
+ 0 == num_of_H( at, i ) &&
668
+ NULL != memchr( en+ELEM_O_FST, at[i].el_number, ELEM_O_LEN) &&
669
+ 0 <= (i1 = nNoMetalNeighIndex( at, i )) &&
670
+ at[i].bond_type[i1] <= BOND_TYPE_TRIPLE ) {
671
+
672
+ /* terminal O(-)- */
673
+
674
+ n = at[i].neighbor[i1];
675
+
676
+ if ( (!type || type == 4) && 0 < num_O_minus && 0 < num_N_plus && /* O(-)-N(+)(IV) */
677
+ 1 == at[n].charge && 3 >= nNoMetalNumBonds(at, n) && 4 == nNoMetalBondsValence(at, n) &&
678
+ 0 == num_of_H( at, n ) &&
679
+ NULL != memchr( en+ELEM_N_FST, at[n].el_number, ELEM_N_LEN) /* except >O(+)- */
680
+ ) {
681
+ /* found O(-)-N(+)(IV) */
682
+ /* convert O(-)-N(+)(IV) => O=N(V) */
683
+
684
+ i2 = is_in_the_list( at[n].neighbor, (AT_NUMB)i, at[n].valence ) - at[n].neighbor; /* index of at[i] neighbor of at[n] */
685
+ at[i].charge ++;
686
+ at[n].charge --;
687
+ at[i].chem_bonds_valence ++;
688
+ at[n].chem_bonds_valence ++;
689
+ at[i].bond_type[i1] ++;
690
+ at[n].bond_type[i2] ++;
691
+ num_changes ++;
692
+ num_O_minus --;
693
+ num_N_plus --;
694
+ num_All -= 2;
695
+ continue;
696
+ }
697
+
698
+ if ( (!type || type == 5) && 0 < num_O_minus && 0 < num_O_plus &&/* O(-)-O(+)(III) */
699
+ 1 == at[n].charge && 3 >= nNoMetalNumBonds(at, n) && 3 == nNoMetalBondsValence(at, n) &&
700
+ 0 == num_of_H( at, n ) &&
701
+ NULL != memchr( en+ELEM_O_FST, at[n].el_number, ELEM_O_LEN) /* except >O(+)- */
702
+ ) {
703
+ /* found O(+)(III) */
704
+ /* convert O(-)-O(+)(III) => O=O(IV) */
705
+
706
+ i2 = is_in_the_list( at[n].neighbor, (AT_NUMB)i, at[n].valence ) - at[n].neighbor; /* index of at[i] neighbor of at[n] */
707
+ at[i].charge ++;
708
+ at[n].charge --;
709
+ at[i].chem_bonds_valence ++;
710
+ at[n].chem_bonds_valence ++;
711
+ at[i].bond_type[i1] ++;
712
+ at[n].bond_type[i2] ++;
713
+ num_changes ++;
714
+ num_O_minus --;
715
+ num_O_plus --;
716
+ num_All -= 2;
717
+ continue;
718
+ }
719
+ /* i n n2 */
720
+ if ( (!type || type == 6) && /* O(-)-O-C(+)(III) */
721
+ 0 < num_O_minus && 0 < num_C_plus &&
722
+ 0 == at[n].charge && 2 == nNoMetalNumBonds(at, n) && 2 == nNoMetalBondsValence(at, n) &&
723
+ 0 == num_of_H( at, n ) &&
724
+ NULL != memchr( en+ELEM_O_FST, at[n].el_number, ELEM_O_LEN) &&
725
+ 0 <= (i2=nNoMetalOtherNeighIndex( at, n, i )) &&
726
+ at[n].bond_type[i2] <= BOND_TYPE_TRIPLE ) {
727
+ /* found O(-)-O- */
728
+ /* i2 = index of opposite to at[i] neighbor of at[n] */
729
+ /*i2 = (at[n].neighbor[0] == i);*/
730
+ n2 = at[n].neighbor[i2];
731
+ if ( 1 == at[n2].charge && 3 >= nNoMetalNumBonds(at, n2) &&
732
+ 3 == nNoMetalBondsValence(at, n2)+NUMH(at,n2) &&
733
+ NULL != memchr( en+ELEM_C_FST, at[n2].el_number, ELEM_C_LEN) ) {
734
+ /* i n n2 */
735
+ /* found O(-)-O-C(+)(III) */
736
+ /* convert O(-)-O-C(+)(III) => O=O=C(IV) */
737
+ /*i3 = (at[n2].neighbor[0] != n);*/ /* i3 = index of at[n] neighbor of at[n2] */
738
+ i3 = is_in_the_list( at[n2].neighbor, (AT_NUMB)n, at[n2].valence ) - at[n2].neighbor;
739
+ /*i4 = index of at[i] in the adjacency list of at[n] */
740
+ i4 = is_in_the_list( at[n].neighbor, (AT_NUMB)i, at[n].valence ) - at[n].neighbor;
741
+ at[ i].charge ++;
742
+ at[n2].charge --;
743
+ at[ i].chem_bonds_valence += 1; /* O- => O= */
744
+ at[ n].chem_bonds_valence += 2; /* -O- => =O= */
745
+ at[n2].chem_bonds_valence += 1; /* -C => =C */
746
+ at[ i].bond_type[i1] = BOND_TYPE_DOUBLE;
747
+ at[ n].bond_type[i4] = BOND_TYPE_DOUBLE;
748
+ at[ n].bond_type[i2] = BOND_TYPE_DOUBLE;
749
+ at[n2].bond_type[i3] = BOND_TYPE_DOUBLE;
750
+ num_changes ++;
751
+ num_O_minus --;
752
+ num_C_plus --;
753
+ num_All -= 2;
754
+ continue;
755
+ }
756
+ }
757
+ } else
758
+ if ( -1 == at[i].charge && 0 < num_N_minus && 0 < num_N_plus+num_O_plus+num_C_plus &&
759
+ 1 == nNoMetalNumBonds(at, i) && 2 == nNoMetalBondsValence(at, i)+NUMH(at, i) &&
760
+ /*0 == num_of_H( at, i ) &&*/
761
+ NULL != memchr( en+ELEM_N_FST, at[i].el_number, ELEM_N_LEN) &&
762
+ 0 <= (i1 = nNoMetalNeighIndex( at, i )) &&
763
+ at[i].bond_type[i1] <= BOND_TYPE_TRIPLE ) {
764
+ /* terminal N(-)= */
765
+ n = at[i].neighbor[i1 = 0];
766
+ if ( (!type || type == 7) && 0 < num_N_plus && /* N(-)=N(+)(IV) */
767
+ 1 == at[n].charge && 3 >= nNoMetalNumBonds(at, n) && 4 == nNoMetalBondsValence(at, n) &&
768
+ 0 == num_of_H( at, n ) &&
769
+ NULL != memchr( en+ELEM_N_FST, at[n].el_number, ELEM_N_LEN)
770
+ ) {
771
+ /* found N(-)-N(+)(IV) */
772
+ /* convert N(-)=N(+)(IV) => N#N(V) */
773
+
774
+ i2 = is_in_the_list( at[n].neighbor, (AT_NUMB)i, at[n].valence ) - at[n].neighbor; /* index of at[i] neighbor of at[n] */
775
+ at[i].charge ++;
776
+ at[n].charge --;
777
+ at[i].chem_bonds_valence ++;
778
+ at[n].chem_bonds_valence ++;
779
+ at[i].bond_type[i1] ++;
780
+ at[n].bond_type[i2] ++;
781
+ num_changes ++;
782
+ num_N_minus --;
783
+ num_N_plus --;
784
+ num_All -= 2;
785
+ continue;
786
+ }
787
+ if ( (!type || type == 8) && 0 < num_O_plus && /* N(-)=O(+)(III) */
788
+ 1 == at[n].charge && 2 == nNoMetalNumBonds(at, n) && 3 == nNoMetalBondsValence(at, n) &&
789
+ 0 == num_of_H( at, n ) &&
790
+ NULL != memchr( en+ELEM_O_FST, at[n].el_number, ELEM_O_LEN)
791
+ ) {
792
+ /* found N(-)-O(+)(III) */
793
+ /* convert N(-)=O(+)(III) => N#O(IV)- */
794
+ i2 = is_in_the_list( at[n].neighbor, (AT_NUMB)i, at[n].valence ) - at[n].neighbor; /* index of at[i] neighbor of at[n] */
795
+ at[i].charge ++;
796
+ at[n].charge --;
797
+ at[i].chem_bonds_valence ++;
798
+ at[n].chem_bonds_valence ++;
799
+ at[i].bond_type[i1] ++;
800
+ at[n].bond_type[i2] ++;
801
+ num_changes ++;
802
+ num_N_minus --;
803
+ num_O_plus --;
804
+ num_All -= 2;
805
+ continue;
806
+ }
807
+ if ( (!type || type == 9) && 0 < num_C_plus && /* N(-)=C(+)(III) */
808
+ 1 == at[n].charge && 2 == at[n].valence && 3 == at[n].chem_bonds_valence &&
809
+ 0 == num_of_H( at, n ) &&
810
+ NULL != memchr( en+ELEM_C_FST, at[n].el_number, ELEM_C_LEN)
811
+ ) {
812
+ /* found N(-)=C(+)(III) */
813
+ /* convert N(-)=C(+)(III) => N#C(IV)- */
814
+
815
+ i2 = is_in_the_list( at[n].neighbor, (AT_NUMB)i, at[n].valence ) - at[n].neighbor; /* index of at[i] neighbor of at[n] */
816
+ at[i].charge ++;
817
+ at[n].charge --;
818
+ at[i].chem_bonds_valence ++;
819
+ at[n].chem_bonds_valence ++;
820
+ at[i].bond_type[i1] ++;
821
+ at[n].bond_type[i2] ++;
822
+ num_changes ++;
823
+ num_N_minus --;
824
+ num_C_plus --;
825
+ num_All -= 2;
826
+ continue;
827
+ }
828
+ }
829
+ }
830
+ }
831
+
832
+ /**************************************************************************/
833
+ /*********************** NON-Terminal ion pairs ***************************/
834
+ /**************************************************************************/
835
+ /*-------------------------------------------------------------------------
836
+ Non-Terminal pair types: 10,11,12,13,14 N=N,P,As,Sb; O=O,S,Se,Te; C=C,Si
837
+ ========================================
838
+
839
+ 10: N(+)(IV)-C(-)(III) => N(V)=C(IV) (N has 3 or 2 bonds)
840
+ 11: N(+)(IV)=C(-)(III) => N(V)#C(IV) (N has 3 or 2 bonds)
841
+ 12: N(+)(IV)-N(-)(II) => N(V)=N(III) (allow terminal H on N(-))
842
+ 13: -O(+)-C(-)(III) => -O=C-
843
+ 14: -O(+)=C(-)(III) => -O#C-
844
+ 15: O(+)(III)-N(-)(II) => O(IV)=N(III) (allow terminal H on N(-))
845
+ --------------------------------------------------------------------------*/
846
+ if ( !type || 10 <= type && type <= 15 ) {
847
+ for ( i = 0; i < num_atoms && 0 < num_All; i ++ ) {
848
+ if ( 1 == at[i].charge &&
849
+ 0 < num_N_plus + num_O_plus && 0 < num_C_minus + num_N_minus &&
850
+ 4 >= nNoMetalNumBonds(at, i) && 4 == nNoMetalBondsValence(at, i) &&
851
+ 0 == num_of_H( at, i ) &&
852
+ NULL != memchr( en+ELEM_N_FST, at[i].el_number, ELEM_N_LEN) ) {
853
+ /* found non-terminal N(+)(IV) */
854
+ if ( (!type || 10 == type) && 0 < num_N_plus && 0 < num_C_minus ) {
855
+ int num_neigh = 0, pos_neigh = -1;
856
+ for ( i1 = 0; i1 < at[i].valence; i1 ++ ) {
857
+ n = at[i].neighbor[i1];
858
+ if ( -1 == at[n].charge && 3 >= at[n].valence && 3 == at[n].chem_bonds_valence+NUMH(at,n) &&
859
+ /*0 == at[n].num_H &&*/
860
+ at[i].bond_type[i1] == BOND_TYPE_SINGLE &&
861
+ NULL != memchr( en+ELEM_C_FST, at[n].el_number, ELEM_C_LEN) ) {
862
+ /* found N(+)(IV)-C(-)(III); prepare conversion to N(V)=C(IV) */
863
+ num_neigh ++;
864
+ pos_neigh = i1;
865
+ }
866
+ }
867
+ i1=pos_neigh;
868
+ if ( 1 == num_neigh &&
869
+ at[i].bond_type[i1] <= BOND_TYPE_TRIPLE &&
870
+ !has_other_ion_neigh( at, i, n=at[i].neighbor[i1], en, ne ) &&
871
+ !has_other_ion_neigh( at, n, i, en, ne )) {
872
+ /*n = at[i].neighbor[i1=pos_neigh];*/
873
+ i2 = is_in_the_list( at[n].neighbor, (AT_NUMB)i, at[n].valence ) - at[n].neighbor;
874
+ at[i].charge --;
875
+ at[n].charge ++;
876
+ at[i].chem_bonds_valence ++;
877
+ at[n].chem_bonds_valence ++;
878
+ at[i].bond_type[i1] ++;
879
+ at[n].bond_type[i2] ++;
880
+ num_changes ++;
881
+ num_C_minus --;
882
+ num_N_plus --;
883
+ num_All -= 2;
884
+ continue;
885
+ }
886
+ }
887
+ if ( (!type || 11 == type) && 0 < num_N_plus && 0 < num_C_minus ) {
888
+ int num_neigh = 0, pos_neigh = -1;
889
+ for ( i1 = 0; i1 < at[i].valence; i1 ++ ) {
890
+ n = at[i].neighbor[i1];
891
+ if ( -1 == at[n].charge && 3 >= at[n].valence && 3 == at[n].chem_bonds_valence+NUMH(at,n) &&
892
+ /*0 == at[n].num_H &&*/
893
+ at[i].bond_type[i1] == BOND_TYPE_DOUBLE &&
894
+ NULL != memchr( en+ELEM_C_FST, at[n].el_number, ELEM_C_LEN) ) {
895
+ /* found N(+)(IV)=C(-)(III); prepare conversion to N(V)#C(IV) */
896
+ num_neigh ++;
897
+ pos_neigh = i1;
898
+ }
899
+ }
900
+ if ( 1 == num_neigh &&
901
+ !has_other_ion_neigh( at, i, n=at[i].neighbor[i1=pos_neigh], en, ne ) &&
902
+ !has_other_ion_neigh( at, n, i, en, ne )) {
903
+ /*n = at[i].neighbor[i1=pos_neigh];*/
904
+ i2 = is_in_the_list( at[n].neighbor, (AT_NUMB)i, at[n].valence ) - at[n].neighbor;
905
+ at[i].charge --;
906
+ at[n].charge ++;
907
+ at[i].chem_bonds_valence ++;
908
+ at[n].chem_bonds_valence ++;
909
+ at[i].bond_type[i1] ++;
910
+ at[n].bond_type[i2] ++;
911
+ num_changes ++;
912
+ num_C_minus --;
913
+ num_N_plus --;
914
+ num_All -= 2;
915
+ continue;
916
+ }
917
+ }
918
+ if ( !type || 12 == type && 0 < num_N_plus && 0 < num_N_minus ) {
919
+ int num_neigh = 0, pos_neigh = -1;
920
+ for ( i1 = 0; i1 < at[i].valence; i1 ++ ) {
921
+ n = at[i].neighbor[i1];
922
+ if ( -1 == at[n].charge && 2 >= nNoMetalNumBonds(at, n) &&
923
+ 2 == nNoMetalBondsValence(at, n)+NUMH(at, n) &&
924
+ /*0 == num_of_H( at, n ) &&*/
925
+ at[i].bond_type[i1] == BOND_TYPE_SINGLE &&
926
+ NULL != memchr( en+ELEM_N_FST, at[n].el_number, ELEM_N_LEN) ) {
927
+ /* found N(+)(IV)=N(-)(II); prepare conversion to N(V)#N(III) */
928
+ num_neigh ++;
929
+ pos_neigh = i1;
930
+ }
931
+ }
932
+ if ( 1 == num_neigh &&
933
+ !has_other_ion_neigh( at, i, n=at[i].neighbor[i1=pos_neigh], en, ne ) &&
934
+ !has_other_ion_neigh( at, n, i, en, ne )) {
935
+ /*n = at[i].neighbor[i1=pos_neigh];*/
936
+ i2 = is_in_the_list( at[n].neighbor, (AT_NUMB)i, at[n].valence ) - at[n].neighbor;
937
+ at[i].charge --;
938
+ at[n].charge ++;
939
+ at[i].chem_bonds_valence ++;
940
+ at[n].chem_bonds_valence ++;
941
+ at[i].bond_type[i1] ++;
942
+ at[n].bond_type[i2] ++;
943
+ num_changes ++;
944
+ num_N_minus --;
945
+ num_N_plus --;
946
+ num_All -= 2;
947
+ continue;
948
+ }
949
+ }
950
+ } else
951
+ if ( 1 == at[i].charge &&
952
+ 0 < num_O_plus && 0 < num_C_minus + num_N_minus &&
953
+ 3 >= nNoMetalNumBonds(at, i) && 3 == nNoMetalBondsValence(at, i) &&
954
+ 0 == num_of_H( at, i ) &&
955
+ NULL != memchr( en+ELEM_O_FST, at[i].el_number, ELEM_O_LEN) ) {
956
+ /* found non-terminal O(+)(III) */
957
+ if ( (!type || 13 == type) && 0 < num_C_minus ) {
958
+ int num_neigh = 0, pos_neigh = -1;
959
+ for ( i1 = 0; i1 < at[i].valence; i1 ++ ) {
960
+ n = at[i].neighbor[i1];
961
+ if ( -1 == at[n].charge && 3 >= at[n].valence && 3 == at[n].chem_bonds_valence+NUMH(at,n) &&
962
+ /*0 == at[n].num_H &&*/
963
+ at[i].bond_type[i1] == BOND_TYPE_SINGLE &&
964
+ NULL != memchr( en+ELEM_C_FST, at[n].el_number, ELEM_C_LEN) ) {
965
+ /* found O(+)(III)-C(-)(II); prepare conversion to O(IV)=C(IV) */
966
+ num_neigh ++;
967
+ pos_neigh = i1;
968
+ }
969
+ }
970
+ if ( 1 == num_neigh &&
971
+ !has_other_ion_neigh( at, i, n=at[i].neighbor[i1=pos_neigh], en, ne ) &&
972
+ !has_other_ion_neigh( at, n, i, en, ne )) {
973
+ /*n = at[i].neighbor[i1=pos_neigh];*/
974
+ i2 = is_in_the_list( at[n].neighbor, (AT_NUMB)i, at[n].valence ) - at[n].neighbor;
975
+ at[i].charge --;
976
+ at[n].charge ++;
977
+ at[i].chem_bonds_valence ++;
978
+ at[n].chem_bonds_valence ++;
979
+ at[i].bond_type[i1] ++;
980
+ at[n].bond_type[i2] ++;
981
+ num_changes ++;
982
+ num_C_minus --;
983
+ num_O_plus --;
984
+ num_All -= 2;
985
+ continue;
986
+ }
987
+ }
988
+ if ( (!type || 14 == type) && 0 < num_C_minus ) {
989
+ int num_neigh = 0, pos_neigh = -1;
990
+ for ( i1 = 0; i1 < at[i].valence; i1 ++ ) {
991
+ n = at[i].neighbor[i1];
992
+ if ( -1 == at[n].charge && 3 >= at[n].valence && 3 == at[n].chem_bonds_valence+NUMH(at,n) &&
993
+ /*0 == at[n].num_H &&*/
994
+ at[i].bond_type[i1] == BOND_TYPE_DOUBLE &&
995
+ NULL != memchr( en+ELEM_C_FST, at[n].el_number, ELEM_C_LEN) ) {
996
+ /* found O(+)(III)=C(-)(III); prepare conversion to O(IV)#C(IV) */
997
+ num_neigh ++;
998
+ pos_neigh = i1;
999
+ }
1000
+ }
1001
+ if ( 1 == num_neigh &&
1002
+ !has_other_ion_neigh( at, i, n=at[i].neighbor[i1=pos_neigh], en, ne ) &&
1003
+ !has_other_ion_neigh( at, n, i, en, ne )) {
1004
+ /*n = at[i].neighbor[i1=pos_neigh];*/
1005
+ i2 = is_in_the_list( at[n].neighbor, (AT_NUMB)i, at[n].valence ) - at[n].neighbor;
1006
+ at[i].charge --;
1007
+ at[n].charge ++;
1008
+ at[i].chem_bonds_valence ++;
1009
+ at[n].chem_bonds_valence ++;
1010
+ at[i].bond_type[i1] ++;
1011
+ at[n].bond_type[i2] ++;
1012
+ num_changes ++;
1013
+ num_C_minus --;
1014
+ num_O_plus --;
1015
+ num_All -= 2;
1016
+ continue;
1017
+ }
1018
+ }
1019
+ if ( (!type || 15 == type) && 0 < num_N_minus ) {
1020
+ int num_neigh = 0, pos_neigh = -1;
1021
+ for ( i1 = 0; i1 < at[i].valence; i1 ++ ) {
1022
+ n = at[i].neighbor[i1];
1023
+ if ( -1 == at[n].charge && 2 >= nNoMetalNumBonds(at, n) &&
1024
+ 2 == nNoMetalBondsValence(at, n)+NUMH(at, n) &&
1025
+ /*0 == num_of_H( at, n ) &&*/
1026
+ at[i].bond_type[i1] == BOND_TYPE_SINGLE &&
1027
+ NULL != memchr( en+ELEM_N_FST, at[n].el_number, ELEM_N_LEN) ) {
1028
+ /* found O(+)(III)=N(-)(II); prepare conversion to O(IV)#N(III) */
1029
+ num_neigh ++;
1030
+ pos_neigh = i1;
1031
+ }
1032
+ }
1033
+ if ( 1 == num_neigh &&
1034
+ !has_other_ion_neigh( at, i, n=at[i].neighbor[i1=pos_neigh], en, ne ) &&
1035
+ !has_other_ion_neigh( at, n, i, en, ne )) {
1036
+ /*n = at[i].neighbor[i1=pos_neigh];*/
1037
+ i2 = is_in_the_list( at[n].neighbor, (AT_NUMB)i, at[n].valence ) - at[n].neighbor;
1038
+ at[i].charge --;
1039
+ at[n].charge ++;
1040
+ at[i].chem_bonds_valence ++;
1041
+ at[n].chem_bonds_valence ++;
1042
+ at[i].bond_type[i1] ++;
1043
+ at[n].bond_type[i2] ++;
1044
+ num_changes ++;
1045
+ num_N_minus --;
1046
+ num_O_plus --;
1047
+ num_All -= 2;
1048
+ continue;
1049
+ }
1050
+ }
1051
+ }
1052
+ }
1053
+ }
1054
+ /**************************************************************************/
1055
+ /*********************** NON-Terminal ion triples *************************/
1056
+ /**************************************************************************/
1057
+ /*-------------------------------------------------------------------------
1058
+ Non-Terminal triple types: 16, 17, 18 N=N,P,As,Sb; O=O,S,Se,Te; C=C,Si
1059
+ ========================================
1060
+ 16: C(+)(III)-O-N(-)(II) => C(IV)=O=N(III) (allow terminal H on N(-))
1061
+
1062
+ | |
1063
+ 17: C(+)(III)-N-C(-)(III) => C(IV)=N=C(IV)
1064
+
1065
+ 18: C(-)(III)-N=C(+)(III) => C(IV)=N#C(IV) (may have two or no charges)
1066
+ C(IV)=N-C(II) => C(IV)=N#C(IV)
1067
+
1068
+ */
1069
+ if ( (!type || 16 == type) && 0 < num_C_plus && 0 < num_N_minus ) {
1070
+ int m[2], j[2], k;
1071
+ for ( i = 0; i < num_atoms; i ++ ) {
1072
+ if ( 0 == at[i].charge && 2 == nNoMetalNumBonds(at, i) && 2 == nNoMetalBondsValence(at, i) &&
1073
+ 0 == num_of_H( at, i ) &&
1074
+ 0 <= (j[0] = nNoMetalNeighIndex( at, i )) &&
1075
+ at[m[0]=at[i].neighbor[j[0]]].charge &&
1076
+ 0 <= (j[1] = nNoMetalOtherNeighIndex( at, i, m[0] )) &&
1077
+ 0 == at[m[0]].charge + at[m[1]=at[i].neighbor[j[1]]].charge &&
1078
+ 5 >= nNoMetalBondsValence(at, m[0]) + nNoMetalBondsValence(at, m[1]) &&
1079
+ /*5 >= at[m[0]].chem_bonds_valence + at[m[1]].chem_bonds_valence &&*/
1080
+ NULL != memchr( en+ELEM_O_FST, at[i].el_number, ELEM_O_LEN) ) {
1081
+ /* found non-terminal A(+)-O-B(-); chem_bond_val of A+B <= 5 */
1082
+ int n_N=-1, n_C=-1, i_C=-1;
1083
+ for ( k = 0; k < 2; k ++ ) {
1084
+ n = m[k];
1085
+ if ( -1 == at[n].charge && 2 == nNoMetalNumBonds(at, n)+NUMH(at, n) &&
1086
+ /*0 == num_of_H( at, n ) &&*/
1087
+ NULL != memchr( en+ELEM_N_FST, at[n].el_number, ELEM_N_LEN) ) {
1088
+ n_N = n;
1089
+ } else
1090
+ if ( 1 == at[n].charge && 3 == at[n].chem_bonds_valence+NUMH(at,n) &&
1091
+ NULL != memchr( en+ELEM_C_FST, at[n].el_number, ELEM_C_LEN) ) {
1092
+ n_C = n;
1093
+ i_C = k;
1094
+ }
1095
+ }
1096
+ if ( n_C < 0 || n_N < 0 ||
1097
+ has_other_ion_in_sphere_2(at, n_C, n_N, en, ne ) ||
1098
+ has_other_ion_in_sphere_2(at, n_N, n_C, en, ne ) ) {
1099
+ continue;
1100
+ }
1101
+ /* C(+)(III)-O-N(-)(II) => C(IV)=O=N(III) */
1102
+ for ( k = 0; k < 2; k ++ ) {
1103
+ n = k? n_C : n_N;
1104
+ i1 = k? j[i_C] : j[1-i_C];
1105
+ i2 = is_in_the_list( at[n].neighbor, (AT_NUMB)i, at[n].valence ) - at[n].neighbor;
1106
+ at[i].bond_type[i1] ++;
1107
+ at[n].bond_type[i2] ++;
1108
+ at[i].chem_bonds_valence ++;
1109
+ at[n].chem_bonds_valence ++;
1110
+ at[n].charge += (k? -1:1);
1111
+ }
1112
+ num_changes ++;
1113
+ num_N_minus --;
1114
+ num_C_plus --;
1115
+ num_All -= 2;
1116
+ }
1117
+ }
1118
+ }
1119
+ if ( (!type || 17 == type) && 0 < num_C_plus && 0 < num_C_minus ) {
1120
+ int m[3], c[3], j[3], k;
1121
+ for ( i = 0; i < num_atoms; i ++ ) {
1122
+ if ( 0 == at[i].charge && 3 == nNoMetalNumBonds(at, i) && 3 == nNoMetalBondsValence(at, i) &&
1123
+ 0 == num_of_H( at, i ) &&
1124
+ 0 <= ( j[0] = nNoMetalNeighIndex(at, i) ) &&
1125
+ 0 <= ( j[1] = nNoMetalOtherNeighIndex( at, i, m[0] = at[i].neighbor[j[0]] ) ) &&
1126
+ 0 <= ( j[2] = nNoMetalOtherNeighIndex2( at, i, m[0], m[1] = at[i].neighbor[j[1]] ) ) &&
1127
+ 1 == !(c[0]=at[m[0]].charge)
1128
+ + !(c[1]=at[m[1]].charge)
1129
+ + !(c[2]=at[m[2]=at[i].neighbor[j[2]]].charge) &&
1130
+ 0 == c[0] + c[1] + c[2] &&
1131
+ 2 == (3== (c[0]? at[m[0]].chem_bonds_valence+NUMH(at,m[0]):0))
1132
+ + (3== (c[1]? at[m[1]].chem_bonds_valence+NUMH(at,m[1]):0))
1133
+ + (3== (c[2]? at[m[2]].chem_bonds_valence+NUMH(at,m[2]):0)) &&
1134
+ NULL != memchr( en+ELEM_N_FST, at[i].el_number, ELEM_N_LEN) ) {
1135
+ /* found non-terminal A(+)-O-B(-) */
1136
+ int n_Cp=-1, n_Cm=-1, i_Cp=-1, i_Cm=-1; /* p = positive, m = negatice ion C */
1137
+ for ( k = 0; k < 3; k ++ ) {
1138
+ if ( c[k] ) {
1139
+ n = m[k];
1140
+ if ( -1 == at[n].charge &&
1141
+ NULL != memchr( en+ELEM_C_FST, at[n].el_number, ELEM_C_LEN) ) {
1142
+ n_Cm = n;
1143
+ i_Cm = k;
1144
+ } else
1145
+ if ( 1 == at[n].charge &&
1146
+ NULL != memchr( en+ELEM_C_FST, at[n].el_number, ELEM_C_LEN) ) {
1147
+ n_Cp = n;
1148
+ i_Cp = k;
1149
+ }
1150
+ }
1151
+ }
1152
+ if ( n_Cp < 0 || n_Cm < 0 ||
1153
+ has_other_ion_in_sphere_2(at, n_Cp, n_Cm, en, ne ) ||
1154
+ has_other_ion_in_sphere_2(at, n_Cm, n_Cp, en, ne )) {
1155
+ continue;
1156
+ }
1157
+ /* | | */
1158
+ /* C(+)(III)-N-C(-)(III) => C(IV)=N=C(IV) */
1159
+ for ( k = 0; k < 2; k ++ ) {
1160
+ n = k? n_Cp : n_Cm;
1161
+ i1 = k? j[i_Cp] : j[i_Cm];
1162
+ i2 = is_in_the_list( at[n].neighbor, (AT_NUMB)i, at[n].valence ) - at[n].neighbor;
1163
+ at[i].bond_type[i1] ++;
1164
+ at[n].bond_type[i2] ++;
1165
+ at[i].chem_bonds_valence ++;
1166
+ at[n].chem_bonds_valence ++;
1167
+ at[n].charge += (k? -1:1);
1168
+ }
1169
+ num_changes ++;
1170
+ num_C_minus --;
1171
+ num_C_plus --;
1172
+ num_All -= 2;
1173
+ }
1174
+ }
1175
+ }
1176
+ if ( (!type || 18 == type) && (0 < num_C_plus && 0 < num_C_minus || 0 < num_C_II) ) {
1177
+ int m[2], v[2], j[2], k;
1178
+ for ( i = 0; i < num_atoms; i ++ ) {
1179
+ if ( 0 == at[i].charge && 2 == nNoMetalNumBonds(at, i) && 3 == nNoMetalBondsValence(at, i) &&
1180
+ 0 == num_of_H( at, i ) &&
1181
+ 0 <= (j[0] = nNoMetalNeighIndex( at, i )) &&
1182
+ 0 <= (j[1] = nNoMetalOtherNeighIndex( at, i, m[0] = at[i].neighbor[j[0]] )) &&
1183
+ 0 == at[m[0]].charge
1184
+ +at[m[1]=at[i].neighbor[j[1]]].charge &&
1185
+ 6 == (v[0]=at[m[0]].chem_bonds_valence+NUMH(at,m[0]))
1186
+ +(v[1]=at[m[1]].chem_bonds_valence+NUMH(at,m[1])) &&
1187
+ 2 >= abs(v[0]-v[1]) &&
1188
+ NULL != memchr( en+ELEM_N_FST, at[i].el_number, ELEM_N_LEN) &&
1189
+ NULL != memchr( en+ELEM_C_FST, at[m[0]].el_number, ELEM_C_LEN) &&
1190
+ NULL != memchr( en+ELEM_C_FST, at[m[1]].el_number, ELEM_C_LEN)
1191
+ ) {
1192
+ /* n_Cm i n_Cp */
1193
+ /* found non-terminal C(-)(III)-N=C(+)(III) or C(IV)=N-C(II): Cm-N-Cp */
1194
+ /* convert to C(IV)=N#C(IV) */
1195
+ int n_Cp=-1, n_Cm=-1, i_Cp=-1, i_Cm=-1; /* p = positive, m = negatice ion C */
1196
+ for ( k = 0; k < 2; k ++ ) {
1197
+ n = m[k];
1198
+ if ( v[k] == 4 || v[k] == 3 && at[i].bond_type[j[k]] == BOND_TYPE_SINGLE ) {
1199
+ n_Cm = n;
1200
+ i_Cm = k;
1201
+ } else
1202
+ if ( v[k] == 2 || v[k] == 3 && at[i].bond_type[j[k]] == BOND_TYPE_DOUBLE ) {
1203
+ n_Cp = n;
1204
+ i_Cp = k;
1205
+ }
1206
+ }
1207
+ if ( n_Cp < 0 || n_Cm < 0 || at[n_Cp].valence+NUMH(at,n_Cp) != 2 ) {
1208
+ continue; /* guarantees at[n_Cp].valence <= 2 */
1209
+ }
1210
+ if ( v[i_Cp] == 2 || !at[n_Cp].charge ) {
1211
+ if ( at[n_Cp].valence == 2 ) {
1212
+ /* neighbor of at[n_Cp] opposite to at[i] */
1213
+ k = at[n_Cp].neighbor[at[n_Cp].neighbor[0]==i];
1214
+ if ( NULL != memchr( en+ELEM_N_FST, at[k].el_number, ELEM_N_LEN) ) {
1215
+ continue;
1216
+ }
1217
+ }
1218
+ } else
1219
+ if ( at[n_Cp].charge ) {
1220
+ if ( has_other_ion_in_sphere_2(at, n_Cp, n_Cm, en, ne ) ||
1221
+ has_other_ion_in_sphere_2(at, n_Cm, n_Cp, en, ne )) {
1222
+ continue;
1223
+ }
1224
+ } else {
1225
+ continue; /* unknown case */
1226
+ }
1227
+ /* */
1228
+ /* C(-)(III)-N=C(+)(III) => C(IV)=N#C(IV) */
1229
+ /* C(IV)=N-C(II) => C(IV)=N#C(IV) */
1230
+ if ( at[n_Cp].charge ) {
1231
+ num_C_minus --;
1232
+ num_C_plus --;
1233
+ num_All -= 2;
1234
+ } else {
1235
+ num_C_II --;
1236
+ num_All --;
1237
+ }
1238
+
1239
+ for ( k = 0; k < 2; k ++ ) {
1240
+ n = k? n_Cp : n_Cm;
1241
+ i1 = k? j[i_Cp] : j[i_Cm];
1242
+ if ( v[i1] < 4 ) {
1243
+ int delta = 4 - v[i1];
1244
+ i2 = is_in_the_list( at[n].neighbor, (AT_NUMB)i, at[n].valence ) - at[n].neighbor;
1245
+ at[i].bond_type[i1] += delta;
1246
+ at[n].bond_type[i2] += delta;
1247
+ at[i].chem_bonds_valence += delta;
1248
+ at[n].chem_bonds_valence += delta;
1249
+ at[n].charge = 0;
1250
+ at[n].radical = 0;
1251
+ }
1252
+ }
1253
+ at[i].charge = 0;
1254
+ at[i].radical = 0;
1255
+ num_changes ++;
1256
+ }
1257
+ }
1258
+ }
1259
+ }
1260
+
1261
+ return num_changes;
1262
+ }
1263
+
1264
+ /*#if( DISCONNECT_SALTS == 1 )*/ /* { */
1265
+ /*************************************************************************************************/
1266
+ int RemoveInpAtBond( inp_ATOM *atom, int iat, int k )
1267
+ {
1268
+ int i, j, m, m2, k2;
1269
+ inp_ATOM *at = atom + iat;
1270
+ inp_ATOM *at2;
1271
+ int val = at->valence - 1;
1272
+ if ( val >= 0 ) {
1273
+ int bond = at->bond_type[k];
1274
+ if ( bond > BOND_TYPE_TRIPLE )
1275
+ bond = BOND_TYPE_SINGLE; /* added 08-06-2003 */
1276
+
1277
+ /* update CML tetrahedral atom parity. */
1278
+ if ( at->p_parity ) {
1279
+ for( m = 0; m < MAX_NUM_STEREO_ATOM_NEIGH; m ++ ) {
1280
+ if ( at->p_orig_at_num[m] == at->orig_at_number ) {
1281
+ at->p_parity = 0;
1282
+ break; /* only 3 bonds are present; removing one bond removes stereo */
1283
+ }
1284
+ }
1285
+ if ( at->p_parity /* at->valence == MAX_NUM_STEREO_ATOM_NEIGH*/ ) {
1286
+ for ( m = 0; m < at->valence; m ++ ) {
1287
+ if ( atom[(int)at->neighbor[k]].orig_at_number == at->p_orig_at_num[m] ) {
1288
+ break;
1289
+ }
1290
+ }
1291
+ if ( m < at->valence ) {
1292
+ at->p_orig_at_num[m] = at->orig_at_number;
1293
+ } else {
1294
+ at->p_parity = 0; /* wrong neighbors: at->neighbor[k] is not in the list of a stereo neighbors */
1295
+ }
1296
+ }
1297
+ }
1298
+
1299
+ /* update CML stereogenic bond parities; at this point no removed explicit H exist yet */
1300
+ if ( at->sb_parity[0] ) {
1301
+ for ( m = 0; m < MAX_NUM_STEREO_BONDS && at->sb_parity[m]; ) {
1302
+ if ( k == at->sb_ord[m] || k == at->sn_ord[m] && val < 2 && ATOM_PARITY_WELL_DEF(at->sb_parity[m]) ) {
1303
+ /* !!! FLAW: does take into account removed H !!! */
1304
+ /* stereogenic bond is being removed OR */
1305
+ /* remove stereogenic bond because its only neighbor is being removed */
1306
+ int pnxt_atom, pinxt2cur, pinxt_sb_parity_ord;
1307
+ int len= get_opposite_sb_atom( atom, iat, at->sb_ord[m], &pnxt_atom, &pinxt2cur, &pinxt_sb_parity_ord );
1308
+ if ( len ) {
1309
+ i = pinxt_sb_parity_ord;
1310
+ at2 = atom + pnxt_atom;
1311
+ k2 = pinxt2cur;
1312
+ } else {
1313
+ i = MAX_NUM_STEREO_BONDS;
1314
+ }
1315
+ /*
1316
+ at2 = atom + at->neighbor[ (int)at->sb_ord[m] ];
1317
+ for ( i = 0; i < MAX_NUM_STEREO_BONDS && at2->sb_parity[i]; i ++ ) {
1318
+ if ( iat == at2->neighbor[ (int)at2->sb_ord[i] ] )
1319
+ break;
1320
+ }
1321
+ */
1322
+ if ( i < MAX_NUM_STEREO_BONDS && at2->sb_parity[i] ) {
1323
+ m2 = i;
1324
+ /* remove bond parity from at */
1325
+ if ( m < MAX_NUM_STEREO_BONDS-1 ) {
1326
+ memmove( at->sb_parity+m, at->sb_parity+m+1, (MAX_NUM_STEREO_BONDS-1 - m) * sizeof(at->sb_parity[0]));
1327
+ memmove( at->sb_ord+m, at->sb_ord+m+1, (MAX_NUM_STEREO_BONDS-1 - m) * sizeof(at->sb_ord[0]));
1328
+ memmove( at->sn_ord+m, at->sn_ord+m+1, (MAX_NUM_STEREO_BONDS-1 - m) * sizeof(at->sn_ord[0]));
1329
+ memmove( at->sn_orig_at_num+m, at->sn_orig_at_num+m+1, (MAX_NUM_STEREO_BONDS-1 - m) * sizeof(at->sn_orig_at_num[0]));
1330
+ }
1331
+ at->sb_parity[MAX_NUM_STEREO_BONDS-1] = 0;
1332
+ at->sb_ord[MAX_NUM_STEREO_BONDS-1] = 0;
1333
+ at->sn_ord[MAX_NUM_STEREO_BONDS-1] = 0;
1334
+ at->sn_orig_at_num[MAX_NUM_STEREO_BONDS-1] = 0;
1335
+ /* remove bond parity from at2 */
1336
+ if ( m2 < MAX_NUM_STEREO_BONDS-1 ) {
1337
+ memmove( at2->sb_parity+m2, at2->sb_parity+m2+1, (MAX_NUM_STEREO_BONDS-1 - m2) * sizeof(at2->sb_parity[0]));
1338
+ memmove( at2->sb_ord+m2, at2->sb_ord+m2+1, (MAX_NUM_STEREO_BONDS-1 - m2) * sizeof(at2->sb_ord[0]));
1339
+ memmove( at2->sn_ord+m2, at2->sn_ord+m2+1, (MAX_NUM_STEREO_BONDS-1 - m2) * sizeof(at2->sn_ord[0]));
1340
+ memmove( at2->sn_orig_at_num+m2, at2->sn_orig_at_num+m2+1, (MAX_NUM_STEREO_BONDS-1 - m2) * sizeof(at2->sn_orig_at_num[0]));
1341
+ }
1342
+ at2->sb_parity[MAX_NUM_STEREO_BONDS-1] = 0;
1343
+ at2->sb_ord[MAX_NUM_STEREO_BONDS-1] = 0;
1344
+ at2->sn_ord[MAX_NUM_STEREO_BONDS-1] = 0;
1345
+ at2->sn_orig_at_num[MAX_NUM_STEREO_BONDS-1] = 0;
1346
+ /* do not increment m here because the array elements have been shifted */
1347
+ } else {
1348
+ m ++; /* program error: inconsistent stereobond parity */
1349
+ }
1350
+ } else
1351
+ if ( k == at->sn_ord[m] ) {
1352
+ /* stereogenic bond neighbor is being removed; another neighbor remains */
1353
+ /* !!! FLAW: does take into account removed H !!! */
1354
+ for ( j = 0, i = -1; j < at->valence; j ++ ) {
1355
+ if ( j != k && j != at->sb_ord[m] ) {
1356
+ i = j;
1357
+ break;
1358
+ }
1359
+ }
1360
+ /* i is the position of the neighbor that will become a new neighbor */
1361
+ /***************************************************************************
1362
+ * at->sb_parity[m] is the direction (EVEN=clockwise, ODD=counterclockwise)
1363
+ * from stereobond to the neighbor. If the neighbor is removed then
1364
+ * the parity should invert, otherwise it should be unchanged.
1365
+ ***************************************************************************/
1366
+ if ( i < 0 ) {
1367
+ /* no alternative neighbor is available */
1368
+ if ( ATOM_PARITY_WELL_DEF(at->sb_parity[m] ) ) {
1369
+ /* parity cannot be not well-defined anymore */
1370
+ int pnxt_atom, pinxt2cur, pinxt_sb_parity_ord;
1371
+ int len= get_opposite_sb_atom( atom, iat, at->sb_ord[m], &pnxt_atom, &pinxt2cur, &pinxt_sb_parity_ord );
1372
+ if ( len > 0 ) {
1373
+ atom[pnxt_atom].sb_parity[pinxt_sb_parity_ord] = at->sb_parity[m] = AB_PARITY_UNDF;
1374
+ }
1375
+ #ifdef _DEBUG
1376
+ else {
1377
+ int stop = 1; /* sb parities error */
1378
+ }
1379
+ #endif
1380
+ }
1381
+ at->sn_ord[m] = -99; /* sb neighbor has been disconnected */
1382
+ at->sb_ord[m] -= (at->sb_ord[m] > k); /* same as above */
1383
+ at->sn_orig_at_num[m] = 0;
1384
+ } else
1385
+ if ( i < at->valence ) {
1386
+ /* choose another stereogenic bond neighbor, its ord. number is i before bond removal */
1387
+ if ( ATOM_PARITY_WELL_DEF(at->sb_parity[m]) ) {
1388
+ /* ALL WRONG: 'move' previous stereo bond neighbor to the last position (pos. 2 out of 0,1,2) */
1389
+ /* the parity of the transpositions is (2 - at->sn_ord[m])%2 = at->sn_ord[m] % 2 */
1390
+ /* and replace the neighbor with another; the contribution to the parity is 1 */
1391
+
1392
+ /*at->sb_parity[m] = 2 - ( at->sb_parity[m] + at->sn_ord[m] + 1 ) % 2;*/
1393
+
1394
+ /*at->sb_parity[m] = 2 - ( at->sb_parity[m] + k + i +
1395
+ (i > k) + (i > at->sb_ord[m]) ) % 2;*/
1396
+ /*=== parity should be INVERTED ===*/
1397
+ at->sb_parity[m] = 3 - at->sb_parity[m];
1398
+ }
1399
+ at->sn_ord[m] = i - (i > k); /* ord. number shifted because preceding bond is removed */
1400
+ at->sb_ord[m] -= (at->sb_ord[m] > k); /* same as above */
1401
+ at->sn_orig_at_num[m] = atom[(int)at->neighbor[i]].orig_at_number;
1402
+ /*at->sb_parity[m] = 2 - ( at->sb_parity[m] + 1 ) % 2;*/
1403
+ } else {
1404
+ at->sb_parity[m] = 0; /* program error: inconsistent stereobond parity */
1405
+ }
1406
+ m ++;
1407
+ } else {
1408
+ /* removing another neighbor, k: first move it to the last position (pos. 2 out of 0,1,2) */
1409
+ if ( k < 2 && ATOM_PARITY_WELL_DEF(at->sb_parity[m]) ) {
1410
+ /*at->sb_parity[m] = 2 - ( at->sb_parity[m] + k ) % 2;*/
1411
+ /*at->sb_parity[m] = 2 - ( at->sb_parity[m] + (at->sn_ord[m] > k) + (at->sb_ord[m] > k) ) % 2;*/
1412
+ ;/*==== Parity should remain UNCHANGED ===*/
1413
+ }
1414
+ if ( at->sb_ord[m] > k ) {
1415
+ at->sb_ord[m] --;
1416
+ }
1417
+ if ( at->sn_ord[m] > k ) {
1418
+ at->sn_ord[m] --;
1419
+ }
1420
+ m ++;
1421
+ }
1422
+ }
1423
+ }
1424
+
1425
+ if ( k < val ) {
1426
+ memmove( at->neighbor+k, at->neighbor+k+1, sizeof(at->neighbor[0])*(val-k) );
1427
+ memmove( at->bond_stereo+k, at->bond_stereo+k+1, sizeof(at->bond_stereo[0])*(val-k) );
1428
+ memmove( at->bond_type+k, at->bond_type+k+1, sizeof(at->bond_type[0])*(val-k) );
1429
+ }
1430
+ at->neighbor[val] = 0;
1431
+ at->bond_stereo[val] = 0;
1432
+ at->bond_type[val] = 0;
1433
+ at->valence = val;
1434
+ at->chem_bonds_valence -= bond;
1435
+ return 1;
1436
+ }
1437
+ return 0;
1438
+ }
1439
+ /*************************************************************************************************/
1440
+ int DisconnectInpAtBond( inp_ATOM *at, AT_NUMB *nOldCompNumber, int iat, int neigh_ord )
1441
+ {
1442
+ int neigh, i, ret = 0;
1443
+ int component;
1444
+ neigh = at[iat].neighbor[neigh_ord];
1445
+ for ( i = 0; i < at[neigh].valence; i ++ ) {
1446
+ if ( iat == (int)at[neigh].neighbor[i] )
1447
+ break;
1448
+ }
1449
+ if ( i < at[neigh].valence ) {
1450
+ ret += RemoveInpAtBond( at, iat, neigh_ord );
1451
+ ret += RemoveInpAtBond( at, neigh, i );
1452
+ if ( nOldCompNumber && ret ) {
1453
+ if ( component = at[iat].component ) {
1454
+ nOldCompNumber[component-1] = 0;
1455
+ }
1456
+ if ( component = at[neigh].component ) {
1457
+ nOldCompNumber[component-1] = 0;
1458
+ }
1459
+ }
1460
+ }
1461
+ return (ret == 2);
1462
+ }
1463
+ /*************************************************************************************************/
1464
+ int bIsAmmoniumSalt( inp_ATOM *at, int i, int *piO, int *pk, S_CHAR *num_explicit_H )
1465
+ {
1466
+ /* NH4(+charge)-O(-charge)-C -> NH3 + HO-C; any charge including 0, any C except charged or radical */
1467
+ /* F, Cl, Br, I */
1468
+ static U_CHAR el_number_C=0, el_number_O=0, el_number_H=0, el_number_N=0;
1469
+ static U_CHAR el_number_F=0, el_number_Cl=0, el_number_Br=0, el_number_I=0;
1470
+ int num_H, num_non_iso_H, num_impl_iso_H, bDisconnect = 1;
1471
+ int j, val, neigh, iO=-1, iC, k=-1;
1472
+ if ( 0 == el_number_C ) {
1473
+ /* one time initialization */
1474
+ el_number_C = get_periodic_table_number( "C" );
1475
+ el_number_O = get_periodic_table_number( "O" );
1476
+ el_number_H = get_periodic_table_number( "H" );
1477
+ el_number_N = get_periodic_table_number( "N" );
1478
+ el_number_F = get_periodic_table_number( "F" );
1479
+ el_number_Cl= get_periodic_table_number( "Cl" );
1480
+ el_number_Br= get_periodic_table_number( "Br" );
1481
+ el_number_I = get_periodic_table_number( "I" );
1482
+ }
1483
+ if ( at[i].el_number != el_number_N )
1484
+ return 0;
1485
+
1486
+ /* check for NH4-O-C... -> NH3 + HO-C... */
1487
+ val = at[i].valence;
1488
+ num_impl_iso_H = NUM_ISO_H(at,i);
1489
+ num_non_iso_H = at[i].num_H;
1490
+ num_H = num_non_iso_H + num_impl_iso_H;
1491
+ if ( val + num_H == 5 ) {
1492
+ int num_O = 0;
1493
+ memset( num_explicit_H, 0, (NUM_H_ISOTOPES+1)*sizeof(num_explicit_H[0]) );
1494
+ for ( j = 0; j < val; j ++ ) { /* looking for O: H4N-O-C... */
1495
+ neigh = at[i].neighbor[j];
1496
+ if ( at[neigh].num_H ||
1497
+ at[neigh].charge && (at[neigh].el_number != el_number_O || at[neigh].charge + at[i].charge) ||
1498
+ at[neigh].radical && at[neigh].radical != RADICAL_SINGLET ) {
1499
+ bDisconnect = 0;
1500
+ break; /* reject */
1501
+ }
1502
+ if ( at[neigh].el_number == el_number_H && at[neigh].valence == 1 &&
1503
+ !at[neigh].charge && !at[neigh].radical ) {
1504
+ num_H ++; /* at this point at[].num_H does not include explicit H count */
1505
+ num_non_iso_H += (0==at[neigh].iso_atw_diff);
1506
+ num_explicit_H[at[neigh].iso_atw_diff] ++; /* explicit H on N */
1507
+ } else
1508
+ if ( at[neigh].el_number == el_number_O && at[neigh].valence == 2 && !num_O ) {
1509
+ num_O ++; /* found O: N-O- */
1510
+ iO = neigh;
1511
+ k = j;
1512
+ iC = at[iO].neighbor[at[iO].neighbor[0] == i];
1513
+ if ( at[iC].el_number != el_number_C || /*
1514
+ at[iC].num_H ||
1515
+ at[iC].chem_bonds_valence != 4 || */
1516
+ at[iC].charge ||
1517
+ at[iC].radical && at[iC].radical != RADICAL_SINGLET /*||
1518
+ at[iC].valence == at[iC].chem_bonds_valence*/ ) {
1519
+ bDisconnect = 0;
1520
+ break; /* reject */
1521
+ }
1522
+ } else
1523
+ if ( (at[neigh].el_number == el_number_F ||
1524
+ at[neigh].el_number == el_number_Cl ||
1525
+ at[neigh].el_number == el_number_Br ||
1526
+ at[neigh].el_number == el_number_I ) &&
1527
+ at[neigh].valence == 1 && at[neigh].chem_bonds_valence == 1 &&
1528
+ !at[neigh].charge && !NUMH(at,neigh) && !num_O ) {
1529
+ num_O ++; /* found O: N-O- */
1530
+ iO = neigh;
1531
+ k = j;
1532
+ iC = -1;
1533
+ } else {
1534
+ bDisconnect = 0;
1535
+ break; /* reject */
1536
+ }
1537
+ }
1538
+ if ( bDisconnect && (num_O != 1 || num_H != 4) ) {
1539
+ bDisconnect = 0; /* reject */
1540
+ }
1541
+ } else {
1542
+ bDisconnect = 0;
1543
+ }
1544
+ if ( bDisconnect ) {
1545
+ *piO = iO;
1546
+ *pk = k;
1547
+ }
1548
+ return bDisconnect;
1549
+ }
1550
+ /*************************************************************************************************/
1551
+ int DisconnectAmmoniumSalt ( inp_ATOM *at, int iN, int iO, int k, S_CHAR *num_explicit_H )
1552
+ {
1553
+ /* disconnect NH4-O from O */
1554
+ /* Note: iO = at[iN].neighbor[k], at[iN] is N, at[iO].neighbor[0] is either N=at[iN] or C=at[iC] */
1555
+ int nMove_H_iso_diff = -1; /* do not move explicit H */
1556
+ int j, neigh, iso_diff, neigh_pos;
1557
+ static U_CHAR el_number_H = 0;
1558
+ int val = at[iN].valence;
1559
+
1560
+ if ( !el_number_H ) {
1561
+ el_number_H = get_periodic_table_number( "H" );
1562
+ }
1563
+ if ( at[iN].charge && !(at[iN].charge + at[iO].charge) ) {
1564
+ at[iN].charge = at[iO].charge = 0; /* remove charges */
1565
+ }
1566
+ neigh_pos = (at[iO].valence == 2)? (at[iO].neighbor[1] == iN) : 0; /* position of at[iN] in the neigh list of iO */
1567
+ /* disconnect bond O-N */
1568
+ RemoveInpAtBond( at, iO, neigh_pos );
1569
+ RemoveInpAtBond( at, iN, k );
1570
+ val --;
1571
+
1572
+ /* move 1 H from NH4 to O- or Cl */
1573
+
1574
+ /* find non-isotopic or the lightest isotopic H to move from N to O */
1575
+ for ( iso_diff = 0; iso_diff <= NUM_H_ISOTOPES; iso_diff ++ ) {
1576
+ if ( !iso_diff ) {
1577
+ /* find non-isotopic H */
1578
+ if ( at[iN].num_H ) {
1579
+ at[iN].num_H --; /* move non-isotopic implicit H */
1580
+ at[iO].num_H ++;
1581
+ break;
1582
+ } else
1583
+ if ( num_explicit_H[0] ) {
1584
+ nMove_H_iso_diff = 0; /* flag: move explicit non-isotopic H */
1585
+ break;
1586
+ }
1587
+ } else {
1588
+ /* find isotopic H */
1589
+ if ( at[iN].num_iso_H[iso_diff] ) {
1590
+ at[iN].num_iso_H[iso_diff] --; /* move implicit isotopic H, atw = 1 */
1591
+ at[iO].num_iso_H[iso_diff] ++;
1592
+ break;
1593
+ } else
1594
+ if ( num_explicit_H[iso_diff] ) {
1595
+ nMove_H_iso_diff = iso_diff; /* flag: move explicit isotopic H, atw = 1 */
1596
+ break;
1597
+ }
1598
+ }
1599
+ }
1600
+ if ( nMove_H_iso_diff >= 0 ) {
1601
+ /* move explicit H, it is isotopic if nMove_H_iso_diff > 0 */
1602
+ double dist2_H_O, min_dist2_H_O = -1.0;
1603
+ int jH = -1, iH = -1;
1604
+ for ( j = 0; j < val; j ++ ) { /* looking H in N-H such that H-O is shortest */
1605
+ neigh = at[iN].neighbor[j];
1606
+ if ( at[neigh].el_number == el_number_H &&
1607
+ at[neigh].iso_atw_diff == nMove_H_iso_diff ) {
1608
+ dist2_H_O = (at[neigh].x - at[iO].x) * (at[neigh].x - at[iO].x) +
1609
+ (at[neigh].y - at[iO].y) * (at[neigh].y - at[iO].y) +
1610
+ (at[neigh].z - at[iO].z) * (at[neigh].z - at[iO].z);
1611
+ if ( min_dist2_H_O < 0.0 || min_dist2_H_O > dist2_H_O ) {
1612
+ min_dist2_H_O = dist2_H_O;
1613
+ iH = neigh;
1614
+ jH = j;
1615
+ }
1616
+ }
1617
+ }
1618
+ /* reconnect; bonds do not need changes except stereo */
1619
+ neigh_pos = at[iO].valence;
1620
+ at[iO].neighbor[neigh_pos] = iH;
1621
+ at[iO].bond_stereo[neigh_pos] = 0;
1622
+ at[iO].bond_type[neigh_pos] = at[iH].bond_type[0];
1623
+ at[iO].chem_bonds_valence += at[iH].bond_type[0];
1624
+ at[iO].valence ++;
1625
+ at[iH].neighbor[0] = iO;
1626
+ at[iH].bond_stereo[0] = 0;
1627
+ /* disconnect H from N */
1628
+ RemoveInpAtBond( at, iN, jH );
1629
+ val --;
1630
+ if ( k > jH ) {
1631
+ k --;
1632
+ }
1633
+ }
1634
+ return 1;
1635
+ }
1636
+ /*************************************************************************************************/
1637
+ int bIsMetalSalt( inp_ATOM *at, int i )
1638
+ {
1639
+ int type, val, k, iO, iC, j, neigh;
1640
+ int bDisconnect = 1;
1641
+ static U_CHAR el_number_C=0, el_number_O=0, el_number_H=0;
1642
+ static U_CHAR el_number_F=0, el_number_Cl=0, el_number_Br=0, el_number_I=0;
1643
+ if ( 0 == el_number_C ) {
1644
+ /* one time initialization */
1645
+ el_number_C = get_periodic_table_number( "C" );
1646
+ el_number_O = get_periodic_table_number( "O" );
1647
+ el_number_H = get_periodic_table_number( "H" );
1648
+ el_number_F = get_periodic_table_number( "F" );
1649
+ el_number_Cl= get_periodic_table_number( "Cl" );
1650
+ el_number_Br= get_periodic_table_number( "Br" );
1651
+ el_number_I = get_periodic_table_number( "I" );
1652
+ }
1653
+ /* check for a metal atom:
1654
+ metal atom should be connected and be a metal */
1655
+ if ( !(val = at[i].valence) ||
1656
+ !(type = get_el_type( at[i].el_number )) ||
1657
+ !(type & IS_METAL) ) {
1658
+ bDisconnect = 0; /* reject */
1659
+ } else
1660
+ /* metal atom should not have adjacent H or multiple bonds or radical */
1661
+ if ( at[i].num_H ) {
1662
+ bDisconnect = 0; /* reject */
1663
+ } else
1664
+ /* check valence */
1665
+ if ( at[i].charge == 0 &&
1666
+ ( (type & 1) && val == get_el_valence( at[i].el_number, 0, 0 ) ||
1667
+ (type & 2) && val == get_el_valence( at[i].el_number, 0, 1 ) ) ||
1668
+ at[i].charge > 0 &&
1669
+ (type & 1) && val == get_el_valence( at[i].el_number, at[i].charge, 0 ) ) {
1670
+ ; /* accept */
1671
+ } else {
1672
+ bDisconnect = 0; /* reject */
1673
+ }
1674
+ if ( bDisconnect ) {
1675
+ /*************************************************************************
1676
+ * | *
1677
+ * check M neighbors. Disconnect if all neighbors are M-O-C# or M-O-C= *
1678
+ * | *
1679
+ *************************************************************************/
1680
+ for ( k = 0; k < at[i].valence; k ++ ) {
1681
+ iO = at[i].neighbor[k];
1682
+ /* halogenide 2004-07-08 */
1683
+ if ( (at[iO].el_number == el_number_F ||
1684
+ at[iO].el_number == el_number_Cl ||
1685
+ at[iO].el_number == el_number_Br ||
1686
+ at[iO].el_number == el_number_I ) &&
1687
+ at[iO].valence == 1 && at[iO].chem_bonds_valence == 1 &&
1688
+ !at[iO].charge && !(at[iO].radical && at[iO].radical != RADICAL_SINGLET) && !NUMH(at,iO) ) {
1689
+ ; /* found */
1690
+ } else {
1691
+ /* -O-C= */
1692
+ if ( at[iO].el_number != el_number_O ||
1693
+ NUMH(at, iO) ||
1694
+ at[iO].valence != 2 ||
1695
+ at[iO].charge ||
1696
+ at[iO].radical && at[iO].radical != RADICAL_SINGLET ||
1697
+ at[iO].valence != at[iO].chem_bonds_valence ) {
1698
+ bDisconnect = 0; /* reject */
1699
+ break;
1700
+ }
1701
+ iC = at[iO].neighbor[at[iO].neighbor[0] == i];
1702
+ if ( at[iC].el_number != el_number_C ||
1703
+ at[iC].num_H ||
1704
+ at[iC].chem_bonds_valence != 4 ||
1705
+ at[iC].charge ||
1706
+ at[iC].radical && at[iC].radical != RADICAL_SINGLET ||
1707
+ at[iC].valence == at[iC].chem_bonds_valence ) {
1708
+ bDisconnect = 0; /* reject */
1709
+ break;
1710
+ }
1711
+ for ( j = 0; j < at[iC].valence; j ++ ) {
1712
+ neigh = at[iC].neighbor[j];
1713
+ if ( at[neigh].el_number == el_number_H ) {
1714
+ break;
1715
+ }
1716
+ }
1717
+ if ( j != at[iC].valence ) {
1718
+ bDisconnect = 0; /* reject */
1719
+ break;
1720
+ }
1721
+ }
1722
+ }
1723
+ }
1724
+ return bDisconnect;
1725
+ }
1726
+ /*************************************************************************************************/
1727
+ int DisconnectMetalSalt( inp_ATOM *at, int i )
1728
+ {
1729
+ int k, iO;
1730
+ /* disconnect metal atom or ion at[i] */
1731
+ for ( k = 0; k < at[i].valence; k ++ ) {
1732
+ iO = at[i].neighbor[k];
1733
+ if ( at[iO].valence == 2 ) {
1734
+ if ( at[iO].neighbor[0] == i ) { /* assuming atom O always has 2 bonds */
1735
+ /* copy the remaining neighbor to the 0 position */
1736
+ at[iO].neighbor[0] = at[iO].neighbor[1];
1737
+ at[iO].bond_stereo[0] = at[iO].bond_stereo[1];
1738
+ at[iO].bond_type[0] = at[iO].bond_type[1];
1739
+ }
1740
+ /* clear neighbor at position 1 */
1741
+ at[iO].neighbor[1] = 0;
1742
+ at[iO].bond_stereo[1] = 0;
1743
+ at[iO].bond_type[1] = 0;
1744
+ } else {
1745
+ /* clear neighbor at position 1 */
1746
+ at[iO].neighbor[0] = 0;
1747
+ at[iO].bond_stereo[0] = 0;
1748
+ at[iO].bond_type[0] = 0;
1749
+ }
1750
+ /* make O negatively charged */
1751
+ at[iO].charge = -1;
1752
+ /* reduce O valence to account for the removed single bond */
1753
+ at[iO].valence --;
1754
+ at[iO].chem_bonds_valence --;
1755
+
1756
+ /* clear metal neighbor (O) */
1757
+ at[i].neighbor[k] = 0;
1758
+ at[i].bond_stereo[k] = 0;
1759
+ at[i].bond_type[k] = 0;
1760
+ /* add a positive charge to the metal */
1761
+ at[i].charge ++;
1762
+ }
1763
+ /* set metal valence to zero because it has been disconnected */
1764
+ at[i].valence = 0;
1765
+ at[i].chem_bonds_valence = 0;
1766
+ return k;
1767
+ }
1768
+
1769
+ /*************************************************************************************************/
1770
+ int DisconnectSalts( ORIG_ATOM_DATA *orig_inp_data, int bDisconnect )
1771
+ {
1772
+ int i, k, iO, num_changes, val;
1773
+ S_CHAR num_explicit_H[NUM_H_ISOTOPES+1];
1774
+ inp_ATOM *at = orig_inp_data->at;
1775
+ int num_at = orig_inp_data->num_inp_atoms;
1776
+
1777
+ /* check each atom */
1778
+ for ( i = 0, num_changes = 0; i < num_at; i ++ ) {
1779
+
1780
+ if ( !(val = at[i].valence) || /* disconnected atom */
1781
+ val != at[i].chem_bonds_valence || /* a bond has higher multiplicity than 1 */
1782
+ at[i].radical && at[i].radical != RADICAL_SINGLET /* radical */ ) {
1783
+ continue; /* reject */
1784
+ }
1785
+ if ( bIsAmmoniumSalt( at, i, &iO, &k, num_explicit_H ) ) {
1786
+ if ( bDisconnect ) {
1787
+ DisconnectAmmoniumSalt ( at, i, iO, k, num_explicit_H );
1788
+ orig_inp_data->num_inp_bonds --;
1789
+ }
1790
+ /* count disconnected atoms */
1791
+ num_changes ++;
1792
+ } else
1793
+ if ( bIsMetalSalt( at, i ) ) {
1794
+ if ( bDisconnect ) {
1795
+ k = DisconnectMetalSalt( at, i );
1796
+ orig_inp_data->num_inp_bonds -= k;
1797
+ }
1798
+ num_changes ++;
1799
+ }
1800
+ }
1801
+ return num_changes;
1802
+ }
1803
+ /*****************************************************************************/
1804
+ /* Important: Salt disconnection is independent from coord. disconnection: */
1805
+ /* because different atoms are disconnected. */
1806
+ /* However, sal disconnection may need to be rerun after metal disconnection */
1807
+ /* because metal disconnection may make certain atoms be eligible for salt */
1808
+ /* disconnection */
1809
+ /*****************************************************************************/
1810
+ int bIsMetalToDisconnect(inp_ATOM *at, int i, int bCheckMetalValence)
1811
+ {
1812
+ int type, at_valence, num_H;
1813
+ /*
1814
+ if ( !at[i].valence )
1815
+ */
1816
+ if ( !(type = get_el_type( at[i].el_number )) ||
1817
+ !(type & IS_METAL ) ) {
1818
+ return 0;
1819
+ }
1820
+ num_H = NUMH(at,i);
1821
+ at_valence = num_H + at[i].chem_bonds_valence;
1822
+ if ( !at_valence ) {
1823
+ return 0; /* nothing to disconnect */
1824
+ }
1825
+ if ( bCheckMetalValence ) {
1826
+ if ( abs(at[i].charge) > 1 ) {
1827
+ return 1; /* multiple charges */
1828
+ }
1829
+ for ( i = 0; i < 2 && (i & type); i ++ ) {
1830
+ if ( at_valence == get_el_valence( at[i].el_number, at[i].charge, i ) ) {
1831
+ return 2; /* atom has normal valence */
1832
+ }
1833
+ }
1834
+ }
1835
+ return 1;
1836
+
1837
+ }
1838
+ /*****************************************************************************/
1839
+ int bMayDisconnectMetals( ORIG_ATOM_DATA *orig_inp_data, int bCheckMetalValence, INCHI_MODE *bTautFlagsDone )
1840
+ {
1841
+ int i, j, k, iO, num_changes, val, bRadOrMultBonds, num_impl_H = 0;
1842
+ S_CHAR num_explicit_H[NUM_H_ISOTOPES+1];
1843
+ inp_ATOM *at = orig_inp_data->at;
1844
+ int num_at = orig_inp_data->num_inp_atoms;
1845
+ int *nNumImplH = &orig_inp_data->bDisconnectCoord;
1846
+ /* check each atom */
1847
+ for ( i = 0, num_changes = 0; i < num_at; i ++ ) {
1848
+
1849
+ if ( !(val = at[i].valence) && !NUMH(at,i) ) {
1850
+ continue; /* disconnected atom */
1851
+ }
1852
+ bRadOrMultBonds = (val == 0) ||
1853
+ (val != at[i].chem_bonds_valence) || /* a bond has higher multiplicity than 1 */
1854
+ (at[i].radical && at[i].radical != RADICAL_SINGLET); /* radical */
1855
+
1856
+ if ( !bRadOrMultBonds && bIsAmmoniumSalt( at, i, &iO, &k, num_explicit_H ) ) {
1857
+ ;
1858
+ } else
1859
+ if ( !bRadOrMultBonds && bIsMetalSalt( at, i ) ) {
1860
+ ;
1861
+ } else
1862
+ if ( 1 == (j = bIsMetalToDisconnect(at, i, bCheckMetalValence)) ) {
1863
+ num_impl_H += NUMH(at,i);
1864
+ num_changes ++;
1865
+ } else
1866
+ if ( 2 == j && bTautFlagsDone ) {
1867
+ *bTautFlagsDone |= TG_FLAG_CHECK_VALENCE_COORD_DONE;
1868
+ }
1869
+ }
1870
+ if ( nNumImplH )
1871
+ *nNumImplH = num_changes? num_impl_H+1 : 0;
1872
+ return num_changes;
1873
+ }
1874
+ /*****************************************************************************/
1875
+ #if( bRELEASE_VERSION == 0 && (EXTR_HAS_METAL_ATOM & (EXTR_MASK | EXTR_FLAG) ) )
1876
+ int bHasMetalAtom( ORIG_ATOM_DATA *orig_inp_data )
1877
+ {
1878
+ int i;
1879
+ inp_ATOM *at;
1880
+ if ( orig_inp_data && (at = orig_inp_data->at) ) {
1881
+ int num_at = orig_inp_data->num_inp_atoms;
1882
+ /* check each atom */
1883
+ for ( i = 0; i < num_at; i ++ ) {
1884
+ if ( IS_METAL & get_el_type( at[i].el_number ) ) {
1885
+ return 1;
1886
+ }
1887
+ }
1888
+ }
1889
+ return 0;
1890
+ }
1891
+ #endif
1892
+ /*****************************************************************************
1893
+ { "F", 19, 19, 18.998403220, 0 , 0, {{0,}, {0,}, {1,}, {2,}, {3,5}, },},
1894
+ { "Cl", 35, 35, 34.968852730, 0 , 0, {{0,}, {0,}, {1,3,5,7}, {2,4,6}, {3,5,}, },},
1895
+ { "Br", 80, 79, 78.918336100, 0 , 0, {{0,}, {0,}, {1,3,5,7,}, {2,4,6,}, {3,5,}, },},
1896
+ { "I", 127, 127, 126.904500000, 0 , 0, {{0,}, {0,}, {1,3,5,7,}, {2,4,6}, {3,5,}, },},
1897
+ { "At", 210, 210, 209.987100000, 0 , 0, {{0,}, {0,}, {1,3,5,7,}, {2,4,6}, {3,5,}, },},
1898
+ { "N", 14, 14, 14.003074000, 0 , 0, {{1,}, {2,}, {3,5}, {4,}, {3,}, },},
1899
+ { "P", 31, 31, 30.973762000, 0 , 0, {{1,3,5,7,}, {2,4,6,}, {3,5,}, {4,}, {3,}, },},
1900
+ { "As", 75, 75, 74.921594200, 0 , 0, {{0,}, {2,4,6,}, {3,5,}, {4,}, {3,}, },},
1901
+ { "Sb", 122, 121, 120.903800000, 0 , 0, {{1,3,5,7,}, {2,4,6,}, {3,5,}, {2,4,}, {3,}, },},
1902
+ { "O", 16, 16, 15.994914630, 0 , 0, {{0,}, {1,}, {2,}, {3,5,}, {4,}, },},
1903
+ { "S", 32, 32, 31.972070700, 0 , 0, {{0,}, {1,3,5,7,}, {2,4,6}, {3,5,}, {4,}, },},
1904
+ { "Se", 79, 80, 79.916519600, 0 , 0, {{0,}, {1,3,5,7,}, {2,4,6,}, {3,5,}, {4,}, },},
1905
+ { "Te", 128, 130, 129.906200000, 0 , 0, {{0,}, {1,3,5,7,}, {2,4,6,}, {3,5,}, {2,4,}, },},
1906
+ { "Po", 209, 209, 208.982400000, 0 , 0, {{0,}, {1,3,5,7,}, {2,4,6,}, {3,5,}, {2,4,}, },},
1907
+ { "B", 11, 11, 11.009300000, 0 , 0, {{3,}, {4,}, {3,}, {2,}, {1,}, },},
1908
+ *****************************************************************************/
1909
+ int DisconnectMetals( ORIG_ATOM_DATA *orig_inp_data, int bCheckMetalValence, INCHI_MODE *bTautFlagsDone )
1910
+ /*inp_ATOM *atom, int num_atoms, int nNumExplH, int *new_num_atoms */
1911
+ {
1912
+ int i, j, k, n, iO, num_changes, val, bRadOrMultBonds;
1913
+ int num_impl_H, num_at, err, num_disconnected;
1914
+ S_CHAR num_explicit_H[NUM_H_ISOTOPES+1];
1915
+ static char elnumber_Heteroat[16] = {'\0', };
1916
+ static int num_halogens;
1917
+ inp_ATOM *at = NULL;
1918
+ S_CHAR *bMetal = NULL;
1919
+ inp_ATOM *atom = orig_inp_data->at;
1920
+ int num_atoms = orig_inp_data->num_inp_atoms;
1921
+ int nNumExplH = (orig_inp_data->bDisconnectCoord > 0)? orig_inp_data->bDisconnectCoord - 1 : 0;
1922
+ AT_NUMB *nOldCompNumber = orig_inp_data->nOldCompNumber;
1923
+
1924
+ err = 0;
1925
+ num_impl_H = 0;
1926
+ num_at = num_atoms;
1927
+ num_disconnected = 0;
1928
+ if ( !(at = (inp_ATOM *)inchi_calloc( num_at + nNumExplH, sizeof(at[0] ) )) ||
1929
+ !(bMetal = ( S_CHAR *)inchi_calloc( num_at + nNumExplH, sizeof(bMetal[0]) )) ) {
1930
+ err = 1;
1931
+ goto exit_function;
1932
+ }
1933
+ if (!elnumber_Heteroat[0] ) {
1934
+ i = 0;
1935
+ /* halogens */
1936
+ elnumber_Heteroat[i++] = (char)get_periodic_table_number( "F" ); /* 0 */
1937
+ elnumber_Heteroat[i++] = (char)get_periodic_table_number( "Cl" );
1938
+ elnumber_Heteroat[i++] = (char)get_periodic_table_number( "Br" );
1939
+ elnumber_Heteroat[i++] = (char)get_periodic_table_number( "I" );
1940
+ elnumber_Heteroat[i++] = (char)get_periodic_table_number( "At" ); /* 4 */
1941
+ num_halogens = i;
1942
+ /* other non-metal */
1943
+ elnumber_Heteroat[i++] = (char)get_periodic_table_number( "N" );
1944
+ elnumber_Heteroat[i++] = (char)get_periodic_table_number( "P" );
1945
+ elnumber_Heteroat[i++] = (char)get_periodic_table_number( "As" );
1946
+ /*elnumber_Heteroat[i++] = get_periodic_table_number( "Sb" );*/ /* metal 10-28-2003 */
1947
+ elnumber_Heteroat[i++] = (char)get_periodic_table_number( "O" );
1948
+ elnumber_Heteroat[i++] = (char)get_periodic_table_number( "S" );
1949
+ elnumber_Heteroat[i++] = (char)get_periodic_table_number( "Se" );
1950
+ elnumber_Heteroat[i++] = (char)get_periodic_table_number( "Te" );
1951
+ /*elnumber_Heteroat[i++] = get_periodic_table_number( "Po" );*/ /* metal 10-28-2003 */
1952
+ elnumber_Heteroat[i++] = (char)get_periodic_table_number( "B" );
1953
+ elnumber_Heteroat[i++] = 0;
1954
+ }
1955
+
1956
+ memcpy( at, atom, num_atoms * sizeof(at[0]) );
1957
+
1958
+ /* check each atom, mark metals */
1959
+ for ( i = 0, k = 0, num_changes = 0; i < num_atoms; i ++ ) {
1960
+
1961
+ if ( !(val = at[i].valence) && !NUMH(at,i) ) {
1962
+ continue; /* disconnected atom */
1963
+ }
1964
+ bRadOrMultBonds = (val == 0) ||
1965
+ (val != at[i].chem_bonds_valence) || /* a bond has higher multiplicity than 1 */
1966
+ (at[i].radical && at[i].radical != RADICAL_SINGLET); /* radical */
1967
+
1968
+ if ( !bRadOrMultBonds && bIsAmmoniumSalt( at, i, &iO, &k, num_explicit_H ) ) {
1969
+ ;
1970
+ } else
1971
+ if ( !bRadOrMultBonds && bIsMetalSalt( at, i ) ) {
1972
+ ;
1973
+ } else
1974
+ if ( 1 == (j = bIsMetalToDisconnect(at, i, bCheckMetalValence)) ) {
1975
+ num_impl_H += (k = NUMH(at,i));
1976
+ bMetal[i] = 1+k;
1977
+ num_changes ++;
1978
+ } else
1979
+ if ( 2 == j && bTautFlagsDone ) {
1980
+ *bTautFlagsDone |= TG_FLAG_CHECK_VALENCE_COORD_DONE;
1981
+ }
1982
+ }
1983
+ if ( num_impl_H != nNumExplH ) {
1984
+ err = 2;
1985
+ goto exit_function;
1986
+ }
1987
+
1988
+
1989
+ /* replace implicit H atoms with explicit H atoms */
1990
+ for ( i = 0; i < num_atoms && 0 < num_impl_H; i ++ ) {
1991
+ if ( bMetal[i] <= 1 ) {
1992
+ continue;
1993
+ }
1994
+ for ( k = 0; k < NUM_H_ISOTOPES+1; k ++ ) {
1995
+ n = k? at[i].num_iso_H[k-1] : at[i].num_H;
1996
+ for ( j = 0; j < n; j ++ ) {
1997
+ if ( num_at >= num_atoms + nNumExplH ) {
1998
+ err = 3;
1999
+ goto exit_function;
2000
+ }
2001
+ at[num_at].elname[0] = 'H';
2002
+ at[num_at].el_number = get_periodic_table_number(at[num_at].elname);
2003
+ at[num_at].iso_atw_diff = k;
2004
+ at[num_at].component = at[i].component;
2005
+ move_explicit_Hcation(at, num_at+1, i, num_at, 1);
2006
+ at[num_at].orig_at_number = num_at+1;
2007
+ num_at ++;
2008
+ num_impl_H --;
2009
+ bMetal[i] --;
2010
+ if ( k ) {
2011
+ at[i].num_iso_H[k-1] --;
2012
+ } else {
2013
+ at[i].num_H --;
2014
+ }
2015
+ }
2016
+ }
2017
+ if ( bMetal[i] != 1 ) {
2018
+ err = 4;
2019
+ goto exit_function;
2020
+ }
2021
+ }
2022
+ if ( num_at != num_atoms + nNumExplH ) {
2023
+ err = 5;
2024
+ goto exit_function;
2025
+ }
2026
+
2027
+ /* disconnect metal - ligand bonds */
2028
+ for ( i = 0; i < num_atoms; i ++ ) {
2029
+ if ( !bMetal[i] ) {
2030
+ continue;
2031
+ }
2032
+ /* disconnect metal atom M
2033
+
2034
+ Note: Defect in case of bridging ligands:
2035
+
2036
+ M M M M M M(+)
2037
+ \ / will be transformed to , not to
2038
+ N(+) N(+) N(-)
2039
+ / \ / \ / \
2040
+ R R R R R R
2041
+
2042
+ Non-bridging are OK:
2043
+
2044
+ M R M(+) R
2045
+ \ / /
2046
+ N(+) ---> N
2047
+ / \ / \
2048
+ R R R R
2049
+
2050
+ */
2051
+ for ( j = at[i].valence-1; 0 <= j; j -- ) {
2052
+ if ( j < at[i].valence && !bMetal[ (int)at[i].neighbor[j] ] ) {
2053
+ /* do not break metal-metal bond here */
2054
+ num_disconnected += DisconnectOneLigand( at, nOldCompNumber, bMetal, elnumber_Heteroat,
2055
+ num_halogens, num_atoms, i, j, bTautFlagsDone );
2056
+ }
2057
+ }
2058
+ }
2059
+ /* disconnect metal-metal bonds */
2060
+ for ( i = 0; i < num_atoms; i ++ ) {
2061
+ if ( !bMetal[i] ) {
2062
+ continue;
2063
+ }
2064
+ for ( j = at[i].valence-1; 0 <= j; j -- ) {
2065
+ if ( j < at[i].valence && bMetal[ (int)at[i].neighbor[j] ] ) {
2066
+ /* break metal-metal bond here */
2067
+ num_disconnected += DisconnectOneLigand( at, nOldCompNumber, bMetal, elnumber_Heteroat,
2068
+ num_halogens, num_atoms, i, j, bTautFlagsDone );
2069
+ }
2070
+ }
2071
+ }
2072
+
2073
+
2074
+ exit_function:
2075
+ if ( !num_disconnected ) {
2076
+ err = 6;
2077
+ }
2078
+ if ( at && err ) {
2079
+ inchi_free( at );
2080
+ at = NULL;
2081
+ }
2082
+ if ( atom && at ) { /* changed if ( at ) to if ( atom && at ) 2004-04-03 */
2083
+ inchi_free( atom );
2084
+ atom = NULL;
2085
+ }
2086
+ if ( bMetal )
2087
+ inchi_free( bMetal );
2088
+
2089
+ if ( at ) {
2090
+ orig_inp_data->at = at;
2091
+ orig_inp_data->num_inp_atoms = num_at;
2092
+ }
2093
+ return err? -err : num_disconnected;
2094
+ }
2095
+ /*****************************************************************************/
2096
+ int DisconnectOneLigand( inp_ATOM *at, AT_NUMB *nOldCompNumber, S_CHAR *bMetal, char *elnumber_Heteroat,
2097
+ int num_halogens, int num_atoms, int iMetal, int jLigand, INCHI_MODE *bTautFlagsDone )
2098
+ {
2099
+ int i, j, iLigand, neigh, val;
2100
+ int metal_neigh_ord[MAXVAL], num_neigh_arom_bonds[MAXVAL];
2101
+ int num_metal_neigh, num_disconnections;
2102
+ int num_del_arom_bonds, num_tot_arom_bonds, new_charge;
2103
+ char *p;
2104
+
2105
+ iLigand = at[iMetal].neighbor[jLigand];
2106
+ num_metal_neigh = 0;
2107
+ num_disconnections = 0;
2108
+ num_del_arom_bonds = num_tot_arom_bonds = 0;
2109
+
2110
+ /* find bonds to disconnect */
2111
+ for ( i = 0; i < at[iLigand].valence; i ++ ) {
2112
+ num_neigh_arom_bonds[i] = 0;
2113
+ neigh = (int)at[iLigand].neighbor[i];
2114
+ if ( neigh < num_atoms && bMetal[ neigh ] ) {
2115
+ metal_neigh_ord[ num_metal_neigh ++ ] = i;
2116
+ if ( at[iLigand].bond_type[i] > BOND_TYPE_TRIPLE ) {
2117
+ /* aromatic bond */
2118
+ for ( j = 0; j < at[neigh].valence; j ++ ) {
2119
+ num_neigh_arom_bonds[i] += ( at[neigh].bond_type[j] > BOND_TYPE_TRIPLE );
2120
+ }
2121
+ num_del_arom_bonds ++;
2122
+ }
2123
+ }
2124
+ num_tot_arom_bonds += (at[iLigand].bond_type[i] > BOND_TYPE_TRIPLE);
2125
+ }
2126
+ /* Disconnect */
2127
+ if ( num_del_arom_bonds ) {
2128
+ /* fix chem_valence of the ligand and its neighbors in case of disconnecting arom. bonds */
2129
+ /* because in this case special care should be taken of updating at[].chem_bonds_valence */
2130
+ for ( i = 0; i < num_metal_neigh; i ++ ) {
2131
+ j = metal_neigh_ord[i];
2132
+ if ( num_neigh_arom_bonds[j] ) {
2133
+ neigh = at[iLigand].neighbor[j];
2134
+ at[neigh].chem_bonds_valence -= num_neigh_arom_bonds[j]/2 - (num_neigh_arom_bonds[j]-1)/2;
2135
+ }
2136
+ }
2137
+ at[iLigand].chem_bonds_valence -= num_tot_arom_bonds/2 - (num_tot_arom_bonds-num_del_arom_bonds)/2;
2138
+ }
2139
+ /* disconnect in reverse order, otherwise the metal_neigh_ord[i]
2140
+ becomes invalid after the first disconnection
2141
+ */
2142
+ for ( i = num_metal_neigh-1; 0 <= i; i -- ) {
2143
+ num_disconnections += DisconnectInpAtBond( at, nOldCompNumber, iLigand, metal_neigh_ord[i] );
2144
+ }
2145
+
2146
+ /* attempt to change ligand charge to make its valence 'natural' */
2147
+ i = num_tot_arom_bonds - num_del_arom_bonds;
2148
+ if ( i && i != 2 && i != 3 ||
2149
+ at[iLigand].radical && at[iLigand].radical != RADICAL_SINGLET ||
2150
+ !(p = strchr( elnumber_Heteroat, at[iLigand].el_number ) ) ) {
2151
+ goto exit_function; /* non-standard atom */
2152
+ }
2153
+ val = at[iLigand].chem_bonds_valence + NUMH(at, iLigand);
2154
+ new_charge = MAX_ATOMS; /* impossible value */
2155
+ if ( !val ) {
2156
+ if ( p - elnumber_Heteroat < num_halogens ) {
2157
+ new_charge = -1;
2158
+ }
2159
+ } else {
2160
+ for ( i = -1; i <= 1; i ++ ) {
2161
+ if ( val == get_el_valence( at[iLigand].el_number, i, 0 ) ) {
2162
+ new_charge = i; /* found charge that fits chem. valence */
2163
+ break;
2164
+ }
2165
+ }
2166
+ }
2167
+ if ( new_charge != MAX_ATOMS ) {
2168
+ if ( (new_charge != at[iLigand].charge ||
2169
+ (at[iLigand].radical && at[iLigand].radical != RADICAL_SINGLET)) &&
2170
+ 1 == num_metal_neigh ) {
2171
+ if ( 1 == new_charge && 4 == val && 2 == at[iLigand].valence &&
2172
+ 4 == at[iLigand].chem_bonds_valence &&
2173
+ at[iLigand].bond_type[0] == at[iLigand].bond_type[1] ) {
2174
+ ; /* do not add +1 charge to disconnected =N=, etc. 2004-10-27 */
2175
+ } else {
2176
+ if ( bTautFlagsDone && new_charge != at[iLigand].charge ) {
2177
+ *bTautFlagsDone |= TG_FLAG_MOVE_CHARGE_COORD_DONE;
2178
+ }
2179
+ at[iMetal].charge -= new_charge - at[iLigand].charge;
2180
+ at[iLigand].charge = new_charge;
2181
+ /*at[iLigand].radical = 0;*/
2182
+ }
2183
+ }
2184
+ }
2185
+ exit_function:
2186
+ return num_disconnections; /* ret;*/
2187
+ }
2188
+
2189
+ /****************************************************************************************/
2190
+ double dist3D( inp_ATOM *at1, inp_ATOM *at2 )
2191
+ {
2192
+ double dx = at1->x - at2->x;
2193
+ double dy = at1->y - at2->y;
2194
+ double dz = at1->z - at2->z;
2195
+ return sqrt( dx*dx+dy*dy+dz*dz );
2196
+ }
2197
+ /****************************************************************************************/
2198
+ #define MIN_BOND_LENGTH (1.0e-6)
2199
+ #define MIN_COS (1.0e-6)
2200
+ #define MIN_BOND_LENGTH2 (MIN_BOND_LENGTH*MIN_BOND_LENGTH)
2201
+ #define MAX_BOND_LENGTH (1.0e30)
2202
+ /****************************************************************************************/
2203
+ double GetMinDistDistribution( inp_ATOM *at, int num_at, int iat, int iat_H,
2204
+ int bInAllComponents, double min_dist[], int num_segm )
2205
+ {
2206
+ const double one_pi = 2.0*atan2(1.0 /* y */, 0.0 /* x */);
2207
+ const double two_pi = 2.0*one_pi;
2208
+ const double f_step = two_pi / num_segm;
2209
+ const double h_step = f_step/2.0;
2210
+
2211
+ int i, j, k, kk, ki, kn, n, num_bonds;
2212
+ double xi, yi, xn, yn, cross_prod_in, dot_prod_in, xni, yni, rni, tni, rmin;
2213
+ double fi, fk, fn, ft, rt, rk, ri, rn, c, ave_bond_len;
2214
+
2215
+ for ( i = 0; i < num_segm; i ++ ) {
2216
+ min_dist[i] = MAX_BOND_LENGTH; /* more than any distance */
2217
+ }
2218
+ num_bonds = 0;
2219
+ ave_bond_len = 0.0;
2220
+ for ( i = 0; i < num_at; i ++ ) {
2221
+ if ( i != iat && i != iat_H && (bInAllComponents || at[i].component == at[iat].component) ) {
2222
+ for ( j = 0; j < at[i].valence; j ++ ) {
2223
+ n = at[i].neighbor[j];
2224
+ if ( (n > i && n != iat) || n == iat_H )
2225
+ continue;
2226
+ #if( bRELEASE_VERSION != 1 && defined(_DEBUG) )
2227
+ if ( n == iat ) {
2228
+ int stop = 1; /* <BRKPT> */
2229
+ }
2230
+ #endif
2231
+ xi = at[i].x - at[iat].x; /* ri; i != iat */
2232
+ yi = at[i].y - at[iat].y;
2233
+ xn = at[n].x - at[iat].x; /* rn; possibly n == iat */
2234
+ yn = at[n].y - at[iat].y;
2235
+ cross_prod_in = xi*yn - xn*yi; /* ((r(i)-r(iat)) x (r(n)-r(iat)) */
2236
+ if ( cross_prod_in < -0.01*MIN_BOND_LENGTH2 ) {
2237
+ /* make sure the r(i)->r(n) vector is counterclockwise around at[iat] */
2238
+ swap( (char*)&xi, (char*)&xn, sizeof(xi) );
2239
+ swap( (char*)&yi, (char*)&yn, sizeof(yi) );
2240
+ cross_prod_in = -cross_prod_in;
2241
+ }
2242
+ xni = xn - xi; /* r(n)->r(i) */
2243
+ yni = yn - yi;
2244
+ rni = xni*xni + yni*yni;
2245
+ if ( rni > 0.01*MIN_BOND_LENGTH2 ) {
2246
+ /* vector length |ri->rn| is not too small */
2247
+ /* arrowhead of the vector r(t) = ri + (rn-ri)*t; 0 <= t <= 1 points to the bond ri->rn */
2248
+ /* r(tni) is perpendicular to the bond ri->rn so that min|r(t)| = r(tni) = |tni|*rni */
2249
+ tni = -(xni*xi + yni*yi)/rni;
2250
+ /* find min. distance from n-i bond to at[iat] */
2251
+ if ( tni < 0.0 ) {
2252
+ rmin = sqrt( xi*xi + yi*yi );
2253
+ } else
2254
+ if ( tni > 1.0 ) {
2255
+ rmin = sqrt( xn*xn + yn*yn );
2256
+ } else {
2257
+ rmin = sqrt(tni*tni*rni);
2258
+ }
2259
+ ave_bond_len += sqrt( rni );
2260
+ num_bonds ++;
2261
+ } else {
2262
+ /* zero length i-n bond */
2263
+ tni = 0.5; /* fake */
2264
+ rmin = sqrt( xi*xi + yi*yi ); /* arbitrarily choose one */
2265
+ }
2266
+ if ( rmin >= 0.1*MIN_BOND_LENGTH ) {
2267
+ /* at[iat] does not belong to at[i]-at[n] bond */
2268
+ int bCalc_rt = 1;
2269
+ fi = atan2( yi, xi );
2270
+ fn = (n == iat)? fi : atan2( yn, xn );
2271
+ if ( fi > fn ) {
2272
+ /* make sure fn - fi >= 0 */
2273
+ fn += two_pi;
2274
+ }
2275
+ if ( fi < 0.0 ) {
2276
+ fi += two_pi;
2277
+ fn += two_pi;
2278
+ }
2279
+ ki = (int)floor((fi+h_step)/f_step); /* cast does not match function type */
2280
+ kn = (int)floor((fn+h_step)/f_step);
2281
+ /* the bond may affect several segments */
2282
+ for ( k = ki; k <= kn; k ++ ) {
2283
+ kk = k % num_segm;
2284
+ if ( min_dist[kk] < rmin )
2285
+ continue;
2286
+ if ( bCalc_rt ) {
2287
+ if ( n == iat ) {
2288
+ ft = fi;
2289
+ rt = rmin;
2290
+ } else {
2291
+ double xt, yt;
2292
+ xt = xi + xni*tni;
2293
+ yt = yi + yni*tni;
2294
+ ft = atan2( yt, xt );
2295
+ rt = sqrt(xt*xt + yt*yt);
2296
+ }
2297
+ bCalc_rt = 0;
2298
+ }
2299
+ fk = f_step * kk;
2300
+ c = fabs(cos( fk - ft ));
2301
+ if ( c < MIN_COS )
2302
+ c = MIN_COS;
2303
+ rk = rt / c;
2304
+ if ( min_dist[kk] > rk ) {
2305
+ min_dist[kk] = rk;
2306
+ }
2307
+ }
2308
+ } else {
2309
+ /* rmin < 0.1*MIN_BOND_LENGTH */
2310
+ ri = xi*xi + yi*yi;
2311
+ rn = xn*xn + yn*yn;
2312
+ if ( ri > MIN_BOND_LENGTH2 && rn > MIN_BOND_LENGTH2 ) {
2313
+ dot_prod_in = xn*xi + yn*yi;
2314
+ /* a very short bond */
2315
+ if ( dot_prod_in > 0.01*MIN_BOND_LENGTH2 ) {
2316
+ /* bond does not cross at[iat] */
2317
+ double fyixi = atan2( yi, xi );
2318
+ if ( fyixi < 0.0 ) fyixi += two_pi;
2319
+ kk = (int)floor((fyixi+h_step)/f_step) % num_segm;
2320
+ if ( min_dist[kk] > rmin ) {
2321
+ min_dist[kk] = rmin;
2322
+ }
2323
+ } else
2324
+ if ( dot_prod_in < -0.01*MIN_BOND_LENGTH2 ) {
2325
+ /* bond does cross at[iat] */
2326
+ double fyixi = atan2( yi, xi );
2327
+ if ( fyixi < 0.0 ) fyixi += two_pi;
2328
+ kk = (int)floor((fyixi+h_step)/f_step) % num_segm;
2329
+ if ( min_dist[kk] > rmin ) {
2330
+ min_dist[kk] = rmin;
2331
+ }
2332
+ fyixi += one_pi;
2333
+ kk = (int)floor((fyixi+h_step)/f_step) % num_segm;
2334
+ if ( min_dist[kk] > rmin ) {
2335
+ min_dist[kk] = rmin;
2336
+ }
2337
+ } else {
2338
+ ; /* error, should not happen */
2339
+ }
2340
+ } else
2341
+ if ( ri <= MIN_BOND_LENGTH2 && rn <= MIN_BOND_LENGTH2 ) {
2342
+ /* a very short bond coincides with at[iat]; ignore */
2343
+ ;
2344
+ } else {
2345
+ /* one end of the bond coincides with at[iat] */
2346
+ fi = ri>rn? atan2( yi, xi) : atan2( yn, xn );
2347
+ if ( fi < 0.0 ) fi += two_pi;
2348
+ kk = (int)floor((fi+h_step)/f_step) % num_segm;
2349
+ if ( min_dist[kk] > rmin ) {
2350
+ min_dist[kk] = rmin;
2351
+ }
2352
+ }
2353
+ }
2354
+ }
2355
+ }
2356
+ }
2357
+ if ( num_bonds ) {
2358
+ return ave_bond_len / (double)num_bonds;
2359
+ } else {
2360
+ return 0.0;
2361
+ }
2362
+ }
2363
+
2364
+ /****************************************************************************************/
2365
+ int move_explicit_Hcation(inp_ATOM *at, int num_at, int iat, int iat_H, int bInAllComponents)
2366
+ {
2367
+ #define NUM_SEGM 20
2368
+ const double one_pi = 2.0*atan2(1.0 /* y */, 0.0 /* x */);
2369
+ const double two_pi = 2.0*one_pi;
2370
+ const double f_step = two_pi / NUM_SEGM;
2371
+ const double h_step = f_step/2.0;
2372
+ double min_dist[NUM_SEGM];
2373
+ int nB, i, k, kk, next, val;
2374
+ double r, r0, xd, yd, zd, xr, yr, zr, ave_bond_len;
2375
+ /*double step = 4.0*atan(1.0)/NUM_SEGM;*/
2376
+ /* find at[iat] neighbors coordinates */
2377
+ xd=yd=zd=0.0;
2378
+ if ( at[iat].valence ) {
2379
+ for ( i = 0, nB=0, r = 0.0; i < at[iat].valence; i ++ ) {
2380
+ next = at[iat].neighbor[i];
2381
+ xd += at[next].x;
2382
+ yd += at[next].y;
2383
+ zd += at[next].z;
2384
+ r += dist3D( at+iat, at+next );
2385
+ nB ++;
2386
+ }
2387
+ xd /= (double)nB;
2388
+ yd /= (double)nB;
2389
+ zd /= (double)nB;
2390
+ r /= (double)nB;
2391
+ r0 = sqrt((double)(xd-at[iat].x)*(xd-at[iat].x)
2392
+ + (double)(yd-at[iat].y)*(yd-at[iat].y));
2393
+ } else {
2394
+ if ( at[iat_H].valence ) {
2395
+ r = dist3D( at+iat_H, at+ (int)at[iat_H].neighbor[0] );
2396
+ } else {
2397
+ r = 0.0;
2398
+ }
2399
+ r0 = 0.0;
2400
+ }
2401
+ ave_bond_len = GetMinDistDistribution( at, num_at, iat, iat_H, bInAllComponents, min_dist, NUM_SEGM );
2402
+ if ( r < MIN_BOND_LENGTH && ave_bond_len > MIN_BOND_LENGTH ) {
2403
+ r = ave_bond_len; /* ave_bond_len = 0.0 may mean that it is 0D structure */
2404
+ }
2405
+ if ( r > MIN_BOND_LENGTH ) {
2406
+ /* process non-zero bond lengths */
2407
+ double f;
2408
+ if ( 10.0*r0 < r ) {
2409
+ xr = -r; /* arbitrary */
2410
+ yr = 0.0;
2411
+ zr = 0.0;
2412
+ } else {
2413
+ /*
2414
+ if ( r0 < MIN_BOND_LENGTH ) {
2415
+ r0 = 1.0;
2416
+ }
2417
+ */
2418
+ xr = r * ( at[iat].x - xd )/r0;
2419
+ yr = r * ( at[iat].y - yd )/r0; /* length = r */
2420
+ zr = r * ( at[iat].z - zd )/r0;
2421
+
2422
+ /* -- test: opposire direction --
2423
+ xr = -r * ( at[iat].x - xd )/r0;
2424
+ yr = -r * ( at[iat].y - yd )/r0;
2425
+ zr = -r * ( at[iat].z - zd )/r0;
2426
+ */
2427
+ if ( xr*xr + yr*yr < 0.04*r*r ) {
2428
+ xr = -r;
2429
+ yr = 0.0;
2430
+ }
2431
+ }
2432
+ r = sqrt( xr*xr + yr*yr );
2433
+ f = atan2( yr, xr );
2434
+
2435
+ if ( f < 0.0 )
2436
+ f += two_pi;
2437
+
2438
+
2439
+
2440
+ kk = (int)floor((f+h_step)/f_step) % NUM_SEGM; /* cast does not match function type by design */
2441
+ if ( min_dist[kk] < 1.5* r ) {
2442
+ double dist = 1.5*r;
2443
+ int start=-1, len=0, start_max=-1, len_max=0;
2444
+ again:
2445
+ /* look for longest kk interval with min_dist[kk] >= dist */
2446
+ for ( k = 0, start = 0, len = 0, len_max = 0; k < 2*NUM_SEGM; k ++ ) {
2447
+ kk = k % NUM_SEGM;
2448
+ if ( min_dist[kk] >= dist ) {
2449
+ if ( !len ++) {
2450
+ start = k;
2451
+ }
2452
+ } else {
2453
+ if ( len > len_max ) {
2454
+ len_max = len;
2455
+ start_max = start;
2456
+ }
2457
+ len = 0;
2458
+ }
2459
+ }
2460
+ if ( !len_max ) {
2461
+ if ( dist > 0.1*r ) {
2462
+ dist *= 0.75;
2463
+ goto again;
2464
+ } else {
2465
+ goto done; /* do it anyway */
2466
+ }
2467
+ } else {
2468
+ /* found a good sector */
2469
+ f = f_step * (start_max + (double)(len_max - 1)/2.0);
2470
+ r0 = dist / 1.5;
2471
+ xr = r0 * cos(f);
2472
+ yr = r0 * sin(f);
2473
+ zr = zr/r*r0;
2474
+ }
2475
+ }
2476
+ } else {
2477
+ xr = yr = zr = 0;
2478
+ }
2479
+
2480
+ done:
2481
+
2482
+ if ( at[iat_H].valence ) {
2483
+ /* disconnect H */
2484
+ next = at[iat_H].neighbor[0];
2485
+ for ( i = 0; i < at[next].valence; i ++ ) {
2486
+ if ( at[next].neighbor[i] == iat_H ) {
2487
+ RemoveInpAtBond( at, next, i );
2488
+ i = 0; /* success */
2489
+ break;
2490
+ }
2491
+ }
2492
+ } else {
2493
+ /* isolated H+ cation */
2494
+ next = iat_H;
2495
+ i = 0;
2496
+ at[iat_H].valence = 1;
2497
+ at[iat_H].chem_bonds_valence = 1;
2498
+ at[iat_H].bond_type[0] = BOND_TYPE_SINGLE;
2499
+ }
2500
+ if ( 0 == i /*i < at[next].valence*/ ) {
2501
+ /* move charge */
2502
+ if ( at[next].charge > 0 && at[iat].charge < 0 ) {
2503
+ at[next].charge --;
2504
+ at[iat].charge ++;
2505
+ }
2506
+ /* connect H to at[iat] */
2507
+ val = at[iat].valence;
2508
+ at[iat].neighbor[val] = iat_H;
2509
+ at[iat].bond_type[val] = at[iat_H].bond_type[0];
2510
+ at[iat].bond_stereo[val] = 0;
2511
+ at[iat].chem_bonds_valence += at[iat_H].bond_type[0];
2512
+ at[iat].valence = val+1;
2513
+
2514
+ at[iat_H].component = at[iat].component;
2515
+ at[iat_H].neighbor[0] = iat;
2516
+ at[iat_H].bond_stereo[0] = 0; /* possible loss of stereo info */
2517
+ at[iat_H].x = at[iat].x + xr;
2518
+ at[iat_H].y = at[iat].y + yr;
2519
+ at[iat_H].z = at[iat].z + zr;
2520
+ return 1; /* success */
2521
+ }
2522
+ return 0; /* failed */
2523
+ }
2524
+ /****************************************************************************************/
2525
+ int get_iat_number( int el_number, const int el_num[], int el_num_len )
2526
+ {
2527
+ int i;
2528
+ for ( i = 0; i < el_num_len; i ++ ) {
2529
+ if ( el_num[i] == el_number )
2530
+ return i;
2531
+ }
2532
+ return -1;
2533
+ }
2534
+
2535
+
2536
+ /*#endif*/ /* } DISCONNECT_SALTS */
2537
+ typedef enum tagIonAtomType {
2538
+ IAT_H=0,
2539
+ IAT_C,
2540
+ IAT_N,
2541
+ IAT_P,
2542
+ IAT_O,
2543
+ IAT_S,
2544
+ IAT_Se,
2545
+ IAT_Te,
2546
+ IAT_F,
2547
+ IAT_Cl,
2548
+ IAT_Br,
2549
+ IAT_I,
2550
+ IAT_MAX
2551
+ } ION_ATOM_TYPE;
2552
+
2553
+ /****************************************************************************************/
2554
+ int bNumHeterAtomHasIsotopicH( inp_ATOM *atom, int num_atoms )
2555
+ {
2556
+ static int el_num[IAT_MAX];
2557
+ int i, j, val, is_O=0, is_Cl=0, is_N=0, is_H=0, num_H, iat_numb, bAccept, num_iso_H, cur_num_iso_H, num_iso_atoms;
2558
+ inp_ATOM *at, *at2;
2559
+ /* one time initialization */
2560
+ if ( !el_num[IAT_H]) {
2561
+ el_num[IAT_H ] = get_periodic_table_number( "H" );
2562
+ el_num[IAT_C ] = get_periodic_table_number( "C" );
2563
+ el_num[IAT_N ] = get_periodic_table_number( "N" );
2564
+ el_num[IAT_P ] = get_periodic_table_number( "P" );
2565
+ el_num[IAT_O ] = get_periodic_table_number( "O" );
2566
+ el_num[IAT_S ] = get_periodic_table_number( "S" );
2567
+ el_num[IAT_Se] = get_periodic_table_number( "Se");
2568
+ el_num[IAT_Te] = get_periodic_table_number( "Te");
2569
+ el_num[IAT_F ] = get_periodic_table_number( "F" );
2570
+ el_num[IAT_Cl] = get_periodic_table_number( "Cl");
2571
+ el_num[IAT_Br] = get_periodic_table_number( "Br");
2572
+ el_num[IAT_I ] = get_periodic_table_number( "I" );
2573
+ }
2574
+ num_iso_H = 0;
2575
+ num_iso_atoms = 0;
2576
+ for ( i = 0, at = atom; i < num_atoms; i ++, at ++ ) {
2577
+
2578
+ num_iso_atoms += ( at->iso_atw_diff != 0 || NUM_ISO_H(at,0) ); /* isotopic atoms and implicit isotopic H */
2579
+
2580
+ if ( 0 > (iat_numb = get_iat_number( at->el_number, el_num, IAT_MAX )) ) {
2581
+ continue;
2582
+ }
2583
+
2584
+ if ( abs(at->charge) > 1 || at->radical && RADICAL_SINGLET != at->radical ) {
2585
+ continue;
2586
+ }
2587
+
2588
+ val = -1;
2589
+ switch( iat_numb ) {
2590
+ case IAT_N:
2591
+ case IAT_P:
2592
+ is_N = 1;
2593
+ val = 3+at->charge;
2594
+ break;
2595
+ case IAT_O:
2596
+ case IAT_S:
2597
+ case IAT_Se:
2598
+ case IAT_Te:
2599
+ is_O = 1;
2600
+ val = 2+at->charge;
2601
+ break;
2602
+ case IAT_F:
2603
+ case IAT_Cl:
2604
+ case IAT_Br:
2605
+ case IAT_I:
2606
+ if ( at->charge == 0 ) {
2607
+ is_Cl = 1; /* isolated HCl */
2608
+ val = 1;
2609
+ }
2610
+ break;
2611
+ case IAT_H:
2612
+ if ( at->valence == 0 &&
2613
+ at->charge == 1 ) {
2614
+ is_H = 1; /* isolated proton */
2615
+ val = 0;
2616
+ }
2617
+ }
2618
+ if ( val < 0 ) {
2619
+ continue;
2620
+ }
2621
+ num_H = NUMH(at,0);
2622
+ if ( val != at->chem_bonds_valence + num_H ) {
2623
+ continue;
2624
+ }
2625
+ if ( is_H ) {
2626
+ bAccept = 1;
2627
+ cur_num_iso_H = (at->iso_atw_diff != 0);
2628
+ } else {
2629
+ cur_num_iso_H = 0;
2630
+ for ( j = 0, bAccept = 1; j < at->valence && bAccept; j ++ ) {
2631
+ at2 = atom + (int)at->neighbor[j];
2632
+ if ( at2->charge && at->charge || (at2->radical && RADICAL_SINGLET != at2->radical ) ) {
2633
+ bAccept = 0; /* adjacent charged/radical atoms: do not neutralizate */
2634
+ break;
2635
+ } else
2636
+ if ( at2->el_number == el_num[IAT_H ] && at2->valence == 1 && at2->iso_atw_diff ) {
2637
+ cur_num_iso_H ++; /* isotopic explicit H */
2638
+ }
2639
+ }
2640
+ if ( bAccept ) {
2641
+ num_iso_atoms -= cur_num_iso_H; /* avoid counting explicit H as isotopic atom */
2642
+ cur_num_iso_H += NUM_ISO_H(at,0);
2643
+ }
2644
+
2645
+ }
2646
+ num_iso_H += (bAccept && cur_num_iso_H); /* number of acceptable heteroatoms that have isotopic H */
2647
+ }
2648
+ return ((num_iso_H? 1:0) | (num_iso_atoms? 2:0));
2649
+ }
2650
+
2651
+
2652
+ /****************************************************/
2653
+ /* Mark and count disconnected structure components */
2654
+ /* by Depth-first searching each component */
2655
+ /****************************************************/
2656
+ int cmp_components( const void *a1, const void *a2 )
2657
+ {
2658
+ int ret;
2659
+ AT_NUMB n1;
2660
+ AT_NUMB n2;
2661
+
2662
+ n1 = ((const AT_NUMB *)a1)[0]; /* number of atoms in the component -- descending order */
2663
+ n2 = ((const AT_NUMB *)a2)[0];
2664
+ if ( ret = (int)n2 - (int)n1 ) {
2665
+ return ret;
2666
+ }
2667
+ /* stable sort */
2668
+ n1 = ((const AT_NUMB *)a1)[1]; /* component ordering number -- ascending order */
2669
+ n2 = ((const AT_NUMB *)a2)[1];
2670
+ ret = (int)n1 - (int)n2;
2671
+
2672
+ return ret;
2673
+
2674
+ }
2675
+ /*************************************************************************************************/
2676
+ int mark_one_struct_component( inp_ATOM* at, int j, AT_NUMB *mark, AT_NUMB num_disconnected_components )
2677
+ {
2678
+ if ( mark[j] ) {
2679
+ return 0;
2680
+ } else {
2681
+ int i;
2682
+ mark[j] = num_disconnected_components;
2683
+ for ( i = 0; i < at[j].valence; i++ ) {
2684
+ if ( !mark[(int)at[j].neighbor[i]] ) {
2685
+ mark_one_struct_component( at, (int)at[j].neighbor[i], mark, num_disconnected_components );
2686
+ }
2687
+ }
2688
+ }
2689
+ return 1;
2690
+ }
2691
+ /*************************************************************************************************/
2692
+ int MarkDisconnectedComponents( ORIG_ATOM_DATA *orig_at_data, int bProcessOldCompNumbers )
2693
+ {
2694
+ typedef AT_NUMB AT_TRIPLE[3];
2695
+
2696
+ inp_ATOM *at = orig_at_data->at;
2697
+ int num_at = orig_at_data->num_inp_atoms;
2698
+ AT_NUMB *nCurAtLen = NULL;
2699
+ AT_NUMB *nNewCompNumber = NULL;
2700
+ AT_NUMB *nOldCompNumber = NULL;
2701
+ int i, j, num_components, ret;
2702
+ int new_comp_no;
2703
+ AT_NUMB old_comp_no, another_comp_no, no_component;
2704
+
2705
+ /* component_nbr[i][0] = number of atoms in the component i-1
2706
+ * component_nbr[i][1] = original component number (id-1) = i
2707
+ * after sorting:
2708
+ * component_nbr[j][2] = new number of component #(component_nbr[i][1]+1)
2709
+ */
2710
+ AT_TRIPLE *component_nbr = NULL;
2711
+
2712
+ /* initialize */
2713
+ if ( bProcessOldCompNumbers && !orig_at_data->nOldCompNumber ) {
2714
+ bProcessOldCompNumbers = 0;
2715
+ }
2716
+ /*
2717
+ for ( j = 0; j < num_at; j ++ ) {
2718
+ at[j].component = 0;
2719
+ }
2720
+ */
2721
+ ret = -1;
2722
+ if ( !num_at ) {
2723
+ return 0;
2724
+ }
2725
+ if ( !( nNewCompNumber = (AT_NUMB *) inchi_calloc( num_at, sizeof(nNewCompNumber[0]) ) ) ) {
2726
+ goto exit_function;
2727
+ }
2728
+ /* mark and count */
2729
+ for ( j = 0, num_components = 0; j < num_at; j++ ) {
2730
+ if ( !nNewCompNumber[j] ) {
2731
+ /* nNewCompNumber[i] will contain new component number for atom at[i], i=0..num_at-1 */
2732
+ mark_one_struct_component( at, j, nNewCompNumber, (AT_NUMB)(num_components+1) );
2733
+ num_components ++;
2734
+ }
2735
+ }
2736
+ /* Allocate more memory */
2737
+ i = inchi_max( num_components, orig_at_data->num_components );
2738
+ if ( !(nCurAtLen = (AT_NUMB *) inchi_calloc( num_components+1, sizeof(nCurAtLen[0]) ) ) ||
2739
+ !(nOldCompNumber = (AT_NUMB *) inchi_calloc( i +1, sizeof(nOldCompNumber[0]) ) ) ||
2740
+ !(component_nbr = (AT_TRIPLE *) inchi_calloc( num_components+1, sizeof(component_nbr[0]) ) ) ) {
2741
+ goto exit_function;
2742
+ }
2743
+
2744
+ /* count atoms per component and renumber the components */
2745
+ for ( i = 0; i < num_components; i ++ ) {
2746
+ component_nbr[i][0] = 0; /* number of atoms in the component */
2747
+ component_nbr[i][1] = i; /* component ordering number */
2748
+ }
2749
+ for ( j = 0; j < num_at; j ++ ) {
2750
+ component_nbr[(int)nNewCompNumber[j]-1][0] ++; /* count atoms in each component */
2751
+ }
2752
+ /* sort key: number of atoms; order: descending */
2753
+ qsort( (void*)component_nbr[0], num_components,
2754
+ sizeof(component_nbr[0]), cmp_components);
2755
+ /* invert the transposition */
2756
+ for ( i = 0; i < num_components; i ++ ) {
2757
+ nCurAtLen[i] = component_nbr[i][0];
2758
+ component_nbr[ component_nbr[i][1] ][2] = i+1;
2759
+ }
2760
+ /* renumber the components so that the component with the greatest number of atoms is the first */
2761
+ no_component = num_at+1;
2762
+ for ( j = 0; j < num_at; j ++ ) {
2763
+ /* new component number for at[j] */
2764
+ new_comp_no = component_nbr[(int)nNewCompNumber[j]-1][2]-1; /* starts from 0 */
2765
+ if ( bProcessOldCompNumbers ) {
2766
+ /* old component number for at[j] */
2767
+ old_comp_no = at[j].component;
2768
+ /* fill out nOldCompNumber[]; initially it contains zeroes */
2769
+ if ( !old_comp_no ) {
2770
+ nOldCompNumber[new_comp_no] = no_component; /* atom did not have component number */
2771
+ } else
2772
+ if ( nOldCompNumber[new_comp_no] != old_comp_no ) {
2773
+ if ( !nOldCompNumber[new_comp_no] ) {
2774
+ nOldCompNumber[new_comp_no] = old_comp_no;
2775
+ } else {
2776
+ /* at[j] moved from old comp #old_comp_no to old comp #nOldCompNumber[new_comp_no]
2777
+ Both components cannot be equal to any current component */
2778
+ another_comp_no = nOldCompNumber[new_comp_no];
2779
+ for ( i = 0; i < num_components; i ++ ) {
2780
+ if ( nOldCompNumber[i] == old_comp_no ||
2781
+ nOldCompNumber[i] == another_comp_no ) {
2782
+ nOldCompNumber[i] = no_component;
2783
+ }
2784
+ }
2785
+ /* nOldCompNumber[new_comp_no] = num_at+1; */
2786
+ }
2787
+ }
2788
+ }
2789
+ /* orig_at_data->nOldCompNumber */
2790
+ at[j].component = new_comp_no+1; /* starts from 1 */
2791
+ }
2792
+ if ( bProcessOldCompNumbers ) {
2793
+ for ( j = 0; j < num_components; j ++ ) {
2794
+ if ( nOldCompNumber[j] == no_component ) {
2795
+ /* the component has atom from another component */
2796
+ nOldCompNumber[j] = 0;
2797
+ } else
2798
+ if ( nOldCompNumber[j] &&
2799
+ !orig_at_data->nOldCompNumber[nOldCompNumber[j]-1] ) {
2800
+ /* the component has changed in the previous processing */
2801
+ nOldCompNumber[j] = 0;
2802
+ }
2803
+ }
2804
+ } else {
2805
+ for ( j = 0; j < num_components; j ++ ) {
2806
+ nOldCompNumber[j] = j + 1;
2807
+ }
2808
+ }
2809
+ ret = num_components;
2810
+ exit_function:
2811
+ if ( nNewCompNumber )
2812
+ inchi_free( nNewCompNumber );
2813
+ if ( component_nbr )
2814
+ inchi_free( component_nbr );
2815
+
2816
+ if ( ret < 0 ) {
2817
+ if ( nCurAtLen ) {
2818
+ inchi_free( nCurAtLen );
2819
+ nCurAtLen = NULL;
2820
+ }
2821
+ if ( nOldCompNumber ) {
2822
+ inchi_free( nOldCompNumber );
2823
+ nOldCompNumber = NULL;
2824
+ }
2825
+ num_components = ret;
2826
+ }
2827
+ /* avoid memory leaks */
2828
+ if ( orig_at_data->nCurAtLen )
2829
+ inchi_free ( orig_at_data->nCurAtLen );
2830
+ if ( orig_at_data->nOldCompNumber )
2831
+ inchi_free ( orig_at_data->nOldCompNumber );
2832
+
2833
+ orig_at_data->nCurAtLen = nCurAtLen;
2834
+ orig_at_data->nOldCompNumber = nOldCompNumber;
2835
+
2836
+ orig_at_data->num_components = num_components;
2837
+
2838
+ return num_components; /* number of disconnected components; 1=>single connected structure*/
2839
+ }
2840
+ /******************************************************************************/
2841
+ /* Extract one (connected) component */
2842
+ /******************************************************************************/
2843
+ int ExtractConnectedComponent( inp_ATOM *at, int num_at, int component_number, inp_ATOM *component_at )
2844
+ {
2845
+ int i, j, num_component_at;
2846
+ AT_NUMB *number;
2847
+ if ( NULL == (number = (AT_NUMB*)inchi_calloc(num_at, sizeof(AT_NUMB)))){
2848
+ return CT_OUT_OF_RAM; /* out of memory */ /* <BRKPT> */
2849
+ }
2850
+ /* copy atoms */
2851
+ for ( i = 0, num_component_at = 0; i < num_at; i ++ ) {
2852
+ if ( at[i].component == component_number ) {
2853
+ number[i] = num_component_at;
2854
+ component_at[num_component_at ++] = at[i];
2855
+ }
2856
+ }
2857
+ /* renumber neighbors */
2858
+ for ( i = 0; i < num_component_at; i ++ ) {
2859
+ component_at[i].orig_compt_at_numb = (AT_NUMB)(i + 1);
2860
+ for ( j = 0; j < component_at[i].valence; j ++ ) {
2861
+ component_at[i].neighbor[j] = number[(int)component_at[i].neighbor[j]];
2862
+ }
2863
+ }
2864
+ inchi_free( number );
2865
+ return num_component_at;
2866
+ }
2867
+ /****************************************************************/
2868
+ int SetConnectedComponentNumber( inp_ATOM *at, int num_at, int component_number )
2869
+ {
2870
+ int i;
2871
+ for ( i = 0; i < num_at; i ++ ) {
2872
+ at[i].component = (AT_NUMB)component_number;
2873
+ }
2874
+ return 0;
2875
+ }
2876
+ /****************************************************************/
2877
+
2878
+ int Free_INChI_Stereo( INChI_Stereo *pINChI_Stereo )
2879
+ {
2880
+ if ( pINChI_Stereo ) {
2881
+ qzfree( pINChI_Stereo->nNumber );
2882
+ qzfree( pINChI_Stereo->t_parity );
2883
+ qzfree( pINChI_Stereo->nNumberInv );
2884
+ qzfree( pINChI_Stereo->t_parityInv );
2885
+ qzfree( pINChI_Stereo->nBondAtom1 );
2886
+ qzfree( pINChI_Stereo->nBondAtom2 );
2887
+ qzfree( pINChI_Stereo->b_parity );
2888
+ }
2889
+ return 0;
2890
+ }
2891
+
2892
+ /****************************************************************/
2893
+ INChI_Stereo *Alloc_INChI_Stereo(int num_at, int num_bonds)
2894
+ {
2895
+ INChI_Stereo *pINChI_Stereo = (INChI_Stereo *)inchi_calloc(1, sizeof(INChI_Stereo));
2896
+ if ( pINChI_Stereo ) {
2897
+ if ( num_at &&
2898
+ (pINChI_Stereo->nNumber = (AT_NUMB *)inchi_calloc(num_at, sizeof(pINChI_Stereo->nNumber[0]))) &&
2899
+ (pINChI_Stereo->t_parity = (S_CHAR *)inchi_calloc(num_at, sizeof(pINChI_Stereo->t_parity[0])))
2900
+ && (pINChI_Stereo->nNumberInv = (AT_NUMB *)inchi_calloc(num_at, sizeof(pINChI_Stereo->nNumberInv[0])))
2901
+ && (pINChI_Stereo->t_parityInv = (S_CHAR *)inchi_calloc(num_at, sizeof(pINChI_Stereo->t_parityInv[0])))
2902
+ ) {
2903
+ ;
2904
+ } else
2905
+ if ( num_at ) {
2906
+ goto out_of_RAM;
2907
+ }
2908
+ if ( num_bonds &&
2909
+ (pINChI_Stereo->nBondAtom1 =(AT_NUMB *)inchi_calloc(num_bonds, sizeof(pINChI_Stereo->nBondAtom1[0]))) &&
2910
+ (pINChI_Stereo->nBondAtom2 =(AT_NUMB *)inchi_calloc(num_bonds, sizeof(pINChI_Stereo->nBondAtom2[0]))) &&
2911
+ (pINChI_Stereo->b_parity =(S_CHAR *)inchi_calloc(num_bonds, sizeof(pINChI_Stereo->b_parity[0]))) ) {
2912
+ ;
2913
+ } else
2914
+ if ( num_bonds ) {
2915
+ goto out_of_RAM;
2916
+ }
2917
+ return pINChI_Stereo;
2918
+
2919
+ out_of_RAM:
2920
+ Free_INChI_Stereo( pINChI_Stereo );
2921
+ qzfree( pINChI_Stereo );
2922
+ }
2923
+ return NULL;
2924
+ }
2925
+ /****************************************************************/
2926
+ int Free_INChI(INChI **ppINChI)
2927
+ {
2928
+ INChI *pINChI;
2929
+
2930
+ if ( pINChI = *ppINChI ) {
2931
+ #if( bREUSE_INCHI == 1 )
2932
+ if ( pINChI->nRefCount -- > 0 )
2933
+ return 1;
2934
+ #endif
2935
+
2936
+ Free_INChI_Stereo(pINChI->Stereo );
2937
+ Free_INChI_Stereo(pINChI->StereoIsotopic );
2938
+ /*
2939
+ Free_INChI_Stereo(pINChI->StereoInv );
2940
+ Free_INChI_Stereo(pINChI->StereoIsotopicInv);
2941
+ */
2942
+ qzfree(pINChI->nAtom );
2943
+ qzfree(pINChI->nConnTable );
2944
+ qzfree(pINChI->nTautomer );
2945
+ qzfree(pINChI->nNum_H );
2946
+ qzfree(pINChI->nNum_H_fixed );
2947
+ qzfree(pINChI->IsotopicAtom );
2948
+ qzfree(pINChI->IsotopicTGroup );
2949
+ qzfree(pINChI->nPossibleLocationsOfIsotopicH);
2950
+ qzfree(pINChI->Stereo );
2951
+ qzfree(pINChI->StereoIsotopic );
2952
+ /*
2953
+ qzfree(pINChI->StereoInv );
2954
+ qzfree(pINChI->StereoIsotopicInv);
2955
+ */
2956
+ qzfree(pINChI->szHillFormula );
2957
+ /*
2958
+ pINChI->nAtom = NULL;
2959
+ pINChI->nConnTable = NULL;
2960
+ pINChI->nTautomer = NULL;
2961
+ pINChI->nNum_H = NULL;
2962
+ pINChI->IsotopicAtom = NULL;
2963
+ pINChI->IsotopicTGroup = NULL;
2964
+ pINChI->Stereo = NULL;
2965
+ pINChI->StereoIsotopic = NULL;
2966
+ pINChI->szHillFormula = NULL;
2967
+ */
2968
+ qzfree( pINChI );
2969
+ *ppINChI = NULL;
2970
+
2971
+ }
2972
+ return 0;
2973
+ }
2974
+
2975
+ /****************************************************************/
2976
+ INChI *Alloc_INChI( inp_ATOM *at, int num_at, int *found_num_bonds, int *found_num_isotopic, int nAllocMode )
2977
+ {
2978
+ int i, num_bonds, num_isotopic_atoms;
2979
+ INChI *pINChI;
2980
+ int bIsotopic = (nAllocMode & REQ_MODE_ISO);
2981
+ /* int bTautomeric = (nAllocMode & REQ_MODE_TAUT); */
2982
+
2983
+ if ( num_at <= 0 || NULL == (pINChI = (INChI *)inchi_calloc( 1, sizeof(INChI)))) {
2984
+ return NULL;
2985
+ }
2986
+
2987
+ for ( i = 0, num_bonds = 0, num_isotopic_atoms = 0; i < num_at; i ++ ) {
2988
+ num_bonds += at[i].valence;
2989
+ /* if ( bIsotopic ) { */
2990
+ num_isotopic_atoms += (0 != at[i].iso_atw_diff ||
2991
+ !strcmp(at[i].elname, "D") ||
2992
+ !strcmp(at[i].elname, "T") ||
2993
+ at[i].num_iso_H[0] ||
2994
+ at[i].num_iso_H[1] ||
2995
+ at[i].num_iso_H[2]);
2996
+ /* } */
2997
+
2998
+ }
2999
+ num_bonds /= 2;
3000
+
3001
+ *found_num_bonds = num_bonds;
3002
+ *found_num_isotopic = num_isotopic_atoms;
3003
+
3004
+
3005
+ if ( (pINChI->nAtom = (U_CHAR*) inchi_calloc( num_at, sizeof(pINChI->nAtom[0]))) &&
3006
+ (pINChI->nConnTable = (AT_NUMB*)inchi_calloc( num_at+num_bonds, sizeof(pINChI->nConnTable[0]))) &&
3007
+ (pINChI->nTautomer = (AT_NUMB*)inchi_calloc( ((3+INCHI_T_NUM_MOVABLE)*num_at)/2+1, sizeof(pINChI->nTautomer[0]))) &&
3008
+ (pINChI->nNum_H = (S_CHAR*) inchi_calloc( num_at, sizeof(pINChI->nNum_H[0]))) &&
3009
+ (pINChI->nNum_H_fixed= (S_CHAR*) inchi_calloc( num_at, sizeof(pINChI->nNum_H_fixed[0])))
3010
+ ) {
3011
+ ; /* nTautomer length: max. number of tautomeric groups is num_at/2
3012
+
3013
+ 1 word -> number of t-groups
3014
+
3015
+ each group has:
3016
+
3017
+ 1 word -> number of endpoints+INCHI_T_NUM_MOVABLE
3018
+ INCHI_T_NUM_MOVABLE words -> number(s) of moveable attachments
3019
+ numbers of endpoints words -> canon. numbers
3020
+
3021
+ max. occurs if each t-group has 2 atoms (num_at/2 t-groups) and all atoms
3022
+ belong to t-groups (num_at endpoints)
3023
+
3024
+ Total: 1 + (number of t-groups)*(1+INCHI_T_NUM_MOVABLE) + (number of endpoints) <=
3025
+ 1 + (num_at/2) * (1+INCHI_T_NUM_MOVABLE) + num_at <=
3026
+ 1 + (3+INCHI_T_NUM_MOVABLE)*num_at/2 words.
3027
+ */
3028
+
3029
+ } else {
3030
+ goto out_of_RAM;
3031
+ }
3032
+ pINChI->szHillFormula = NULL; /* the length is unknown */
3033
+ if ( bIsotopic ) {
3034
+ if ( num_isotopic_atoms &&
3035
+ (pINChI->IsotopicAtom = (INChI_IsotopicAtom *)inchi_calloc(num_isotopic_atoms, sizeof(INChI_IsotopicAtom) )) &&
3036
+ (pINChI->IsotopicTGroup = (INChI_IsotopicTGroup *)inchi_calloc(num_isotopic_atoms, sizeof(INChI_IsotopicTGroup) ))
3037
+ ) {
3038
+ ;
3039
+ } else
3040
+ if ( num_isotopic_atoms ) {
3041
+ goto out_of_RAM;
3042
+ }
3043
+ if ( !(pINChI->nPossibleLocationsOfIsotopicH = (AT_NUMB *)inchi_calloc( num_at+1, sizeof(pINChI->nPossibleLocationsOfIsotopicH[0]) ) ) ) {
3044
+ goto out_of_RAM;
3045
+ }
3046
+ }
3047
+
3048
+ if ((pINChI->Stereo = Alloc_INChI_Stereo(num_at, num_bonds))
3049
+ ) {
3050
+ ;
3051
+ } else {
3052
+ goto out_of_RAM;
3053
+ }
3054
+ if ( bIsotopic ) {
3055
+ if ((pINChI->StereoIsotopic = Alloc_INChI_Stereo(num_at, num_bonds))
3056
+ ) {
3057
+ ;
3058
+ } else {
3059
+ goto out_of_RAM;
3060
+ }
3061
+ }
3062
+ return pINChI;
3063
+
3064
+ out_of_RAM:
3065
+ if ( pINChI ) {
3066
+ Free_INChI(&pINChI);
3067
+ /*
3068
+ inchi_free(pINChI);
3069
+ */
3070
+ }
3071
+ return NULL;
3072
+ }
3073
+ /****************************************************************/
3074
+ int Free_INChI_Aux( INChI_Aux **ppINChI_Aux )
3075
+ {
3076
+ INChI_Aux *pINChI_Aux = *ppINChI_Aux;
3077
+ if ( pINChI_Aux ) {
3078
+ #if( bREUSE_INCHI == 1 )
3079
+ if ( pINChI_Aux->nRefCount -- > 0 )
3080
+ return 1;
3081
+ #endif
3082
+
3083
+ qzfree( pINChI_Aux->nOrigAtNosInCanonOrd );
3084
+ qzfree( pINChI_Aux->nIsotopicOrigAtNosInCanonOrd );
3085
+ qzfree( pINChI_Aux->nOrigAtNosInCanonOrdInv );
3086
+ qzfree( pINChI_Aux->nIsotopicOrigAtNosInCanonOrdInv );
3087
+ qzfree( pINChI_Aux->szOrigCoord );
3088
+ qzfree( pINChI_Aux->OrigInfo );
3089
+ /*
3090
+ qzfree( pINChI_Aux->nOriginalAtomNumber );
3091
+ qzfree( pINChI_Aux->nCanonicalTGroupNumbers );
3092
+ qzfree( pINChI_Aux->nIsotopicCanonicalTGroupNumbers);
3093
+ qzfree( pINChI_Aux->nTautomer );
3094
+ qzfree( pINChI_Aux->nNontautomericCanonicalNumbers );
3095
+ qzfree( pINChI_Aux->nIsotopicCanonicalNumbers );
3096
+ qzfree( pINChI_Aux->nNontautomericIsotopicCanonicalNumbers );
3097
+ qzfree( pINChI_Aux->nNontautomericEquNumbers );
3098
+ qzfree( pINChI_Aux->nNontautomericIsotopicEquNumbers );
3099
+ */
3100
+ qzfree( pINChI_Aux->nConstitEquNumbers );
3101
+ qzfree( pINChI_Aux->nConstitEquTGroupNumbers );
3102
+ qzfree( pINChI_Aux->nConstitEquIsotopicNumbers );
3103
+ qzfree( pINChI_Aux->nConstitEquIsotopicTGroupNumbers );
3104
+ qzfree( pINChI_Aux );
3105
+ *ppINChI_Aux = NULL;
3106
+ }
3107
+ return 0;
3108
+ }
3109
+ /****************************************************************/
3110
+ INChI_Aux *Alloc_INChI_Aux( int num_at, int num_isotopic_atoms, int nAllocMode, int bOrigCoord )
3111
+ {
3112
+ INChI_Aux *pINChI_Aux;
3113
+ int bIsotopic = (nAllocMode & REQ_MODE_ISO);
3114
+ int num_at_tg = num_at + num_at/2;
3115
+ /* int bTautomeric = (nAllocMode & REQ_MODE_TAUT); */
3116
+
3117
+ if ( num_at <= 0 || NULL == (pINChI_Aux = (INChI_Aux *)inchi_calloc(sizeof(INChI_Aux), 1))) {
3118
+ return NULL;
3119
+ }
3120
+ if ( (pINChI_Aux->nOrigAtNosInCanonOrd = (AT_NUMB*)inchi_calloc(sizeof(pINChI_Aux->nOrigAtNosInCanonOrd[0]), num_at_tg)) &&
3121
+ (pINChI_Aux->nOrigAtNosInCanonOrdInv = (AT_NUMB*)inchi_calloc(sizeof(pINChI_Aux->nOrigAtNosInCanonOrd[0]), num_at_tg)) &&
3122
+ (pINChI_Aux->nConstitEquNumbers = (AT_NUMB*)inchi_calloc(sizeof(pINChI_Aux->nConstitEquNumbers[0]), num_at_tg)) ) {
3123
+ ;
3124
+ } else {
3125
+ goto out_of_RAM;
3126
+ }
3127
+
3128
+ if ( num_at > 1 &&
3129
+ (pINChI_Aux->nConstitEquTGroupNumbers = (AT_NUMB*)inchi_calloc(sizeof(pINChI_Aux->nConstitEquTGroupNumbers[0]), num_at/2)) ) {
3130
+ ;
3131
+ } else
3132
+ if ( num_at > 1 ) {
3133
+ goto out_of_RAM;
3134
+ }
3135
+
3136
+ if ( num_at > 0 ) {
3137
+ pINChI_Aux->OrigInfo = (ORIG_INFO *)inchi_calloc(sizeof(pINChI_Aux->OrigInfo[0]), num_at);
3138
+ if ( !pINChI_Aux->OrigInfo )
3139
+ goto out_of_RAM;
3140
+ }
3141
+ if ( bOrigCoord && num_at > 0 ) {
3142
+ pINChI_Aux->szOrigCoord = (MOL_COORD *)inchi_calloc(sizeof(pINChI_Aux->szOrigCoord[0]), num_at);
3143
+ if ( !pINChI_Aux->szOrigCoord )
3144
+ goto out_of_RAM;
3145
+ }
3146
+ if ( bIsotopic ) {
3147
+ if ( /*num_isotopic_atoms &&*/
3148
+ (pINChI_Aux->nIsotopicOrigAtNosInCanonOrd = (AT_NUMB*)inchi_calloc(sizeof(pINChI_Aux->nIsotopicOrigAtNosInCanonOrd[0]), num_at_tg)) &&
3149
+ (pINChI_Aux->nIsotopicOrigAtNosInCanonOrdInv = (AT_NUMB*)inchi_calloc(sizeof(pINChI_Aux->nIsotopicOrigAtNosInCanonOrd[0]), num_at_tg)) &&
3150
+ (pINChI_Aux->nConstitEquIsotopicNumbers = (AT_NUMB*)inchi_calloc(sizeof(pINChI_Aux->nConstitEquIsotopicNumbers[0]), num_at_tg)) ) {
3151
+ ;
3152
+ } else
3153
+ if ( num_isotopic_atoms ) {
3154
+ goto out_of_RAM;
3155
+ }
3156
+ if ( /*num_isotopic_atoms && num_at > 1 &&*/
3157
+ (pINChI_Aux->nConstitEquIsotopicTGroupNumbers = (AT_NUMB*)inchi_calloc(sizeof(pINChI_Aux->nConstitEquIsotopicTGroupNumbers[0]), num_at/2)) ) {
3158
+ ;
3159
+ } else
3160
+ if ( num_isotopic_atoms && num_at > 1 ) {
3161
+ goto out_of_RAM;
3162
+ }
3163
+ }
3164
+ return pINChI_Aux;
3165
+
3166
+
3167
+ out_of_RAM:
3168
+ if ( pINChI_Aux ) {
3169
+ Free_INChI_Aux(&pINChI_Aux);
3170
+ /*
3171
+ inchi_free(pINChI_Aux);
3172
+ */
3173
+ }
3174
+ return NULL;
3175
+ }
3176
+ /***********************************************************************************/
3177
+ #define ABNORMAL_AT(i) ( at[i].charge && at[i].radical || abs(at[i].charge) > 3 || \
3178
+ ( at[i].radical && at[i].radical != RADICAL_DOUBLET) || \
3179
+ at[i].iso_atw_diff && (at[i].iso_atw_diff == 1 || at[i].iso_atw_diff < -3 || at[i].iso_atw_diff > 6 ))
3180
+ #define ALIASED_AT(i) (0 < NUM_ISO_H(at, i))
3181
+ /***********************************************************************************/
3182
+ #if( TEST_RENUMB_ATOMS_SAVE_LONGEST == 1 )
3183
+ int WriteToSDfile( const INP_ATOM_DATA *inp_at_data, INCHI_FILE* fcb, const char* name, const char* comment,
3184
+ const char *szLabel, const char *szValue)
3185
+ {
3186
+ int i, j, k, num_bonds=0, ret=0;
3187
+ int bAtomNeedsAlias;
3188
+ int flag_bad_charge=0, nNumAddLines=0, nNumIso=0, nNumChargeLines=0, nNumRadicalLines=0, nNumAliasLines=0;
3189
+ /*sp_ATOM *at; */
3190
+ float fzero=0.0F;
3191
+ double x, y;
3192
+ int bNext /*, s*/;
3193
+ const inp_ATOM *at = inp_at_data->at_fixed_bonds? inp_at_data->at_fixed_bonds : inp_at_data->at;
3194
+ int num_atoms = inp_at_data->num_at;
3195
+ /*at = species->atom;*/
3196
+
3197
+ /*my_fprintf(fcb,"%ld.MOL\n",species->casno);*/
3198
+ { /* block start */
3199
+ char strLocName[82];
3200
+ memset(strLocName, 0, sizeof(strLocName) );
3201
+ if ( name && *name ) {
3202
+ strncpy( strLocName, name, 80 );
3203
+ }
3204
+ inchi_print_nodisplay( fcb,"%s\n", strLocName );
3205
+ } /* block end */
3206
+ /**********************************************************************/
3207
+ /** **/
3208
+ /** Important: Atoms with alias cannot have charge, radical, or **/
3209
+ /** isotope differences. **/
3210
+ /** **/
3211
+ /** Atoms with alias cannot be abnormal. **/
3212
+ /** **/
3213
+ /** Abnormal atoms are atoms which need M CHG, M RAD, M ISO **/
3214
+ /** **/
3215
+ /**********************************************************************/
3216
+
3217
+ /* F10.5 F12.5 I6
3218
+ IIPPPPPPPPMMDDYYHHmmddSSssssssssssEEEEEEEEEEEERRRRRR
3219
+ my_fprintf( fcb,"NISTTRANHP09089809272D 1 1.0 0.0 %6ld\n", lEpa);*/
3220
+ inchi_print_nodisplay( fcb," -%s v%s SDfile Output \n", INCHI_NAME, INCHI_VERSION);
3221
+ /*y_fprintf(fcb, " -CPSS- 1213981200n\n");*/
3222
+
3223
+ { /*block start*/
3224
+ char strLocName[82];
3225
+
3226
+ memset(strLocName, 0, sizeof(strLocName) );
3227
+ if ( comment && *comment ) {
3228
+ strncpy( strLocName, comment, 80 );
3229
+ }
3230
+ inchi_print_nodisplay( fcb,"%s\n", strLocName );
3231
+ } /*block end*/
3232
+ for (i=0; i< num_atoms; i++)
3233
+ num_bonds += at[i].valence;
3234
+ num_bonds /= 2;
3235
+
3236
+ /*find if we need "M CHG" and "M RAD"*/
3237
+ for (i=0, nNumAddLines = 0, nNumIso=0; i < num_atoms; i++) {
3238
+ bAtomNeedsAlias = ALIASED_AT(i); /* 5-3-99 DCh */
3239
+ nNumAddLines += !bAtomNeedsAlias && ABNORMAL_AT(i);
3240
+ nNumAliasLines += 2 * bAtomNeedsAlias;
3241
+ nNumIso += ( 0 == strcmp( at[i].elname, "D" ) || ( 0 == strcmp( at[i].elname, "T" ) ) );
3242
+ }
3243
+
3244
+ /* count additional M lines*/
3245
+ if ( nNumAddLines || nNumAliasLines ) {
3246
+ for (i=0, nNumChargeLines=0, nNumRadicalLines=0; i < num_atoms; i++) {
3247
+ nNumChargeLines += (0 != at[i].charge) && !ALIASED_AT(i);
3248
+ nNumRadicalLines += (0 != at[i].radical) && !ALIASED_AT(i);
3249
+ }
3250
+ }
3251
+ nNumChargeLines = ( nNumChargeLines + 7 ) / 8;
3252
+ nNumRadicalLines = ( nNumRadicalLines + 7 ) / 8;
3253
+ nNumIso = ( nNumIso + 7 ) / 8;
3254
+
3255
+ nNumAddLines = nNumChargeLines + nNumRadicalLines + nNumAliasLines; /* 1 for M END*/
3256
+
3257
+ if ( nNumAddLines == 0 ) {
3258
+ nNumIso = 0; /* keep isotopes description in CTable only*/
3259
+ } else {
3260
+ nNumAddLines += nNumIso+1; /* add 1 for "M END" line*/
3261
+ }
3262
+
3263
+ /* aaa bbblllfffcccsssxxxrrrpppiiimmmvvvvvv*/
3264
+ inchi_print_nodisplay(fcb,"%3d%3d 0 0 0 0 0 0 0 0%3d%s\n",num_atoms, num_bonds, nNumAddLines,nNumAddLines?" V2000":"");
3265
+ /* atoms block*/
3266
+ for (i=0; i < num_atoms; i++) {
3267
+ char elname[ATOM_EL_LEN] = "\0\0\0\0\0";
3268
+ int iso = 0;
3269
+ int charge = 0;
3270
+ int valence = 0;
3271
+ bAtomNeedsAlias = ALIASED_AT(i);
3272
+ /* isotope*/
3273
+ iso = !strcmp( at[i].elname, "D" )? 1:
3274
+ !strcmp( at[i].elname, "T" )? 2: 0;
3275
+
3276
+ if ( iso ) {
3277
+ /* deuterium or tritium*/
3278
+ strcpy ( elname, "H" );
3279
+ } else
3280
+ if ( bAtomNeedsAlias ) {
3281
+ strcpy ( elname, "C" );
3282
+ } else {
3283
+ strncpy ( elname, at[i].elname, sizeof(elname)-1 );
3284
+ }
3285
+ /*
3286
+ if ( !iso ) {
3287
+ strncpy ( elname, at[i].elname, sizeof(elname)-1 );
3288
+ } else
3289
+ if ( ALIASED_AT(i) ) {
3290
+ strcpy ( elname, "C" );
3291
+ } else {
3292
+ -- deuterium or tritium --
3293
+ strcpy ( elname, "H" );
3294
+ }
3295
+ */
3296
+ if ( !ABNORMAL_AT(i) && !bAtomNeedsAlias ) {
3297
+
3298
+ /* Only normal atoms without alias can be here*/
3299
+
3300
+ /* charge*/
3301
+ switch ( at[i].charge ) {
3302
+ case 3: charge = 1; break;
3303
+ case 2: charge = 2; break;
3304
+ case 1: charge = 3; break;
3305
+ case -1: charge = 5; break;
3306
+ case -2: charge = 6; break;
3307
+ case -3: charge = 7; break;
3308
+ case 0: charge = 0; break;
3309
+ default: flag_bad_charge = 1; break;
3310
+ };
3311
+ /* radical*/
3312
+ if ( at[i].radical ) {
3313
+ if ( at[i].radical == RADICAL_DOUBLET ) {
3314
+ flag_bad_charge |= (charge != 0);
3315
+ charge = 4;
3316
+ } else {
3317
+ flag_bad_charge |= 2;
3318
+ }
3319
+ }
3320
+ if ( flag_bad_charge ) {
3321
+ charge = 0;
3322
+ }
3323
+ }
3324
+
3325
+ x = at[i].x;
3326
+ y = at[i].y;
3327
+ /* --- just removed --
3328
+ if ( c && c->xCoeff != 0.0 && c->yCoeff != 0.0 ) {
3329
+ x = (x - c->xShift)/c->xCoeff;
3330
+ y = (y - c->yShift)/c->yCoeff;
3331
+ } else {
3332
+ y = -y;
3333
+ }
3334
+ ----------------------*/
3335
+ if( at[i].num_H > 0 ) {
3336
+ for ( j = 0, valence = 0; j < at[i].valence; j++ ) {
3337
+ switch( k = at[i].bond_type[j] ) { /* fixed valence calculation 12-23-99 DCh.*/
3338
+ case 2:
3339
+ case 3:
3340
+ valence += 2*k;
3341
+ break;
3342
+ case 4:
3343
+ valence += 3;
3344
+ break;
3345
+ default:
3346
+ valence += 2;
3347
+ }
3348
+ }
3349
+ valence = valence/2 + at[i].num_H;
3350
+ } else
3351
+ /* Added 07-09-2003 DCh*/
3352
+ if ( at[i].chem_bonds_valence > 0 && at[i].chem_bonds_valence < 15 ) {
3353
+ valence = at[i].chem_bonds_valence;
3354
+ } else
3355
+ /* Added 07-09-2003 DCh*/
3356
+ if ( !at[i].valence && !at[i].num_H && !at[i].chem_bonds_valence ) {
3357
+ valence = 15;
3358
+ }
3359
+ /*my_fprintf(fcb,"%10.4f%10.4f%10.4f %-3.3s%2d%3d 0 0 0 0 0 0 0\n",*/
3360
+ /* (float)at[i].x, (float)(-at[i].y), fzero, at[i].elname, iso, charge);*/
3361
+ /* xxxxxxyyyyyyzzzzzz aaa____ddcccsssnnnbbbvvvrrriiimmmeee */
3362
+ inchi_print_nodisplay(fcb,"%10.4f%10.4f%10.4f %-3.3s%2d%3d 0 0%3d 0 0 0 0\n",
3363
+ x, y, (double)fzero, elname, (int)iso, (int)charge, valence /* at[i].special*/);
3364
+ /* reflect image against x-axis;
3365
+ when transforming MOLfile back to STDATA in mol_to_stdata(...),
3366
+ make one more reflection to restore original orientation.
3367
+ Reason: in MS Search y-axis is directed from top to bottom,
3368
+ while in MOLfile y-axis goes from bottom to top.
3369
+ */
3370
+ }
3371
+ bNext = 0; /* debug only*/
3372
+
3373
+ /* bonds*/
3374
+ for (i=0; i< num_atoms; i++) {
3375
+ for (j=0; j<at[i].valence; j++) {
3376
+ if (i < at[i].neighbor[j]) {
3377
+ if ( k=at[i].bond_stereo[j] ) {
3378
+ /* bond stereo */
3379
+ if ( k < 0 ) {
3380
+ /* transposition */
3381
+ inchi_print_nodisplay(fcb,"%3u%3u%3u%3u 0 0 0\n",
3382
+ (unsigned)(at[i].neighbor[j]+1), (unsigned)(i+1), (unsigned)(at[i].bond_type[j]), (unsigned)abs(k));
3383
+ } else {
3384
+ /* no transposition*/
3385
+ inchi_print_nodisplay(fcb,"%3u%3u%3u%3u 0 0 0\n",
3386
+ (unsigned)(i+1), (unsigned)(at[i].neighbor[j]+1), (unsigned)(at[i].bond_type[j]), (unsigned)abs(k));
3387
+ }
3388
+ } else {
3389
+ inchi_print_nodisplay(fcb,"%3u%3u%3u 0 0 0 0\n",
3390
+ (unsigned)(i+1), (unsigned)(at[i].neighbor[j]+1), (unsigned)(at[i].bond_type[j]));
3391
+ }
3392
+ }
3393
+ }
3394
+ }
3395
+ if ( nNumAddLines ) {
3396
+ char str_m[66], entry[10];
3397
+ int num_m;
3398
+
3399
+ /* Aliases. 5-3-99 DCh.*/
3400
+ if ( nNumAliasLines ) {
3401
+ num_m = 0;
3402
+ for (i=0; i < num_atoms; i++) {
3403
+ if ( ALIASED_AT(i) ) {
3404
+ inchi_print_nodisplay( fcb, "A %d\n", i+1 );
3405
+ num_m ++;
3406
+ strcpy( str_m, at[i].elname );
3407
+ /* Add charge to the Alias */
3408
+ if ( at[i].charge){
3409
+ strcat(str_m, at[i].charge>0? "+" : "-");
3410
+ if ( 1 < (j=abs(at[i].charge)) )
3411
+ sprintf( str_m+strlen(str_m), "%d", j );
3412
+ }
3413
+ /* Add radical to the Alias */
3414
+ for ( j = inchi_min(2,at[i].radical); 0 < j; j-- ) {
3415
+ strcat( str_m, "^" );
3416
+ }
3417
+ inchi_print_nodisplay( fcb, "%s\n", str_m );
3418
+ num_m ++;
3419
+ }
3420
+ }
3421
+ if ( num_m != nNumAliasLines ) {
3422
+ /* error in lines counting*/
3423
+ ret ++;
3424
+ }
3425
+ }
3426
+ /* charges*/
3427
+ str_m[0] = 0;
3428
+ num_m = 0;
3429
+ if ( nNumChargeLines ) {
3430
+ for (i=0; i < num_atoms; i++) {
3431
+ if ( at[i].charge && !ALIASED_AT(i) ) {
3432
+ sprintf( entry, " %3d %3d", i+1, (int)at[i].charge );
3433
+ strcat( str_m, entry );
3434
+ num_m ++;
3435
+ }
3436
+ if ( i == num_atoms-1 && num_m || num_m == 8 ) {
3437
+ inchi_print_nodisplay( fcb, "M CHG%3d%s\n", num_m, str_m );
3438
+ str_m[0] = 0;
3439
+ num_m = 0;
3440
+ }
3441
+ }
3442
+ }
3443
+ /* radicals*/
3444
+ str_m[0] = 0;
3445
+ num_m = 0;
3446
+ if ( nNumRadicalLines ) {
3447
+ for (i=0; i < num_atoms; i++) {
3448
+ if ( at[i].radical && !ALIASED_AT(i) ) {
3449
+ int radical = (at[i].radical==RADICAL_SINGLET ||
3450
+ at[i].radical==RADICAL_DOUBLET ||
3451
+ at[i].radical==RADICAL_TRIPLET)? at[i].radical : 0;
3452
+ if ( radical ) {
3453
+ sprintf( entry, " %3d %3d", i+1, radical );
3454
+ strcat( str_m, entry );
3455
+ num_m ++;
3456
+ }
3457
+ }
3458
+ if ( i == num_atoms-1 && num_m || num_m == 8 ) {
3459
+ inchi_print_nodisplay( fcb, "M RAD%3d%s\n", num_m, str_m );
3460
+ str_m[0] = 0;
3461
+ num_m = 0;
3462
+ }
3463
+ }
3464
+ }
3465
+ /* isotopes*/
3466
+ str_m[0] = 0;
3467
+ num_m = 0;
3468
+ if ( nNumIso ) {
3469
+ for (i=0; i < num_atoms; i++) {
3470
+ if ( 0 == strcmp( at[i].elname, "D" ) ) {
3471
+ sprintf( entry, " %3d %3d", i+1, 2 );
3472
+ strcat( str_m, entry );
3473
+ num_m ++;
3474
+ } else
3475
+ if ( 0 == strcmp( at[i].elname, "T" ) ) {
3476
+ sprintf( entry, " %3d %3d", i+1, 3 );
3477
+ strcat( str_m, entry );
3478
+ num_m ++;
3479
+ }
3480
+ if ( i == num_atoms-1 && num_m || num_m == 8 ) {
3481
+ inchi_print_nodisplay( fcb, "M ISO%3d%s\n", num_m, str_m );
3482
+ str_m[0] = 0;
3483
+ num_m = 0;
3484
+ }
3485
+ }
3486
+ }
3487
+ inchi_print_nodisplay( fcb, "M END\n" );
3488
+ }
3489
+ if ( szValue && szValue[0] ) {
3490
+ if ( szLabel && szLabel[0] ) {
3491
+ inchi_print_nodisplay( fcb, "> <%s>\n", szLabel );
3492
+ } else {
3493
+ inchi_print_nodisplay( fcb, "> <ID>\n" );
3494
+ }
3495
+ inchi_print_nodisplay( fcb, " %s\n\n", szValue );
3496
+ }
3497
+ inchi_print_nodisplay(fcb, "$$$$\n");
3498
+
3499
+
3500
+ return ret;
3501
+
3502
+ }
3503
+ #endif
3504
+ /***************************************************************************************************/
3505
+ int WriteOrigAtomDataToSDfile( const ORIG_ATOM_DATA *inp_at_data, INCHI_FILE* fcb, const char* name, const char* comment,
3506
+ int bChiralFlag, const char *szLabel, const char *szValue)
3507
+ {
3508
+ int i, j, k, num_bonds=0, ret=0;
3509
+ int bAtomNeedsAlias;
3510
+ int flag_bad_charge=0, nNumAddLines=0, nNumIso=0, nNumAddIso=0, nNumChargeLines=0, nNumRadicalLines=0, nNumAliasLines=0;
3511
+ /*sp_ATOM *at; */
3512
+ /* float fzero=0.0F; */
3513
+ double x, y, z;
3514
+ int bNext /*, s*/;
3515
+ const inp_ATOM *at = inp_at_data->at;
3516
+ int num_atoms = inp_at_data->num_inp_atoms;
3517
+ /*at = species->atom;*/
3518
+
3519
+ /*my_fprintf(fcb,"%ld.MOL\n",species->casno);*/
3520
+ { /* block start */
3521
+ char strLocName[82];
3522
+ memset(strLocName, 0, sizeof(strLocName) );
3523
+ if ( name && *name ) {
3524
+ strncpy( strLocName, name, 80 );
3525
+ /* --- debug only ---
3526
+ if ( strstr( name, "#3959" ) ) {
3527
+ int stop = 1;
3528
+ }
3529
+ */
3530
+ }
3531
+ inchi_print_nodisplay( fcb,"%s\n", strLocName );
3532
+ } /* block end */
3533
+ /**********************************************************************/
3534
+ /** **/
3535
+ /** Important: Atoms with alias cannot have charge, radical **/
3536
+ /** isotope differences are allowed **/
3537
+ /** **/
3538
+ /** Atoms with alias cannot be abnormal. **/
3539
+ /** **/
3540
+ /** Abnormal atoms are atoms which need M CHG, M RAD, M ISO **/
3541
+ /** **/
3542
+ /** Output aliased atoms if they have implicit D or T **/
3543
+ /** **/
3544
+ /**********************************************************************/
3545
+
3546
+ /* F10.5 F12.5 I6
3547
+ IIPPPPPPPPMMDDYYHHmmddSSssssssssssEEEEEEEEEEEERRRRRR
3548
+ my_fprintf( fcb,"NISTTRANHP09089809272D 1 1.0 0.0 %6ld\n", lEpa);*/
3549
+ inchi_print_nodisplay( fcb," %s v%s SDfile Output \n", INCHI_NAME, INCHI_VERSION);
3550
+ /*y_fprintf(fcb, " -CPSS- 1213981200n\n");*/
3551
+
3552
+ { /*block start*/
3553
+ char strLocName[82];
3554
+
3555
+ memset(strLocName, 0, sizeof(strLocName) );
3556
+ if ( comment && *comment ) {
3557
+ strncpy( strLocName, comment, 80 );
3558
+ }
3559
+ inchi_print_nodisplay( fcb,"%s\n", strLocName );
3560
+ } /*block end*/
3561
+ for (i=0; i< num_atoms; i++)
3562
+ num_bonds += at[i].valence;
3563
+ num_bonds /= 2;
3564
+
3565
+ /*find if we need "M CHG" and "M RAD"*/
3566
+ for (i=0, nNumAddLines = 0, nNumIso=0; i < num_atoms; i++) {
3567
+ bAtomNeedsAlias = ALIASED_AT(i); /* has isotopic implicit D or T; ignoring pure 1H */
3568
+ nNumAddLines += !bAtomNeedsAlias && ABNORMAL_AT(i); /* abnormal means atom needs CHG, RAD, or ISO entry */
3569
+ nNumAliasLines += 2 * bAtomNeedsAlias;
3570
+ nNumIso += ( 0 == strcmp( at[i].elname, "D" ) || ( 0 == strcmp( at[i].elname, "T" ) || at[i].iso_atw_diff ) );
3571
+ nNumAddIso += at[i].iso_atw_diff && (at[i].iso_atw_diff == 1 || at[i].iso_atw_diff < -3 || at[i].iso_atw_diff > 6 );
3572
+ }
3573
+
3574
+ /* count additional M lines*/
3575
+ if ( nNumAddLines || nNumAliasLines ) {
3576
+ for (i=0, nNumChargeLines=0, nNumRadicalLines=0; i < num_atoms; i++) {
3577
+ nNumChargeLines += (0 != at[i].charge) && !ALIASED_AT(i);
3578
+ nNumRadicalLines += (0 != at[i].radical) && !ALIASED_AT(i);
3579
+ }
3580
+ }
3581
+ nNumChargeLines = ( nNumChargeLines + 7 ) / 8;
3582
+ nNumRadicalLines = ( nNumRadicalLines + 7 ) / 8;
3583
+ nNumIso = ( nNumIso + 7 ) / 8;
3584
+ /* recalculate number of added lines */
3585
+ nNumAddLines = nNumChargeLines + nNumRadicalLines + nNumAliasLines; /* 1 for M END*/
3586
+
3587
+ if ( nNumAddLines == 0 && nNumAddIso == 0 ) {
3588
+ nNumIso = 0; /* keep isotopes description in CTable only*/
3589
+ } else {
3590
+ nNumAddLines += nNumIso+1; /* add 1 for "M END" line*/
3591
+ }
3592
+ if ( !nNumAddLines )
3593
+ nNumAddLines = 1; /* always add V2000 and M END */
3594
+
3595
+ /* aaabbblllfffcccsssxxxrrrpppiiimmmvvvvvv*/
3596
+ inchi_print_nodisplay(fcb,"%3d%3d 0 0%3d 0 0 0 0 0%3d%s\n",
3597
+ num_atoms, num_bonds, bChiralFlag?1:0, nNumAddLines,nNumAddLines?" V2000":"");
3598
+ /* atoms block*/
3599
+ for (i=0; i < num_atoms; i++) {
3600
+ char elname[ATOM_EL_LEN] = "\0\0\0\0\0";
3601
+ int iso = 0;
3602
+ int charge = 0;
3603
+ int valence = 0;
3604
+ bAtomNeedsAlias = ALIASED_AT(i);
3605
+ /* isotope*/
3606
+ iso = !strcmp( at[i].elname, "D" )? 1:
3607
+ !strcmp( at[i].elname, "T" )? 2: 0;
3608
+
3609
+ if ( iso ) {
3610
+ /* deuterium or tritium*/
3611
+ strcpy ( elname, "H" );
3612
+ } else
3613
+ if ( bAtomNeedsAlias ) {
3614
+ strcpy ( elname, "C" );
3615
+ } else {
3616
+ strncpy ( elname, at[i].elname, sizeof(elname)-1 );
3617
+ }
3618
+ if ( !iso && at[i].iso_atw_diff && at[i].iso_atw_diff != 1 && -3 <= at[i].iso_atw_diff && at[i].iso_atw_diff <= 5 ) {
3619
+ iso = (at[i].iso_atw_diff > 0)? at[i].iso_atw_diff-1 : at[i].iso_atw_diff;
3620
+ }
3621
+
3622
+ /*
3623
+ if ( !iso ) {
3624
+ strncpy ( elname, at[i].elname, sizeof(elname)-1 );
3625
+ } else
3626
+ if ( ALIASED_AT(i) ) {
3627
+ strcpy ( elname, "C" );
3628
+ } else {
3629
+ -- deuterium or tritium --
3630
+ strcpy ( elname, "H" );
3631
+ }
3632
+ */
3633
+ if ( !ABNORMAL_AT(i) && !bAtomNeedsAlias ) {
3634
+
3635
+ /* Only normal atoms without alias can be here*/
3636
+
3637
+ /* charge*/
3638
+ switch ( at[i].charge ) {
3639
+ case 3: charge = 1; break;
3640
+ case 2: charge = 2; break;
3641
+ case 1: charge = 3; break;
3642
+ case -1: charge = 5; break;
3643
+ case -2: charge = 6; break;
3644
+ case -3: charge = 7; break;
3645
+ case 0: charge = 0; break;
3646
+ default: flag_bad_charge = 1; break;
3647
+ };
3648
+ /* radical*/
3649
+ if ( at[i].radical ) {
3650
+ if ( at[i].radical == RADICAL_DOUBLET ) {
3651
+ flag_bad_charge |= (charge != 0);
3652
+ charge = 4;
3653
+ } else {
3654
+ flag_bad_charge |= 2;
3655
+ }
3656
+ }
3657
+ if ( flag_bad_charge ) {
3658
+ charge = 0;
3659
+ }
3660
+ }
3661
+
3662
+ x = at[i].x;
3663
+ y = at[i].y;
3664
+ z = at[i].z;
3665
+ /* --- just removed --
3666
+ if ( c && c->xCoeff != 0.0 && c->yCoeff != 0.0 ) {
3667
+ x = (x - c->xShift)/c->xCoeff;
3668
+ y = (y - c->yShift)/c->yCoeff;
3669
+ } else {
3670
+ y = -y;
3671
+ }
3672
+ ----------------------*/
3673
+ /* valence -- set only if needed */
3674
+ valence=needed_unusual_el_valence( at[i].el_number, at[i].charge, at[i].radical,
3675
+ at[i].chem_bonds_valence, at[i].num_H, at[i].valence );
3676
+ if ( valence < 0 ) {
3677
+ valence = 15; /* means no bonds nor H */
3678
+ }
3679
+
3680
+ /*my_fprintf(fcb,"%10.4f%10.4f%10.4f %-3.3s%2d%3d 0 0 0 0 0 0 0\n",*/
3681
+ /* (float)at[i].x, (float)(-at[i].y), fzero, at[i].elname, iso, charge);*/
3682
+ /* xxxxxxyyyyyyzzzzzz aaa____ddcccsssnnnbbbvvvrrriiimmmeee */
3683
+ inchi_print_nodisplay(fcb,"%10.4f%10.4f%10.4f %-3.3s%2d%3d 0 0%3d 0 0 0 0\n",
3684
+ x, y, z, elname, (int)iso, (int)charge, valence /* at[i].special*/);
3685
+ /* reflect image against x-axis;
3686
+ when transforming MOLfile back to STDATA in mol_to_stdata(...),
3687
+ make one more reflection to restore original orientation.
3688
+ Reason: in MS Search y-axis is directed from top to bottom,
3689
+ while in MOLfile y-axis goes from bottom to top.
3690
+ */
3691
+ }
3692
+ bNext = 0; /* debug only*/
3693
+
3694
+ /* bonds*/
3695
+ for (i=0; i< num_atoms; i++) {
3696
+ for (j=0; j<at[i].valence; j++) {
3697
+ if (i < at[i].neighbor[j]) {
3698
+ if ( k=at[i].bond_stereo[j] ) {
3699
+ /* bond stereo */
3700
+ if ( k < 0 ) {
3701
+ /* transposition */
3702
+ inchi_print_nodisplay(fcb,"%3u%3u%3u%3u 0 0 0\n",
3703
+ (unsigned)(at[i].neighbor[j]+1), (unsigned)(i+1), (unsigned)(at[i].bond_type[j]), (unsigned)abs(k));
3704
+ } else {
3705
+ /* no transposition*/
3706
+ inchi_print_nodisplay(fcb,"%3u%3u%3u%3u 0 0 0\n",
3707
+ (unsigned)(i+1), (unsigned)(at[i].neighbor[j]+1), (unsigned)(at[i].bond_type[j]), (unsigned)abs(k));
3708
+ }
3709
+ } else {
3710
+ inchi_print_nodisplay(fcb,"%3u%3u%3u 0 0 0 0\n",
3711
+ (unsigned)(i+1), (unsigned)(at[i].neighbor[j]+1), (unsigned)(at[i].bond_type[j]));
3712
+ }
3713
+ }
3714
+ }
3715
+ }
3716
+ if ( nNumAddLines ) {
3717
+ char str_m[66], entry[10];
3718
+ int num_m;
3719
+
3720
+ /* Aliases. 5-3-99 DCh.*/
3721
+ if ( nNumAliasLines ) {
3722
+ num_m = 0;
3723
+ for (i=0; i < num_atoms; i++) {
3724
+ if ( ALIASED_AT(i) ) {
3725
+ int len;
3726
+ inchi_print_nodisplay( fcb, "A %d\n", i+1 );
3727
+ num_m ++;
3728
+ len = sprintf( str_m, "%s", at[i].elname );
3729
+ /* add isotopic H to the alias */
3730
+ for ( k = 1; k < NUM_H_ISOTOPES; k ++ ) {
3731
+ if ( at[i].num_iso_H[k] ) {
3732
+ len += sprintf( str_m+len, "%s", k==1? "D" : k==2? "T" : "?" );
3733
+ if ( at[i].num_iso_H[k] != 1 ) {
3734
+ len += sprintf( str_m+len, "%d", (int)at[i].num_iso_H[k] );
3735
+ }
3736
+ }
3737
+ }
3738
+ /* Add charge to the Alias */
3739
+ if ( at[i].charge){
3740
+ len += sprintf(str_m+len, "%s", at[i].charge>0? "+" : "-");
3741
+ if ( 1 < (j=abs(at[i].charge)) ) {
3742
+ len += sprintf( str_m+len, "%d", j );
3743
+ }
3744
+ }
3745
+ /* Add radical to the Alias */
3746
+ if ( at[i].radical == RADICAL_SINGLET ) {
3747
+ len += sprintf( str_m+len, "%s", ":" );
3748
+ } else
3749
+ if ( at[i].radical == RADICAL_DOUBLET ) {
3750
+ len += sprintf( str_m+len, "%s", "^" );
3751
+ } else
3752
+ if ( at[i].radical == RADICAL_TRIPLET ) {
3753
+ len += sprintf( str_m+len, "%s", "^^" );
3754
+ }
3755
+ inchi_print_nodisplay( fcb, "%s\n", str_m );
3756
+ num_m ++;
3757
+ }
3758
+ }
3759
+ if ( num_m != nNumAliasLines ) {
3760
+ /* error in lines counting*/
3761
+ ret ++;
3762
+ }
3763
+ }
3764
+ /* charges*/
3765
+ str_m[0] = 0;
3766
+ num_m = 0;
3767
+ if ( nNumChargeLines ) {
3768
+ for (i=0; i < num_atoms; i++) {
3769
+ if ( at[i].charge && !ALIASED_AT(i) ) {
3770
+ sprintf( entry, " %3d %3d", i+1, (int)at[i].charge );
3771
+ strcat( str_m, entry );
3772
+ num_m ++;
3773
+ }
3774
+ if ( i == num_atoms-1 && num_m || num_m == 8 ) {
3775
+ inchi_print_nodisplay( fcb, "M CHG%3d%s\n", num_m, str_m );
3776
+ str_m[0] = 0;
3777
+ num_m = 0;
3778
+ }
3779
+ }
3780
+ }
3781
+ /* radicals*/
3782
+ str_m[0] = 0;
3783
+ num_m = 0;
3784
+ if ( nNumRadicalLines ) {
3785
+ for (i=0; i < num_atoms; i++) {
3786
+ if ( at[i].radical && !ALIASED_AT(i) ) {
3787
+ int radical = (at[i].radical==RADICAL_SINGLET ||
3788
+ at[i].radical==RADICAL_DOUBLET ||
3789
+ at[i].radical==RADICAL_TRIPLET)? at[i].radical : 0;
3790
+ if ( radical ) {
3791
+ sprintf( entry, " %3d %3d", i+1, radical );
3792
+ strcat( str_m, entry );
3793
+ num_m ++;
3794
+ }
3795
+ }
3796
+ if ( i == num_atoms-1 && num_m || num_m == 8 ) {
3797
+ inchi_print_nodisplay( fcb, "M RAD%3d%s\n", num_m, str_m );
3798
+ str_m[0] = 0;
3799
+ num_m = 0;
3800
+ }
3801
+ }
3802
+ }
3803
+ /* isotopes*/
3804
+ str_m[0] = 0;
3805
+ num_m = 0;
3806
+ if ( nNumIso ) {
3807
+ for (i=0; i < num_atoms; i++) {
3808
+ if ( 0 == strcmp( at[i].elname, "D" ) ) {
3809
+ sprintf( entry, " %3d %3d", i+1, 2 );
3810
+ strcat( str_m, entry );
3811
+ num_m ++;
3812
+ } else
3813
+ if ( 0 == strcmp( at[i].elname, "T" ) ) {
3814
+ sprintf( entry, " %3d %3d", i+1, 3 );
3815
+ strcat( str_m, entry );
3816
+ num_m ++;
3817
+ } else
3818
+ if ( k = at[i].iso_atw_diff ) {
3819
+ int mw = get_atw_from_elnum( at[i].el_number );
3820
+ mw += (k > 0)? k-1 : k;
3821
+ sprintf( entry, " %3d %3d", i+1, mw );
3822
+ strcat( str_m, entry );
3823
+ num_m ++;
3824
+ }
3825
+ if ( i == num_atoms-1 && num_m || num_m == 8 ) {
3826
+ inchi_print_nodisplay( fcb, "M ISO%3d%s\n", num_m, str_m );
3827
+ str_m[0] = 0;
3828
+ num_m = 0;
3829
+ }
3830
+ }
3831
+ }
3832
+ inchi_print_nodisplay( fcb, "M END\n" );
3833
+ }
3834
+ if ( szValue && szValue[0] ) {
3835
+ if ( szLabel && szLabel[0] ) {
3836
+ inchi_print_nodisplay( fcb, "> <%s>\n", szLabel );
3837
+ } else {
3838
+ inchi_print_nodisplay( fcb, "> <ID>\n" );
3839
+ }
3840
+ inchi_print_nodisplay( fcb, " %s\n\n", szValue );
3841
+ }
3842
+ inchi_print_nodisplay(fcb, "$$$$\n");
3843
+
3844
+
3845
+ return ret;
3846
+
3847
+ }
3848
+
3849
+ #ifdef INCHI_ANSI_ONLY
3850
+ #ifndef INCHI_LIBRARY
3851
+ /*
3852
+ #include <stdio.h>
3853
+ #include "inpdef.h"
3854
+ */
3855
+ void PrintFileName( const char *fmt, INCHI_FILE *output_file, const char *szFname )
3856
+ {
3857
+ inchi_print_nodisplay( output_file, fmt, szFname );
3858
+ }
3859
+ #endif
3860
+ #endif
3861
+