Branch data Line data Source code
1 : : /*
2 : : * SPDX-License-Identifier: MIT
3 : : * Copyright (c) 2024 IUPAC and InChI Trust
4 : : */
5 : :
6 : : #include <stdlib.h>
7 : : #include <string.h>
8 : :
9 : : #include "mode.h"
10 : : #include "aromaticity.h"
11 : : #include "ichinorm.h" /* declares mark_alt_bonds_and_taut_groups + engine types */
12 : : #include "util.h" /* is_in_the_list */
13 : : #include "ichierr.h"
14 : :
15 : : #include "bcf_s.h"
16 : :
17 : :
18 : : /****************************************************************************/
19 : 0 : int fix_aromatic_oxygen_and_sulfur( inp_ATOM *atom )
20 : : {
21 [ # # ]: 0 : if (!atom->elname[1] &&
22 [ # # # # ]: 0 : (atom->elname[0] == 'O' || atom->elname[0] == 'S') &&
23 [ # # # # : 0 : atom->valence == 2 && !atom->charge && !atom->radical &&
# # ]
24 [ # # ]: 0 : atom->bond_type[0] + atom->bond_type[1] == 3)
25 : : {
26 : 0 : atom->charge = 1;
27 : 0 : return 1; /* fixed */
28 : : }
29 : :
30 : 0 : return 0;
31 : : }
32 : :
33 : :
34 : : /****************************************************************************/
35 : 0 : int check_arom_chain( inp_ATOM *at,
36 : : int cur /* first*/,
37 : : int from,
38 : : int last,
39 : : int len )
40 : : {
41 : : int i, num;
42 : 0 : num = 0;
43 : : do
44 : : {
45 : : /* check this on all except at[last], which is typically different */
46 [ # # ]: 0 : if (at[cur].el_number != EL_NUMBER_C ||
47 [ # # ]: 0 : at[cur].valence != 2 ||
48 [ # # ]: 0 : at[cur].chem_bonds_valence != 3 ||
49 [ # # ]: 0 : at[cur].num_H != 1)
50 : : {
51 : 0 : goto check_next_derivative;
52 : : }
53 : : /* bond to the next atom - check on all, cur..last, atoms */
54 : 0 : i = ( at[cur].neighbor[0] == from ); /* index of a bond to the next atom */
55 [ # # ]: 0 : if (at[cur].bond_type[i] != BOND_ALTERN)
56 : : {
57 : 0 : goto check_next_derivative;
58 : : }
59 : 0 : num++; /* checks are complete */
60 : : /* prepare for the next atom */
61 : 0 : from = cur;
62 : 0 : cur = at[cur].neighbor[i];
63 [ # # # # ]: 0 : } while (cur != last && num < len);
64 : :
65 [ # # # # ]: 0 : return ( cur == last && ++num == len );
66 : :
67 : 0 : check_next_derivative:
68 : :
69 : 0 : return 0;
70 : : }
71 : :
72 : :
73 : : #if ( RING2CHAIN == 1 || UNDERIVATIZE == 1 )
74 : : /****************************************************************************/
75 : 0 : int mark_arom_bonds( struct tagINCHI_CLOCK *ic, struct tagCANON_GLOBALS *pCG, inp_ATOM *at, int num_atoms )
76 : : {
77 : 0 : INCHI_MODE bTautFlags = 0, bTautFlagsDone = 0;
78 : 0 : inp_ATOM *at_fixed_bonds_out = NULL;
79 : 0 : T_GROUP_INFO *t_group_info = NULL;
80 : : int ret;
81 : :
82 : 0 : ret = mark_alt_bonds_and_taut_groups( ic, pCG, at, at_fixed_bonds_out, num_atoms,
83 : : NULL,
84 : : t_group_info, &bTautFlags, &bTautFlagsDone, 0, NULL );
85 : :
86 : 0 : return ret;
87 : : }
88 : :
89 : :
90 : : /****************************************************************************/
91 : 0 : int is_C_unsat_not_arom( inp_ATOM *at, int i )
92 : : {
93 : : int j, neigh, num_arom, num_DB;
94 [ # # ]: 0 : if (at[i].el_number != EL_NUMBER_C ||
95 [ # # ]: 0 : at[i].valence == at[i].chem_bonds_valence || /* no double/triple bonds */
96 [ # # ]: 0 : at[i].valence + 1 < at[i].chem_bonds_valence || /* >1 double bond or >=1 triple bond */
97 [ # # ]: 0 : at[i].chem_bonds_valence + at[i].num_H != 4 || /* C has wrong valence */
98 [ # # # # ]: 0 : at[i].charge || at[i].radical)
99 : 0 : return 0;
100 : 0 : num_arom = num_DB = 0;
101 [ # # ]: 0 : for (j = 0; j < at[i].valence; j++)
102 : : {
103 : 0 : neigh = at[i].neighbor[j];
104 : 0 : num_arom += at[i].bond_type[j] == BOND_TYPE_ALTERN;
105 [ # # ]: 0 : if (( at[neigh].el_number == EL_NUMBER_O ||
106 [ # # ]: 0 : at[neigh].el_number == EL_NUMBER_S ) &&
107 [ # # # # ]: 0 : !at[neigh].num_H && 1 == at[neigh].valence &&
108 [ # # ]: 0 : 2 == at[neigh].chem_bonds_valence)
109 : : {
110 : 0 : continue; /* do not count double bonds to terminal =O or =S */
111 : : }
112 : 0 : num_DB += at[i].bond_type[j] == BOND_TYPE_DOUBLE;
113 : : }
114 : :
115 [ # # # # ]: 0 : return num_DB && !num_arom;
116 : : }
117 : :
118 : :
119 : : /****************************************************************************/
120 : 0 : int is_Aryl( inp_ATOM *at, int outside_point, int attachment_pont )
121 : : {
122 : : int i, num_arom_bonds, neigh;
123 [ # # ]: 0 : if (at[attachment_pont].el_number == EL_NUMBER_C &&
124 [ # # # # ]: 0 : at[attachment_pont].valence == 3 && at[attachment_pont].chem_bonds_valence == 4 &&
125 [ # # # # : 0 : !at[attachment_pont].num_H && !at[attachment_pont].charge && !at[attachment_pont].radical)
# # ]
126 : : {
127 [ # # ]: 0 : for (i = 0, num_arom_bonds = 0; i < at[attachment_pont].valence; i++)
128 : : {
129 : 0 : neigh = at[attachment_pont].neighbor[i];
130 [ # # ]: 0 : if (neigh != outside_point)
131 : : {
132 [ # # ]: 0 : num_arom_bonds += ( at[attachment_pont].bond_type[i] == BOND_ALTERN &&
133 [ # # # # ]: 0 : ( at[neigh].el_number == EL_NUMBER_C || at[neigh].el_number == EL_NUMBER_N ) );
134 : : }
135 : : }
136 : 0 : return ( num_arom_bonds == 2 );
137 : : }
138 : :
139 : 0 : return 0;
140 : : }
141 : : #endif /* ( RING2CHAIN == 1 || UNDERIVATIZE == 1 ) */
142 : :
143 : :
144 : : #ifdef FIX_UNDERIV_TO_SDF
145 : : /****************************************************************************/
146 : 0 : int replace_arom_bonds( inp_ATOM *at,
147 : : int num_atoms,
148 : : inp_ATOM *at2,
149 : : int num_atoms2 )
150 : : {
151 : 0 : int i, j, num_err = 0;
152 : :
153 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
154 : : {
155 [ # # ]: 0 : for (j = 0; j < at[i].valence; j++)
156 : : {
157 [ # # ]: 0 : if (at[i].bond_type[j] > BOND_TRIPLE)
158 : : {
159 : : /* find pairs of atoms using orig. atom numbers */
160 : : int i1, i2;
161 : 0 : char bSuccess = 0;
162 : 0 : int neigh = at[i].neighbor[j];
163 : 0 : AT_NUMB orig_no1 = at[i].orig_at_number;
164 : 0 : AT_NUMB orig_no2 = at[neigh].orig_at_number;
165 [ # # # # ]: 0 : for (i1 = 0; i1 < num_atoms2 && at2[i1].orig_at_number != orig_no1; i1++)
166 : : {
167 : : ;
168 : : }
169 [ # # # # ]: 0 : for (i2 = 0; i2 < num_atoms2 && at2[i2].orig_at_number != orig_no2; i2++)
170 : : {
171 : : ;
172 : : }
173 [ # # # # ]: 0 : if (i1 < num_atoms2 && i2 < num_atoms2)
174 : : {
175 : 0 : AT_NUMB *p1 = is_in_the_list( at2[i1].neighbor, (AT_NUMB) i2, at2[i1].valence );
176 : 0 : AT_NUMB *pneigh = is_in_the_list( at[neigh].neighbor, (AT_NUMB) i, at[neigh].valence );
177 [ # # # # ]: 0 : if (p1 && pneigh)
178 : : {
179 : 0 : int n1 = p1 - at2[i1].neighbor;
180 : 0 : int nneigh = pneigh - at[neigh].neighbor;
181 : 0 : at[i].bond_type[j] = at[neigh].bond_type[nneigh] = at2[i1].bond_type[n1];
182 : 0 : bSuccess = 1;
183 : : }
184 : : }
185 [ # # ]: 0 : if (!bSuccess)
186 : : {
187 : : #ifdef _DEBUG
188 : : int stop_here = 1;
189 : : #endif
190 : 0 : num_err++;
191 : : }
192 : : }
193 : : }
194 : : }
195 : :
196 : 0 : return num_err;
197 : : }
198 : : #endif /* FIX_UNDERIV_TO_SDF */
|