Branch data Line data Source code
1 : : /*
2 : : * International Chemical Identifier (InChI)
3 : : * Version 1
4 : : * Software version 1.07
5 : : * April 30, 2024
6 : : *
7 : : * MIT License
8 : : *
9 : : * Copyright (c) 2024 IUPAC and InChI Trust
10 : : *
11 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
12 : : * of this software and associated documentation files (the "Software"), to deal
13 : : * in the Software without restriction, including without limitation the rights
14 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 : : * copies of the Software, and to permit persons to whom the Software is
16 : : * furnished to do so, subject to the following conditions:
17 : : *
18 : : * The above copyright notice and this permission notice shall be included in all
19 : : * copies or substantial portions of the Software.
20 : : *
21 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 : : * SOFTWARE.
28 : : *
29 : : * The InChI library and programs are free software developed under the
30 : : * auspices of the International Union of Pure and Applied Chemistry (IUPAC).
31 : : * Originally developed at NIST.
32 : : * Modifications and additions by IUPAC and the InChI Trust.
33 : : * Some portions of code were developed/changed by external contributors
34 : : * (either contractor or volunteer) which are listed in the file
35 : : * 'External-contributors' included in this distribution.
36 : : *
37 : : * info@inchi-trust.org
38 : : *
39 : : */
40 : :
41 : : #include <stdlib.h>
42 : : #include <string.h>
43 : :
44 : : #include "mode.h"
45 : : #include "aromaticity.h"
46 : : #include "ichinorm.h" /* declares mark_alt_bonds_and_taut_groups + engine types */
47 : : #include "util.h" /* is_in_the_list */
48 : : #include "ichierr.h"
49 : :
50 : : #include "bcf_s.h"
51 : :
52 : :
53 : : /****************************************************************************/
54 : 0 : int fix_aromatic_oxygen_and_sulfur( inp_ATOM *atom )
55 : : {
56 [ # # ]: 0 : if (!atom->elname[1] &&
57 [ # # # # ]: 0 : (atom->elname[0] == 'O' || atom->elname[0] == 'S') &&
58 [ # # # # : 0 : atom->valence == 2 && !atom->charge && !atom->radical &&
# # ]
59 [ # # ]: 0 : atom->bond_type[0] + atom->bond_type[1] == 3)
60 : : {
61 : 0 : atom->charge = 1;
62 : 0 : return 1; /* fixed */
63 : : }
64 : :
65 : 0 : return 0;
66 : : }
67 : :
68 : :
69 : : /****************************************************************************/
70 : 0 : int check_arom_chain( inp_ATOM *at,
71 : : int cur /* first*/,
72 : : int from,
73 : : int last,
74 : : int len )
75 : : {
76 : : int i, num;
77 : 0 : num = 0;
78 : : do
79 : : {
80 : : /* check this on all except at[last], which is typically different */
81 [ # # ]: 0 : if (at[cur].el_number != EL_NUMBER_C ||
82 [ # # ]: 0 : at[cur].valence != 2 ||
83 [ # # ]: 0 : at[cur].chem_bonds_valence != 3 ||
84 [ # # ]: 0 : at[cur].num_H != 1)
85 : : {
86 : 0 : goto check_next_derivative;
87 : : }
88 : : /* bond to the next atom - check on all, cur..last, atoms */
89 : 0 : i = ( at[cur].neighbor[0] == from ); /* index of a bond to the next atom */
90 [ # # ]: 0 : if (at[cur].bond_type[i] != BOND_ALTERN)
91 : : {
92 : 0 : goto check_next_derivative;
93 : : }
94 : 0 : num++; /* checks are complete */
95 : : /* prepare for the next atom */
96 : 0 : from = cur;
97 : 0 : cur = at[cur].neighbor[i];
98 [ # # # # ]: 0 : } while (cur != last && num < len);
99 : :
100 [ # # # # ]: 0 : return ( cur == last && ++num == len );
101 : :
102 : 0 : check_next_derivative:
103 : :
104 : 0 : return 0;
105 : : }
106 : :
107 : :
108 : : #if ( RING2CHAIN == 1 || UNDERIVATIZE == 1 )
109 : : /****************************************************************************/
110 : 0 : int mark_arom_bonds( struct tagINCHI_CLOCK *ic, struct tagCANON_GLOBALS *pCG, inp_ATOM *at, int num_atoms )
111 : : {
112 : 0 : INCHI_MODE bTautFlags = 0, bTautFlagsDone = 0;
113 : 0 : inp_ATOM *at_fixed_bonds_out = NULL;
114 : 0 : T_GROUP_INFO *t_group_info = NULL;
115 : : int ret;
116 : :
117 : 0 : ret = mark_alt_bonds_and_taut_groups( ic, pCG, at, at_fixed_bonds_out, num_atoms,
118 : : NULL,
119 : : t_group_info, &bTautFlags, &bTautFlagsDone, 0, NULL );
120 : :
121 : 0 : return ret;
122 : : }
123 : :
124 : :
125 : : /****************************************************************************/
126 : 0 : int is_C_unsat_not_arom( inp_ATOM *at, int i )
127 : : {
128 : : int j, neigh, num_arom, num_DB;
129 [ # # ]: 0 : if (at[i].el_number != EL_NUMBER_C ||
130 [ # # ]: 0 : at[i].valence == at[i].chem_bonds_valence || /* no double/triple bonds */
131 [ # # ]: 0 : at[i].valence + 1 < at[i].chem_bonds_valence || /* >1 double bond or >=1 triple bond */
132 [ # # ]: 0 : at[i].chem_bonds_valence + at[i].num_H != 4 || /* C has wrong valence */
133 [ # # # # ]: 0 : at[i].charge || at[i].radical)
134 : 0 : return 0;
135 : 0 : num_arom = num_DB = 0;
136 [ # # ]: 0 : for (j = 0; j < at[i].valence; j++)
137 : : {
138 : 0 : neigh = at[i].neighbor[j];
139 : 0 : num_arom += at[i].bond_type[j] == BOND_TYPE_ALTERN;
140 [ # # ]: 0 : if (( at[neigh].el_number == EL_NUMBER_O ||
141 [ # # ]: 0 : at[neigh].el_number == EL_NUMBER_S ) &&
142 [ # # # # ]: 0 : !at[neigh].num_H && 1 == at[neigh].valence &&
143 [ # # ]: 0 : 2 == at[neigh].chem_bonds_valence)
144 : : {
145 : 0 : continue; /* do not count double bonds to terminal =O or =S */
146 : : }
147 : 0 : num_DB += at[i].bond_type[j] == BOND_TYPE_DOUBLE;
148 : : }
149 : :
150 [ # # # # ]: 0 : return num_DB && !num_arom;
151 : : }
152 : :
153 : :
154 : : /****************************************************************************/
155 : 0 : int is_Aryl( inp_ATOM *at, int outside_point, int attachment_pont )
156 : : {
157 : : int i, num_arom_bonds, neigh;
158 [ # # ]: 0 : if (at[attachment_pont].el_number == EL_NUMBER_C &&
159 [ # # # # ]: 0 : at[attachment_pont].valence == 3 && at[attachment_pont].chem_bonds_valence == 4 &&
160 [ # # # # : 0 : !at[attachment_pont].num_H && !at[attachment_pont].charge && !at[attachment_pont].radical)
# # ]
161 : : {
162 [ # # ]: 0 : for (i = 0, num_arom_bonds = 0; i < at[attachment_pont].valence; i++)
163 : : {
164 : 0 : neigh = at[attachment_pont].neighbor[i];
165 [ # # ]: 0 : if (neigh != outside_point)
166 : : {
167 [ # # ]: 0 : num_arom_bonds += ( at[attachment_pont].bond_type[i] == BOND_ALTERN &&
168 [ # # # # ]: 0 : ( at[neigh].el_number == EL_NUMBER_C || at[neigh].el_number == EL_NUMBER_N ) );
169 : : }
170 : : }
171 : 0 : return ( num_arom_bonds == 2 );
172 : : }
173 : :
174 : 0 : return 0;
175 : : }
176 : : #endif /* ( RING2CHAIN == 1 || UNDERIVATIZE == 1 ) */
177 : :
178 : :
179 : : #ifdef FIX_UNDERIV_TO_SDF
180 : : /****************************************************************************/
181 : 0 : int replace_arom_bonds( inp_ATOM *at,
182 : : int num_atoms,
183 : : inp_ATOM *at2,
184 : : int num_atoms2 )
185 : : {
186 : 0 : int i, j, num_err = 0;
187 : :
188 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
189 : : {
190 [ # # ]: 0 : for (j = 0; j < at[i].valence; j++)
191 : : {
192 [ # # ]: 0 : if (at[i].bond_type[j] > BOND_TRIPLE)
193 : : {
194 : : /* find pairs of atoms using orig. atom numbers */
195 : : int i1, i2;
196 : 0 : char bSuccess = 0;
197 : 0 : int neigh = at[i].neighbor[j];
198 : 0 : AT_NUMB orig_no1 = at[i].orig_at_number;
199 : 0 : AT_NUMB orig_no2 = at[neigh].orig_at_number;
200 [ # # # # ]: 0 : for (i1 = 0; i1 < num_atoms2 && at2[i1].orig_at_number != orig_no1; i1++)
201 : : {
202 : : ;
203 : : }
204 [ # # # # ]: 0 : for (i2 = 0; i2 < num_atoms2 && at2[i2].orig_at_number != orig_no2; i2++)
205 : : {
206 : : ;
207 : : }
208 [ # # # # ]: 0 : if (i1 < num_atoms2 && i2 < num_atoms2)
209 : : {
210 : 0 : AT_NUMB *p1 = is_in_the_list( at2[i1].neighbor, (AT_NUMB) i2, at2[i1].valence );
211 : 0 : AT_NUMB *pneigh = is_in_the_list( at[neigh].neighbor, (AT_NUMB) i, at[neigh].valence );
212 [ # # # # ]: 0 : if (p1 && pneigh)
213 : : {
214 : 0 : int n1 = p1 - at2[i1].neighbor;
215 : 0 : int nneigh = pneigh - at[neigh].neighbor;
216 : 0 : at[i].bond_type[j] = at[neigh].bond_type[nneigh] = at2[i1].bond_type[n1];
217 : 0 : bSuccess = 1;
218 : : }
219 : : }
220 [ # # ]: 0 : if (!bSuccess)
221 : : {
222 : : #ifdef _DEBUG
223 : : int stop_here = 1;
224 : : #endif
225 : 0 : num_err++;
226 : : }
227 : : }
228 : : }
229 : : }
230 : :
231 : 0 : return num_err;
232 : : }
233 : : #endif /* FIX_UNDERIV_TO_SDF */
|