rino 0.1.0 → 0.2.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 (104) hide show
  1. data/Rakefile +1 -1
  2. data/ext/extconf.rb +1 -24
  3. data/ext/libinchi.so +0 -0
  4. data/ext/src/aux2atom.h +120 -39
  5. data/ext/src/comdef.h +3 -3
  6. data/ext/src/dispstru.c +2547 -0
  7. data/ext/src/dispstru.h +73 -0
  8. data/ext/src/extr_ct.h +5 -2
  9. data/ext/src/ichi.h +27 -11
  10. data/ext/src/ichi_bns.c +1800 -254
  11. data/ext/src/ichi_bns.h +205 -4
  12. data/ext/src/ichican2.c +197 -86
  13. data/ext/src/ichicano.c +8 -13
  14. data/ext/src/ichicano.h +2 -2
  15. data/ext/src/ichicans.c +11 -6
  16. data/ext/src/ichicant.h +2 -2
  17. data/ext/src/ichicomn.h +2 -2
  18. data/ext/src/ichicomp.h +19 -4
  19. data/ext/src/ichidrp.h +9 -5
  20. data/ext/src/ichierr.h +5 -3
  21. data/ext/src/ichiisot.c +2 -2
  22. data/ext/src/ichimain.c +461 -0
  23. data/ext/src/ichimain.h +23 -15
  24. data/ext/src/ichimak2.c +6 -6
  25. data/ext/src/ichimake.c +843 -42
  26. data/ext/src/ichimake.h +4 -2
  27. data/ext/src/ichimap1.c +5 -5
  28. data/ext/src/ichimap2.c +2 -2
  29. data/ext/src/ichimap4.c +34 -21
  30. data/ext/src/ichinorm.c +11 -5
  31. data/ext/src/ichinorm.h +3 -2
  32. data/ext/src/ichiparm.c +2 -2
  33. data/ext/src/ichiparm.h +232 -30
  34. data/ext/src/ichiprt1.c +35 -11
  35. data/ext/src/ichiprt2.c +78 -7
  36. data/ext/src/ichiprt3.c +300 -120
  37. data/ext/src/ichiqueu.c +17 -2
  38. data/ext/src/ichiread.c +6932 -0
  39. data/ext/src/ichiring.c +3 -2
  40. data/ext/src/ichiring.h +2 -2
  41. data/ext/src/ichirvr1.c +4891 -0
  42. data/ext/src/ichirvr2.c +6344 -0
  43. data/ext/src/ichirvr3.c +5499 -0
  44. data/ext/src/ichirvr4.c +3177 -0
  45. data/ext/src/ichirvr5.c +1166 -0
  46. data/ext/src/ichirvr6.c +1287 -0
  47. data/ext/src/ichirvr7.c +2319 -0
  48. data/ext/src/ichirvrs.h +882 -0
  49. data/ext/src/ichisize.h +2 -2
  50. data/ext/src/ichisort.c +5 -5
  51. data/ext/src/ichister.c +281 -86
  52. data/ext/src/ichister.h +9 -3
  53. data/ext/src/ichitaut.c +208 -9
  54. data/ext/src/ichitaut.h +13 -11
  55. data/ext/src/ichitime.h +16 -2
  56. data/ext/src/inchicmp.h +107 -0
  57. data/ext/src/inpdef.h +6 -3
  58. data/ext/src/libinchi_wrap.c +912 -0
  59. data/ext/src/lreadmol.h +34 -31
  60. data/ext/src/mode.h +244 -7
  61. data/ext/src/mol2atom.c +1060 -0
  62. data/ext/src/mol2atom.h +31 -0
  63. data/ext/src/readinch.c +239 -0
  64. data/ext/src/readmol.c +28 -0
  65. data/ext/src/{e_readmol.h → readmol.h} +7 -9
  66. data/ext/src/runichi.c +251 -177
  67. data/ext/src/strutil.c +444 -238
  68. data/ext/src/strutil.h +150 -11
  69. data/ext/src/util.c +176 -118
  70. data/ext/src/util.h +15 -3
  71. data/lib/rino.rb +71 -3
  72. data/test/test.rb +33 -4
  73. metadata +22 -34
  74. data/ext/ruby_inchi_main.so +0 -0
  75. data/ext/src/e_0dstereo.c +0 -3014
  76. data/ext/src/e_0dstereo.h +0 -31
  77. data/ext/src/e_comdef.h +0 -57
  78. data/ext/src/e_ctl_data.h +0 -147
  79. data/ext/src/e_ichi_io.c +0 -498
  80. data/ext/src/e_ichi_io.h +0 -40
  81. data/ext/src/e_ichi_parms.c +0 -37
  82. data/ext/src/e_ichi_parms.h +0 -41
  83. data/ext/src/e_ichicomp.h +0 -50
  84. data/ext/src/e_ichierr.h +0 -40
  85. data/ext/src/e_ichimain.c +0 -593
  86. data/ext/src/e_ichisize.h +0 -43
  87. data/ext/src/e_inchi_atom.c +0 -75
  88. data/ext/src/e_inchi_atom.h +0 -33
  89. data/ext/src/e_inpdef.h +0 -41
  90. data/ext/src/e_mode.h +0 -706
  91. data/ext/src/e_mol2atom.c +0 -649
  92. data/ext/src/e_readinch.c +0 -58
  93. data/ext/src/e_readmol.c +0 -54
  94. data/ext/src/e_readstru.c +0 -251
  95. data/ext/src/e_readstru.h +0 -33
  96. data/ext/src/e_util.c +0 -284
  97. data/ext/src/e_util.h +0 -61
  98. data/ext/src/ichilnct.c +0 -286
  99. data/ext/src/inchi_api.h +0 -670
  100. data/ext/src/inchi_dll.c +0 -1480
  101. data/ext/src/inchi_dll.h +0 -34
  102. data/ext/src/inchi_dll_main.c +0 -23
  103. data/ext/src/inchi_dll_main.h +0 -31
  104. data/ext/src/ruby_inchi_main.c +0 -558
@@ -2,8 +2,8 @@
2
2
  * International Union of Pure and Applied Chemistry (IUPAC)
3
3
  * International Chemical Identifier (InChI)
4
4
  * Version 1
5
- * Software version 1.00
6
- * April 13, 2005
5
+ * Software version 1.01
6
+ * July 21, 2006
7
7
  * Developed at NIST
8
8
  */
