rino 0.1.0

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