LCOV - code coverage report
Current view: top level - src - aromaticity.c (source / functions) Coverage Total Hit
Test: InChI Unit Test Coverage Lines: 0.0 % 82 0
Test Date: 2026-08-20 14:32:48 Functions: 0.0 % 6 0
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0.0 % 106 0

             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 */
        

Generated by: LCOV version 2.0-1