9
9
 
@@ -2,8 +2,8 @@
2
2
  * International Union of Pure and Applied Chemistry (IUPAC)
3
3
  * International Chemical Identifier (InChI)
4
4
  * Version 1
5
- * Software version 1.00
6
- * April 13, 2005
5
+ * Software version 1.01
6
+ * July 21, 2006
7
7
  * Developed at NIST
8
8
  */
9
9
 
@@ -38,10 +38,10 @@ void swap ( char *a, char *b, size_t width )
38
38
  /* Sort by insertions */
39
39
  int insertions_sort( void *base, size_t num, size_t width, int ( *compare )(const void *e1, const void *e2 ) )
40
40
  {
41
- char *i, *j, *pk;
41
+ char *i, *j, *pk = (char*)base;
42
42
  int num_trans = 0;
43
43
  size_t k;
44
- for( k=1, pk = (char*)base; k < num; k++, pk += width ) {
44
+ for( k=1; k < num; k++, pk += width ) {
45
45
  for( i = pk, j = pk + width; j > (char*)base && (*compare)(i,j) > 0; j=i, i -= width ) {
46
46
  swap( i, j, width );
47
47
  num_trans ++;
@@ -203,7 +203,7 @@ int CompAtomInvariants2( const void* a1, const void* a2 )
203
203
  return ret;
204
204
  }
205
205
  /**********************************************************************************/
206
- /* Compare two elements lexic�graphically */
206
+ /* Compare two elements lexicographically */
207
207
  int CompChemElemLex( const void *a1, const void *a2 )
208
208
  {
209
209
  return memcmp( a1, a2, 2);
@@ -2,8 +2,8 @@
2
2
  * International Union of Pure and Applied Chemistry (IUPAC)
3
3
  * International Chemical Identifier (InChI)
4
4
  * Version 1
5
- * Software version 1.00
6
- * April 13, 2005
5
+ * Software version 1.01
6
+ * July 21, 2006
7
7
  * Developed at NIST
8
8
  */
9
9
 
@@ -51,43 +51,41 @@
51
51
  #define MAX_EDGE_RATIO 6.00 /* max max/min edge ratio for a tetrahedra close to a parallelogram */
52
52
  #endif
53
53
  /* local prototypes */
54
- int save_a_stereo_bond( int z_prod, int result_action,
54
+ static int save_a_stereo_bond( int z_prod, int result_action,
55
55
  int at1, int ord1, AT_NUMB *stereo_bond_neighbor1, S_CHAR *stereo_bond_ord1, S_CHAR *stereo_bond_z_prod1, S_CHAR *stereo_bond_parity1,
56
56
  int at2, int ord2, AT_NUMB *stereo_bond_neighbor2, S_CHAR *stereo_bond_ord2, S_CHAR *stereo_bond_z_prod2, S_CHAR *stereo_bond_parity2 );
57
- double get_z_coord( inp_ATOM* at, int cur_atom, int neigh_no, int *nType,int bPointedEdgeStereo );
58
- double len3( const double c[] );
59
- double len2( const double c[] );
60
- double* diff3( const double a[], const double b[], double result[] );
61
- double* add3( const double a[], const double b[], double result[] );
62
- double* mult3( const double a[], double b, double result[] );
63
- double* copy3( const double a[], double result[] );
64
- double* change_sign3( const double a[], double result[] );
65
- double dot_prod3( const double a[], const double b[] );
66
- int dot_prodchar3( const S_CHAR a[], const S_CHAR b[] );
67
- double* cross_prod3( const double a[], const double b[], double result[] );
68
- double triple_prod( double a[], double b[], double c[], double *sine_value );
69
- double triple_prod_and_min_abs_sine(double at_coord[][3], double *min_sine);
70
- double sp3_triple_prod_and_min_abs_sine(double at_coord[][3], double central_at_coord[], double *min_sine, int *bAmbiguous);
71
- int are_3_vect_in_one_plane( double at_coord[][3], double min_sine);
72
- int triple_prod_char( inp_ATOM *at, int at_1, int i_next_at_1, S_CHAR *z_dir1,
73
- int at_2, int i_next_at_2, S_CHAR *z_dir2 );
74
-
75
- int CompDble( const void *a1, const void *a2 );
76
- int Get2DTetrahedralAmbiguity( double at_coord[][3], int bAddExplicitNeighbor );
77
- double triple_prod_and_min_abs_sine2(double at_coord[][3], double central_at_coord[], int bAddedExplicitNeighbor, double *min_sine, int *bAmbiguous);
78
- int are_4at_in_one_plane( double at_coord[][3], double min_sine);
79
- int bInpAtomHasRequirdNeigh ( inp_ATOM *at, int cur_at, int RequirdNeighType, int NumDbleBonds );
80
- int bCanAtomBeMiddleAllene( char *elname, S_CHAR charge, S_CHAR radical );
81
- int bIsSuitableHeteroInpAtom( inp_ATOM *at );
82
- int bIsOxide( inp_ATOM *at, int cur_at );
83
- int half_stereo_bond_parity( inp_ATOM *at, int cur_at, inp_ATOM *at_removed_H, int num_removed_H, S_CHAR *z_dir, int bPointedEdgeStereo );
84
- int get_allowed_stereo_bond_type( int bond_type );
85
- int can_be_a_stereo_bond_with_isotopic_H( inp_ATOM *at, int cur_at, INCHI_MODE nMode );
86
- int half_stereo_bond_action( int nParity, int bUnknown, int bIsotopic );
87
- int set_stereo_bonds_parity( sp_ATOM *out_at, inp_ATOM *at, int at_1, inp_ATOM *at_removed_H, int num_removed_H,
88
- INCHI_MODE nMode, QUEUE *q, AT_RANK *nAtomLevel, S_CHAR *cSource, AT_RANK min_sb_ring_size, int bPointedEdgeStereo );
89
- int can_be_a_stereo_atom_with_isotopic_H( inp_ATOM *at, int cur_at );
90
- int set_stereo_atom_parity( sp_ATOM *out_at, inp_ATOM *at, int cur_at, inp_ATOM *at_removed_H, int num_removed_H, int bPointedEdgeStereo );
57
+ static double get_z_coord( inp_ATOM* at, int cur_atom, int neigh_no, int *nType,int bPointedEdgeStereo );
58
+ static double len3( const double c[] );
59
+ static double len2( const double c[] );
60
+ static double* diff3( const double a[], const double b[], double result[] );
61
+ static double* add3( const double a[], const double b[], double result[] );
62
+ static double* mult3( const double a[], double b, double result[] );
63
+ static double* copy3( const double a[], double result[] );
64
+ static double* change_sign3( const double a[], double result[] );
65
+ static double dot_prod3( const double a[], const double b[] );
66
+ static int dot_prodchar3( const S_CHAR a[], const S_CHAR b[] );
67
+ static double* cross_prod3( const double a[], const double b[], double result[] );
68
+ static double triple_prod( double a[], double b[], double c[], double *sine_value );
69
+ static double triple_prod_and_min_abs_sine(double at_coord[][3], double *min_sine);
70
+ static int are_3_vect_in_one_plane( double at_coord[][3], double min_sine);
71
+ static int triple_prod_char( inp_ATOM *at, int at_1, int i_next_at_1, S_CHAR *z_dir1,
72
+ int at_2, int i_next_at_2, S_CHAR *z_dir2 );
73
+
74
+ static int CompDble( const void *a1, const void *a2 );
75
+ static int Get2DTetrahedralAmbiguity( double at_coord[][3], int bAddExplicitNeighbor, int bFix2DstereoBorderCase );
76
+ static double triple_prod_and_min_abs_sine2(double at_coord[][3], double central_at_coord[], int bAddedExplicitNeighbor, double *min_sine, int *bAmbiguous);
77
+ static int are_4at_in_one_plane( double at_coord[][3], double min_sine);
78
+ static int bInpAtomHasRequirdNeigh ( inp_ATOM *at, int cur_at, int RequirdNeighType, int NumDbleBonds );
79
+ static int bIsSuitableHeteroInpAtom( inp_ATOM *at );
80
+ static int bIsOxide( inp_ATOM *at, int cur_at );
81
+ static int half_stereo_bond_parity( inp_ATOM *at, int cur_at, inp_ATOM *at_removed_H, int num_removed_H, S_CHAR *z_dir, int bPointedEdgeStereo );
82
+ static int get_allowed_stereo_bond_type( int bond_type );
83
+ static int can_be_a_stereo_bond_with_isotopic_H( inp_ATOM *at, int cur_at, INCHI_MODE nMode );
84
+ static int half_stereo_bond_action( int nParity, int bUnknown, int bIsotopic );
85
+ static int set_stereo_bonds_parity( sp_ATOM *out_at, inp_ATOM *at, int at_1, inp_ATOM *at_removed_H, int num_removed_H,
86
+ INCHI_MODE nMode, QUEUE *q, AT_RANK *nAtomLevel, S_CHAR *cSource, AT_RANK min_sb_ring_size, int bPointedEdgeStereo );
87
+ static int can_be_a_stereo_atom_with_isotopic_H( inp_ATOM *at, int cur_at, int bPointedEdgeStereo );
88
+ static int set_stereo_atom_parity( sp_ATOM *out_at, inp_ATOM *at, int cur_at, inp_ATOM *at_removed_H, int num_removed_H, int bPointedEdgeStereo );
91
89
  /*
92
90
  int set_stereo_parity( inp_ATOM* at, sp_ATOM* at_output, int num_at, int num_removed_H,
93
91
  int *nMaxNumStereoAtoms, int *nMaxNumStereoBonds, INCHI_MODE nMode, int bPointedEdgeStereo );
@@ -293,7 +291,7 @@ int CompDble( const void *a1, const void *a2 )
293
291
  #define T2D_OKAY 1
294
292
  #define T2D_WARN 2
295
293
  #define T2D_UNDF 4
296
- int Get2DTetrahedralAmbiguity( double at_coord[][3], int bAddExplicitNeighbor )
294
+ int Get2DTetrahedralAmbiguity( double at_coord[][3], int bAddExplicitNeighbor, int bFix2DstereoBorderCase )
297
295
  {
298
296
  const double one_pi = 2.0*atan2(1.0 /* y */, 0.0 /* x */);
299
297
  const double two_pi = 2.0*one_pi;
@@ -367,6 +365,83 @@ int Get2DTetrahedralAmbiguity( double at_coord[][3], int bAddExplicitNeighbor )
367
365
  }
368
366
  }
369
367
  }
368
+ #if( FIX_2D_STEREO_BORDER_CASE == 1 )
369
+ /* check if the bonds with ordering numbers first_Up+len_Up and first_Up+len_Up+1 */
370
+ /* have identical angles. In this case switch their order to enlarge the Up sequence */
371
+ #define ZERO_ANGLE 0.000001
372
+ if ( nNumNeigh - len_Up >= 2 ) {
373
+ int next1, next2;
374
+ for ( i = 1; i < nNumNeigh - len_Up; i ++ ) {
375
+ next2 = (first_Up+len_Up + i) % nNumNeigh; /* the 2nd after Up sequence */
376
+ if ( nBondType[nBondOrder[next2]] > 0 ) {
377
+ next1 = (first_Up+len_Up) % nNumNeigh; /* the 1st after Up sequence */
378
+ dAngle = dBondDirection[nBondOrder[next1]] - dBondDirection[nBondOrder[next2]];
379
+ if ( fabs(dAngle) < ZERO_ANGLE ) {
380
+ swap( (char*)&nBondOrder[next1], (char*)&nBondOrder[next2], sizeof(nBondOrder[0]) );
381
+ len_Up ++;
382
+ break;
383
+ }
384
+ }
385
+ }
386
+ }
387
+ /* check whether the not-Up bond (located before the found first-Up) has */
388
+ /* same angle as the Up bond that precedes this not-Up bond */
389
+ if ( nNumNeigh - len_Up >= 2 ) {
390
+ int next1, next2;
391
+ for ( i = 1; i < nNumNeigh - len_Up; i ++ ) {
392
+ next2 = (first_Up+nNumNeigh - i - 1 ) % nNumNeigh; /* the 2nd before Up sequence */
393
+ if ( nBondType[nBondOrder[next2]] > 0 ) {
394
+ next1 = (first_Up+nNumNeigh-1) % nNumNeigh; /* the 1st before Up sequence */
395
+ dAngle = dBondDirection[nBondOrder[next1]] - dBondDirection[nBondOrder[next2]];
396
+ if ( fabs(dAngle) < ZERO_ANGLE ) {
397
+ swap( (char*)&nBondOrder[next1], (char*)&nBondOrder[next2], sizeof(nBondOrder[0]) );
398
+ first_Up = next1;
399
+ len_Up ++;
400
+ break;
401
+ }
402
+ }
403
+ }
404
+ }
405
+ #else
406
+ if ( bFix2DstereoBorderCase ) {
407
+ /* check if the bonds with ordering numbers first_Up+len_Up and first_Up+len_Up+1 */
408
+ /* have identical angles. In this case switch their order to enlarge the Up sequence */
409
+ #define ZERO_ANGLE 0.000001
410
+ if ( nNumNeigh - len_Up >= 2 ) {
411
+ int next1, next2;
412
+ for ( i = 1; i < nNumNeigh - len_Up; i ++ ) {
413
+ next2 = (first_Up+len_Up + i) % nNumNeigh; /* the 2nd after Up sequence */
414
+ if ( nBondType[nBondOrder[next2]] > 0 ) {
415
+ next1 = (first_Up+len_Up) % nNumNeigh; /* the 1st after Up sequence */
416
+ dAngle = dBondDirection[nBondOrder[next1]] - dBondDirection[nBondOrder[next2]];
417
+ if ( fabs(dAngle) < ZERO_ANGLE ) {
418
+ swap( (char*)&nBondOrder[next1], (char*)&nBondOrder[next2], sizeof(nBondOrder[0]) );
419
+ len_Up ++;
420
+ break;
421
+ }
422
+ }
423
+ }
424
+ }
425
+ /* check whether the not-Up bond (located before the found first-Up) has */
426
+ /* same angle as the Up bond that precedes this not-Up bond */
427
+ if ( nNumNeigh - len_Up >= 2 ) {
428
+ int next1, next2;
429
+ for ( i = 1; i < nNumNeigh - len_Up; i ++ ) {
430
+ next2 = (first_Up+nNumNeigh - i - 1 ) % nNumNeigh; /* the 2nd before Up sequence */
431
+ if ( nBondType[nBondOrder[next2]] > 0 ) {
432
+ next1 = (first_Up+nNumNeigh-1) % nNumNeigh; /* the 1st before Up sequence */
433
+ dAngle = dBondDirection[nBondOrder[next1]] - dBondDirection[nBondOrder[next2]];
434
+ if ( fabs(dAngle) < ZERO_ANGLE ) {
435
+ swap( (char*)&nBondOrder[next1], (char*)&nBondOrder[next2], sizeof(nBondOrder[0]) );
436
+ first_Up = next1;
437
+ len_Up ++;
438
+ break;
439
+ }
440
+ }
441
+ }
442
+ }
443
+ }
444
+ #endif
370
445
  /* Turn all the bonds around the center so that */
371
446
  /* the 1st Up bond has zero radian direction */
372
447
  dAlpha = dBondDirection[nBondOrder[first_Up]];
@@ -517,11 +592,51 @@ int Get2DTetrahedralAmbiguity( double at_coord[][3], int bAddExplicitNeighbor )
517
592
  break;
518
593
  /* -------------------------- 2 Up ------------ */
519
594
  case 2:
520
- if ( cur_len_Up == 1 ) {
595
+ #if( FIX_2D_STEREO_BORDER_CASE == 1 )
596
+ if ( len_Up == 1 ) {
521
597
  ret = T2D_OKAY;
522
598
  } else {
523
- ret = (T2D_UNDF | T2D_WARN);
599
+ dAngle = dBondDirection[nBondOrder[(first_Up + 3) % nNumNeigh]] -
600
+ dBondDirection[nBondOrder[(first_Up + 0) % nNumNeigh]];
601
+ dAngle = fabs(two_pi - dAngle);
602
+ dAlpha = dBondDirection[nBondOrder[(first_Up + 2) % nNumNeigh]] -
603
+ dBondDirection[nBondOrder[(first_Up + 1) % nNumNeigh]];
604
+ dAlpha = fabs(dAlpha);
605
+ if ( dAngle < 2.0 * ZERO_ANGLE && dAlpha > MIN_ANGLE ||
606
+ dAlpha < 2.0 * ZERO_ANGLE && dAngle > MIN_ANGLE ) {
607
+ ret = (T2D_OKAY | T2D_WARN);
608
+ } else {
609
+ ret = (T2D_UNDF | T2D_WARN);
610
+ }
524
611
  }
612
+ #else
613
+ if ( bFix2DstereoBorderCase ) {
614
+ /* bug fix */
615
+ if ( len_Up == 1 ) {
616
+ ret = T2D_OKAY;
617
+ } else {
618
+ dAngle = dBondDirection[nBondOrder[(first_Up + 3) % nNumNeigh]] -
619
+ dBondDirection[nBondOrder[(first_Up + 0) % nNumNeigh]];
620
+ dAngle = fabs(two_pi - dAngle);
621
+ dAlpha = dBondDirection[nBondOrder[(first_Up + 2) % nNumNeigh]] -
622
+ dBondDirection[nBondOrder[(first_Up + 1) % nNumNeigh]];
623
+ dAlpha = fabs(dAlpha);
624
+ if ( dAngle < 2.0 * ZERO_ANGLE && dAlpha > MIN_ANGLE ||
625
+ dAlpha < 2.0 * ZERO_ANGLE && dAngle > MIN_ANGLE ) {
626
+ ret = (T2D_OKAY | T2D_WARN);
627
+ } else {
628
+ ret = (T2D_UNDF | T2D_WARN);
629
+ }
630
+ }
631
+ } else {
632
+ /* original InChI v. 1 bug */
633
+ if ( cur_len_Up == 1 ) {
634
+ ret = T2D_OKAY;
635
+ } else {
636
+ ret = (T2D_UNDF | T2D_WARN);
637
+ }
638
+ }
639
+ #endif
525
640
  break;
526
641
  /* -------------------------- 3 Up ------------ */
527
642
  case 3:
@@ -945,7 +1060,7 @@ int bInpAtomHasRequirdNeigh ( inp_ATOM *at, int cur_at, int RequirdNeighType, in
945
1060
  return 1;
946
1061
  }
947
1062
  /********************************************************************************************/
948
- int bCanInpAtomBeAStereoCenter( inp_ATOM *at, int cur_at )
1063
+ int bCanInpAtomBeAStereoCenter( inp_ATOM *at, int cur_at, int bPointedEdgeStereo )
949
1064
  {
950
1065
 
951
1066
  /*************************************************************************************
@@ -955,6 +1070,7 @@ int bCanInpAtomBeAStereoCenter( inp_ATOM *at, int cur_at )
955
1070
  * to make it easier to read
956
1071
  *
957
1072
  * --------- 4 single bonds stereocenters -------
1073
+ * 0 1 2 3 4 5
958
1074
  *
959
1075
  * | | | | | |
960
1076
  * -C- -Si- -Ge- -Sn- >As[+] >B[-]
@@ -968,6 +1084,7 @@ int bCanInpAtomBeAStereoCenter( inp_ATOM *at, int cur_at )
968
1084
  #define CREQUIRDNEIGH1 0, 0, 0, 0, 3, 0,
969
1085
  /*
970
1086
  * --------------- S, Se stereocenters ----------
1087
+ * 6 7 8 9 10 11 12 13
971
1088
  *
972
1089
  * | | || | | ||
973
1090
  * -S= =S= -S[+] >S[+] -Se= =Se= -Se[+] >Se[+]
@@ -980,21 +1097,24 @@ int bCanInpAtomBeAStereoCenter( inp_ATOM *at, int cur_at )
980
1097
  #define CHAS3MEMBRING2 0, 0, 0, 0, 0, 0, 0, 0,
981
1098
  #define CREQUIRDNEIGH2 3, 3, 3, 3, 3, 3, 3, 3,
982
1099
  /*
983
- * ------------------ N, P stereocenters --------
984
- *
985
- * X---Y
986
- * | | \ / | |
987
- * =N- >N[+] N >P[+] =P-
988
- * | | | | |
989
- */
990
- #define SZELEM3 "N\000","N\000","N\000","P\000","P\000",
991
- #define CCHARGE3 0, 1, 0, 1, 0,
992
- #define CNUMBONDSANDH3 4, 4, 3, 4, 4,
993
- #define CCHEMVALENCEH3 5, 4, 3, 4, 5,
994
- #define CHAS3MEMBRING3 0, 0, 1, 0, 0,
995
- #define CREQUIRDNEIGH3 3, 3, 1, 3, 3,
996
-
997
-
1100
+ * ------------------ N, P stereocenters -----------------
1101
+ * 14 15 16 17 18 19 20
1102
+ *
1103
+ * Phosphine Arsine
1104
+ * X---Y
1105
+ * | | \ / | | \ / \ /
1106
+ * =N- >N[+] N >P[+] =P- P As
1107
+ * | | | | | | |
1108
+ */
1109
+ #define SZELEM3 "N\000","N\000","N\000","P\000","P\000","P\000", "As",
1110
+ #define CCHARGE3 0, 1, 0, 1, 0, 0, 0,
1111
+ #define CNUMBONDSANDH3 4, 4, 3, 4, 4, 3, 3,
1112
+ #define CCHEMVALENCEH3 5, 4, 3, 4, 5, 3, 3,
1113
+ #define CHAS3MEMBRING3 0, 0, 1, 0, 0, 0, 0,
1114
+ #define CREQUIRDNEIGH3 3, 3, 1, 3, 3, 2, 2,
1115
+
1116
+ #define PHOSPHINE_STEREO 19 /* the number must match Phosphine number in the comments, see above */
1117
+ #define ARSINE_STEREO 20 /* the number must match Arsine number in the comments, see above */
998
1118
 
999
1119
  static char szElem[][3]={ SZELEM1 SZELEM2 SZELEM3 };
1000
1120
  static S_CHAR cCharge[]={ CCHARGE1 CCHARGE2 CCHARGE3 };
@@ -1027,6 +1147,20 @@ int bCanInpAtomBeAStereoCenter( inp_ATOM *at, int cur_at )
1027
1147
  break;
1028
1148
  }
1029
1149
  }
1150
+ #if ( ADD_PHOSPHINE_STEREO == 1 )
1151
+ if ( i == PHOSPHINE_STEREO && !(bPointedEdgeStereo & PES_BIT_PHOSPHINE_STEREO) )
1152
+ ret = 0;
1153
+ #else
1154
+ if ( i == PHOSPHINE_STEREO )
1155
+ ret = 0;
1156
+ #endif
1157
+ #if ( ADD_ARSINE_STEREO == 1 )
1158
+ if ( i == ARSINE_STEREO && !(bPointedEdgeStereo & PES_BIT_ARSINE_STEREO) )
1159
+ ret = 0;
1160
+ #else
1161
+ if ( i == ARSINE_STEREO )
1162
+ ret = 0;
1163
+ #endif
1030
1164
  return ret;
1031
1165
  }
1032
1166
 
@@ -1035,8 +1169,8 @@ int bCanInpAtomBeAStereoCenter( inp_ATOM *at, int cur_at )
1035
1169
  /********************************************************************************************/
1036
1170
  int bCanAtomBeAStereoCenter( char *elname, S_CHAR charge, S_CHAR radical )
1037
1171
  {
1038
- static char szElem[][3] = { "C\000", "Si", "Ge", "N\000", "P\000", "As", "B\000" };
1039
- static S_CHAR cCharge[] = { 0, 0, 0, 1, 1, 1, -1 };
1172
+ static const char szElem[][3] = { "C\000", "Si", "Ge", "N\000", "P\000", "As", "B\000" };
1173
+ static const S_CHAR cCharge[] = { 0, 0, 0, 1, 1, 1, -1 };
1040
1174
  int i, ret = 0;
1041
1175
  for ( i = 0; i < sizeof(szElem)/sizeof(szElem[0]); i++ ) {
1042
1176
  if ( !strcmp( elname, szElem[i] ) && (charge == cCharge[i]) ) {
@@ -1052,8 +1186,8 @@ int bCanAtomBeAStereoCenter( char *elname, S_CHAR charge, S_CHAR radical )
1052
1186
  /* used for atoms adjacent to stereogenic bonds only */
1053
1187
  int bAtomHasValence3( char *elname, S_CHAR charge, S_CHAR radical )
1054
1188
  {
1055
- static char szElem[][3] = { "N\000" };
1056
- static S_CHAR cCharge[] = { 0, };
1189
+ static const char szElem[][3] = { "N\000" };
1190
+ static const S_CHAR cCharge[] = { 0, };
1057
1191
  int i, ret = 0;
1058
1192
  for ( i = 0; i < (int)(sizeof(szElem)/sizeof(szElem[0])); i++ ) {
1059
1193
  if ( !strcmp( elname, szElem[i] ) && (charge == cCharge[i]) ) {
@@ -1068,9 +1202,9 @@ int bAtomHasValence3( char *elname, S_CHAR charge, S_CHAR radical )
1068
1202
  /* used for atoms adjacent to stereogenic bonds only */
1069
1203
  int bCanAtomHaveAStereoBond( char *elname, S_CHAR charge, S_CHAR radical )
1070
1204
  {
1071
- static char szElem[][3] = { "C\000", "Si", "Ge", "N\000", "N\000" };
1072
- static S_CHAR cCharge[] = { 0, 0, 0, 0, 1, };
1073
- static int n = sizeof(szElem)/sizeof(szElem[0]);
1205
+ static const char szElem[][3] = { "C\000", "Si", "Ge", "N\000", "N\000" };
1206
+ static const S_CHAR cCharge[] = { 0, 0, 0, 0, 1, };
1207
+ static const int n = sizeof(szElem)/sizeof(szElem[0]);
1074
1208
  int i, ret = 0;
1075
1209
  for ( i = 0; i < n; i++ ) {
1076
1210
  if ( !strcmp( elname, szElem[i] ) && (charge == cCharge[i]) ) {
@@ -1084,9 +1218,9 @@ int bCanAtomHaveAStereoBond( char *elname, S_CHAR charge, S_CHAR radical )
1084
1218
  /* used for atoms adjacent to stereogenic bonds only */
1085
1219
  int bCanAtomBeMiddleAllene( char *elname, S_CHAR charge, S_CHAR radical )
1086
1220
  {
1087
- static char szElem[][3] = { "C\000", "Si", "Ge", };
1088
- static S_CHAR cCharge[] = { 0, 0, 0, };
1089
- static int n = sizeof(szElem)/sizeof(szElem[0]);
1221
+ static const char szElem[][3] = { "C\000", "Si", "Ge", };
1222
+ static const S_CHAR cCharge[] = { 0, 0, 0, };
1223
+ static const int n = sizeof(szElem)/sizeof(szElem[0]);
1090
1224
  int i, ret = 0;
1091
1225
  for ( i = 0; i < n; i++ ) {
1092
1226
  if ( !strcmp( elname, szElem[i] ) && (charge == cCharge[i]) ) {
@@ -1149,9 +1283,9 @@ int bIsOxide( inp_ATOM *at, int cur_at )
1149
1283
  /* used for atoms adjacent to stereogenic bonds only */
1150
1284
  int bCanAtomBeTerminalAllene( char *elname, S_CHAR charge, S_CHAR radical )
1151
1285
  {
1152
- static char szElem[][3] = { "C\000", "Si", "Ge", };
1153
- static S_CHAR cCharge[] = { 0, 0, 0, };
1154
- static int n = sizeof(szElem)/sizeof(szElem[0]);
1286
+ static const char szElem[][3] = { "C\000", "Si", "Ge", };
1287
+ static const S_CHAR cCharge[] = { 0, 0, 0, };
1288
+ static const int n = sizeof(szElem)/sizeof(szElem[0]);
1155
1289
  int i, ret = 0;
1156
1290
  for ( i = 0; i < n; i++ ) {
1157
1291
  if ( !strcmp( elname, szElem[i] ) && (charge == cCharge[i]) ) {
@@ -1372,7 +1506,47 @@ set_default:
1372
1506
  }
1373
1507
  return 0;
1374
1508
  }
1509
+ /**********************************************************/
1510
+ /* without this InChI fails on reconstructed CID=450438 */
1511
+ /* (isotopic, Unkown SB adjacent to SB with known parity) */
1512
+ /**********************************************************/
1513
+ int FixUnkn0DStereoBonds(inp_ATOM *at, int num_at)
1514
+ {
1515
+ int i, m, num=0;
1375
1516
 
1517
+ /* add usual Unknown stereobond descriptors to each Unknown bond */
1518
+ for( i = 0; i < num_at; i ++ ) {
1519
+ for ( m = 0; m < MAX_NUM_STEREO_BONDS && at[i].sb_parity[m]; m ++ ) {
1520
+ if ( AB_PARITY_UNKN == at[i].sb_parity[m] ) {
1521
+ at[i].bond_stereo[ (int)at[i].sb_ord[m] ] = STEREO_DBLE_EITHER;
1522
+ num ++;
1523
+ }
1524
+ }
1525
+ }
1526
+ #ifdef NEVER
1527
+ if ( num ) {
1528
+ int j;
1529
+ /* how to remove Unknown stereo bond parities */
1530
+ for( i = 0; i < num_at; i ++ ) {
1531
+ for ( m = 0; m < MAX_NUM_STEREO_BONDS && at[i].sb_parity[m]; m ++ ) {
1532
+ if ( AB_PARITY_UNKN == at[i].sb_parity[m] ) {
1533
+ for ( j = m+1; j < MAX_NUM_STEREO_BONDS; j ++ ) {
1534
+ at[i].sb_parity[j-1] = at[i].sb_parity[j];
1535
+ at[i].sb_ord[j-1] = at[i].sb_ord[j];
1536
+ at[i].sn_ord[j-1] = at[i].sn_ord[j];
1537
+ at[i].sn_orig_at_num[j-1] = at[i].sn_orig_at_num[j];
1538
+ }
1539
+ at[i].sb_parity[j-1] = 0;
1540
+ at[i].sb_ord[j-1] = 0;
1541
+ at[i].sn_ord[j-1] = 0;
1542
+ at[i].sn_orig_at_num[j-1] = 0;
1543
+ }
1544
+ }
1545
+ }
1546
+ }
1547
+ #endif
1548
+ return num;
1549
+ }
1376
1550
  /*======================================================================================================
1377
1551
 
1378
1552
  half_stereo_bond_parity() General Description:
@@ -1545,7 +1719,7 @@ int half_stereo_bond_parity( inp_ATOM *at, int cur_at, inp_ATOM *at_removed_H, i
1545
1719
  at_coord[nNumExplictAttachments][1] = at_removed_H[next].y - at[cur_at].y;
1546
1720
  nSbNeighOrigAtNumb[nNumExplictAttachments] = at_removed_H[next].orig_at_number;
1547
1721
  /* use the fact that (at_removed_H - at) = (number of atoms except removed explicit H) */
1548
- z = -get_z_coord( at, (at_removed_H-at)+next, 0 /*neighbor #*/, &nType, -bPointedEdgeStereo );
1722
+ z = -get_z_coord( at, (at_removed_H-at)+next, 0 /*neighbor #*/, &nType, -(bPointedEdgeStereo & PES_BIT_POINT_EDGE_STEREO) );
1549
1723
  switch ( nType ) {
1550
1724
  case ZTYPE_EITHER:
1551
1725
  num_either_single ++; /* bond in "Either" direction. */
@@ -1574,7 +1748,7 @@ int half_stereo_bond_parity( inp_ATOM *at, int cur_at, inp_ATOM *at_removed_H, i
1574
1748
  at_coord[nNumExplictAttachments][1] = at[next].y - at[cur_at].y;
1575
1749
  nSbNeighOrigAtNumb[nNumExplictAttachments] = at[next].orig_at_number;
1576
1750
 
1577
- z = get_z_coord( at, cur_at, j /*neighbor #*/, &nType, bPointedEdgeStereo );
1751
+ z = get_z_coord( at, cur_at, j /*neighbor #*/, &nType, (bPointedEdgeStereo & PES_BIT_POINT_EDGE_STEREO) );
1578
1752
  switch ( nType ) {
1579
1753
  case ZTYPE_EITHER:
1580
1754
  num_either_single ++; /* bond in "Either" direction. */
@@ -2150,9 +2324,10 @@ int set_stereo_bonds_parity( sp_ATOM *out_at, inp_ATOM *at, int at_1, inp_ATOM *
2150
2324
  for ( i_next_at_1 = 0, num_stereo_bonds = 0; i_next_at_1 < at[at_1].valence; i_next_at_1 ++ ) {
2151
2325
  nUnknown = (at[at_1].bond_stereo[i_next_at_1] == STEREO_DBLE_EITHER);
2152
2326
  bond_type = get_allowed_stereo_bond_type( (int)at[at_1].bond_type[i_next_at_1] );
2327
+ at_2 = -1; /* not found */
2153
2328
  if ( bond_type == BOND_ALTERN ||
2154
2329
  bond_type == BOND_DOUBLE ) {
2155
- at_2 = next_at_1 = at[at_1].neighbor[i_next_at_1];
2330
+ next_at_1 = at_2 = at[at_1].neighbor[i_next_at_1];
2156
2331
  next_at_2 = at_1;
2157
2332
  }
2158
2333
  switch ( bond_type ) {
@@ -2230,7 +2405,7 @@ int set_stereo_bonds_parity( sp_ATOM *out_at, inp_ATOM *at, int at_1, inp_ATOM *
2230
2405
 
2231
2406
  /* check atom at the opposite end of possibly stereogenic bond */
2232
2407
 
2233
- bFound = ( at_1 > at_2 ); /* i_next_at_1 = at_1 stereogenic bond neighbor attachment number */
2408
+ bFound = (at_2 >= 0 && at_1 > at_2 ); /* i_next_at_1 = at_1 stereogenic bond neighbor attachment number */
2234
2409
 
2235
2410
  if ( bFound ) {
2236
2411
  /* check "at_2" atom on the opposite side of the bond or cumulene chain */
@@ -2630,8 +2805,8 @@ int set_stereo_bonds_parity( sp_ATOM *out_at, inp_ATOM *at, int at_1, inp_ATOM *
2630
2805
  memcpy( out_at[at_1].z_dir, z_dir1, sizeof(out_at[0].z_dir) );
2631
2806
  }
2632
2807
  }
2633
- if ( !out_at[at_2].parity2 ||
2634
- next_parity_defined && !ATOM_PARITY_WELL_DEF(abs(out_at[at_2].parity)) ) {
2808
+ if ( !out_at[at_2].parity2 || /* next line changed from abs(out_at[at_2].parity) 2006-03-05 */
2809
+ next_parity_defined && !ATOM_PARITY_WELL_DEF(abs(out_at[at_2].parity2)) ) {
2635
2810
  out_at[at_2].parity2 = next_parity /*| chain_len_bits*/;
2636
2811
  if ( !out_at[at_2].parity ) {
2637
2812
  memcpy( out_at[at_2].z_dir, z_dir2, sizeof(out_at[0].z_dir) );
@@ -2659,10 +2834,10 @@ int set_stereo_bonds_parity( sp_ATOM *out_at, inp_ATOM *at, int at_1, inp_ATOM *
2659
2834
  /* if isotopic H, D, T added, can the atom be a stereo center? */
2660
2835
  #if( NEW_STEREOCENTER_CHECK == 1 )
2661
2836
  /* int bCanInpAtomBeAStereoCenter( inp_ATOM *at, int cur_at ) */
2662
- int can_be_a_stereo_atom_with_isotopic_H( inp_ATOM *at, int cur_at )
2837
+ int can_be_a_stereo_atom_with_isotopic_H( inp_ATOM *at, int cur_at, int bPointedEdgeStereo )
2663
2838
  {
2664
2839
  int nNumNeigh;
2665
- if ( (nNumNeigh = bCanInpAtomBeAStereoCenter( at, cur_at )) &&
2840
+ if ( (nNumNeigh = bCanInpAtomBeAStereoCenter( at, cur_at, bPointedEdgeStereo )) &&
2666
2841
  at[cur_at].valence + at[cur_at].num_H == nNumNeigh &&
2667
2842
  at[cur_at].num_H <= NUM_H_ISOTOPES
2668
2843
  ) {
@@ -2750,7 +2925,7 @@ int set_stereo_atom_parity( sp_ATOM *out_at, inp_ATOM *at, int cur_at, inp_ATOM
2750
2925
  num_explicit_H = 0;
2751
2926
 
2752
2927
  #if( NEW_STEREOCENTER_CHECK == 1 )
2753
- if ( !(nMustHaveNumNeigh = bCanInpAtomBeAStereoCenter( at, cur_at ) ) ||
2928
+ if ( !(nMustHaveNumNeigh = bCanInpAtomBeAStereoCenter( at, cur_at, bPointedEdgeStereo ) ) ||
2754
2929
  at[cur_at].num_H > NUM_H_ISOTOPES
2755
2930
  ) {
2756
2931
  goto exit_function;
@@ -2822,7 +2997,7 @@ int set_stereo_atom_parity( sp_ATOM *out_at, inp_ATOM *at, int cur_at, inp_ATOM
2822
2997
  /* use bond description located at removed_H atom */
2823
2998
  /* minus sign at get_z_coord: at_removed_H[] contains bonds TO at[cur_at], not FROM it. */
2824
2999
  /* Note: &at[(at_removed_H-at)+ next_at] == &at_removed_H[next_at] */
2825
- z = -get_z_coord( at, (at_removed_H-at)+ next_at, 0 /*neighbor #*/, &nType, -bPointedEdgeStereo );
3000
+ z = -get_z_coord( at, (at_removed_H-at)+ next_at, 0 /*neighbor #*/, &nType, -(bPointedEdgeStereo & PES_BIT_POINT_EDGE_STEREO) );
2826
3001
  switch ( nType ) {
2827
3002
  case ZTYPE_EITHER:
2828
3003
  parity = AB_PARITY_UNKN; /* no parity: bond in "Either" direction. */
@@ -2850,7 +3025,7 @@ int set_stereo_atom_parity( sp_ATOM *out_at, inp_ATOM *at, int cur_at, inp_ATOM
2850
3025
  /* add all coordinates of other neighboring atoms */
2851
3026
  for ( j = 0; j < at[cur_at].valence; j ++, j1 ++ ) {
2852
3027
  next_at = at[cur_at].neighbor[j];
2853
- z = get_z_coord( at, cur_at, j, &nType, bPointedEdgeStereo );
3028
+ z = get_z_coord( at, cur_at, j, &nType, (bPointedEdgeStereo & PES_BIT_POINT_EDGE_STEREO) );
2854
3029
  switch ( nType ) {
2855
3030
  case ZTYPE_EITHER:
2856
3031
  parity = AB_PARITY_UNKN; /* unknown parity: bond in "Either" direction. */
@@ -2991,8 +3166,30 @@ int set_stereo_atom_parity( sp_ATOM *out_at, inp_ATOM *at, int cur_at, inp_ATOM
2991
3166
  copy3( sum_xyz, at_coord[j] );
2992
3167
  change_sign3( at_coord[j], at_coord[j] );
2993
3168
  z = len3( at_coord[j] );
2994
- rmax = inchi_max( rmax, z );
2995
- rmin = inchi_min( rmin, z );
3169
+ #if ( FIX_STEREO_SCALING_BUG == 1 )
3170
+ if ( z > 1.0 ) {
3171
+ rmax *= z;
3172
+ } else {
3173
+ rmin *= z;
3174
+ }
3175
+ #else
3176
+ /* Comparing the original bond lengths to lenghts derived from normalized to 1 */
3177
+ /* This bug leads to pronouncing legitimate stereogenic atoms */
3178
+ /* connected by 3 bonds "undefined" if in a nicely drawn 2D structure */
3179
+ /* bond lengths are about 20 or greater. Reported by Reinhard Dunkel 2005-08-05 */
3180
+ if ( bPointedEdgeStereo & PES_BIT_FIX_SP3_BUG ) {
3181
+ /* coordinate scaling bug fixed here */
3182
+ if ( z > 1.0 ) {
3183
+ rmax *= z;
3184
+ } else {
3185
+ rmin *= z;
3186
+ }
3187
+ } else {
3188
+ /* original InChI v.1 bug */
3189
+ rmax = inchi_max( rmax, z );
3190
+ rmin = inchi_min( rmin, z );
3191
+ }
3192
+ #endif
2996
3193
  if ( z < MIN_BOND_LEN || rmin/rmax < MIN_SINE ) {
2997
3194
  /* the new 4th bond is too short: try to get 0D parities */
2998
3195
  if ( AB_PARITY_NONE == (parity = GetStereocenter0DParity( at, cur_at, j1, nSbNeighOrigAtNumb, FlagSC_0D )) ) {
@@ -3038,7 +3235,7 @@ int set_stereo_atom_parity( sp_ATOM *out_at, inp_ATOM *at, int cur_at, inp_ATOM
3038
3235
  * check for tetrahedral ambiguity in 2D case
3039
3236
  */
3040
3237
  if ( b2D ) {
3041
- if ( 0 < (n2DTetrahedralAmbiguity = Get2DTetrahedralAmbiguity( at_coord, bAddExplicitNeighbor )) ) {
3238
+ if ( 0 < (n2DTetrahedralAmbiguity = Get2DTetrahedralAmbiguity( at_coord, bAddExplicitNeighbor, (bPointedEdgeStereo & PES_BIT_FIX_SP3_BUG ) ) ) ) {
3042
3239
  if ( T2D_WARN & n2DTetrahedralAmbiguity ) {
3043
3240
  bAmbiguous |= AMBIGUOUS_STEREO;
3044
3241
  }
@@ -3081,9 +3278,7 @@ int set_stereo_atom_parity( sp_ATOM *out_at, inp_ATOM *at, int cur_at, inp_ATOM
3081
3278
  ********************************************************/
3082
3279
  triple_product = triple_prod_and_min_abs_sine2(&at_coord[1], at_coord_center, bAddExplicitNeighbor, &min_sine, &bAmbiguous);
3083
3280
  /*
3084
- *triple_product = triple_prod_and_min_abs_sine( &at_coord[1], &min_sine);
3085
3281
  * check for tetrahedral ambiguity -- leave it out for now
3086
- *triple_product = sp3_triple_prod_and_min_abs_sine( &at_coord[1], at_coord_center, &min_sine, &bAmbiguous);
3087
3282
  */
3088
3283
  if ( fabs(triple_product) > ZERO_FLOAT && (min_sine > MIN_SINE || fabs(min_sine) > ZERO_FLOAT && (n2DTetrahedralAmbiguity & T2D_OKAY ) ) ) {
3089
3284
  /* Even => sorted in correct order, Odd=>transposed */
@@ -3274,7 +3469,7 @@ int set_stereo_parity( inp_ATOM* at, sp_ATOM* at_output, int num_at, int num_rem
3274
3469
  if ( nMaxNumStereoAtoms || nMaxNumStereoBonds ) {
3275
3470
  for( i = 0, num_stereo = 0; i < num_at; i ++ ) {
3276
3471
  int num;
3277
- num = can_be_a_stereo_atom_with_isotopic_H( at, i );
3472
+ num = can_be_a_stereo_atom_with_isotopic_H( at, i, bPointedEdgeStereo );
3278
3473
  if ( num ) {
3279
3474
  max_stereo_atoms += num;
3280
3475
  } else