| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Chemistry::Harmonia; |
|
2
|
|
|
|
|
|
|
|
|
3
|
8
|
|
|
8
|
|
311519
|
use 5.008008; |
|
|
8
|
|
|
|
|
30
|
|
|
|
8
|
|
|
|
|
523
|
|
|
4
|
8
|
|
|
8
|
|
73
|
use strict; |
|
|
8
|
|
|
|
|
17
|
|
|
|
8
|
|
|
|
|
1493
|
|
|
5
|
8
|
|
|
8
|
|
45
|
use warnings; |
|
|
8
|
|
|
|
|
50
|
|
|
|
8
|
|
|
|
|
322
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
8
|
|
|
8
|
|
125
|
use Carp; |
|
|
8
|
|
|
|
|
15
|
|
|
|
8
|
|
|
|
|
975
|
|
|
8
|
8
|
|
|
8
|
|
18284
|
use Chemistry::File::Formula; |
|
|
8
|
|
|
|
|
7651042
|
|
|
|
8
|
|
|
|
|
115
|
|
|
9
|
8
|
|
|
8
|
|
21519
|
use Algorithm::Combinatorics qw( variations_with_repetition subsets ); |
|
|
8
|
|
|
|
|
1186969
|
|
|
|
8
|
|
|
|
|
819
|
|
|
10
|
8
|
|
|
8
|
|
9328
|
use String::CRC::Cksum qw( cksum ); |
|
|
8
|
|
|
|
|
925482
|
|
|
|
8
|
|
|
|
|
717
|
|
|
11
|
8
|
|
|
8
|
|
19574
|
use Math::BigInt qw( blcm bgcd ); |
|
|
8
|
|
|
|
|
2510123
|
|
|
|
8
|
|
|
|
|
50
|
|
|
12
|
8
|
|
|
8
|
|
194738
|
use Math::BigRat; |
|
|
8
|
|
|
|
|
417543
|
|
|
|
8
|
|
|
|
|
68
|
|
|
13
|
8
|
|
|
8
|
|
22811
|
use Math::Assistant qw(:algebra); |
|
|
8
|
|
|
|
|
25990
|
|
|
|
8
|
|
|
|
|
1307
|
|
|
14
|
|
|
|
|
|
|
|
|
15
|
8
|
|
|
8
|
|
19406
|
use Data::Dumper; |
|
|
8
|
|
|
|
|
72302
|
|
|
|
8
|
|
|
|
|
1557
|
|
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
require Exporter; |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( 'all' => [ qw( |
|
23
|
|
|
|
|
|
|
parse_chem_mix |
|
24
|
|
|
|
|
|
|
prepare_mix |
|
25
|
|
|
|
|
|
|
oxidation_state |
|
26
|
|
|
|
|
|
|
redox_test |
|
27
|
|
|
|
|
|
|
class_cir_brutto |
|
28
|
|
|
|
|
|
|
good_formula |
|
29
|
|
|
|
|
|
|
brutto_formula |
|
30
|
|
|
|
|
|
|
stoichiometry |
|
31
|
|
|
|
|
|
|
ttc_reaction |
|
32
|
|
|
|
|
|
|
) ], |
|
33
|
|
|
|
|
|
|
'redox' => [ qw( |
|
34
|
|
|
|
|
|
|
parse_chem_mix |
|
35
|
|
|
|
|
|
|
prepare_mix |
|
36
|
|
|
|
|
|
|
oxidation_state |
|
37
|
|
|
|
|
|
|
redox_test |
|
38
|
|
|
|
|
|
|
) ], |
|
39
|
|
|
|
|
|
|
'equation' => [ qw( |
|
40
|
|
|
|
|
|
|
parse_chem_mix |
|
41
|
|
|
|
|
|
|
prepare_mix |
|
42
|
|
|
|
|
|
|
class_cir_brutto |
|
43
|
|
|
|
|
|
|
good_formula |
|
44
|
|
|
|
|
|
|
brutto_formula |
|
45
|
|
|
|
|
|
|
stoichiometry |
|
46
|
|
|
|
|
|
|
ttc_reaction |
|
47
|
|
|
|
|
|
|
) ], |
|
48
|
|
|
|
|
|
|
); |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
our @EXPORT = qw( ); |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
our $VERSION = '0.118'; |
|
55
|
|
|
|
|
|
|
|
|
56
|
8
|
|
|
8
|
|
159
|
use base qw(Exporter); |
|
|
8
|
|
|
|
|
13
|
|
|
|
8
|
|
|
|
|
118165
|
|
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
# Returns array of "good" chemical formulas |
|
60
|
|
|
|
|
|
|
sub good_formula{ |
|
61
|
46
|
|
50
|
46
|
1
|
46952
|
my $substance = shift || return; |
|
62
|
46
|
|
|
|
|
80
|
my $opts = shift; |
|
63
|
|
|
|
|
|
|
|
|
64
|
46
|
|
|
|
|
87
|
for( $substance ){ |
|
65
|
46
|
|
|
|
|
71
|
my $m = '(?:1|!|\|)'; # mask |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
# Replacement by iodine |
|
68
|
46
|
|
|
|
|
441
|
s/^(\W*)$m(\d*)$/$1I$2/; |
|
69
|
46
|
|
|
|
|
106
|
s/j/I/ig; |
|
70
|
|
|
|
|
|
|
|
|
71
|
46
|
|
|
|
|
86
|
s/\$/s/g; # for 'S' or 's' |
|
72
|
|
|
|
|
|
|
|
|
73
|
46
|
|
|
|
|
344
|
s/((?:^|[^BCGLNPRT])A)$m/$1l/ig; # for 'Al' |
|
74
|
46
|
|
|
|
|
280
|
s/((?:^|[^ACT])L)$m/$1i/ig; # for 'Li' |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# Is it 'o' or oxigen? |
|
77
|
46
|
|
|
|
|
198
|
1 while s/(?<=[CHNP])0(?![,.]\d)/\$/g; # temporarilly to replace --> '$' |
|
78
|
46
|
|
|
|
|
165
|
1 while s/(? 'o' |
|
79
|
|
|
|
|
|
|
|
|
80
|
46
|
|
|
|
|
298
|
s/(?<=[ACT])$m(?=\D|$)/l/ig; # for Al, Cl, Tl |
|
81
|
46
|
|
|
|
|
258
|
s/(?<=[BLNS])$m(?=\D|$)/i/ig; # for Bi, Li, Ni, Si (without Ti) |
|
82
|
|
|
|
|
|
|
|
|
83
|
46
|
|
|
|
|
78
|
s/Q/O/g; # for oxigen |
|
84
|
46
|
|
|
|
|
208
|
s/(?<=[AHMRS])q/g/ig; # for Aq, Hq, Mq, Rq, Sq |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
|
|
87
|
46
|
|
|
|
|
68
|
my(@maU, @maUl); |
|
88
|
0
|
|
|
|
|
0
|
my %sa; # Letters of possible atoms |
|
89
|
|
|
|
|
|
|
|
|
90
|
46
|
|
|
|
|
107
|
my $adb = &_atoms_db; |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
# Possible atoms of substance |
|
93
|
46
|
|
|
|
|
347
|
for( my $i = 0; $i < @$adb; $i+=5 ){ |
|
94
|
5382
|
|
|
|
|
6836
|
$_ = $adb->[$i]; |
|
95
|
|
|
|
|
|
|
|
|
96
|
5382
|
100
|
|
|
|
47255
|
next if $substance !~ /$_/i; |
|
97
|
|
|
|
|
|
|
|
|
98
|
181
|
100
|
|
|
|
338
|
if( length > 1 ){ |
|
99
|
78
|
|
|
|
|
131
|
push @maUl, $_; # Double chem.symbol: 1th - CAPITAL, 2th - small |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
}else{ |
|
102
|
103
|
|
|
|
|
195
|
push @maU, $_; # Unary chem.symbol |
|
103
|
|
|
|
|
|
|
} |
|
104
|
181
|
|
|
|
|
1185
|
$sa{ uc $_ } = '' for split //; # String of CAPITAL letters |
|
105
|
|
|
|
|
|
|
} |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
# All atom letters (CAPITAL) || return 0 |
|
108
|
46
|
|
50
|
|
|
232
|
my $sas = join('', keys %sa) || return; |
|
109
|
|
|
|
|
|
|
|
|
110
|
46
|
|
|
|
|
83
|
my $mz = '(?
|
|
111
|
|
|
|
|
|
|
|
|
112
|
46
|
|
|
|
|
83
|
for( $substance ){ |
|
113
|
46
|
|
|
|
|
3567
|
s/,/./g; |
|
114
|
46
|
|
|
|
|
2070
|
s/[^0-9\$\.\*\(\)\[\]\{\}$sas]+//ig; # to clean bad symbols |
|
115
|
|
|
|
|
|
|
|
|
116
|
46
|
|
|
|
|
267
|
s/\.+$//; # to clean points |
|
117
|
46
|
|
|
|
|
268
|
s/(?
|
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
# to clean sequences not unary symbols |
|
120
|
46
|
|
100
|
|
|
1423
|
while( @maU && $sas =~ /([^@maU])/gx ){ |
|
121
|
42
|
|
|
|
|
273
|
my $ul = $1; |
|
122
|
42
|
|
|
|
|
1374
|
s/($ul)$ul+($ul)/$1$2/ig; |
|
123
|
|
|
|
|
|
|
} |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
# remove bordering brackets |
|
126
|
46
|
|
|
|
|
85
|
our( $maskr, $maskf, $maskq ); |
|
127
|
46
|
|
|
|
|
315
|
$maskr = qr/\((?:(?>[^\(\)]+)|(??{$maskr}))*\)/; |
|
128
|
46
|
|
|
|
|
202
|
$maskf = qr/{(?:(?>[^{}]+)|(??{$maskf}))*}/; |
|
129
|
46
|
|
|
|
|
213
|
$maskq = qr/\[(?:(?>[^\[\]]+)|(??{$maskq}))*\]/; |
|
130
|
|
|
|
|
|
|
|
|
131
|
46
|
|
100
|
|
|
3678
|
s/^.|.$//g while /($maskr|$maskf|$maskq)/g && $_ eq $1; |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# to do small the last symbol of double |
|
134
|
46
|
|
|
|
|
188
|
s/([AEGLMR])(?=[^a-z]|$)/\l$1/g; |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
# Double symbol similar unary with coefficient in the end |
|
137
|
46
|
100
|
100
|
|
|
886
|
if( /^@maUl\d+$/i && @maU && /^(?i:[@maU])\L[@maU]\d+$/ ){ |
|
|
|
|
100
|
|
|
|
|
|
138
|
3
|
|
|
|
|
17
|
my @cf = ( "\u$_", uc ); |
|
139
|
|
|
|
|
|
|
|
|
140
|
3
|
100
|
100
|
|
|
32
|
if( /$mz/ && exists( $opts->{'zero2oxi'} ) ){ |
|
141
|
1
|
|
|
|
|
4
|
my @a = @cf; |
|
142
|
1
|
|
|
|
|
15
|
s/$mz/O/g for @a; |
|
143
|
1
|
|
|
|
|
50
|
return [ @cf, @a ]; |
|
144
|
|
|
|
|
|
|
} |
|
145
|
2
|
|
|
|
|
92
|
return \@cf; |
|
146
|
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# Normalization of oxide-coated formulas (written through '*') |
|
149
|
43
|
100
|
|
|
|
130
|
if(/\*/){ |
|
150
|
4
|
|
|
|
|
7
|
my %k; |
|
151
|
4
|
|
|
|
|
9
|
my $l = 1; |
|
152
|
4
|
|
|
|
|
18
|
for my $i (split /\*/){ |
|
153
|
8
|
100
|
|
|
|
138
|
if($i =~ /^(\d+)[a-zA-Z]/){ # Integer coefficient |
|
|
|
100
|
|
|
|
|
|
|
154
|
1
|
|
|
|
|
6
|
$k{ $1 } = $1; |
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
}elsif($i =~ /^(\d*\.(\d+))/){ # Fractional coefficient |
|
157
|
2
|
|
|
|
|
56
|
$k{ $1 } = $1; |
|
158
|
2
|
100
|
|
|
|
12
|
$l *= 10 if length $2 >= length $l; |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
}else{ # without coefficient (=1) |
|
161
|
5
|
|
|
|
|
17
|
$k{ '' } = 1; |
|
162
|
|
|
|
|
|
|
} |
|
163
|
|
|
|
|
|
|
} |
|
164
|
|
|
|
|
|
|
|
|
165
|
4
|
100
|
|
|
|
15
|
if( $l > 1 ){ |
|
166
|
1
|
|
|
|
|
8
|
$k{ $_ } *= $l for keys %k; |
|
167
|
|
|
|
|
|
|
} |
|
168
|
|
|
|
|
|
|
# by GCD reduce order of coefficients |
|
169
|
4
|
|
|
|
|
32
|
my $gcd = bgcd(values %k); |
|
170
|
|
|
|
|
|
|
|
|
171
|
4
|
100
|
|
|
|
743
|
if( $gcd > 1 ){ |
|
172
|
1
|
|
|
|
|
118
|
$k{ $_ } /= $gcd for keys %k; |
|
173
|
|
|
|
|
|
|
} |
|
174
|
|
|
|
|
|
|
|
|
175
|
4
|
|
|
|
|
559
|
my $f; |
|
176
|
4
|
|
|
|
|
15
|
for my $i (split /\*/){ |
|
177
|
8
|
100
|
|
|
|
47
|
$i =~ s/^(\d*\.?\d*)([\w\(\)\[\]\{\}]+)$/$k{$1}>1?"{$2}".$k{$1}:"{$2}"/e; |
|
|
8
|
|
|
|
|
39
|
|
|
178
|
8
|
|
|
|
|
211
|
$f .= $i; |
|
179
|
|
|
|
|
|
|
} |
|
180
|
4
|
|
|
|
|
25
|
$_ = $f; |
|
181
|
|
|
|
|
|
|
} |
|
182
|
|
|
|
|
|
|
|
|
183
|
43
|
|
|
|
|
218
|
1 while s/[\(\{\[][\)\}\]]//g; # clean empty brackets |
|
184
|
|
|
|
|
|
|
} |
|
185
|
|
|
|
|
|
|
|
|
186
|
43
|
|
|
|
|
100
|
my $cf = ['']; |
|
187
|
43
|
|
|
|
|
352
|
for my $s (split /((?:\$|\d|\(|\)|\[|\]|\{|\})+)/,$substance){ |
|
188
|
|
|
|
|
|
|
|
|
189
|
127
|
100
|
100
|
|
|
1431
|
if( $s =~ /[$sas]/i ){ # Atom symbols |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
190
|
67
|
|
|
|
|
206
|
&_in_gf($s, \@maU, \@maUl, $cf); |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
}elsif( $s =~ /\$/ ){ # Zero symbols: 'o' && 'O' |
|
193
|
4
|
|
|
|
|
15
|
$s =~ s/^\$//; |
|
194
|
4
|
|
|
|
|
22
|
&_add_zero( $cf, "O$s", "o$s" ); # add oxigen to { C H N P } -> { CO HO NO PO } |
|
195
|
|
|
|
|
|
|
# add 'o' to { C H N P } -> { Co Ho No Po } |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
}elsif($s =~ /$mz/ && exists( $opts->{'zero2oxi'} ) ){ # Zero symbols |
|
198
|
4
|
|
|
|
|
9
|
my $z = $s; # zero |
|
199
|
4
|
|
|
|
|
25
|
$s =~ s/$mz/O/g; # oxigen |
|
200
|
|
|
|
|
|
|
|
|
201
|
4
|
|
|
|
|
15
|
&_add_zero( $cf, $s, $z ); |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
}else{ # Others |
|
204
|
52
|
|
|
|
|
212
|
$_ .= $s for @$cf; |
|
205
|
|
|
|
|
|
|
} |
|
206
|
|
|
|
|
|
|
} |
|
207
|
|
|
|
|
|
|
|
|
208
|
43
|
50
|
|
|
|
2475
|
$cf->[0] =~ /\w/ ? return $cf : return; |
|
209
|
|
|
|
|
|
|
} |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
sub _add_zero{ |
|
212
|
8
|
|
|
8
|
|
15
|
my( $cf, $oxi, $z ) = @_; |
|
213
|
8
|
|
|
|
|
12
|
my $n = $#{$cf}; |
|
|
8
|
|
|
|
|
19
|
|
|
214
|
|
|
|
|
|
|
|
|
215
|
8
|
|
|
|
|
33
|
for( my $i = 0; $i <= $n; $i++ ){ |
|
216
|
8
|
|
|
|
|
30
|
$cf->[$i + $n + 1] = $cf->[$i].$oxi; # add oxigen to { C H N P } -> { CO HO NO PO } |
|
217
|
8
|
|
|
|
|
65
|
$cf->[$i] .= $z; # add 'o' to { C H N P } -> { Co Ho No Po } |
|
218
|
|
|
|
|
|
|
} |
|
219
|
|
|
|
|
|
|
} |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
sub _in_gf{ |
|
222
|
25770
|
|
|
25770
|
|
43778
|
my($s, $maU, $maUl, $cf) = @_; |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
# Unary symbols of fragment |
|
225
|
25770
|
|
|
|
|
497909
|
my @i_maU = grep $s =~ /$_/i, @$maU; |
|
226
|
|
|
|
|
|
|
|
|
227
|
25770
|
100
|
|
|
|
75510
|
if( length($s) == 1 ){ # Unary atom symbol |
|
228
|
9167
|
100
|
|
|
|
31288
|
@i_maU || return; |
|
229
|
|
|
|
|
|
|
|
|
230
|
9155
|
|
|
|
|
31516
|
$_ .= $i_maU[0] for @$cf; |
|
231
|
9155
|
|
|
|
|
35250
|
return 1; |
|
232
|
|
|
|
|
|
|
} |
|
233
|
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
# Double symbols of fragment |
|
235
|
16603
|
100
|
100
|
|
|
297934
|
( my @i_maUl = grep $s =~ /$_/i, @$maUl ) || @i_maU || return; # not present |
|
236
|
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
# Strings of unary and double atom letters |
|
238
|
16565
|
|
|
|
|
31510
|
my $saU = join '', @i_maU; # String of unary atom letters |
|
239
|
16565
|
|
|
|
|
24796
|
my $saUl = join '|', @i_maUl; # 1th - CAPITAL, 2th - small |
|
240
|
|
|
|
|
|
|
|
|
241
|
16565
|
|
|
|
|
17886
|
my @w; # Anchor symbols |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
# Unique unary symbols (is not present in double) |
|
244
|
16565
|
|
|
|
|
27228
|
for( @i_maU ){ |
|
245
|
34405
|
100
|
|
|
|
276930
|
next if $saUl =~ /$_/i; |
|
246
|
2834
|
|
|
|
|
23097
|
$s =~ s/\L$_/$_/g; # to CAPITAL |
|
247
|
2834
|
|
|
|
|
7135
|
push @w, $_; |
|
248
|
|
|
|
|
|
|
} |
|
249
|
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
# Unique double (is not present in others) |
|
251
|
16565
|
|
|
|
|
28309
|
for my $ul (@i_maUl){ |
|
252
|
24919
|
|
|
|
|
211114
|
(my $m = $saUl) =~ s/$ul//; # To copy and clean the tested |
|
253
|
|
|
|
|
|
|
|
|
254
|
24919
|
|
|
|
|
62814
|
for(split //,$ul){ |
|
255
|
46713
|
100
|
100
|
|
|
644296
|
next if $m =~ /$_/i || $saU =~ /$_/i; |
|
256
|
|
|
|
|
|
|
|
|
257
|
5910
|
|
|
|
|
49725
|
$s =~ s/$ul/$ul/ig; |
|
258
|
5910
|
|
|
|
|
9826
|
push @w, $ul; |
|
259
|
5910
|
|
|
|
|
16083
|
last; |
|
260
|
|
|
|
|
|
|
} |
|
261
|
|
|
|
|
|
|
} |
|
262
|
|
|
|
|
|
|
|
|
263
|
16565
|
|
|
|
|
27378
|
$_ = $s; |
|
264
|
|
|
|
|
|
|
|
|
265
|
16565
|
100
|
|
|
|
35160
|
if( length == 2){ # Two symbols |
|
266
|
|
|
|
|
|
|
|
|
267
|
9367
|
|
|
|
|
47981
|
(my $salU = $saUl) =~ s/(\w+)/\l\U$1/g; # 1th - small, 2th - CAPITAL |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
# The order is important!!! |
|
270
|
9367
|
|
|
|
|
12622
|
my @in_cf; |
|
271
|
9367
|
100
|
100
|
|
|
305716
|
if( /$saUl/ || /[$saU]{2}/ ){ # Usual writing of atom: 1th - CAPITAL, 2th - small |
|
|
|
50
|
66
|
|
|
|
|
|
|
|
100
|
33
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
# or both - CAPITAL unary letters |
|
273
|
4561
|
|
|
|
|
7094
|
push @in_cf, $_; |
|
274
|
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
}elsif( /\U$saUl/ ){ # 1th and 2th - CAPITAL letters of double symbol |
|
276
|
0
|
|
|
|
|
0
|
push @in_cf, ucfirst lc; |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
}elsif( @i_maU && ( /[$saU][\L$saU\E]/ || /[\L$saU\E][$saU]/ ) ){ # For unary symbols: |
|
279
|
|
|
|
|
|
|
# 1th - CAPITAL, 2th - small or 1th - small, 2th - CAPITAL letter |
|
280
|
1
|
|
|
|
|
3
|
push @in_cf, uc; |
|
281
|
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
}elsif( /$salU/ ){ # 1th - small, 2th - CAPITAL letter of double symbol |
|
283
|
0
|
|
|
|
|
0
|
push @in_cf, ucfirst lc; |
|
284
|
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
}elsif( length($saUl) == 0 ){ # Without double symbol |
|
286
|
1
|
|
|
|
|
22
|
s/.?([$saU]+).?/$1/i; # unary symbol(s) |
|
287
|
1
|
|
|
|
|
5
|
push @in_cf, uc; |
|
288
|
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
}else{ # 1th and 2th small letters - two alternative variants |
|
290
|
4804
|
50
|
|
|
|
50253
|
if( /[\L$saU]{2}/ ){ # unary symbols |
|
291
|
4804
|
|
|
|
|
12854
|
push @in_cf, uc; |
|
292
|
|
|
|
|
|
|
} |
|
293
|
4804
|
50
|
|
|
|
38930
|
if( /\L$saUl/ ){ # double symbol |
|
294
|
4804
|
|
|
|
|
10398
|
push @in_cf, ucfirst; |
|
295
|
|
|
|
|
|
|
} |
|
296
|
|
|
|
|
|
|
|
|
297
|
4804
|
50
|
|
|
|
11274
|
@in_cf || return; |
|
298
|
|
|
|
|
|
|
|
|
299
|
4804
|
50
|
|
|
|
9900
|
if( @in_cf == 2 ){ |
|
300
|
|
|
|
|
|
|
|
|
301
|
4804
|
|
|
|
|
5099
|
my $n = $#{$cf}; |
|
|
4804
|
|
|
|
|
7779
|
|
|
302
|
4804
|
|
|
|
|
10891
|
for( my $i = 0; $i <= $n; $i++ ){ |
|
303
|
13473
|
|
|
|
|
31473
|
$cf->[$i + $n + 1] = $cf->[$i].$in_cf[1]; |
|
304
|
13473
|
|
|
|
|
33419
|
$cf->[$i] .= $in_cf[0]; |
|
305
|
|
|
|
|
|
|
} |
|
306
|
4804
|
|
|
|
|
43532
|
return 1; |
|
307
|
|
|
|
|
|
|
} |
|
308
|
|
|
|
|
|
|
} |
|
309
|
|
|
|
|
|
|
|
|
310
|
4563
|
|
|
|
|
14056
|
$_ .= $in_cf[0] for @$cf; |
|
311
|
4563
|
|
|
|
|
22509
|
return 1; |
|
312
|
|
|
|
|
|
|
} |
|
313
|
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
# More 2 symbols |
|
315
|
|
|
|
|
|
|
|
|
316
|
7198
|
|
|
|
|
10068
|
for( $s ){ |
|
317
|
7198
|
|
|
|
|
15143
|
my $m = join '|', $saUl, @i_maU; |
|
318
|
|
|
|
|
|
|
|
|
319
|
7198
|
|
|
|
|
237117
|
while( ! /^(?:$m)/i ){ s/^.// } # Clear head |
|
|
5
|
|
|
|
|
45
|
|
|
320
|
7198
|
|
|
|
|
253538
|
while( ! /(?:$m)$/i ){ s/.$// } # Clear tail |
|
|
31
|
|
|
|
|
304
|
|
|
321
|
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
# Search double and unary symbols |
|
323
|
7198
|
|
|
|
|
18456
|
my $z = ''; |
|
324
|
7198
|
|
|
|
|
202829
|
while( /^((?:$m)+)/g ){ $z .= $1 } |
|
|
2222
|
|
|
|
|
15321
|
|
|
325
|
|
|
|
|
|
|
|
|
326
|
7198
|
100
|
|
|
|
29031
|
if( length $z ){ |
|
327
|
|
|
|
|
|
|
|
|
328
|
2218
|
|
|
|
|
7054
|
$_ .= $z for @$cf; |
|
329
|
2218
|
100
|
|
|
|
8049
|
return 1 if length($z) == length; # The end |
|
330
|
|
|
|
|
|
|
|
|
331
|
1738
|
|
|
|
|
14163
|
s/^$z//; |
|
332
|
1738
|
100
|
|
|
|
7421
|
return &_in_gf($_, \@i_maU, \@i_maUl, $cf) if 3 > length; |
|
333
|
|
|
|
|
|
|
} |
|
334
|
|
|
|
|
|
|
} |
|
335
|
|
|
|
|
|
|
|
|
336
|
5749
|
100
|
|
|
|
14411
|
if( @w ){ # Search by fragments of anchor symbols |
|
337
|
1802
|
|
|
|
|
3159
|
my $m = join '|', @w; |
|
338
|
|
|
|
|
|
|
|
|
339
|
1802
|
|
|
|
|
19498
|
for my $f (split /($m)/, $s){ |
|
340
|
|
|
|
|
|
|
|
|
341
|
2926
|
|
|
|
|
7558
|
&_in_gf($f, \@i_maU, \@i_maUl, $cf); |
|
342
|
|
|
|
|
|
|
|
|
343
|
2926
|
100
|
|
|
|
4514
|
if( $#{$cf} ){ # For >1 formula |
|
|
2926
|
|
|
|
|
8004
|
|
|
344
|
|
|
|
|
|
|
# To leave the longest fragments |
|
345
|
2058
|
|
|
|
|
7371
|
for( my $i = $#$cf; $i > 0; $i-- ){ |
|
346
|
8072
|
50
|
|
|
|
28581
|
splice @$cf, $i, 1 if length( $cf->[$i] ) < length( $cf->[0] ); |
|
347
|
|
|
|
|
|
|
} |
|
348
|
|
|
|
|
|
|
} |
|
349
|
|
|
|
|
|
|
} |
|
350
|
1802
|
|
|
|
|
14753
|
return 1; |
|
351
|
|
|
|
|
|
|
} |
|
352
|
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
# Difficult fragment |
|
354
|
3947
|
|
|
|
|
9290
|
my $cf_copy = [ @$cf ]; |
|
355
|
3947
|
|
|
|
|
4315
|
$#{$cf} = -1; # Reset |
|
|
3947
|
|
|
|
|
11640
|
|
|
356
|
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
_M_gf_1: # Letter by letter search |
|
358
|
3947
|
|
|
|
|
10534
|
for( my $i = 1; $i < length($s); $i++ ){ |
|
359
|
|
|
|
|
|
|
|
|
360
|
10907
|
|
|
|
|
23295
|
my $cf_new = [ @$cf_copy ]; |
|
361
|
|
|
|
|
|
|
|
|
362
|
10907
|
|
|
|
|
474258
|
for( $s =~ /^(\w{$i})(\w+)/ ){ |
|
363
|
21808
|
100
|
|
|
|
49475
|
&_in_gf($_, \@i_maU, \@i_maUl, $cf_new) || next _M_gf_1; |
|
364
|
|
|
|
|
|
|
} |
|
365
|
|
|
|
|
|
|
# To accumulate only unique, big fragments |
|
366
|
10895
|
|
|
|
|
29057
|
for my $k ( @$cf_new ){ |
|
367
|
47611
|
100
|
100
|
|
|
1368674
|
scalar( grep length($_) > length($k) || $_ eq $k, @$cf ) || push @$cf, $k; |
|
368
|
|
|
|
|
|
|
} |
|
369
|
|
|
|
|
|
|
} |
|
370
|
3947
|
|
|
|
|
19526
|
return 1; |
|
371
|
|
|
|
|
|
|
} |
|
372
|
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
# Tactico-technical characteristics of chemical reaction. |
|
375
|
|
|
|
|
|
|
# Return quantity hash (SAR): |
|
376
|
|
|
|
|
|
|
# 's'ubstance |
|
377
|
|
|
|
|
|
|
# 'a'toms |
|
378
|
|
|
|
|
|
|
# 'r'ank |
|
379
|
|
|
|
|
|
|
sub ttc_reaction{ |
|
380
|
2
|
|
50
|
2
|
1
|
15
|
my $ce = shift || return; |
|
381
|
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
# Hash atom matrix and quantity of atoms |
|
383
|
2
|
|
|
|
|
9
|
my( $atoms_substance, $atoms ) = &_search_atoms_subs( $ce ); |
|
384
|
|
|
|
|
|
|
|
|
385
|
2
|
|
50
|
|
|
20
|
my $rank = Rank( [ values %$atoms_substance ] ) || return; |
|
386
|
|
|
|
|
|
|
|
|
387
|
2
|
|
|
|
|
19894
|
return { 's' => scalar( keys %$atoms_substance ), |
|
388
|
|
|
|
|
|
|
'a' => $atoms, |
|
389
|
|
|
|
|
|
|
'r' => $rank, |
|
390
|
|
|
|
|
|
|
}; |
|
391
|
|
|
|
|
|
|
} |
|
392
|
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
# Calculation common identifier for reaction: |
|
394
|
|
|
|
|
|
|
# Alphabetic CLASS |
|
395
|
|
|
|
|
|
|
# and |
|
396
|
|
|
|
|
|
|
# Chemical Interger Reaction (CIR) identifier |
|
397
|
|
|
|
|
|
|
# also |
|
398
|
|
|
|
|
|
|
# brutto (gross) formulas of substances |
|
399
|
|
|
|
|
|
|
sub class_cir_brutto{ |
|
400
|
66
|
|
|
66
|
1
|
120
|
my( $ce, $coef ) = @_; |
|
401
|
66
|
50
|
|
|
|
142
|
$ce || return; |
|
402
|
|
|
|
|
|
|
|
|
403
|
66
|
|
|
|
|
81
|
my( %elm, %bf, @cir ); |
|
404
|
|
|
|
|
|
|
|
|
405
|
66
|
|
|
|
|
141
|
for my $c ( @$ce ){ |
|
406
|
132
|
|
|
|
|
205
|
for my $s ( @$c ){ |
|
407
|
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
# stoichiometry coefficient |
|
409
|
358
|
50
|
|
|
|
884
|
my $k = exists $coef->{$s} ? $coef->{$s} : 1; |
|
410
|
|
|
|
|
|
|
|
|
411
|
358
|
|
|
|
|
1143
|
my %e = Chemistry::File::Formula->parse_formula( $s ); |
|
412
|
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
# for brutto |
|
414
|
358
|
|
|
|
|
58248
|
$bf{ $s } = join '', map( "$_$e{$_}", sort{ $a cmp $b } keys %e ); |
|
|
687
|
|
|
|
|
2476
|
|
|
415
|
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
# for cir |
|
417
|
358
|
|
|
|
|
991
|
push @cir, $k.$bf{ $s }; |
|
418
|
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
# For class |
|
420
|
358
|
|
|
|
|
1520
|
@elm{ keys %e } = ''; # reaction atoms |
|
421
|
|
|
|
|
|
|
} |
|
422
|
|
|
|
|
|
|
} |
|
423
|
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
# CLASS, CIR of reaction and hash: formula => brutto of substances |
|
425
|
520
|
|
|
|
|
691
|
return [ join( '', sort { $a cmp $b } keys %elm ), |
|
|
622
|
|
|
|
|
956
|
|
|
426
|
66
|
|
|
|
|
195
|
( cksum( join '+', sort { $a cmp $b } @cir ) )[0], |
|
427
|
|
|
|
|
|
|
\%bf ]; |
|
428
|
|
|
|
|
|
|
} |
|
429
|
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
# Transformation substance arrays to chemical mix (equation) |
|
432
|
|
|
|
|
|
|
# $ce -- ref to array of substance arrays |
|
433
|
|
|
|
|
|
|
# $opts ->{ } (facultative parameters) |
|
434
|
|
|
|
|
|
|
# ->'substances' -- ref to array of real (required) substances |
|
435
|
|
|
|
|
|
|
# ->'coefficients' -- ref to hash stoichiometry coefficients for substances |
|
436
|
|
|
|
|
|
|
# ->'norma' -- chemical mix to brutto-normalize |
|
437
|
|
|
|
|
|
|
sub prepare_mix{ |
|
438
|
829
|
|
|
829
|
1
|
1198
|
my( $ce, $opts ) = @_; |
|
439
|
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
# Check empty reactants & products |
|
441
|
1658
|
|
|
|
|
4695
|
croak('Bad equation!') if @$ce != 2 || |
|
442
|
|
|
|
|
|
|
scalar( grep ! defined, @$ce ) || |
|
443
|
829
|
50
|
50
|
|
|
4733
|
scalar( grep { grep ! defined, @{$_} } @$ce ); |
|
|
1658
|
|
50
|
|
|
1613
|
|
|
444
|
|
|
|
|
|
|
|
|
445
|
829
|
|
|
|
|
1110
|
my $sign = 0; |
|
446
|
|
|
|
|
|
|
# Any coefficient isn't set --> to bypass |
|
447
|
829
|
100
|
66
|
|
|
2273
|
if( exists( $opts->{'norma'} ) && |
|
|
98
|
|
|
|
|
639
|
|
|
448
|
|
|
|
|
|
|
scalar( grep { |
|
449
|
98
|
|
|
|
|
109
|
grep ! exists( $opts->{'coefficients'}{$_} ), @{$_} |
|
450
|
|
|
|
|
|
|
} @$ce ) == 0 ){ # All coefficients are set |
|
451
|
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
# Test stoichiometry coefficient sign on initial (first) substances |
|
453
|
49
|
|
|
|
|
71
|
$sign = 1; |
|
454
|
49
|
|
|
|
|
60
|
for( @{ $ce->[0] } ){ |
|
|
49
|
|
|
|
|
123
|
|
|
455
|
55
|
100
|
|
|
|
339
|
$opts->{'coefficients'}{$_} || next; # Zero stoichiometry coefficient |
|
456
|
49
|
100
|
|
|
|
1115
|
$sign = -1 if $opts->{'coefficients'}{$_} < 0; |
|
457
|
49
|
|
|
|
|
5932
|
last; |
|
458
|
|
|
|
|
|
|
} |
|
459
|
|
|
|
|
|
|
} |
|
460
|
|
|
|
|
|
|
|
|
461
|
829
|
100
|
|
|
|
1952
|
if( $sign != 0 ){ # chemical mix to brutto-normalize |
|
462
|
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
# if assume all coefficients positive '+' |
|
464
|
49
|
50
|
|
|
|
127
|
if( $opts->{'norma'} != 1 ){ |
|
465
|
0
|
|
|
|
|
0
|
$opts->{'coefficients'}{$_} *= -1 for @{ $ce->[1] }; |
|
|
0
|
|
|
|
|
0
|
|
|
466
|
|
|
|
|
|
|
} |
|
467
|
|
|
|
|
|
|
|
|
468
|
49
|
|
|
|
|
97
|
my @cir; # for brutto-formula |
|
469
|
49
|
|
|
|
|
78
|
while( my($s, $c) = each %{ $opts->{'coefficients'} } ){ |
|
|
306
|
|
|
|
|
2902
|
|
|
470
|
257
|
100
|
|
|
|
755
|
$c || next; |
|
471
|
234
|
100
|
|
|
|
6529
|
my $ip = $sign * $c > 0 ? 0 : 1; |
|
472
|
|
|
|
|
|
|
|
|
473
|
234
|
|
|
|
|
55555
|
my $ff = abs($c)." $s"; |
|
474
|
|
|
|
|
|
|
|
|
475
|
234
|
|
|
|
|
11761
|
my %e = Chemistry::File::Formula->parse_formula( $ff ); |
|
476
|
234
|
|
|
|
|
45258
|
$cir[$ip]{$ff} = join '', map( "$_$e{$_}", sort{ $a cmp $b} keys %e ); |
|
|
431
|
|
|
|
|
2338
|
|
|
477
|
|
|
|
|
|
|
} |
|
478
|
|
|
|
|
|
|
# Result |
|
479
|
49
|
|
|
|
|
104
|
$_ = join(' == ', map{ join ' + ',sort {$_->{$a} cmp $_->{$b}} keys %{$_} } @cir); |
|
|
98
|
|
|
|
|
134
|
|
|
|
194
|
|
|
|
|
682
|
|
|
|
98
|
|
|
|
|
313
|
|
|
480
|
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
}else{ |
|
482
|
780
|
100
|
66
|
|
|
5577
|
if( exists( $opts->{'substances'} ) && @{ $opts->{'substances'} } ){ |
|
|
779
|
|
|
|
|
3272
|
|
|
483
|
|
|
|
|
|
|
# List of real substances is specified |
|
484
|
779
|
|
|
|
|
869
|
my %bs; |
|
485
|
779
|
|
|
|
|
1024
|
@bs{ @{ $opts->{'substances'} } } = (); |
|
|
779
|
|
|
|
|
2682
|
|
|
486
|
|
|
|
|
|
|
|
|
487
|
779
|
|
|
|
|
1233
|
$_ = join(' == ', map{ join ' + ', map{ |
|
488
|
5642
|
100
|
|
|
|
9290
|
if( exists $bs{$_} ){ |
|
|
1558
|
|
|
|
|
2162
|
|
|
489
|
2928
|
100
|
|
|
|
10779
|
exists( $opts->{'coefficients'}{$_} ) ? abs( $opts->{'coefficients'}{$_} )." $_" : $_ |
|
490
|
|
|
|
|
|
|
}else{ |
|
491
|
|
|
|
|
|
|
( ) |
|
492
|
2714
|
|
|
|
|
4886
|
} |
|
493
|
1558
|
|
|
|
|
1662
|
} @{$_} } @$ce ); |
|
494
|
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
}else{ # List isn't specified |
|
496
|
1
|
100
|
|
|
|
3
|
$_ = join(' == ', map{ join ' + ', map{ |
|
|
6
|
|
|
|
|
32
|
|
|
497
|
2
|
|
|
|
|
3
|
exists( $opts->{'coefficients'}{$_} ) ? abs( $opts->{'coefficients'}{$_} )." $_" : $_ } @{$_} } @$ce ); |
|
|
2
|
|
|
|
|
4
|
|
|
498
|
|
|
|
|
|
|
} |
|
499
|
|
|
|
|
|
|
} |
|
500
|
|
|
|
|
|
|
|
|
501
|
829
|
|
|
|
|
6462
|
s/^\s*==|==\s*$//g; |
|
502
|
829
|
50
|
|
|
|
6912
|
/\S\s*[=+]+\s*\S/ ? $_ : return; |
|
503
|
|
|
|
|
|
|
} |
|
504
|
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
# Расчёт (поиск) стехиометрических коэффициентов |
|
507
|
|
|
|
|
|
|
# Возвращает : |
|
508
|
|
|
|
|
|
|
# решение в $cheq |
|
509
|
|
|
|
|
|
|
# undef --- нет решения |
|
510
|
|
|
|
|
|
|
sub stoichiometry{ |
|
511
|
16
|
|
|
16
|
1
|
16996
|
my($mix, $opts) = @_; |
|
512
|
16
|
100
|
|
|
|
58
|
$opts->{'redox_pairs'} = 1 unless exists $opts->{'redox_pairs'}; # вкл. redox-уравниватель |
|
513
|
|
|
|
|
|
|
|
|
514
|
16
|
|
|
|
|
23
|
my @cheq; # возвращаемые уравнения |
|
515
|
|
|
|
|
|
|
|
|
516
|
16
|
|
|
|
|
51
|
&_in_search_stoich($mix, \@cheq, $opts ); # Рекурсивный поиск |
|
517
|
|
|
|
|
|
|
|
|
518
|
16
|
50
|
|
|
|
113
|
@cheq ? \@cheq : return undef; |
|
519
|
|
|
|
|
|
|
} |
|
520
|
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
# Рекурсивный поиск стехиометрических коэффициентов |
|
523
|
|
|
|
|
|
|
sub _in_search_stoich{ |
|
524
|
1389
|
|
|
1389
|
|
2530
|
my($mix, $cheq, $opts) = @_; |
|
525
|
|
|
|
|
|
|
|
|
526
|
1389
|
|
|
|
|
2164
|
my %coef; # на случай заданных коэф. в $mix |
|
527
|
1389
|
|
|
|
|
3224
|
my $chem_eq = parse_chem_mix($mix, \%coef); |
|
528
|
|
|
|
|
|
|
|
|
529
|
1389
|
50
|
|
|
|
3698
|
croak('Bad equation!') if @$chem_eq != 2; |
|
530
|
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
# Хеш Атомной матрицы и кол-во атомов |
|
532
|
1389
|
|
|
|
|
2936
|
my ( $atoms_substance, $num_atoms ) = &_search_atoms_subs( $chem_eq ); |
|
533
|
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
# Список Всех веществ и копия атомной матрицы (для проверки баланса в конце) |
|
535
|
672
|
|
|
|
|
2684
|
my $All_substances = [ keys %$atoms_substance ]; |
|
536
|
672
|
|
|
|
|
1420
|
my $ini_am = { map{ $_, [ @{ $atoms_substance->{$_} } ] } @$All_substances }; |
|
|
4558
|
|
|
|
|
4421
|
|
|
|
4558
|
|
|
|
|
4271059
|
|
|
537
|
|
|
|
|
|
|
|
|
538
|
672
|
|
|
|
|
2709
|
my $R_free = [ (0) x $num_atoms ]; # R-вектор свободных членов (правая часть) |
|
539
|
672
|
|
|
|
|
1429
|
my $R_zero = 1; # Признак нулевого R-вектора |
|
540
|
|
|
|
|
|
|
|
|
541
|
672
|
|
|
|
|
2449
|
while( my($s, $c) = each %coef ){ # В-во и стех.коэф. |
|
542
|
2
|
50
|
|
|
|
12
|
$opts->{'coefficients'}{$s} = $c unless exists( $opts->{'coefficients'}{$s} ); |
|
543
|
|
|
|
|
|
|
} |
|
544
|
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
# Если заданы стех.коэффициенты |
|
546
|
672
|
100
|
100
|
|
|
2299
|
if( exists $opts->{'coefficients'} && keys %{ $opts->{'coefficients'} } ){ |
|
|
662
|
|
|
|
|
3422
|
|
|
547
|
|
|
|
|
|
|
|
|
548
|
597
|
|
|
|
|
1471
|
my $sign = 1; # знак переноса вправо по исходным в-вам |
|
549
|
|
|
|
|
|
|
|
|
550
|
597
|
|
|
|
|
1126
|
for my $ip ( @$chem_eq ){ |
|
551
|
1194
|
|
|
|
|
1610
|
for my $s ( @$ip ){ |
|
552
|
|
|
|
|
|
|
|
|
553
|
4176
|
100
|
|
|
|
10309
|
if( exists $opts->{'coefficients'}{$s} ){ |
|
554
|
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
# устанавливаем знак-признак исх./продукт |
|
556
|
2875
|
|
|
|
|
6685
|
$opts->{'coefficients'}{$s} = $sign * abs( $opts->{'coefficients'}{$s} ); |
|
557
|
|
|
|
|
|
|
|
|
558
|
2875
|
|
|
|
|
2859
|
my $i; |
|
559
|
|
|
|
|
|
|
# формируем Вектор правой части СЛАУ |
|
560
|
2875
|
|
|
|
|
19099
|
$R_free->[$i++] -= $_ * $opts->{'coefficients'}{$s} |
|
561
|
2875
|
|
|
|
|
2762
|
for @{ $atoms_substance->{$s} }; |
|
562
|
|
|
|
|
|
|
# удаляем вещество после переноса вправо |
|
563
|
2875
|
|
|
|
|
7844
|
delete $atoms_substance->{$s}; |
|
564
|
|
|
|
|
|
|
} |
|
565
|
|
|
|
|
|
|
} |
|
566
|
1194
|
|
|
|
|
2081
|
$sign = -1; # знак переноса вправо по продуктам |
|
567
|
|
|
|
|
|
|
} |
|
568
|
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
# Поиск полностью нулевых атомных строк |
|
570
|
597
|
|
|
|
|
1582
|
my @sum_atom = (0) x $num_atoms; |
|
571
|
597
|
|
|
|
|
703
|
for my $s ( keys %{ $atoms_substance} ) { |
|
|
597
|
|
|
|
|
1342
|
|
|
572
|
1301
|
|
|
|
|
1383
|
my $i; |
|
573
|
1301
|
|
|
|
|
1239
|
$sum_atom[$i++] += $_ for @{ $atoms_substance->{$s} }; |
|
|
1301
|
|
|
|
|
6862
|
|
|
574
|
|
|
|
|
|
|
} |
|
575
|
|
|
|
|
|
|
|
|
576
|
597
|
|
|
|
|
920
|
my @atom_del; # удаляемые 0-строки |
|
577
|
597
|
|
|
|
|
1755
|
for( my $i = $#sum_atom; $i >= 0; $i--){ # Обратный отсчёт |
|
578
|
|
|
|
|
|
|
|
|
579
|
1864
|
100
|
|
|
|
3757
|
unless( $sum_atom[$i] ){ # Все атомы нули |
|
580
|
590
|
100
|
|
|
|
8899
|
return if $R_free->[$i]; # Нет баланса, нет решения |
|
581
|
52
|
|
|
|
|
118
|
push @atom_del, $i; |
|
582
|
|
|
|
|
|
|
} |
|
583
|
|
|
|
|
|
|
|
|
584
|
1326
|
100
|
|
|
|
5699
|
$R_zero = 0 if $R_free->[$i]; # R-вектор не 0 |
|
585
|
|
|
|
|
|
|
} |
|
586
|
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
# Удаление 0-х атомных строк |
|
588
|
59
|
|
|
|
|
106
|
for my $i ( @atom_del ){ |
|
589
|
52
|
|
|
|
|
167
|
splice @$R_free, $i, 1; |
|
590
|
|
|
|
|
|
|
|
|
591
|
52
|
|
|
|
|
92
|
for( values %{ $atoms_substance} ) { |
|
|
52
|
|
|
|
|
126
|
|
|
592
|
113
|
|
|
|
|
141
|
splice @{ $_ }, $i, 1; |
|
|
113
|
|
|
|
|
288
|
|
|
593
|
|
|
|
|
|
|
} |
|
594
|
|
|
|
|
|
|
} |
|
595
|
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
# Уменьшаем число атомов |
|
597
|
59
|
50
|
|
|
|
217
|
unless( $num_atoms -= @atom_del ){ |
|
598
|
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
# Заданы все правильные стех.коэф. |
|
600
|
0
|
|
|
|
|
0
|
push @$cheq, prepare_mix( $chem_eq, |
|
601
|
|
|
|
|
|
|
{ 'norma' => 1, 'coefficients' => $opts->{'coefficients'} } ); |
|
602
|
0
|
|
|
|
|
0
|
return; |
|
603
|
|
|
|
|
|
|
} |
|
604
|
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
# Одно в-во без стех.коэф. |
|
606
|
59
|
50
|
|
|
|
372
|
if( (my @v = values %$atoms_substance) == 1 ){ |
|
607
|
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
# Должна быть пропорция между атомами в в-ве и правом векторе |
|
609
|
0
|
|
|
|
|
0
|
for( my $i = 0; $i < $#{ $v[0] }; $i++){ |
|
|
0
|
|
|
|
|
0
|
|
|
610
|
0
|
0
|
|
|
|
0
|
return if $v[0]->[$i] * $R_free->[$i+1] != $v[0]->[$i+1] * $R_free->[$i] |
|
611
|
|
|
|
|
|
|
} |
|
612
|
|
|
|
|
|
|
} |
|
613
|
|
|
|
|
|
|
} |
|
614
|
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
# Список искомых веществ |
|
616
|
134
|
|
|
|
|
688
|
my $substances_X = [ keys %$atoms_substance ]; |
|
617
|
|
|
|
|
|
|
|
|
618
|
134
|
50
|
33
|
|
|
554
|
return if @$substances_X < 2 && $R_zero; # 0|1 вещество и не заданы коэф. |
|
619
|
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
# Ранг матрицы --- кол-ва независимых строк, столбцов |
|
621
|
134
|
|
|
|
|
1113
|
my $order = Rank( [ values %$atoms_substance ] ); |
|
622
|
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
# print "$mix\n"; |
|
624
|
|
|
|
|
|
|
# print "Atoms = $num_atoms |
|
625
|
|
|
|
|
|
|
#Substances = ",scalar(keys %$atoms_substance), |
|
626
|
|
|
|
|
|
|
#"\nRank = $order\n--------\n"; |
|
627
|
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
# не задан R-вектор (коэффициенты) и ранг == веществам |
|
629
|
134
|
100
|
100
|
|
|
370568
|
return if $R_zero && $order == @$substances_X; # нет решения |
|
630
|
|
|
|
|
|
|
|
|
631
|
117
|
100
|
|
|
|
468
|
if( @$substances_X - $order > 1 ){ # Веществ больше Ранга на 2 и более |
|
632
|
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
# Ограничить рекурсию самым Верхним!!! уровнем перебора |
|
634
|
12
|
100
|
|
|
|
135
|
return if @$cheq; # || @$substances_X < 3; |
|
635
|
|
|
|
|
|
|
|
|
636
|
6
|
100
|
100
|
|
|
35
|
if( $opts->{'redox_pairs'} && ( my $redox = &redox_test($chem_eq) ) ){ |
|
637
|
|
|
|
|
|
|
# Проверить реакцию на ОВР |
|
638
|
|
|
|
|
|
|
# if( my $redox = &redox_test($chem_eq) ){ # Это ОВР |
|
639
|
|
|
|
|
|
|
|
|
640
|
2
|
|
|
|
|
15
|
my @nm_rx = sort keys %$redox; # 0='oxidant' и 1='reducer' |
|
641
|
2
|
|
|
|
|
4
|
my %pairs; |
|
642
|
|
|
|
|
|
|
|
|
643
|
2
|
|
|
|
|
3
|
for my $nm ( @nm_rx ){ |
|
644
|
4
|
|
|
|
|
5
|
for my $e ( keys %{ $redox->{$nm} } ){ # Элементы |
|
|
4
|
|
|
|
|
11
|
|
|
645
|
|
|
|
|
|
|
# Исходное->Конечное состояние элемента |
|
646
|
6
|
|
|
|
|
8
|
for my $i_k ( keys %{ $redox->{$nm}{$e} } ){ |
|
|
6
|
|
|
|
|
12
|
|
|
647
|
8
|
|
|
|
|
7
|
push @{ $pairs{$nm} }, $i_k; |
|
|
8
|
|
|
|
|
29
|
|
|
648
|
|
|
|
|
|
|
} |
|
649
|
|
|
|
|
|
|
} |
|
650
|
|
|
|
|
|
|
} |
|
651
|
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
# print Dumper \%pairs; |
|
653
|
|
|
|
|
|
|
|
|
654
|
2
|
|
|
|
|
14
|
my $iter_oxi = subsets( $pairs{ $nm_rx[0] }); # можно задать ,1 - один окислитель |
|
655
|
|
|
|
|
|
|
|
|
656
|
2
|
|
|
|
|
87
|
while(my $pair_oxi = $iter_oxi->next){ # Набор пар |
|
657
|
12
|
100
|
|
|
|
297
|
next unless @$pair_oxi; # убрать пустые (фича subsets) |
|
658
|
|
|
|
|
|
|
|
|
659
|
10
|
|
|
|
|
18
|
my $sum_oxi_e = 0; # сумма e- нов принимаемых окислителями |
|
660
|
|
|
|
|
|
|
|
|
661
|
10
|
|
|
|
|
16
|
for my $e ( keys %{ $redox->{ $nm_rx[0] } } ){ # Элементы окислителя |
|
|
10
|
|
|
|
|
32
|
|
|
662
|
20
|
|
|
|
|
306
|
for my $i_k ( @{ $pair_oxi } ){ |
|
|
20
|
|
|
|
|
37
|
|
|
663
|
32
|
100
|
|
|
|
938
|
$sum_oxi_e += $redox->{ $nm_rx[0] }{$e}{$i_k}[0] if exists( $redox->{ $nm_rx[0] }{$e}{$i_k} ); |
|
664
|
|
|
|
|
|
|
} |
|
665
|
|
|
|
|
|
|
} |
|
666
|
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
# 1 - один восстановитель (надо настраивать!!!) |
|
668
|
10
|
|
|
|
|
763
|
my $iter_red = subsets( $pairs{ $nm_rx[1] } ); |
|
669
|
|
|
|
|
|
|
|
|
670
|
10
|
|
|
|
|
371
|
while(my $pair_red = $iter_red->next){ # Набор пар |
|
671
|
34
|
50
|
|
|
|
2087
|
next if $sum_oxi_e < @{ $pair_red }; # принимаемых e- нов меньше восст-лей |
|
|
34
|
|
|
|
|
129
|
|
|
672
|
|
|
|
|
|
|
|
|
673
|
34
|
|
|
|
|
3301
|
my $sum_red_e = 0; # сумма e- нов отдаваемых восстановителями |
|
674
|
|
|
|
|
|
|
|
|
675
|
34
|
|
|
|
|
53
|
for my $e ( keys %{ $redox->{ $nm_rx[1] } } ){ # Элементы восстановителя |
|
|
34
|
|
|
|
|
132
|
|
|
676
|
34
|
|
|
|
|
47
|
for my $i_k ( @{ $pair_red } ){ |
|
|
34
|
|
|
|
|
82
|
|
|
677
|
31
|
50
|
|
|
|
1392
|
$sum_red_e += $redox->{ $nm_rx[1] }{$e}{$i_k}[0] if exists( $redox->{ $nm_rx[1] }{$e}{$i_k} ); |
|
678
|
|
|
|
|
|
|
} |
|
679
|
|
|
|
|
|
|
} |
|
680
|
|
|
|
|
|
|
|
|
681
|
34
|
100
|
|
|
|
3447
|
next if $sum_red_e < @{ $pair_oxi }; # отдаваемых e- нов меньше окисл-ей |
|
|
34
|
|
|
|
|
139
|
|
|
682
|
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
# Формируем вектор правых частей |
|
684
|
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
# из окислителей |
|
686
|
23
|
|
|
|
|
80
|
my $oxi_in = variations_with_repetition( [ (1..($sum_red_e - @{ $pair_oxi } + 1) ) ], |
|
|
23
|
|
|
|
|
6989
|
|
|
687
|
23
|
|
|
|
|
1878
|
scalar(@{ $pair_oxi }) ); |
|
688
|
23
|
|
|
|
|
990
|
while (my $e_oxi = $oxi_in->next) { |
|
689
|
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
# Все e-ны должны быть распределены по окислителям |
|
691
|
1198
|
|
|
|
|
117285
|
my $sum_e = 0; |
|
692
|
1198
|
|
|
|
|
3760
|
$sum_e += $_ for @$e_oxi; |
|
693
|
1198
|
100
|
|
|
|
3480
|
next if $sum_e != $sum_red_e; |
|
694
|
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
# из восстановителей |
|
696
|
122
|
|
|
|
|
459
|
my $red_in = variations_with_repetition( [ (1..($sum_oxi_e - @{ $pair_red } + 1) ) ], |
|
|
122
|
|
|
|
|
47939
|
|
|
697
|
122
|
|
|
|
|
9327
|
scalar(@{ $pair_red }) ); |
|
698
|
122
|
|
|
|
|
5573
|
while (my $e_red = $red_in->next) { |
|
699
|
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
# Все e-ны должны быть распределены по восстановителям |
|
701
|
5204
|
|
|
|
|
448594
|
my $sum_e = 0; |
|
702
|
5204
|
|
|
|
|
15883
|
$sum_e += $_ for @$e_red; |
|
703
|
5204
|
100
|
|
|
|
14572
|
next if $sum_e != $sum_oxi_e; |
|
704
|
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
# Копируем во временный хеш опций |
|
706
|
595
|
|
|
|
|
44067
|
my %in_opts; |
|
707
|
595
|
|
|
|
|
1662
|
$in_opts{'redox_pairs'} = $opts->{'redox_pairs'}; |
|
708
|
595
|
|
|
|
|
742
|
$in_opts{'coefficients'}{ $_ } = $opts->{'coefficients'}{ $_ } for keys %{ $opts->{'coefficients'} }; |
|
|
595
|
|
|
|
|
2099
|
|
|
709
|
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
# Доформировываем внутренний хеш опций для R-вектора |
|
711
|
595
|
|
|
|
|
1026
|
my $j = 0; |
|
712
|
595
|
|
|
|
|
643
|
for my $i_k ( @{ $pair_oxi } ){ # пары для окислителей |
|
|
595
|
|
|
|
|
1160
|
|
|
713
|
1555
|
|
|
|
|
4176
|
for( split "->",$i_k ){ # Получаем Исходное и конечное |
|
714
|
3110
|
50
|
|
|
|
6883
|
unless( exists( $opts->{'coefficients'}{$_} ) ){ |
|
715
|
3110
|
|
|
|
|
7925
|
$in_opts{'coefficients'}{$_} += $e_oxi->[$j]; |
|
716
|
|
|
|
|
|
|
} |
|
717
|
|
|
|
|
|
|
# last; |
|
718
|
|
|
|
|
|
|
} |
|
719
|
1555
|
|
|
|
|
3408
|
$j++; |
|
720
|
|
|
|
|
|
|
} |
|
721
|
595
|
|
|
|
|
910
|
$j = 0; |
|
722
|
595
|
|
|
|
|
1100
|
for my $i_k ( @$pair_red ){ # пары для восстановителей |
|
723
|
1134
|
|
|
|
|
2596
|
for( split "->",$i_k ){ |
|
724
|
2268
|
50
|
|
|
|
5394
|
unless( exists( $opts->{'coefficients'}{$_} ) ){ |
|
725
|
2268
|
|
|
|
|
4766
|
$in_opts{'coefficients'}{$_} += $e_red->[$j]; |
|
726
|
|
|
|
|
|
|
} |
|
727
|
|
|
|
|
|
|
} |
|
728
|
1134
|
|
|
|
|
2046
|
$j++; |
|
729
|
|
|
|
|
|
|
} |
|
730
|
|
|
|
|
|
|
|
|
731
|
595
|
|
|
|
|
1037
|
eval{ &_in_search_stoich($mix, $cheq, \%in_opts) }; |
|
|
595
|
|
|
|
|
1491
|
|
|
732
|
|
|
|
|
|
|
} |
|
733
|
|
|
|
|
|
|
} |
|
734
|
|
|
|
|
|
|
} |
|
735
|
|
|
|
|
|
|
} |
|
736
|
|
|
|
|
|
|
} |
|
737
|
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
# Ordinary no-ОВР reactions |
|
739
|
|
|
|
|
|
|
|
|
740
|
6
|
|
|
|
|
49
|
my $iter = subsets($All_substances); |
|
741
|
6
|
|
|
|
|
260
|
$iter->next; # to discard 1st full substances list |
|
742
|
|
|
|
|
|
|
|
|
743
|
6
|
|
|
|
|
98
|
while(my $ys = $iter->next){ # Substances list |
|
744
|
826
|
100
|
|
|
|
36184
|
next if @$ys < 2; # it isn't enough substances for a variation (not last!) |
|
745
|
|
|
|
|
|
|
|
|
746
|
778
|
|
50
|
|
|
2593
|
my $new_mix = prepare_mix( $chem_eq, { 'substances' => $ys } ) || next; |
|
747
|
|
|
|
|
|
|
|
|
748
|
778
|
|
|
|
|
1859
|
eval{ &_in_search_stoich($new_mix, $cheq, $opts) }; # recursion |
|
|
778
|
|
|
|
|
1521
|
|
|
749
|
|
|
|
|
|
|
} |
|
750
|
6
|
|
|
|
|
215
|
return; |
|
751
|
|
|
|
|
|
|
} |
|
752
|
|
|
|
|
|
|
|
|
753
|
105
|
|
|
|
|
365
|
my $base_subst = [ @$substances_X ]; # Base substances list |
|
754
|
105
|
|
|
|
|
202
|
my $var_subst; # Varied substance |
|
755
|
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
# R-vector не задан (0) или задан (1) and matrix недоопределённая |
|
757
|
105
|
100
|
33
|
|
|
722
|
if( $R_zero || ( $R_zero == 0 && @$substances_X == $order + 1 ) ){ |
|
|
|
|
66
|
|
|
|
|
|
758
|
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
# Search linear-dependent substance (column) |
|
760
|
46
|
|
|
|
|
75
|
for( 1..$#{ $substances_X } ){ |
|
|
46
|
|
|
|
|
130
|
|
|
761
|
50
|
|
|
|
|
98
|
$var_subst = pop @$base_subst; # взять последнее |
|
762
|
50
|
100
|
|
|
|
463
|
last if Rank( [ ( map $atoms_substance->{$_}, @$base_subst ) ] ) == $order; |
|
763
|
4
|
|
|
|
|
9984
|
unshift @$base_subst, $var_subst; # add в начало |
|
764
|
|
|
|
|
|
|
} |
|
765
|
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
# return if @$base_subst == @$substances_X; # no found (?) |
|
767
|
|
|
|
|
|
|
|
|
768
|
46
|
|
|
|
|
162668
|
my $i; |
|
769
|
|
|
|
|
|
|
# доформировываем R-vector |
|
770
|
46
|
|
|
|
|
77
|
$R_free->[$i++] -= $_ for @{ $atoms_substance->{$var_subst} }; |
|
|
46
|
|
|
|
|
298
|
|
|
771
|
|
|
|
|
|
|
} |
|
772
|
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
# Переопределённая матрица (atoms >= substances > rank) |
|
774
|
105
|
|
|
|
|
222
|
my $ao = $num_atoms - $order; |
|
775
|
105
|
100
|
|
|
|
337
|
if( $ao > 0 ){ |
|
776
|
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
# Copy vector & atom matrix |
|
778
|
82
|
|
|
|
|
211
|
my $R_copy = [ @$R_free ]; |
|
779
|
82
|
|
|
|
|
277
|
my $cam = { map{ $_, [ @{ $atoms_substance->{$_} } ] } keys %$atoms_substance }; |
|
|
234
|
|
|
|
|
278
|
|
|
|
234
|
|
|
|
|
835
|
|
|
780
|
|
|
|
|
|
|
|
|
781
|
82
|
|
|
|
|
570
|
my $it = subsets( [ ( 0..$num_atoms - 1 ) ], $ao ); |
|
782
|
82
|
|
|
|
|
5116
|
while( my $p = $it->next ){ |
|
783
|
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
# Удаление атомных строк (от старших) |
|
785
|
88
|
|
|
|
|
986
|
for my $i ( reverse @$p ){ |
|
786
|
149
|
|
|
|
|
302
|
splice @$R_free, $i, 1; # из вектора |
|
787
|
149
|
|
|
|
|
340
|
splice @{ $_ }, $i, 1 for values %$atoms_substance; # из атомной матрицы |
|
|
410
|
|
|
|
|
896
|
|
|
788
|
|
|
|
|
|
|
} |
|
789
|
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
# All linear-dependent atom rows removed |
|
791
|
88
|
100
|
|
|
|
518
|
last if Rank( [ map $atoms_substance->{$_}, @$base_subst ] ) == $order; |
|
792
|
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
# Recovery and search repetition |
|
794
|
6
|
|
|
|
|
7214
|
$R_free = [ @$R_copy ]; # vector |
|
795
|
6
|
|
|
|
|
21
|
$atoms_substance = { map{ $_, [ @{ $cam->{$_} } ] } keys %$cam }; # matrix |
|
|
23
|
|
|
|
|
25
|
|
|
|
23
|
|
|
|
|
97
|
|
|
796
|
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
} |
|
798
|
|
|
|
|
|
|
# $num_atoms -= $ao; # уменьшаем число атомов |
|
799
|
|
|
|
|
|
|
} |
|
800
|
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
# Находим решение |
|
802
|
|
|
|
|
|
|
# Формируем атомную матрицу, |
|
803
|
105
|
50
|
|
|
|
5580326
|
my $steX = Solve_Det( |
|
804
|
|
|
|
|
|
|
[ map $atoms_substance->{$_}, @$base_subst ], |
|
805
|
|
|
|
|
|
|
$R_free, |
|
806
|
|
|
|
|
|
|
{ 'eqs' => 'column', 'int' => 1 } ) |
|
807
|
|
|
|
|
|
|
or |
|
808
|
|
|
|
|
|
|
croak("No solver!"); # Нет решения |
|
809
|
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
# Решение НАЙДЕНО! |
|
811
|
105
|
|
|
|
|
331023
|
my @den; # Знаменатели |
|
812
|
105
|
|
|
|
|
388
|
for( @$steX ){ |
|
813
|
330
|
|
|
|
|
8633
|
my($n, $d) = Math::BigRat->new("$_")->parts(); |
|
814
|
330
|
|
|
|
|
83139
|
$_ = $n; # числитель |
|
815
|
|
|
|
|
|
|
|
|
816
|
330
|
|
50
|
|
|
1298
|
push @den, $d || 1; |
|
817
|
|
|
|
|
|
|
} |
|
818
|
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
# lowest common multiplicator |
|
820
|
105
|
|
|
|
|
3194
|
my $lcm = blcm(@den); |
|
821
|
|
|
|
|
|
|
|
|
822
|
105
|
|
|
|
|
47186
|
my %cfs; # Стех. коэффициенты |
|
823
|
105
|
100
|
|
|
|
427
|
$cfs{$var_subst} = $lcm if defined $var_subst; # варьируемого в-ва |
|
824
|
|
|
|
|
|
|
|
|
825
|
105
|
100
|
|
|
|
300
|
unless( $R_zero ){ # Некоторые в-ва заданы |
|
826
|
59
|
|
|
|
|
92
|
while( my($s, $c) = each %{ $opts->{'coefficients'} } ){ |
|
|
332
|
|
|
|
|
31913
|
|
|
827
|
273
|
|
|
|
|
673
|
$cfs{$s} = $lcm * $c; |
|
828
|
|
|
|
|
|
|
} |
|
829
|
|
|
|
|
|
|
} |
|
830
|
|
|
|
|
|
|
|
|
831
|
105
|
|
|
|
|
228
|
my $i = 0; |
|
832
|
105
|
|
|
|
|
253
|
for( @$base_subst ){ # Искомые |
|
833
|
330
|
|
|
|
|
1139
|
$cfs{$_} = $steX->[$i] * $lcm / $den[$i]; |
|
834
|
330
|
|
|
|
|
6914603
|
$i++; |
|
835
|
|
|
|
|
|
|
} |
|
836
|
|
|
|
|
|
|
|
|
837
|
105
|
100
|
|
|
|
347
|
if( $ao > 0 ){ # Для переопределённых - Проверка мат.баланса |
|
838
|
|
|
|
|
|
|
|
|
839
|
82
|
|
|
|
|
146
|
my @balance; |
|
840
|
82
|
|
|
|
|
489
|
for my $s (keys %cfs){ # в-во |
|
841
|
505
|
|
|
|
|
24700
|
my $i = 0; |
|
842
|
|
|
|
|
|
|
|
|
843
|
505
|
|
|
|
|
565
|
$balance[ $i++ ] += $_ * $cfs{$s}->numify() for @{ $ini_am->{$s} }; |
|
|
505
|
|
|
|
|
2047
|
|
|
844
|
|
|
|
|
|
|
} |
|
845
|
|
|
|
|
|
|
|
|
846
|
82
|
100
|
|
|
|
6353
|
return if scalar(grep $_, @balance); # no balance |
|
847
|
|
|
|
|
|
|
} |
|
848
|
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
# С помощью НОД (GCD) уменьшаем порядок стех.коэф. |
|
850
|
49
|
50
|
|
|
|
188
|
if( ( my $gcd = bgcd(values %cfs) ) > 1 ){ |
|
851
|
0
|
|
|
|
|
0
|
$cfs{$_} /= $gcd for keys %cfs; |
|
852
|
|
|
|
|
|
|
} |
|
853
|
|
|
|
|
|
|
|
|
854
|
49
|
|
|
|
|
8004
|
my $keq = prepare_mix( $chem_eq, { 'norma' => 1, 'coefficients' => \%cfs } ); |
|
855
|
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
# Save only unique chemical equation |
|
857
|
49
|
100
|
|
|
|
2000
|
scalar(grep $_ eq $keq, @$cheq) || push @$cheq, $keq; |
|
858
|
|
|
|
|
|
|
} |
|
859
|
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
|
|
861
|
|
|
|
|
|
|
# Возвращает массив хешей: |
|
862
|
|
|
|
|
|
|
# $redox{oxidant/reducer}{Элементы}{исх.->прод.} |
|
863
|
|
|
|
|
|
|
# [0] - число e- нов принимаемых/отдаваемых |
|
864
|
|
|
|
|
|
|
# [1] - OS элемента в исходном |
|
865
|
|
|
|
|
|
|
# [2] - ... в продукте |
|
866
|
|
|
|
|
|
|
# [3] - число атомов элемента в исходном |
|
867
|
|
|
|
|
|
|
# [4] - ... в продукте |
|
868
|
|
|
|
|
|
|
# [5] - множитель на MAX число атомов исх. |
|
869
|
|
|
|
|
|
|
# [6] - ... продукта |
|
870
|
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
# $el_half_eqs{oxidant/reducer}[..] - 2 массива полуреакций (в проекте для другой п/п) |
|
872
|
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
sub redox_test{ |
|
874
|
4
|
|
|
4
|
0
|
6
|
my $chem_eq = shift; |
|
875
|
|
|
|
|
|
|
|
|
876
|
4
|
|
|
|
|
8
|
my @rx; # $rx[исх/прод] {элементы} {OS элемента} {вещества} = Кол-во атомов элемента |
|
877
|
|
|
|
|
|
|
my %ve; # $ve{в-во} = количество элементов |
|
878
|
|
|
|
|
|
|
|
|
879
|
4
|
|
|
|
|
7
|
my $z = 0; # Признак исх.в-в |
|
880
|
4
|
|
|
|
|
6
|
for my $eq (@{ $chem_eq }){ |
|
|
4
|
|
|
|
|
8
|
|
|
881
|
8
|
|
|
|
|
12
|
for my $s (@{ $eq }){ |
|
|
8
|
|
|
|
|
12
|
|
|
882
|
|
|
|
|
|
|
|
|
883
|
29
|
|
|
|
|
84
|
my $os = oxidation_state($s); |
|
884
|
|
|
|
|
|
|
# Рез-ты: $os->{элемент} |
|
885
|
|
|
|
|
|
|
# {num}[0 .. n-1] - кол-во по каждому 1..n атому элемента |
|
886
|
|
|
|
|
|
|
# {OS}[0 .. n-1][ ] - степень(и) окисления (OS) 1..n атому элемента |
|
887
|
|
|
|
|
|
|
|
|
888
|
29
|
|
|
|
|
92
|
$ve{$s} = keys %$os; # кол-во Элементов |
|
889
|
|
|
|
|
|
|
|
|
890
|
29
|
|
|
|
|
40
|
for my $e ( keys %{$os} ){ # Элемент |
|
|
29
|
|
|
|
|
71
|
|
|
891
|
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
# Берём OS атомов элемента в в-ве |
|
893
|
67
|
|
|
|
|
101
|
for ( my $i=0; $i<=$#{ $os->{$e}{'OS'} }; $i++ ){ |
|
|
134
|
|
|
|
|
509
|
|
|
894
|
|
|
|
|
|
|
|
|
895
|
|
|
|
|
|
|
# !!! Продумать дробные степени окисления (сделано) |
|
896
|
|
|
|
|
|
|
# Объединяем множественные OS |
|
897
|
67
|
|
|
|
|
127
|
my($a, $sum, $n); |
|
898
|
67
|
|
|
|
|
95
|
for( @{ $os->{$e}{'OS'}[$i] } ){ |
|
|
67
|
|
|
|
|
189
|
|
|
899
|
67
|
|
|
|
|
75
|
$sum += $_; |
|
900
|
67
|
|
|
|
|
126
|
$n++; # кол-во |
|
901
|
|
|
|
|
|
|
} |
|
902
|
|
|
|
|
|
|
|
|
903
|
67
|
50
|
|
|
|
145
|
if($n > 1){ |
|
904
|
0
|
|
|
|
|
0
|
my $gcd = bgcd(abs($sum), $n); # НОД |
|
905
|
0
|
0
|
|
|
|
0
|
if($gcd > 1){ |
|
906
|
0
|
|
|
|
|
0
|
$sum /= $gcd; |
|
907
|
0
|
|
|
|
|
0
|
$n /= $gcd; |
|
908
|
|
|
|
|
|
|
} |
|
909
|
0
|
|
|
|
|
0
|
$a = "$sum/$n"; |
|
910
|
|
|
|
|
|
|
|
|
911
|
|
|
|
|
|
|
}else{ |
|
912
|
67
|
|
|
|
|
95
|
$a = $sum; |
|
913
|
|
|
|
|
|
|
} |
|
914
|
|
|
|
|
|
|
# Кол-во атомов элемента |
|
915
|
67
|
|
|
|
|
295
|
$rx[$z]{$e}{$a}{$s} = $os->{$e}{'num'}[$i]; |
|
916
|
|
|
|
|
|
|
} |
|
917
|
|
|
|
|
|
|
} |
|
918
|
|
|
|
|
|
|
} |
|
919
|
8
|
|
|
|
|
25
|
$z = 1; # продукты |
|
920
|
|
|
|
|
|
|
} |
|
921
|
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
_M_redox_1: |
|
923
|
4
|
|
|
|
|
11
|
for my $e ( keys %{ $rx[0] } ){ # Элементы (берём из исходных) |
|
|
4
|
|
|
|
|
19
|
|
|
924
|
22
|
|
|
|
|
25
|
for( keys %{ $rx[0]{$e} } ) { # OS элемента |
|
|
22
|
|
|
|
|
55
|
|
|
925
|
23
|
100
|
|
|
|
86
|
next _M_redox_1 unless exists( $rx[1]{$e}{$_} ); # Другая в продуктах |
|
926
|
|
|
|
|
|
|
} |
|
927
|
|
|
|
|
|
|
|
|
928
|
10
|
|
|
|
|
17
|
for( keys %{ $rx[1]{$e} } ) { # OS элемента |
|
|
10
|
|
|
|
|
25
|
|
|
929
|
10
|
50
|
|
|
|
32
|
next _M_redox_1 unless exists( $rx[0]{$e}{$_} ); # Другая в исходных |
|
930
|
|
|
|
|
|
|
} |
|
931
|
|
|
|
|
|
|
# Удалить не ОВР элементы |
|
932
|
10
|
|
|
|
|
57
|
delete $rx[$_]{$e} for 0,1; |
|
933
|
|
|
|
|
|
|
} |
|
934
|
|
|
|
|
|
|
|
|
935
|
|
|
|
|
|
|
# не ОВР |
|
936
|
4
|
50
|
33
|
|
|
9
|
return if ! keys( %{ $rx[0] } ) || ! keys( %{ $rx[1] } ); |
|
|
4
|
|
|
|
|
18
|
|
|
|
4
|
|
|
|
|
13
|
|
|
937
|
|
|
|
|
|
|
# return undef unless keys( %{ $rx[1] } ); |
|
938
|
|
|
|
|
|
|
|
|
939
|
4
|
|
|
|
|
7
|
my %del_rx; # хеш исключённых в-в |
|
940
|
|
|
|
|
|
|
my %redox; # результаты |
|
941
|
|
|
|
|
|
|
|
|
942
|
|
|
|
|
|
|
_M_redox_2: |
|
943
|
4
|
|
|
|
|
7
|
while( 1 ){ |
|
944
|
6
|
|
|
|
|
12
|
my %vv; # $vv{в-во} {'yes'} = встечаемость в-ва в redox-парах |
|
945
|
|
|
|
|
|
|
# {'os'}{элемент} = 1 - Элементы меняющие свою OS |
|
946
|
|
|
|
|
|
|
|
|
947
|
6
|
|
|
|
|
15
|
for my $e ( keys %{ $rx[0] } ){ # Элементы (берём из исходных) |
|
|
6
|
|
|
|
|
20
|
|
|
948
|
16
|
|
|
|
|
22
|
for my $os_i ( keys %{ $rx[0]{$e} } ) { # OS элемента в исх. |
|
|
16
|
|
|
|
|
44
|
|
|
949
|
19
|
|
|
|
|
23
|
for my $os_p ( keys %{ $rx[1]{$e} } ) { # OS элемента в продуктах |
|
|
19
|
|
|
|
|
63
|
|
|
950
|
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
|
|
952
|
|
|
|
|
|
|
# !!! Продумать дробные степени окисления (сделано) |
|
953
|
18
|
|
|
|
|
95
|
my $n_os_i = Math::BigRat -> new("$os_i") -> numify(); |
|
954
|
18
|
|
|
|
|
2470
|
my $n_os_p = Math::BigRat -> new("$os_p") -> numify(); |
|
955
|
|
|
|
|
|
|
|
|
956
|
18
|
|
|
|
|
2000
|
my $nm; # название: oxidant / reducer |
|
957
|
18
|
100
|
|
|
|
75
|
if($n_os_i > $n_os_p){ # Окислитель? |
|
|
|
100
|
|
|
|
|
|
|
958
|
8
|
|
|
|
|
15
|
$nm = 'oxidant'; |
|
959
|
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
}elsif($n_os_i < $n_os_p){ # Восстановитель? |
|
961
|
7
|
|
|
|
|
17
|
$nm = 'reducer'; |
|
962
|
|
|
|
|
|
|
|
|
963
|
|
|
|
|
|
|
}else{ |
|
964
|
3
|
|
|
|
|
12
|
next; |
|
965
|
|
|
|
|
|
|
} |
|
966
|
|
|
|
|
|
|
|
|
967
|
|
|
|
|
|
|
# Составляем пару |
|
968
|
15
|
|
|
|
|
20
|
while( my($v_i, $n_i) = each %{ $rx[0]{$e}{$os_i} } ){ # исх. в-ва и кол-во атомов |
|
|
33
|
|
|
|
|
187
|
|
|
969
|
18
|
100
|
|
|
|
53
|
next if exists $del_rx{$v_i}; # исключённое в-во |
|
970
|
|
|
|
|
|
|
|
|
971
|
17
|
|
|
|
|
41
|
$vv{$v_i}{'yes'}++; |
|
972
|
17
|
|
|
|
|
43
|
$vv{$v_i}{'os'}{$e} = 1; # Элементы меняющие свою OS |
|
973
|
|
|
|
|
|
|
|
|
974
|
17
|
|
|
|
|
21
|
while( my($v_p, $n_p) = each %{ $rx[1]{$e}{$os_p} } ){ # продукты и кол-во атомов |
|
|
40
|
|
|
|
|
202
|
|
|
975
|
23
|
100
|
|
|
|
57
|
next if exists $del_rx{$v_p}; # исключённое в-во |
|
976
|
|
|
|
|
|
|
|
|
977
|
21
|
|
|
|
|
48
|
$vv{$v_p}{'yes'}++; |
|
978
|
21
|
|
|
|
|
48
|
$vv{$v_p}{'os'}{$e} = 1; # Элементы меняющие свою OS |
|
979
|
|
|
|
|
|
|
|
|
980
|
21
|
|
|
|
|
66
|
my $lcm = blcm($n_i, $n_p); # наименьший общий множитель кол-ва атомов |
|
981
|
|
|
|
|
|
|
|
|
982
|
21
|
|
|
|
|
6064
|
my($c, $z) = Math::BigRat->new("$os_i")->parts(); |
|
983
|
21
|
|
|
|
|
4184
|
my $ee = $lcm * $c / $z; |
|
984
|
|
|
|
|
|
|
|
|
985
|
21
|
|
|
|
|
3102
|
($c, $z) = Math::BigRat->new("$os_p")->parts(); |
|
986
|
21
|
|
|
|
|
4261
|
$ee -= $lcm * $c / $z; |
|
987
|
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
# Принятые элек-ны, OS, число атомов и |
|
989
|
|
|
|
|
|
|
# множители на MAX число атомов исх. и прод. |
|
990
|
21
|
|
|
|
|
4416
|
@{ $redox{$nm}{$e}{"$v_i->$v_p"} } = ( abs($ee), |
|
|
21
|
|
|
|
|
6654
|
|
|
991
|
|
|
|
|
|
|
$os_i, $os_p, |
|
992
|
|
|
|
|
|
|
$n_i, $n_p, |
|
993
|
|
|
|
|
|
|
$lcm / $n_i, $lcm / $n_p ); |
|
994
|
|
|
|
|
|
|
} |
|
995
|
|
|
|
|
|
|
} |
|
996
|
|
|
|
|
|
|
} |
|
997
|
|
|
|
|
|
|
} |
|
998
|
|
|
|
|
|
|
} |
|
999
|
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
# !!! Интуитивно исключаем из redox-списков не ОВР в-ва |
|
1001
|
6
|
|
|
|
|
22
|
for my $nm ( 'oxidant','reducer' ){ |
|
1002
|
11
|
|
|
|
|
20
|
for my $e ( keys %{ $redox{$nm} } ){ # Элементы |
|
|
11
|
|
|
|
|
44
|
|
|
1003
|
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
# Redox-пары элемента |
|
1005
|
11
|
100
|
|
|
|
15
|
next if keys %{ $redox{$nm}{$e} } < 2; # одна пара |
|
|
11
|
|
|
|
|
48
|
|
|
1006
|
|
|
|
|
|
|
|
|
1007
|
5
|
|
|
|
|
10
|
for my $i_k ( keys %{ $redox{$nm}{$e} } ){ |
|
|
5
|
|
|
|
|
21
|
|
|
1008
|
10
|
|
|
|
|
38
|
for( split "->",$i_k ){ |
|
1009
|
19
|
100
|
|
|
|
68
|
next if $ve{$_} < 3; # кол-во Элементов в в-ве |
|
1010
|
6
|
100
|
|
|
|
26
|
next if $vv{$_}{'yes'} > 1; # в-во встречается часто |
|
1011
|
2
|
50
|
|
|
|
3
|
next if keys %{ $vv{$_}{'os'} } > 1; # OS меняет более 1 Элемента |
|
|
2
|
|
|
|
|
13
|
|
|
1012
|
|
|
|
|
|
|
|
|
1013
|
2
|
|
|
|
|
7
|
$del_rx{$_} = ''; # внести в список исключённых в-в |
|
1014
|
2
|
|
|
|
|
43
|
%redox = (); # очистить |
|
1015
|
2
|
|
|
|
|
53
|
next _M_redox_2; |
|
1016
|
|
|
|
|
|
|
} |
|
1017
|
|
|
|
|
|
|
} |
|
1018
|
|
|
|
|
|
|
} |
|
1019
|
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
|
|
1021
|
|
|
|
|
|
|
} |
|
1022
|
4
|
100
|
66
|
|
|
19
|
return keys( %{ $redox{'oxidant'} } ) && keys( %{ $redox{'reducer'} } ) ? \%redox : undef; # не ОВР |
|
1023
|
|
|
|
|
|
|
} |
|
1024
|
|
|
|
|
|
|
} |
|
1025
|
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
|
|
1027
|
|
|
|
|
|
|
sub _search_atoms_subs{ |
|
1028
|
1391
|
|
|
1391
|
|
1569
|
my $chem_eq = shift; |
|
1029
|
|
|
|
|
|
|
|
|
1030
|
1391
|
|
|
|
|
1378
|
my %tmp_subs; # Atoms of substance |
|
1031
|
|
|
|
|
|
|
my %atoms; # Atom hash |
|
1032
|
|
|
|
|
|
|
|
|
1033
|
1391
|
|
|
|
|
2183
|
for my $i ( @$chem_eq ){ |
|
1034
|
2782
|
|
|
|
|
4068
|
for my $s ( @$i ){ |
|
1035
|
|
|
|
|
|
|
# Atoms of substance |
|
1036
|
7213
|
50
|
|
|
|
9137
|
my %f = eval{ Chemistry::File::Formula->parse_formula( $s ) } or |
|
|
7213
|
|
|
|
|
22999
|
|
|
1037
|
|
|
|
|
|
|
croak("'$s' is not substance!"); |
|
1038
|
|
|
|
|
|
|
|
|
1039
|
7213
|
|
|
|
|
1226380
|
for( keys %f ){ |
|
1040
|
17235
|
|
|
|
|
38960
|
$tmp_subs{$s}{$_} = $f{$_}; |
|
1041
|
17235
|
|
|
|
|
44603
|
$atoms{$_}++; # Atom balance |
|
1042
|
|
|
|
|
|
|
} |
|
1043
|
|
|
|
|
|
|
} |
|
1044
|
|
|
|
|
|
|
} |
|
1045
|
|
|
|
|
|
|
|
|
1046
|
1391
|
|
|
|
|
4862
|
while( my($k,$v) = each %atoms){ |
|
1047
|
4792
|
100
|
|
|
|
148463
|
croak("No balance of '$k' atom!") if $v == 1; |
|
1048
|
|
|
|
|
|
|
} |
|
1049
|
|
|
|
|
|
|
|
|
1050
|
|
|
|
|
|
|
# Atom (stoichiometry) matrix vectors (quantity of atoms for each substance) |
|
1051
|
674
|
|
|
|
|
1218
|
my %atoms_substance; |
|
1052
|
674
|
|
|
|
|
2125
|
for my $subs (keys %tmp_subs){ |
|
1053
|
4574
|
100
|
|
|
|
8773
|
$atoms_substance{$subs} = [ map { $tmp_subs{$subs}{$_} || 0 } keys %atoms ]; |
|
|
23109
|
|
|
|
|
89361
|
|
|
1054
|
|
|
|
|
|
|
} |
|
1055
|
|
|
|
|
|
|
|
|
1056
|
674
|
|
|
|
|
17041
|
return( \%atoms_substance, scalar(keys %atoms) ); |
|
1057
|
|
|
|
|
|
|
} |
|
1058
|
|
|
|
|
|
|
|
|
1059
|
|
|
|
|
|
|
# Transform classic into brutto (gross) formula |
|
1060
|
|
|
|
|
|
|
sub brutto_formula{ |
|
1061
|
3
|
|
|
3
|
1
|
1518
|
my $s = shift; |
|
1062
|
|
|
|
|
|
|
|
|
1063
|
3
|
50
|
|
|
|
6
|
my %e = eval{ Chemistry::File::Formula->parse_formula( $s ) } or |
|
|
3
|
|
|
|
|
18
|
|
|
1064
|
|
|
|
|
|
|
croak("'$s' is not substance!"); |
|
1065
|
|
|
|
|
|
|
|
|
1066
|
3
|
|
|
|
|
2568
|
return( join( '', map{ "$_$e{$_}" } sort { $a cmp $b } keys %e ) ); |
|
|
14
|
|
|
|
|
55
|
|
|
|
19
|
|
|
|
|
25
|
|
|
1067
|
|
|
|
|
|
|
} |
|
1068
|
|
|
|
|
|
|
|
|
1069
|
|
|
|
|
|
|
# Decomposes the chemical equation to |
|
1070
|
|
|
|
|
|
|
# arrays of initial substances and products |
|
1071
|
|
|
|
|
|
|
sub parse_chem_mix{ |
|
1072
|
1498
|
|
|
1498
|
1
|
65472
|
$_ = shift; # List of substances with delimiters (spaces, comma, + ) |
|
1073
|
1498
|
|
|
|
|
1977
|
my $coef = shift; # hash of coefficients |
|
1074
|
|
|
|
|
|
|
|
|
1075
|
1498
|
|
|
|
|
1542
|
my %cf; # temp hash of coefficients |
|
1076
|
|
|
|
|
|
|
|
|
1077
|
1498
|
|
|
|
|
3850
|
s/^\s+//; |
|
1078
|
1498
|
|
|
|
|
5363
|
s/\s+$//; |
|
1079
|
|
|
|
|
|
|
|
|
1080
|
1498
|
|
|
|
|
5505
|
my $m = qr/\s*[ ,;+]+\s*/; # mask of delimeters |
|
1081
|
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
# to unite the separeted numerals ( coefficient ? ) |
|
1083
|
1498
|
|
|
|
|
36049
|
1 while s/((?:$m|^)[1-9]+)$m([1-9]+(?:$m|$))/$1$2/g; |
|
1084
|
|
|
|
|
|
|
|
|
1085
|
|
|
|
|
|
|
# to unite the separeted substance & index |
|
1086
|
1498
|
|
|
|
|
10985
|
s/([)}\]a-zA-Z1-9])\s+([1-9]+\s*[)}\]\-=+])/$1$2/g; |
|
1087
|
|
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
# remove spaces around brackets |
|
1089
|
1498
|
|
|
|
|
2703
|
s/([({\[])\s+/$1/g; |
|
1090
|
1498
|
|
|
|
|
7747
|
s/\s+([)}\]])/$1/g; |
|
1091
|
|
|
|
|
|
|
|
|
1092
|
|
|
|
|
|
|
# The chemical equation is set: |
|
1093
|
|
|
|
|
|
|
# A + B --> C + D || |
|
1094
|
|
|
|
|
|
|
# A, B, C, D |
|
1095
|
1498
|
100
|
|
|
|
45897
|
my $chem_eq = /(.+?)\s*[=-]+>*\s*(.+)/ ? |
|
1096
|
|
|
|
|
|
|
[ map [ split "$m" ], ($1,$2) ] : |
|
1097
|
|
|
|
|
|
|
[ map [ split "$m" ], ( /(.+)$m(\S+)/ ) ]; |
|
1098
|
|
|
|
|
|
|
|
|
1099
|
1498
|
50
|
|
|
|
3912
|
return unless @$chem_eq; |
|
1100
|
|
|
|
|
|
|
|
|
1101
|
1498
|
|
|
|
|
4404
|
for my $ip ( @$chem_eq ){ |
|
1102
|
|
|
|
|
|
|
|
|
1103
|
2996
|
|
|
|
|
3886
|
my @ip_del; # For removal from an array of coefficients |
|
1104
|
|
|
|
|
|
|
|
|
1105
|
2996
|
|
|
|
|
5433
|
for(my $i=0; $i<=$#{ $ip }; $i++ ){ |
|
|
11112
|
|
|
|
|
25181
|
|
|
1106
|
8116
|
|
|
|
|
11868
|
$_ = $ip->[$i]; |
|
1107
|
|
|
|
|
|
|
|
|
1108
|
8116
|
100
|
|
|
|
41546
|
if( /^(\d+)([({\[a-zA-Z].*)/ ){ # together coefficient and substance |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
1109
|
|
|
|
|
|
|
|
|
1110
|
39
|
|
|
|
|
83
|
my ($c, $s) = ($1, $2); # coefficient, substance |
|
1111
|
|
|
|
|
|
|
|
|
1112
|
|
|
|
|
|
|
# zero coefficient |
|
1113
|
39
|
100
|
66
|
|
|
160
|
if( $c =~ /^0$/ && ( $i==0 || ( $i>0 && $ip->[$i-1] =~ /\D/ ) ) ){ |
|
|
|
100
|
66
|
|
|
|
|
|
1114
|
2
|
|
|
|
|
6
|
push @ip_del, $i; # remove substance |
|
1115
|
|
|
|
|
|
|
|
|
1116
|
|
|
|
|
|
|
}elsif( s/^0/O/ ){ # oxigen? |
|
1117
|
2
|
|
|
|
|
5
|
&_p_c_m( $_, $i, \%cf, $ip ); |
|
1118
|
|
|
|
|
|
|
|
|
1119
|
|
|
|
|
|
|
}else{ |
|
1120
|
35
|
|
|
|
|
118
|
$cf{$s} = $c; # coefficient |
|
1121
|
35
|
|
|
|
|
80
|
$ip->[$i] = $s; # substance |
|
1122
|
|
|
|
|
|
|
} |
|
1123
|
|
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
}elsif( s/^0(.)/O$1/ ){ # oxigen |
|
1125
|
6
|
|
|
|
|
19
|
&_p_c_m( $_, $i, \%cf, $ip ); |
|
1126
|
|
|
|
|
|
|
|
|
1127
|
|
|
|
|
|
|
}elsif( /^0$/ ){ # zero coefficient |
|
1128
|
12
|
100
|
100
|
|
|
35
|
if( $i < $#{ $ip } && ! exists( $coef->{'zero2oxi'} ) ){ # remove |
|
|
12
|
|
|
|
|
58
|
|
|
1129
|
5
|
|
|
|
|
6
|
push @ip_del, $i; # coefficient |
|
1130
|
5
|
|
|
|
|
11
|
push @ip_del, ++$i; # substance |
|
1131
|
|
|
|
|
|
|
|
|
1132
|
|
|
|
|
|
|
}else{ |
|
1133
|
7
|
|
|
|
|
20
|
s/^0/O/; # oxigen |
|
1134
|
7
|
|
|
|
|
17
|
&_p_c_m( $_, $i, \%cf, $ip ); |
|
1135
|
|
|
|
|
|
|
} |
|
1136
|
|
|
|
|
|
|
|
|
1137
|
|
|
|
|
|
|
}elsif( /^\d+$/ ){ # only numerals |
|
1138
|
|
|
|
|
|
|
# coefficient |
|
1139
|
411
|
100
|
66
|
|
|
832
|
if( defined $ip->[$i+1] ){ |
|
|
5
|
100
|
66
|
|
|
41
|
|
|
1140
|
402
|
|
|
|
|
992
|
$cf{ $ip->[$i+1] } = $_; |
|
1141
|
|
|
|
|
|
|
|
|
1142
|
|
|
|
|
|
|
}elsif( $ip eq $chem_eq->[0] && |
|
1143
|
|
|
|
|
|
|
@{ $chem_eq->[1] } == 1 && |
|
1144
|
|
|
|
|
|
|
$chem_eq->[1][0] =~ /[a-zA-Z]/ ){ |
|
1145
|
|
|
|
|
|
|
|
|
1146
|
|
|
|
|
|
|
# coefficient of product |
|
1147
|
5
|
|
|
|
|
14
|
$chem_eq->[1][0] = $_.$chem_eq->[1][0]; |
|
1148
|
|
|
|
|
|
|
} |
|
1149
|
411
|
|
|
|
|
724
|
push @ip_del, $i; |
|
1150
|
|
|
|
|
|
|
} |
|
1151
|
|
|
|
|
|
|
} |
|
1152
|
2996
|
|
|
|
|
11077
|
splice @$ip, $_, 1 for( reverse @ip_del ); |
|
1153
|
|
|
|
|
|
|
} |
|
1154
|
|
|
|
|
|
|
|
|
1155
|
|
|
|
|
|
|
# To removal identical reactants and products |
|
1156
|
1498
|
|
|
|
|
2480
|
for my $ip ( @$chem_eq ){ |
|
1157
|
|
|
|
|
|
|
|
|
1158
|
2996
|
|
|
|
|
3183
|
my @ip_del; |
|
1159
|
2996
|
|
|
|
|
3847
|
for(my $i = 0; $i < $#{ $ip }; $i++ ){ |
|
|
7706
|
|
|
|
|
15799
|
|
|
1160
|
|
|
|
|
|
|
|
|
1161
|
4710
|
|
|
|
|
5842
|
for(my $j = $i + 1; $j <= $#{ $ip }; $j++ ){ |
|
|
13143
|
|
|
|
|
27528
|
|
|
1162
|
|
|
|
|
|
|
|
|
1163
|
8443
|
100
|
|
|
|
18416
|
if( $ip->[$i] eq $ip->[$j] ){ |
|
1164
|
10
|
|
|
|
|
11
|
push @ip_del, $j; |
|
1165
|
10
|
|
|
|
|
19
|
last; |
|
1166
|
|
|
|
|
|
|
} |
|
1167
|
|
|
|
|
|
|
} |
|
1168
|
|
|
|
|
|
|
} |
|
1169
|
2996
|
|
|
|
|
9748
|
splice @$ip, $_, 1 for( sort{ $b <=> $a } @ip_del ); |
|
|
4
|
|
|
|
|
15
|
|
|
1170
|
|
|
|
|
|
|
} |
|
1171
|
|
|
|
|
|
|
|
|
1172
|
|
|
|
|
|
|
# Check empty reactants |
|
1173
|
1498
|
100
|
|
|
|
2263
|
if( ! @{ $chem_eq->[0] } ){ |
|
|
1498
|
|
|
|
|
4170
|
|
|
1174
|
3
|
100
|
|
|
|
4
|
return if @{ $chem_eq->[1] } < 2; # bad mix (one or no substance) |
|
|
3
|
|
|
|
|
13
|
|
|
1175
|
2
|
|
|
|
|
3
|
push @{ $chem_eq->[0] }, shift @{ $chem_eq->[1] }; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
26
|
|
|
1176
|
|
|
|
|
|
|
} |
|
1177
|
|
|
|
|
|
|
|
|
1178
|
|
|
|
|
|
|
# To removal identical products with reactants |
|
1179
|
1497
|
|
|
|
|
1651
|
for my $s ( @{ $chem_eq->[0] } ){ |
|
|
1497
|
|
|
|
|
2660
|
|
|
1180
|
3882
|
|
|
|
|
3732
|
my @ip_del; |
|
1181
|
3882
|
|
|
|
|
5041
|
for(my $i=0; $i<=$#{ $chem_eq->[1] }; $i++ ){ |
|
|
14261
|
|
|
|
|
29024
|
|
|
1182
|
10379
|
100
|
|
|
|
21644
|
push @ip_del, $i if $s eq $chem_eq->[1][$i]; |
|
1183
|
|
|
|
|
|
|
} |
|
1184
|
3882
|
|
|
|
|
11420
|
splice @{ $chem_eq->[1] }, $_, 1 for( reverse @ip_del ); |
|
|
2
|
|
|
|
|
9
|
|
|
1185
|
|
|
|
|
|
|
} |
|
1186
|
|
|
|
|
|
|
|
|
1187
|
|
|
|
|
|
|
# Check empty products |
|
1188
|
1497
|
100
|
|
|
|
1779
|
if( ! @{ $chem_eq->[1] } ){ |
|
|
1497
|
|
|
|
|
3616
|
|
|
1189
|
6
|
100
|
|
|
|
7
|
return if @{ $chem_eq->[0] } < 2; # bad mix (one or no substance) |
|
|
6
|
|
|
|
|
38
|
|
|
1190
|
4
|
|
|
|
|
6
|
push @{ $chem_eq->[1] }, pop @{ $chem_eq->[0] }; |
|
|
4
|
|
|
|
|
6
|
|
|
|
4
|
|
|
|
|
8
|
|
|
1191
|
|
|
|
|
|
|
} |
|
1192
|
|
|
|
|
|
|
|
|
1193
|
1495
|
|
|
|
|
10948
|
@$coef{ keys %cf} = values %cf; # join (copy) |
|
1194
|
|
|
|
|
|
|
|
|
1195
|
1495
|
|
|
|
|
2374
|
delete $coef->{'zero2oxi'}; |
|
1196
|
|
|
|
|
|
|
|
|
1197
|
|
|
|
|
|
|
# Lists of substances: |
|
1198
|
|
|
|
|
|
|
# fist --- reactants or '=','-','>' |
|
1199
|
|
|
|
|
|
|
# last --- products or '=','-','>' |
|
1200
|
1495
|
|
|
|
|
6004
|
return $chem_eq; |
|
1201
|
|
|
|
|
|
|
} |
|
1202
|
|
|
|
|
|
|
|
|
1203
|
|
|
|
|
|
|
sub _p_c_m{ |
|
1204
|
15
|
|
|
15
|
|
26
|
my( $s, $i, $cf, $ip ) = @_; |
|
1205
|
|
|
|
|
|
|
|
|
1206
|
15
|
100
|
|
|
|
39
|
if( exists $cf->{ $ip->[$i] } ){ |
|
1207
|
8
|
|
|
|
|
17
|
$cf->{$s} = $cf->{ $ip->[$i] }; |
|
1208
|
8
|
|
|
|
|
18
|
delete $cf->{ $ip->[$i] }; |
|
1209
|
|
|
|
|
|
|
} |
|
1210
|
15
|
|
|
|
|
44
|
$ip->[$i] = $s; # replacement |
|
1211
|
|
|
|
|
|
|
} |
|
1212
|
|
|
|
|
|
|
|
|
1213
|
|
|
|
|
|
|
|
|
1214
|
|
|
|
|
|
|
# Calculation of oxidation state |
|
1215
|
|
|
|
|
|
|
sub oxidation_state{ |
|
1216
|
199
|
|
50
|
199
|
1
|
562612
|
my $s = shift || return; |
|
1217
|
|
|
|
|
|
|
|
|
1218
|
199
|
|
|
|
|
359
|
our $mask; |
|
1219
|
199
|
|
|
|
|
1917
|
$mask = qr/{(?:(?>[^{}]+)|(??{$mask}))*}\d*/; |
|
1220
|
199
|
|
|
|
|
1847
|
my @species = $s =~ /$mask/g; |
|
1221
|
|
|
|
|
|
|
|
|
1222
|
|
|
|
|
|
|
# One substance |
|
1223
|
199
|
100
|
66
|
|
|
1296
|
return &_in_os($s) if @species < 2 || $s ne join('',@species); |
|
1224
|
|
|
|
|
|
|
|
|
1225
|
1
|
|
|
|
|
2
|
my $r; # Result: |
|
1226
|
|
|
|
|
|
|
# HASH{element}{num}[0 .. n-1] - Element amount on everyone 1..n atom |
|
1227
|
|
|
|
|
|
|
# HASH{element}{OS}[0 .. n-1][ .. ] - Oxidation States of Element (OSE) arrays 1..n atom |
|
1228
|
|
|
|
|
|
|
|
|
1229
|
|
|
|
|
|
|
# Mix of substances |
|
1230
|
1
|
|
|
|
|
3
|
for( @species ){ |
|
1231
|
|
|
|
|
|
|
|
|
1232
|
|
|
|
|
|
|
# remove bordering brackets |
|
1233
|
2
|
|
|
|
|
9
|
s/^\{//; |
|
1234
|
2
|
|
|
|
|
9
|
s/\}(\d*)$//; |
|
1235
|
|
|
|
|
|
|
# save possible coefficient |
|
1236
|
2
|
|
|
|
|
6
|
my $d = $1; |
|
1237
|
|
|
|
|
|
|
|
|
1238
|
2
|
|
50
|
|
|
6
|
my $p = &_in_os($_) || return; |
|
1239
|
|
|
|
|
|
|
|
|
1240
|
2
|
|
|
|
|
7
|
for my $e ( keys %$p ){ |
|
1241
|
4
|
|
|
|
|
7
|
push @{ $r->{$e}{'OS'} }, @{ $p->{$e}{'OS'} }; |
|
|
4
|
|
|
|
|
11
|
|
|
|
4
|
|
|
|
|
11
|
|
|
1242
|
|
|
|
|
|
|
|
|
1243
|
4
|
100
|
|
|
|
12
|
if( $d ){ |
|
1244
|
2
|
|
|
|
|
4
|
$_ *= $d for @{ $p->{$e}{'num'} } |
|
|
2
|
|
|
|
|
8
|
|
|
1245
|
|
|
|
|
|
|
} |
|
1246
|
4
|
|
|
|
|
5
|
push @{ $r->{$e}{'num'} }, @{ $p->{$e}{'num'} }; |
|
|
4
|
|
|
|
|
11
|
|
|
|
4
|
|
|
|
|
19
|
|
|
1247
|
|
|
|
|
|
|
} |
|
1248
|
|
|
|
|
|
|
} |
|
1249
|
|
|
|
|
|
|
|
|
1250
|
1
|
|
|
|
|
9
|
$r; |
|
1251
|
|
|
|
|
|
|
} |
|
1252
|
|
|
|
|
|
|
|
|
1253
|
|
|
|
|
|
|
sub _in_os{ |
|
1254
|
200
|
|
|
200
|
|
436
|
my $chem_sub = shift; |
|
1255
|
|
|
|
|
|
|
|
|
1256
|
|
|
|
|
|
|
# prepare atomic composition of substance |
|
1257
|
200
|
|
|
|
|
454
|
my %nf = eval{ Chemistry::File::Formula->parse_formula( $chem_sub ) }; |
|
|
200
|
|
|
|
|
1687
|
|
|
1258
|
200
|
50
|
|
|
|
58676
|
return unless keys %nf; |
|
1259
|
|
|
|
|
|
|
|
|
1260
|
|
|
|
|
|
|
# Count of "pure" atoms each element of substance |
|
1261
|
200
|
|
|
|
|
515
|
$_ = $chem_sub; |
|
1262
|
200
|
|
|
|
|
1061
|
s/\d+//g; # remove digits |
|
1263
|
200
|
|
|
|
|
843
|
my %num = Chemistry::File::Formula->parse_formula( $_ ); |
|
1264
|
|
|
|
|
|
|
|
|
1265
|
|
|
|
|
|
|
# Ions: { element }{ length }{ ion-pattern }[ [ array OSE ] ] |
|
1266
|
200
|
|
|
|
|
42202
|
my $ions = &_read_ions( $chem_sub ); |
|
1267
|
|
|
|
|
|
|
|
|
1268
|
|
|
|
|
|
|
# Read Pauling electronegativity and OSE: |
|
1269
|
|
|
|
|
|
|
# atom electronegativity, oxidation state, intermetallic compound |
|
1270
|
200
|
|
|
|
|
811
|
my( $atom_el_neg, $atom_OS, $intermet ) = &_read_atoms( \%nf ); |
|
1271
|
200
|
50
|
|
|
|
944
|
return if keys( %$atom_el_neg ) != keys( %nf ); |
|
1272
|
|
|
|
|
|
|
|
|
1273
|
200
|
|
|
|
|
246
|
my $prop; # Result: |
|
1274
|
|
|
|
|
|
|
|
|
1275
|
|
|
|
|
|
|
# Substance is intermetallic compound or Simple substance (one element) |
|
1276
|
200
|
100
|
66
|
|
|
1467
|
if( $intermet || keys %nf == 1 ){ |
|
1277
|
|
|
|
|
|
|
|
|
1278
|
2
|
|
|
|
|
11
|
while( my( $e, $n ) = each %nf ){ |
|
1279
|
|
|
|
|
|
|
# Total quantity of atoms for element |
|
1280
|
2
|
|
|
|
|
10
|
$prop->{ $e }{ 'num' }[ 0 ] = $n; |
|
1281
|
|
|
|
|
|
|
|
|
1282
|
|
|
|
|
|
|
# By default in the list of OSE only 0th charge |
|
1283
|
2
|
|
|
|
|
13
|
$prop->{ $e }{ 'OS' }[ 0 ] = [ 0 ]; |
|
1284
|
|
|
|
|
|
|
} |
|
1285
|
|
|
|
|
|
|
|
|
1286
|
2
|
|
|
|
|
17
|
return $prop ; |
|
1287
|
|
|
|
|
|
|
} |
|
1288
|
|
|
|
|
|
|
|
|
1289
|
|
|
|
|
|
|
# Sort atoms in decreasing order of electronegativity: |
|
1290
|
|
|
|
|
|
|
# 1th --- the most electronegative |
|
1291
|
198
|
|
|
|
|
275
|
my @neg = sort { $atom_el_neg->{$b} <=> $atom_el_neg->{$a} } keys %{ $atom_el_neg }; |
|
|
471
|
|
|
|
|
4516
|
|
|
|
198
|
|
|
|
|
1589
|
|
|
1292
|
|
|
|
|
|
|
|
|
1293
|
198
|
|
|
|
|
513
|
my %bOS; # by default OSE basic list |
|
1294
|
|
|
|
|
|
|
|
|
1295
|
|
|
|
|
|
|
# Basic OSE list of atoms on decrease of electronegativities |
|
1296
|
198
|
|
|
|
|
1378
|
for(my $i = 0; $i <= $#neg; $i++){ |
|
1297
|
|
|
|
|
|
|
|
|
1298
|
556
|
|
|
|
|
974
|
my $e = $neg[$i]; # element |
|
1299
|
|
|
|
|
|
|
|
|
1300
|
|
|
|
|
|
|
# Electronegative 1th is identical with next elements |
|
1301
|
556
|
100
|
66
|
|
|
4828
|
if( ( $i < $#neg && |
|
|
|
100
|
66
|
|
|
|
|
|
1302
|
|
|
|
|
|
|
$atom_el_neg->{ $neg[0] } == $atom_el_neg->{ $neg[$i+1] } ) || |
|
1303
|
|
|
|
|
|
|
$i == 1 ){ |
|
1304
|
|
|
|
|
|
|
|
|
1305
|
|
|
|
|
|
|
# '-' and '+' OSE, without 0 |
|
1306
|
198
|
|
|
|
|
742
|
$bOS{ $e } = [ grep $_, @{ $atom_OS->{$e} } ]; |
|
|
198
|
|
|
|
|
878
|
|
|
1307
|
|
|
|
|
|
|
|
|
1308
|
|
|
|
|
|
|
}elsif( $i == 0 ) { # 1th (most electronegative) -> only '-' OSE |
|
1309
|
198
|
|
|
|
|
321
|
$bOS{ $e } = [ grep $_ < 0, @{ $atom_OS->{$e} } ]; |
|
|
198
|
|
|
|
|
2571
|
|
|
1310
|
|
|
|
|
|
|
|
|
1311
|
|
|
|
|
|
|
}else{ # Others -> only '+' OSE |
|
1312
|
160
|
|
|
|
|
246
|
$bOS{ $e } = [ grep $_ > 0, @{ $atom_OS->{$e} } ]; |
|
|
160
|
|
|
|
|
696
|
|
|
1313
|
|
|
|
|
|
|
} |
|
1314
|
|
|
|
|
|
|
|
|
1315
|
|
|
|
|
|
|
# Inert elements |
|
1316
|
556
|
100
|
|
|
|
1775
|
$bOS{ $e } = [ @{ $atom_OS->{$e} } ] if $e=~/He|Ne|Ar|Kr|Xe|Rn/; |
|
|
5
|
|
|
|
|
17
|
|
|
1317
|
|
|
|
|
|
|
|
|
1318
|
|
|
|
|
|
|
# mask for search ions |
|
1319
|
556
|
100
|
|
|
|
2463
|
my $m = length($e)==1 ? "$e\\d+|$e(?![a-gik-pr-u])" : "$e\\d*"; |
|
1320
|
|
|
|
|
|
|
|
|
1321
|
556
|
|
|
|
|
1516
|
for(my $j = 0; $j < $num{$e}; $j++){ |
|
1322
|
|
|
|
|
|
|
|
|
1323
|
|
|
|
|
|
|
# Number of various atoms for element in substance |
|
1324
|
586
|
100
|
|
|
|
1317
|
if( $num{$e} == 1 ){ # One atom of element in substance |
|
1325
|
526
|
|
|
|
|
564
|
push @{ $prop->{$e}{'num'} }, $nf{$e}; |
|
|
526
|
|
|
|
|
4131
|
|
|
1326
|
|
|
|
|
|
|
|
|
1327
|
|
|
|
|
|
|
}else{ |
|
1328
|
60
|
|
|
|
|
92
|
my $count = 0; |
|
1329
|
60
|
|
|
|
|
102
|
$_ = $chem_sub; |
|
1330
|
|
|
|
|
|
|
|
|
1331
|
|
|
|
|
|
|
# Search ion-group. Remove all atoms of element, except current |
|
1332
|
60
|
100
|
|
|
|
1314
|
s{ ($m) }{ $1 if $count++ == $j }gex; |
|
|
120
|
|
|
|
|
747
|
|
|
1333
|
|
|
|
|
|
|
|
|
1334
|
60
|
|
|
|
|
600
|
my %f = Chemistry::File::Formula->parse_formula( $_ ); |
|
1335
|
60
|
|
|
|
|
28077
|
push @{ $prop->{ $e }{'num'} }, $f{ $e }; |
|
|
60
|
|
|
|
|
465
|
|
|
1336
|
|
|
|
|
|
|
} |
|
1337
|
|
|
|
|
|
|
} |
|
1338
|
|
|
|
|
|
|
} |
|
1339
|
|
|
|
|
|
|
|
|
1340
|
|
|
|
|
|
|
# Two pass: 1st -- ion recognition, 0th -- without ions (possible) |
|
1341
|
198
|
|
|
|
|
632
|
for my $yni (1, 0){ |
|
1342
|
201
|
|
|
|
|
299
|
my $no_ion = 1; # no ions |
|
1343
|
|
|
|
|
|
|
|
|
1344
|
201
|
|
|
|
|
296
|
my $balance_A = 0; # for Electronic balance |
|
1345
|
201
|
|
|
|
|
204
|
my $max_n_OS = 0; # Number of OSE in maximum list |
|
1346
|
201
|
|
|
|
|
321
|
my @atoms; # Varied atoms of elements |
|
1347
|
|
|
|
|
|
|
my %osin; # lists of OSE ions |
|
1348
|
|
|
|
|
|
|
|
|
1349
|
201
|
|
|
|
|
907
|
for(my $i = 0; $i <= $#neg; $i++){ |
|
1350
|
|
|
|
|
|
|
|
|
1351
|
566
|
|
|
|
|
878
|
my $e = $neg[$i]; # element |
|
1352
|
|
|
|
|
|
|
|
|
1353
|
|
|
|
|
|
|
# mask for search ions |
|
1354
|
566
|
100
|
|
|
|
1661
|
my $m = length($e)==1 ? "$e\\d+|$e(?![a-gik-pr-u])" : "$e\\d*"; |
|
1355
|
|
|
|
|
|
|
|
|
1356
|
|
|
|
|
|
|
_SO_M1: # Number of various atoms for element in substance |
|
1357
|
566
|
|
|
|
|
1565
|
for(my $j = 0; $j < $num{$e}; $j++){ |
|
1358
|
|
|
|
|
|
|
|
|
1359
|
598
|
|
|
|
|
933
|
$_ = $chem_sub; |
|
1360
|
|
|
|
|
|
|
|
|
1361
|
598
|
|
|
|
|
689
|
my $count = 0; |
|
1362
|
|
|
|
|
|
|
# Search ion-group. Remove all atoms of element, except current |
|
1363
|
598
|
100
|
|
|
|
16242
|
s{ ($m) }{ $1 if $count++ == $j }gex; |
|
|
662
|
|
|
|
|
9865
|
|
|
1364
|
|
|
|
|
|
|
|
|
1365
|
598
|
100
|
|
|
|
1677
|
if( $yni ){ |
|
1366
|
|
|
|
|
|
|
# Sort by decrease length of ion-group |
|
1367
|
586
|
|
|
|
|
719
|
for my $l (sort {$b <=> $a} keys %{ $ions->{$e} } ) { |
|
|
57
|
|
|
|
|
227
|
|
|
|
586
|
|
|
|
|
2534
|
|
|
1368
|
|
|
|
|
|
|
|
|
1369
|
339
|
|
|
|
|
436
|
for my $mg ( keys %{ $ions->{$e}{$l} } ){ |
|
|
339
|
|
|
|
|
1003
|
|
|
1370
|
343
|
100
|
|
|
|
3800
|
next unless /$mg/; # Ion-group isn't found |
|
1371
|
|
|
|
|
|
|
|
|
1372
|
321
|
|
|
|
|
547
|
$no_ion = 0; # yes ions |
|
1373
|
|
|
|
|
|
|
|
|
1374
|
|
|
|
|
|
|
# Ion-group is found. Save list of OSE |
|
1375
|
|
|
|
|
|
|
# for j-th atom of element |
|
1376
|
321
|
100
|
|
|
|
369
|
if( @{ $ions->{$e}{$l}{$mg} } == 1 ){ # One list OSE ion |
|
|
321
|
|
|
|
|
942
|
|
|
1377
|
|
|
|
|
|
|
|
|
1378
|
298
|
|
|
|
|
373
|
push @{ $prop->{$e}{'OS'} }, $ions->{$e}{$l}{$mg}[0]; |
|
|
298
|
|
|
|
|
1136
|
|
|
1379
|
|
|
|
|
|
|
|
|
1380
|
|
|
|
|
|
|
# Calculation total and mean OSE |
|
1381
|
298
|
|
|
|
|
570
|
my $os; |
|
1382
|
298
|
|
|
|
|
337
|
$os += $_ for @{ $prop->{$e}{'OS'}[$j] }; |
|
|
298
|
|
|
|
|
1542
|
|
|
1383
|
|
|
|
|
|
|
|
|
1384
|
|
|
|
|
|
|
# sum OSE * number of atoms / number of OSE |
|
1385
|
298
|
|
|
|
|
785
|
$balance_A += $os * $prop->{$e}{'num'}[$j] / @{ $prop->{$e}{'OS'}[$j] }; |
|
|
298
|
|
|
|
|
919
|
|
|
1386
|
|
|
|
|
|
|
|
|
1387
|
|
|
|
|
|
|
}else{ # Many OSE ion lists |
|
1388
|
|
|
|
|
|
|
# Add in array varied OSE for j-th atom of element |
|
1389
|
23
|
|
|
|
|
73
|
push @atoms, "$e:$j"; |
|
1390
|
23
|
|
|
|
|
104
|
$osin{"$e:$j"} = $ions->{$e}{$l}{$mg}; |
|
1391
|
|
|
|
|
|
|
|
|
1392
|
|
|
|
|
|
|
# Define from a basic list of OSE |
|
1393
|
23
|
|
|
|
|
33
|
push @{ $prop->{$e}{'OS'} }, [ -999 ]; |
|
|
23
|
|
|
|
|
92
|
|
|
1394
|
|
|
|
|
|
|
|
|
1395
|
|
|
|
|
|
|
# Quantity of OSE from basic list |
|
1396
|
23
|
|
|
|
|
31
|
my $n_OS = $#{ $ions->{$e}{$l}{$mg} }; |
|
|
23
|
|
|
|
|
60
|
|
|
1397
|
23
|
100
|
|
|
|
65
|
$max_n_OS = $n_OS if $n_OS > $max_n_OS; # max list of OSE |
|
1398
|
|
|
|
|
|
|
} |
|
1399
|
321
|
|
|
|
|
2095
|
next _SO_M1; # Ion-group is found |
|
1400
|
|
|
|
|
|
|
} |
|
1401
|
|
|
|
|
|
|
} |
|
1402
|
|
|
|
|
|
|
} |
|
1403
|
|
|
|
|
|
|
|
|
1404
|
|
|
|
|
|
|
# Quantity of OSE from basic list |
|
1405
|
277
|
|
|
|
|
546
|
my $n_OS = $#{ $bOS{ $e } }; |
|
|
277
|
|
|
|
|
554
|
|
|
1406
|
277
|
100
|
|
|
|
667
|
$max_n_OS = $n_OS if $n_OS > $max_n_OS; # max list of OSE |
|
1407
|
|
|
|
|
|
|
|
|
1408
|
277
|
100
|
|
|
|
644
|
if( $n_OS ) { # number of OSE > 1 |
|
1409
|
|
|
|
|
|
|
# Add in array varied OSE for j-th atom of element |
|
1410
|
144
|
|
|
|
|
394
|
push @atoms, "$e:$j"; |
|
1411
|
|
|
|
|
|
|
|
|
1412
|
|
|
|
|
|
|
# Define from a basic list of OSE |
|
1413
|
144
|
|
|
|
|
186
|
push @{ $prop->{$e}{'OS'} }, [ -999 ]; |
|
|
144
|
|
|
|
|
1075
|
|
|
1414
|
|
|
|
|
|
|
|
|
1415
|
|
|
|
|
|
|
}else{ # One OSE in list |
|
1416
|
133
|
|
|
|
|
182
|
push @{ $prop->{$e}{'OS'} }, [ $bOS{ $e }[0] ]; |
|
|
133
|
|
|
|
|
533
|
|
|
1417
|
|
|
|
|
|
|
|
|
1418
|
|
|
|
|
|
|
# charge * number of atoms |
|
1419
|
133
|
|
|
|
|
873
|
$balance_A += $bOS{ $e }[0] * $prop->{$e}{'num'}[$j]; |
|
1420
|
|
|
|
|
|
|
} |
|
1421
|
|
|
|
|
|
|
} |
|
1422
|
|
|
|
|
|
|
} |
|
1423
|
|
|
|
|
|
|
|
|
1424
|
201
|
|
|
|
|
344
|
my $balance_B = 0; # for Electronic balance |
|
1425
|
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
# Select oxidation states |
|
1427
|
201
|
100
|
|
|
|
478
|
if( $max_n_OS ){ |
|
1428
|
106
|
|
|
|
|
918
|
my $iter = variations_with_repetition( [ (0..$max_n_OS) ], scalar( @atoms ) ); |
|
1429
|
|
|
|
|
|
|
_SO_M2: |
|
1430
|
106
|
|
|
|
|
4339
|
while (my $p = $iter->next) { |
|
1431
|
|
|
|
|
|
|
|
|
1432
|
467
|
|
|
|
|
4537
|
$balance_B = 0; |
|
1433
|
467
|
|
|
|
|
649
|
for(my $i = 0; $i<=$#{ $p }; $i++){ |
|
|
1430
|
|
|
|
|
7738
|
|
|
1434
|
|
|
|
|
|
|
|
|
1435
|
1041
|
|
|
|
|
1733
|
my $x = $atoms[$i]; |
|
1436
|
1041
|
|
|
|
|
2592
|
my($e, $j) = split /:/,$x; |
|
1437
|
|
|
|
|
|
|
|
|
1438
|
1041
|
|
|
|
|
1296
|
my($sum, @os); |
|
1439
|
|
|
|
|
|
|
|
|
1440
|
1041
|
100
|
|
|
|
2033
|
if( exists $osin{ $x } ){ # Some OSE ion lists |
|
1441
|
|
|
|
|
|
|
|
|
1442
|
135
|
|
|
|
|
172
|
$sum += $_ for @{ $osin{ $x }[ $p->[$i] ] }; |
|
|
135
|
|
|
|
|
493
|
|
|
1443
|
135
|
|
|
|
|
168
|
@os = @{ $osin{ $x }[ $p->[$i] ] }; |
|
|
135
|
|
|
|
|
340
|
|
|
1444
|
|
|
|
|
|
|
|
|
1445
|
|
|
|
|
|
|
}else{ |
|
1446
|
906
|
|
|
|
|
1948
|
$os[0] = $sum = $bOS{ $e }[ $p->[$i] ]; |
|
1447
|
|
|
|
|
|
|
} |
|
1448
|
|
|
|
|
|
|
|
|
1449
|
1041
|
100
|
|
|
|
2290
|
next _SO_M2 unless defined $sum; # OSE have ended |
|
1450
|
|
|
|
|
|
|
|
|
1451
|
|
|
|
|
|
|
# sum OSE * number of atoms / number of OSE |
|
1452
|
963
|
|
|
|
|
2909
|
$balance_B += $sum * $prop->{ $e }{'num'}[$j] / @os; |
|
1453
|
963
|
|
|
|
|
3732
|
$prop->{ $e }{'OS'}[$j] = [ @os ]; |
|
1454
|
|
|
|
|
|
|
|
|
1455
|
|
|
|
|
|
|
} |
|
1456
|
389
|
100
|
|
|
|
2219
|
last unless $balance_A + $balance_B; # balance is found |
|
1457
|
|
|
|
|
|
|
} |
|
1458
|
|
|
|
|
|
|
} |
|
1459
|
|
|
|
|
|
|
|
|
1460
|
201
|
50
|
66
|
|
|
802
|
return if $no_ion && ($balance_A + $balance_B); # balance is not found |
|
1461
|
|
|
|
|
|
|
|
|
1462
|
201
|
|
|
|
|
360
|
$balance_A = 0; # for electronic balance |
|
1463
|
|
|
|
|
|
|
|
|
1464
|
|
|
|
|
|
|
# Check electronic balance |
|
1465
|
201
|
|
|
|
|
759
|
for my $e (keys %$prop ){ |
|
1466
|
566
|
|
|
|
|
845
|
my $i=0; |
|
1467
|
566
|
|
|
|
|
641
|
for my $os ( @{ $prop->{$e}{'OS'} } ){ |
|
|
566
|
|
|
|
|
1189
|
|
|
1468
|
|
|
|
|
|
|
|
|
1469
|
598
|
|
|
|
|
620
|
my $sum; |
|
1470
|
598
|
|
|
|
|
1549
|
$sum += $_ for @$os; |
|
1471
|
|
|
|
|
|
|
|
|
1472
|
|
|
|
|
|
|
# sum OSE * number of atoms / number of OSE |
|
1473
|
598
|
|
|
|
|
2501
|
$balance_A += $sum * $prop->{$e}{'num'}[ $i++ ] / @$os; |
|
1474
|
|
|
|
|
|
|
} |
|
1475
|
|
|
|
|
|
|
} |
|
1476
|
|
|
|
|
|
|
|
|
1477
|
201
|
100
|
|
|
|
466
|
if( $balance_A ){ |
|
1478
|
3
|
50
|
|
|
|
11
|
return if $no_ion; |
|
1479
|
|
|
|
|
|
|
}else{ |
|
1480
|
198
|
|
|
|
|
3351
|
return $prop; |
|
1481
|
|
|
|
|
|
|
} |
|
1482
|
3
|
|
|
|
|
26
|
delete $prop->{$_}{'OS'} for keys %$prop; |
|
1483
|
|
|
|
|
|
|
} |
|
1484
|
|
|
|
|
|
|
} |
|
1485
|
|
|
|
|
|
|
|
|
1486
|
|
|
|
|
|
|
# Read Pauling electronegativity and OSE |
|
1487
|
|
|
|
|
|
|
# only for given elements of substance |
|
1488
|
|
|
|
|
|
|
# input: |
|
1489
|
|
|
|
|
|
|
# %atoms -- elements |
|
1490
|
|
|
|
|
|
|
# return: |
|
1491
|
|
|
|
|
|
|
# %atom_el_neg |
|
1492
|
|
|
|
|
|
|
# %atom_OS |
|
1493
|
|
|
|
|
|
|
# $intermet |
|
1494
|
|
|
|
|
|
|
|
|
1495
|
|
|
|
|
|
|
sub _read_atoms{ |
|
1496
|
200
|
|
|
200
|
|
361
|
my $atoms = shift; |
|
1497
|
|
|
|
|
|
|
|
|
1498
|
200
|
|
|
|
|
343
|
my %atom_el_neg; # atom electronegativity |
|
1499
|
|
|
|
|
|
|
my %atom_OS; # oxidation state |
|
1500
|
200
|
|
|
|
|
377
|
my $intermet = 1; # for intermetallic compound |
|
1501
|
|
|
|
|
|
|
|
|
1502
|
200
|
|
|
|
|
963
|
my $adb = &_atoms_db; |
|
1503
|
|
|
|
|
|
|
|
|
1504
|
200
|
|
|
|
|
1690
|
for( my $i = 0; $i < @$adb; $i+=5 ){ |
|
1505
|
23400
|
|
|
|
|
27479
|
$_ = $adb->[$i]; |
|
1506
|
23400
|
100
|
|
|
|
61052
|
next if !exists $atoms->{ $_ }; |
|
1507
|
|
|
|
|
|
|
|
|
1508
|
558
|
|
|
|
|
1390
|
$atom_el_neg{ $_ } = $adb->[$i+2]; |
|
1509
|
558
|
100
|
|
|
|
1376
|
$intermet = 0 unless $adb->[$i+3]; # Not intermetallic compound |
|
1510
|
558
|
|
|
|
|
1668
|
$atom_OS{ $_ } = $adb->[$i+4]; |
|
1511
|
|
|
|
|
|
|
} |
|
1512
|
|
|
|
|
|
|
|
|
1513
|
200
|
|
|
|
|
8039
|
\%atom_el_neg, \%atom_OS, $intermet; |
|
1514
|
|
|
|
|
|
|
} |
|
1515
|
|
|
|
|
|
|
|
|
1516
|
|
|
|
|
|
|
# Read necessary ion-group |
|
1517
|
|
|
|
|
|
|
# input: |
|
1518
|
|
|
|
|
|
|
# $Chemistry_substance |
|
1519
|
|
|
|
|
|
|
# return: |
|
1520
|
|
|
|
|
|
|
# $ions |
|
1521
|
|
|
|
|
|
|
sub _read_ions { |
|
1522
|
200
|
|
|
200
|
|
454
|
my $chem_sub = shift; |
|
1523
|
200
|
|
|
|
|
277
|
my %ions; |
|
1524
|
|
|
|
|
|
|
|
|
1525
|
200
|
|
|
|
|
511
|
my $idb = &_ions_db; |
|
1526
|
|
|
|
|
|
|
|
|
1527
|
|
|
|
|
|
|
# Construct pattern |
|
1528
|
200
|
|
|
|
|
798
|
for( my $j = 0; $j < @$idb; $j+=2 ){ |
|
1529
|
21400
|
|
|
|
|
113241
|
my $frm = $idb->[$j]; |
|
1530
|
21400
|
|
|
|
|
53122
|
my $os = $idb->[$j+1]; |
|
1531
|
|
|
|
|
|
|
|
|
1532
|
21400
|
|
|
|
|
167404
|
my %a = split /_|=/,$os; # Parse to element end OSE |
|
1533
|
|
|
|
|
|
|
|
|
1534
|
21400
|
100
|
|
|
|
69806
|
if($os =~ /~/){ # Macro-substitutions |
|
1535
|
|
|
|
|
|
|
|
|
1536
|
5800
|
|
|
|
|
6934
|
my %ek; |
|
1537
|
5800
|
|
|
|
|
6666
|
my $max_n_ek = 0; # max number of element-pattern in macro-substitutions |
|
1538
|
|
|
|
|
|
|
|
|
1539
|
5800
|
|
|
|
|
30554
|
while( my($e, $v) = each %a ){ |
|
1540
|
|
|
|
|
|
|
|
|
1541
|
12400
|
100
|
|
|
|
53315
|
if($e =~ /(\w+~)(.*)/){ |
|
1542
|
5800
|
|
|
|
|
42951
|
$ek{$1}[0] = [ split ',',$2 ]; # elements |
|
1543
|
5800
|
|
|
|
|
22815
|
$ek{$1}[1] = $v; # OSE for group |
|
1544
|
|
|
|
|
|
|
|
|
1545
|
5800
|
|
|
|
|
6435
|
my $n_ek = $#{ $ek{$1}[0] }; # number of element-substitutions |
|
|
5800
|
|
|
|
|
14361
|
|
|
1546
|
5800
|
100
|
|
|
|
27279
|
$max_n_ek = $n_ek if $n_ek > $max_n_ek; # max list |
|
1547
|
|
|
|
|
|
|
} |
|
1548
|
|
|
|
|
|
|
} |
|
1549
|
|
|
|
|
|
|
|
|
1550
|
5800
|
|
|
|
|
39127
|
my $iter = variations_with_repetition( [ (0..$max_n_ek) ], scalar( keys %ek ) ); |
|
1551
|
|
|
|
|
|
|
ELEMENT_MACRO_1: |
|
1552
|
5800
|
|
|
|
|
215284
|
while (my $p = $iter->next) { |
|
1553
|
27800
|
|
|
|
|
263361
|
my $m = $frm; # macro-formula (mask) |
|
1554
|
27800
|
|
|
|
|
31531
|
my $i = 0; |
|
1555
|
27800
|
|
|
|
|
68279
|
for my $em (sort keys %ek){ |
|
1556
|
27800
|
|
|
|
|
55758
|
my $e = $ek{ $em }[0][ $p->[$i++] ]; # element |
|
1557
|
27800
|
50
|
|
|
|
52346
|
next ELEMENT_MACRO_1 unless defined $e; # pattern have ended |
|
1558
|
|
|
|
|
|
|
|
|
1559
|
27800
|
|
|
|
|
165216
|
$m =~ s/$em/$e/g; # Construct ion mask |
|
1560
|
|
|
|
|
|
|
} |
|
1561
|
|
|
|
|
|
|
|
|
1562
|
27800
|
100
|
|
|
|
485171
|
next unless $chem_sub =~ /($m)/; # Ions in substance aren't present |
|
1563
|
|
|
|
|
|
|
|
|
1564
|
57
|
|
|
|
|
338
|
my $l = length($1); # Length of ion mask |
|
1565
|
|
|
|
|
|
|
|
|
1566
|
57
|
|
|
|
|
95
|
$i = 0; |
|
1567
|
57
|
|
|
|
|
392
|
for my $em (sort keys %ek){ |
|
1568
|
57
|
|
|
|
|
158
|
my $e = $ek{ $em }[0][ $p->[$i++] ]; # element |
|
1569
|
|
|
|
|
|
|
|
|
1570
|
57
|
|
|
|
|
219
|
for my $z ( split /!/, $ek{ $em }[1] ){ |
|
1571
|
|
|
|
|
|
|
# list OSE |
|
1572
|
61
|
|
|
|
|
266
|
push @{ $ions{ $e }{ $l }{ $m } }, [ split /;/,$z ]; |
|
|
61
|
|
|
|
|
889
|
|
|
1573
|
|
|
|
|
|
|
} |
|
1574
|
|
|
|
|
|
|
} |
|
1575
|
|
|
|
|
|
|
|
|
1576
|
57
|
|
|
|
|
431
|
while(my ($e, $v) = each %a ){ |
|
1577
|
124
|
100
|
|
|
|
782
|
next if $e =~ /~/; |
|
1578
|
|
|
|
|
|
|
|
|
1579
|
|
|
|
|
|
|
# list OSE |
|
1580
|
67
|
|
|
|
|
194
|
for my $z ( split /!/, $v ){ |
|
1581
|
67
|
|
|
|
|
93
|
push @{ $ions{ $e }{ $l }{ $m } }, [ split /;/,$z ]; |
|
|
67
|
|
|
|
|
3371
|
|
|
1582
|
|
|
|
|
|
|
} |
|
1583
|
|
|
|
|
|
|
} |
|
1584
|
|
|
|
|
|
|
} |
|
1585
|
|
|
|
|
|
|
|
|
1586
|
|
|
|
|
|
|
}else{ |
|
1587
|
15600
|
100
|
|
|
|
245442
|
next unless $chem_sub =~ /($frm)/; # no ions in substance |
|
1588
|
|
|
|
|
|
|
|
|
1589
|
116
|
|
|
|
|
376
|
my $l = length($1); # Length of the found group |
|
1590
|
|
|
|
|
|
|
|
|
1591
|
116
|
|
|
|
|
480
|
while(my ($e, $v) = each %a ){ |
|
1592
|
|
|
|
|
|
|
# list OSE |
|
1593
|
234
|
|
|
|
|
569
|
for my $z ( split /!/, $v ){ |
|
1594
|
265
|
|
|
|
|
291
|
push @{ $ions{ $e }{ $l }{ $frm } }, [ split /;/,$z ]; |
|
|
265
|
|
|
|
|
2630
|
|
|
1595
|
|
|
|
|
|
|
} |
|
1596
|
|
|
|
|
|
|
} |
|
1597
|
|
|
|
|
|
|
} |
|
1598
|
|
|
|
|
|
|
} |
|
1599
|
|
|
|
|
|
|
|
|
1600
|
200
|
|
|
|
|
4444
|
\%ions; |
|
1601
|
|
|
|
|
|
|
} |
|
1602
|
|
|
|
|
|
|
|
|
1603
|
|
|
|
|
|
|
|
|
1604
|
|
|
|
|
|
|
# Pauling scale (adapted). |
|
1605
|
|
|
|
|
|
|
# Atomic weights from NIST. |
|
1606
|
|
|
|
|
|
|
# Attention! |
|
1607
|
|
|
|
|
|
|
# order of OSE is important (last are exotic OSE) |
|
1608
|
|
|
|
|
|
|
sub _atoms_db{ |
|
1609
|
|
|
|
|
|
|
return [ |
|
1610
|
246
|
|
|
246
|
|
39783
|
'Ac', 227, 110, 1, [0, 3], |
|
1611
|
|
|
|
|
|
|
'Ag', 107.8682, 193, 1, [0, 1, 2, 3, 5], |
|
1612
|
|
|
|
|
|
|
'Al', 26.9815386, 161, 1, [-3, 0, 3, 1, 2], |
|
1613
|
|
|
|
|
|
|
'Am', 243, 113, 1, [0, 2, 3, 4, 5, 6], |
|
1614
|
|
|
|
|
|
|
'Ar', 39.948, 0, 0, [0], |
|
1615
|
|
|
|
|
|
|
'As', 74.9216, 221, 0, [-3, 0, 3, 5], # 2 |
|
1616
|
|
|
|
|
|
|
'At', 210, 225, 0, [-1, 0, 1, 5, 7], # 3 |
|
1617
|
|
|
|
|
|
|
'Au', 196.966569, 254, 1, [0, 1, 2, 3, 5, 7], # -1 |
|
1618
|
|
|
|
|
|
|
'B', 10.811, 204, 0, [-3, 0, 1, 2, 3], |
|
1619
|
|
|
|
|
|
|
'Ba', 137.327, 89, 1, [0, 2], |
|
1620
|
|
|
|
|
|
|
'Be', 9.012182, 157, 1, [0, 2], |
|
1621
|
|
|
|
|
|
|
'Bh', 272.13803, 0, 1, [0, 7], |
|
1622
|
|
|
|
|
|
|
'Bi', 208.9804, 221, 0, [-3, 0, 2, 3, 5], |
|
1623
|
|
|
|
|
|
|
'Bk', 247, 130, 1, [0, 3, 4], |
|
1624
|
|
|
|
|
|
|
'Br', 79.904, 296, 0, [-1, 0, 1, 3, 4, 5, 6, 7], |
|
1625
|
|
|
|
|
|
|
'C', 12.0107, 255, 0, [-4, -3, -1, 0, 2, 3, 4], # -2, 1 |
|
1626
|
|
|
|
|
|
|
'Ca', 40.078, 100, 1, [0, 2], |
|
1627
|
|
|
|
|
|
|
'Cd', 112.411, 169, 1, [0, 2], |
|
1628
|
|
|
|
|
|
|
'Ce', 140.116, 112, 1, [0, 3, 4], # 2 |
|
1629
|
|
|
|
|
|
|
'Cf', 251, 130, 1, [0, 2, 3, 4], |
|
1630
|
|
|
|
|
|
|
'Cl', 35.453, 316, 0, [-1, 0, 1, 3, 4, 5, 6, 7], # 2 |
|
1631
|
|
|
|
|
|
|
'Cm', 247, 128, 1, [0, 3, 4], |
|
1632
|
|
|
|
|
|
|
'Cn', 285.17411, 205, 1, [0, 2, 4], |
|
1633
|
|
|
|
|
|
|
'Co', 58.933195, 188, 1, [0, 1, 2, 3, 4], # -1, 5 |
|
1634
|
|
|
|
|
|
|
'Cr', 51.9961, 166, 1, [0, 1, 2, 3, 4, 5, 6], # -2, -1 |
|
1635
|
|
|
|
|
|
|
'Cs', 132.9054519, 79, 1, [0, 1], |
|
1636
|
|
|
|
|
|
|
'Cu', 63.546, 190, 1, [0, 2, 1, 3], # 4 |
|
1637
|
|
|
|
|
|
|
'D', 2.0141017778, 220, 0, [-1, 0, 1], |
|
1638
|
|
|
|
|
|
|
'Db', 268.12545, 0, 1, [0, 5], # old Ns |
|
1639
|
|
|
|
|
|
|
'Ds', 281.16206, 0, 1, [0, 6, 4, 2, 5], # as Pt |
|
1640
|
|
|
|
|
|
|
'Dy', 162.5, 122, 1, [0, 3, 4], # 2 |
|
1641
|
|
|
|
|
|
|
'Er', 167.259, 124, 1, [0, 3], |
|
1642
|
|
|
|
|
|
|
'Es', 252.08298, 130, 1, [0, 2, 3], |
|
1643
|
|
|
|
|
|
|
'Eu', 151.964, 120, 1, [0, 2, 3], |
|
1644
|
|
|
|
|
|
|
'F', 18.9984032, 400, 0, [-1, 0], |
|
1645
|
|
|
|
|
|
|
'Fe', 55.845, 183, 1, [0, 2, 3, 6, 8, 4, 5], # -2, -1, 1 |
|
1646
|
|
|
|
|
|
|
'Fm', 257.095105, 130, 1, [0, 2, 3], |
|
1647
|
|
|
|
|
|
|
'Fr', 223.0197359, 70, 1, [0, 1], |
|
1648
|
|
|
|
|
|
|
'Ga', 69.723, 181, 1, [0, 1, 2, 3], |
|
1649
|
|
|
|
|
|
|
'Gd', 157.25, 120, 1, [0, 3], # 1, 2 |
|
1650
|
|
|
|
|
|
|
'Ge', 72.64, 201, 0, [-4, -2, 0, 2, 4], # 1, 3 |
|
1651
|
|
|
|
|
|
|
'H', 1.00794, 220, 0, [-1, 0, 1], |
|
1652
|
|
|
|
|
|
|
'He', 4.002602, 0, 0, [0], |
|
1653
|
|
|
|
|
|
|
'Hf', 178.49, 130, 1, [0, 2, 3, 4], |
|
1654
|
|
|
|
|
|
|
'Hg', 200.59, 200, 1, [0, 1, 2], # 4 |
|
1655
|
|
|
|
|
|
|
'Ho', 164.93032, 123, 1, [0, 3], |
|
1656
|
|
|
|
|
|
|
'Hs', 270.13465, 0, 1, [0, 7], |
|
1657
|
|
|
|
|
|
|
'I', 126.90447, 266, 0, [-1, 0, 1, 3, 5, 7], |
|
1658
|
|
|
|
|
|
|
'In', 114.818, 178, 1, [0, 1, 2, 3], |
|
1659
|
|
|
|
|
|
|
'Ir', 192.217, 220, 1, [0, 1, 2, 3, 4, 5, 6, 8], # -3, -1 |
|
1660
|
|
|
|
|
|
|
'K', 39.0983, 82, 1, [0, 1], |
|
1661
|
|
|
|
|
|
|
'Kr', 83.798, 0, 0, [0, 2, 4, 6], |
|
1662
|
|
|
|
|
|
|
'Ku', 265.1167, 0, 1, [0, 4], # now Rf |
|
1663
|
|
|
|
|
|
|
'La', 138.90547, 110, 1, [0, 3], # 2 |
|
1664
|
|
|
|
|
|
|
'Li', 6.941, 98, 1, [0, 1], |
|
1665
|
|
|
|
|
|
|
'Lr', 262.10963, 129, 1, [0, 3], |
|
1666
|
|
|
|
|
|
|
'Lu', 174.9668, 127, 1, [0, 3], |
|
1667
|
|
|
|
|
|
|
'Md', 258.098431, 130, 1, [0, 2, 3], |
|
1668
|
|
|
|
|
|
|
'Mg', 24.305, 131, 1, [0, 2], |
|
1669
|
|
|
|
|
|
|
'Mn', 54.938045, 155, 1, [0, 1, 2, 3, 4, 5, 6, 7], # -3, -2, -1 |
|
1670
|
|
|
|
|
|
|
'Mo', 95.96, 216, 1, [0, 2, 3, 4, 5, 6], # -2, -1, 1 |
|
1671
|
|
|
|
|
|
|
'Mt', 276.15116, 0, 1, [0, 4], |
|
1672
|
|
|
|
|
|
|
'N', 14.0067, 304, 0, [-3, -2, -1, 0, 1, 2, 3, 4, 5], |
|
1673
|
|
|
|
|
|
|
'Na', 22.98976928, 93, 1, [0, 1], |
|
1674
|
|
|
|
|
|
|
'Nb', 92.90638, 160, 1, [0, 1, 2, 3, 4, 5], # -1 |
|
1675
|
|
|
|
|
|
|
'Nd', 144.242, 114, 1, [0, 3], # 2 |
|
1676
|
|
|
|
|
|
|
'Ne', 20.1797, 0, 0, [0], |
|
1677
|
|
|
|
|
|
|
'Ni', 58.6934, 191, 1, [0, 2, 3, 4, 1], # -1 |
|
1678
|
|
|
|
|
|
|
'No', 259.10103, 130, 1, [0, 2, 3], |
|
1679
|
|
|
|
|
|
|
'Np', 237, 136, 1, [0, 3, 4, 5, 6], # 7 |
|
1680
|
|
|
|
|
|
|
'Ns', 268.12545, 0, 1, [0, 5], # now Db |
|
1681
|
|
|
|
|
|
|
'O', 15.9994, 344, 0, [-2, -1, 0, 1, 2], |
|
1682
|
|
|
|
|
|
|
'Os', 190.23, 220, 1, [0, 2, 3, 4, 5, 6, 7, 8], # -2, -1, 1 |
|
1683
|
|
|
|
|
|
|
'P', 30.973762, 221, 0, [-3, -2, 0, 1, 3, 4, 5], # -1, 2 |
|
1684
|
|
|
|
|
|
|
'Pa', 231.03588, 150, 1, [0, 3, 4, 5], |
|
1685
|
|
|
|
|
|
|
'Pb', 207.2, 233, 1, [-4, 0, 2, 4], |
|
1686
|
|
|
|
|
|
|
'Pd', 106.42, 220, 1, [0, 1, 2, 3, 4], |
|
1687
|
|
|
|
|
|
|
'Pm', 145, 113, 1, [0, 3], |
|
1688
|
|
|
|
|
|
|
'Po', 209, 200, 1, [-2, 0, 2, 4, 6], |
|
1689
|
|
|
|
|
|
|
'Pr', 140.90765, 113, 1, [0, 3, 4], # 2 |
|
1690
|
|
|
|
|
|
|
'Pt', 195.084, 228, 1, [0, 2, 3, 4, 5, 6, 1], |
|
1691
|
|
|
|
|
|
|
'Pu', 244, 128, 1, [0, 2, 3, 4, 5, 6], # 7 |
|
1692
|
|
|
|
|
|
|
'Ra', 226, 90, 1, [0, 2, 4], |
|
1693
|
|
|
|
|
|
|
'Rb', 85.4678, 82, 1, [0, 1], |
|
1694
|
|
|
|
|
|
|
'Re', 186.207, 190, 1, [0, 1, 2, 3, 4, 5, 6, 7], # -3, -1 |
|
1695
|
|
|
|
|
|
|
'Rf', 265.1167, 0, 1, [0, 4], # old Ku |
|
1696
|
|
|
|
|
|
|
'Rg', 280.16447, 0, 1, [0, 3, 1, 2], # as Au |
|
1697
|
|
|
|
|
|
|
'Rh', 102.9055, 228, 1, [0, 1, 2, 3, 4, 6], # -1, 5 |
|
1698
|
|
|
|
|
|
|
'Rn', 222, 0, 0, [0, 2, 4, 6, 8], |
|
1699
|
|
|
|
|
|
|
'Ru', 101.07, 220, 1, [0, 2, 3, 4, 5, 6, 7, 8], # -2, 1 |
|
1700
|
|
|
|
|
|
|
'S', 32.065, 258, 0, [-2, 0, 1, 2, 3, 4, 6], #-1, 5 |
|
1701
|
|
|
|
|
|
|
'Sb', 121.76, 221, 1, [-3, 0, 3, 4, 5], |
|
1702
|
|
|
|
|
|
|
'Sc', 44.955912, 136, 1, [0, 3], # 1, 2 |
|
1703
|
|
|
|
|
|
|
'Se', 78.96, 255, 0, [-2, 0, 2, 4, 6], |
|
1704
|
|
|
|
|
|
|
'Sg', 271.13347, 0, 1, [0, 6], |
|
1705
|
|
|
|
|
|
|
'Si', 28.0855, 190, 0, [-4, 0, 2, 4], # -3, -2, -1, 1, 3 |
|
1706
|
|
|
|
|
|
|
'Sm', 150.36, 117, 1, [0, 2, 3], |
|
1707
|
|
|
|
|
|
|
'Sn', 118.71, 196, 1, [-4, -2, 0, 2, 4], |
|
1708
|
|
|
|
|
|
|
'Sr', 87.62, 95, 1, [0, 2], |
|
1709
|
|
|
|
|
|
|
'T', 3.0160492777, 220, 0, [-1, 0, 1], |
|
1710
|
|
|
|
|
|
|
'Ta', 180.94788, 150, 1, [0, 1, 2, 3, 4, 5], # -1 |
|
1711
|
|
|
|
|
|
|
'Tb', 158.92535, 110, 1, [0, 3, 4], # 1 |
|
1712
|
|
|
|
|
|
|
'Tc', 97.9072, 190, 1, [0, 1, 2, 3, 4, 5, 6, 7], # -3, -1 |
|
1713
|
|
|
|
|
|
|
'Te', 127.6, 221, 0, [-2, 0, 2, 4, 6], # 5 |
|
1714
|
|
|
|
|
|
|
'Th', 232.03806, 130, 1, [0, 2, 3, 4], |
|
1715
|
|
|
|
|
|
|
'Ti', 47.867, 154, 1, [-2, 0, 2, 3, 4], # -1 |
|
1716
|
|
|
|
|
|
|
'Tl', 204.3833, 162, 1, [0, 1, 3], |
|
1717
|
|
|
|
|
|
|
'Tm', 168.93421, 125, 1, [0, 2, 3], |
|
1718
|
|
|
|
|
|
|
'Tn', 220, 0, 0, [0, 2, 4, 6, 8], # as Rn^220 |
|
1719
|
|
|
|
|
|
|
'U', 238.02891, 138, 1, [0, 3, 4, 5, 6], |
|
1720
|
|
|
|
|
|
|
'V', 50.9415, 163, 1, [0, 2, 3, 4, 5], # -1, 1 |
|
1721
|
|
|
|
|
|
|
'W', 183.84, 220, 1, [0, 2, 3, 4, 5, 6], # -2, -1, 1 |
|
1722
|
|
|
|
|
|
|
'Xe', 131.293, 0, 0, [0, 1, 2, 4, 6, 8], |
|
1723
|
|
|
|
|
|
|
'Y', 88.90585, 122, 1, [0, 3], # 1, 2 |
|
1724
|
|
|
|
|
|
|
'Yb', 173.054, 110, 1, [0, 2, 3], |
|
1725
|
|
|
|
|
|
|
'Zn', 65.38, 165, 1, [0, 2], |
|
1726
|
|
|
|
|
|
|
'Zr', 91.224, 133, 1, [0, 2, 3, 4], # 1 |
|
1727
|
|
|
|
|
|
|
] |
|
1728
|
|
|
|
|
|
|
} |
|
1729
|
|
|
|
|
|
|
|
|
1730
|
|
|
|
|
|
|
|
|
1731
|
|
|
|
|
|
|
# Attention! |
|
1732
|
|
|
|
|
|
|
# ion-group mask consist individual atoms only |
|
1733
|
|
|
|
|
|
|
sub _ions_db{ |
|
1734
|
|
|
|
|
|
|
return [ |
|
1735
|
|
|
|
|
|
|
# hydroxide |
|
1736
|
200
|
|
|
200
|
|
8798
|
'[^O]OH(?![efgos])', 'H=1_O=-2', |
|
1737
|
|
|
|
|
|
|
'.a~O', 'a~Cl,Br=1_O=-2', |
|
1738
|
|
|
|
|
|
|
'.IO', 'I=1!3_O=-2', |
|
1739
|
|
|
|
|
|
|
# oxychloride: phosgene (carbonyl dichloride), thionyl... |
|
1740
|
|
|
|
|
|
|
'.OCl2', 'Cl=-1_O=-2', |
|
1741
|
|
|
|
|
|
|
# '.OCl2', 'Cl=-1;1_O=-2', |
|
1742
|
|
|
|
|
|
|
# meta- antimonites, arsenites and others |
|
1743
|
|
|
|
|
|
|
'.a~O2', 'a~Sb,Al,Ni,As,Au,Co,Ga,Cl,Br,B=3_O=-2', |
|
1744
|
|
|
|
|
|
|
# nitrites, dioxynitrates |
|
1745
|
|
|
|
|
|
|
'.NO2', 'N=3!2_O=-2', |
|
1746
|
|
|
|
|
|
|
'.BO3', 'B=3_O=-2', |
|
1747
|
|
|
|
|
|
|
# carbonates, selenates, tellurates |
|
1748
|
|
|
|
|
|
|
'.a~O3', 'a~C,Se,Si,Ni,Te,Pt,Mo,Po,Mn,Fe,Ti,Zr,Hf,Re=4_O=-2', |
|
1749
|
|
|
|
|
|
|
# bismuthates, nitrates and others |
|
1750
|
|
|
|
|
|
|
'.a~O3', 'a~Bi,N,V,Cl,Br,I,Nb,Ta=5_O=-2', |
|
1751
|
|
|
|
|
|
|
# plumbates, silicates |
|
1752
|
|
|
|
|
|
|
'.a~O4', 'a~Pb,Si,Ge,Ti=4_O=-2', |
|
1753
|
|
|
|
|
|
|
# ortho- antimonates, arsenates, phosphates and others |
|
1754
|
|
|
|
|
|
|
'.a~O4', 'a~Sb,As,P,V,Ta,Nb=5_O=-2', |
|
1755
|
|
|
|
|
|
|
# molybdates, tungstates, chromates and others (excepting peroxides) |
|
1756
|
|
|
|
|
|
|
'.a~O4(?=[^O]|Os|$)', 'a~Kr,U,S,Se,Te,Mo,W,Cr,Pu,Os=6_O=-2', |
|
1757
|
|
|
|
|
|
|
# per- chlorates, bromates |
|
1758
|
|
|
|
|
|
|
'.a~O4', 'a~Cl,Br=7_O=-2', |
|
1759
|
|
|
|
|
|
|
# rhodanides (thiocyanates) and for selenium |
|
1760
|
|
|
|
|
|
|
'.(?:a~CN|a~NC|CNa~|Ca~N|Na~C|NCa~)(?![a-gik-pr-u])', 'a~S,Se=-2_C=4_N=-3', |
|
1761
|
|
|
|
|
|
|
# ortho-/meta- : /phosphi(-a)tes, antimoni(-a)tes, arseni(-a)tes |
|
1762
|
|
|
|
|
|
|
'.a~O3', 'a~P,Sb,As=5!3_O=-2', |
|
1763
|
|
|
|
|
|
|
|
|
1764
|
|
|
|
|
|
|
'.a~O4', 'a~I,Re=6!7_O=-2', |
|
1765
|
|
|
|
|
|
|
'.a~O4', 'a~Tc,Ru=5!6!7_O=-2', |
|
1766
|
|
|
|
|
|
|
'.MnO4', 'Mn=3!4!5!6!7_O=-2', |
|
1767
|
|
|
|
|
|
|
# ferrate |
|
1768
|
|
|
|
|
|
|
'.FeO4', 'Fe=3!4!6_O=-2', |
|
1769
|
|
|
|
|
|
|
|
|
1770
|
|
|
|
|
|
|
'.a~O5', 'a~Fe,Pu=6_O=-2', |
|
1771
|
|
|
|
|
|
|
'.ReO5', 'Re=7_O=-2', |
|
1772
|
|
|
|
|
|
|
|
|
1773
|
|
|
|
|
|
|
'.I(?:O[56]|2O9)', 'I=7_O=-2', |
|
1774
|
|
|
|
|
|
|
'^I2O4$', 'I=3;5_O=-2', |
|
1775
|
|
|
|
|
|
|
'^I4O9$', 'I=3;5;5;5_O=-2', |
|
1776
|
|
|
|
|
|
|
|
|
1777
|
|
|
|
|
|
|
'.SnO6', 'Sn=4_O=-2', |
|
1778
|
|
|
|
|
|
|
'.SbO6', 'Sb=5_O=-2', |
|
1779
|
|
|
|
|
|
|
'.a~O6', 'a~Te,Am=6_O=-2', |
|
1780
|
|
|
|
|
|
|
# perxenic acid |
|
1781
|
|
|
|
|
|
|
'.XeO6', 'Xe=6!8_O=-2', |
|
1782
|
|
|
|
|
|
|
|
|
1783
|
|
|
|
|
|
|
'.MoO3F3', 'Mo=6_F=-1_O=-2', |
|
1784
|
|
|
|
|
|
|
# sulfamic acid salts |
|
1785
|
|
|
|
|
|
|
'.NSO3', 'S=6_O=-2_N=-3', |
|
1786
|
|
|
|
|
|
|
# thiazates, thionitrites |
|
1787
|
|
|
|
|
|
|
'.(?:NSO|SNO|NOS)(?=[\]\)\}]|$)', 'N=3_S=-2_O=-2', |
|
1788
|
|
|
|
|
|
|
# sulphites |
|
1789
|
|
|
|
|
|
|
'.SO3(?=[^OS]|Os|S[bcegimnr]|$)', 'S=4!6_O=-2', |
|
1790
|
|
|
|
|
|
|
# thiosulphates |
|
1791
|
|
|
|
|
|
|
'.S2O3', 'S=6;-2_O=-2', |
|
1792
|
|
|
|
|
|
|
# peroxydisulfuric (marshal's) acid |
|
1793
|
|
|
|
|
|
|
'.S2O8', 'S=6_O=-2;-2;-2;-2;-2;-2;-1;-1', |
|
1794
|
|
|
|
|
|
|
|
|
1795
|
|
|
|
|
|
|
'.a~2O7', 'a~P,Re=5_O=-2', |
|
1796
|
|
|
|
|
|
|
# pirosulphates, bichromates |
|
1797
|
|
|
|
|
|
|
'.a~2O7', 'a~S,Cr=6_O=-2', |
|
1798
|
|
|
|
|
|
|
# rhodane |
|
1799
|
|
|
|
|
|
|
'^\((?:SCN|SNC|CNS|CSN|NSC|NCS)\)2$', 'S=1_C=2_N=-3', |
|
1800
|
|
|
|
|
|
|
# cyan (dicyan) |
|
1801
|
|
|
|
|
|
|
'^\((?:CN|NC)\)2$', 'C=4;2_N=-3', |
|
1802
|
|
|
|
|
|
|
# cyanamides |
|
1803
|
|
|
|
|
|
|
'.CN2', 'C=4_N=-3', |
|
1804
|
|
|
|
|
|
|
# cyanides |
|
1805
|
|
|
|
|
|
|
'.CN', 'C=2_N=-3', |
|
1806
|
|
|
|
|
|
|
# cyanates (salts of cyanic, isocyanic acid) |
|
1807
|
|
|
|
|
|
|
'.CNO', 'C=4_N=-3_O=-2', |
|
1808
|
|
|
|
|
|
|
# fulminates (salts of fulminic acid) |
|
1809
|
|
|
|
|
|
|
'.ONC', 'C=-2_N=3_O=-2', |
|
1810
|
|
|
|
|
|
|
# flaveanic hydrogen |
|
1811
|
|
|
|
|
|
|
'^C2(?:H2N2S|N2SH2|SH2N2|SN2H2)$', 'C=2;4_H=1_S=-2_N=-3', |
|
1812
|
|
|
|
|
|
|
# rubeanic hydrogen |
|
1813
|
|
|
|
|
|
|
'^C2S2N2H4$', 'C=2;4_H=1_S=-2_N=-3', |
|
1814
|
|
|
|
|
|
|
# salts of peroxonitric acid or orthonitrates |
|
1815
|
|
|
|
|
|
|
'.NO4', 'N=5_O=-1;-1;-2;-2!-2', |
|
1816
|
|
|
|
|
|
|
# salts of hyponitrous acid |
|
1817
|
|
|
|
|
|
|
'.N2O2', 'N=1_O=-2', |
|
1818
|
|
|
|
|
|
|
|
|
1819
|
|
|
|
|
|
|
# salts of hyponitrates (триоксодиазотной) acid |
|
1820
|
|
|
|
|
|
|
'.N2O3', 'N=2_O=-2', |
|
1821
|
|
|
|
|
|
|
|
|
1822
|
|
|
|
|
|
|
# salts of nitroxylic acid |
|
1823
|
|
|
|
|
|
|
'.N2O4', 'N=2_O=-2', |
|
1824
|
|
|
|
|
|
|
# salts of hydrazonic acid and azides (pernitrides) |
|
1825
|
|
|
|
|
|
|
'(?:.[\[\(]?N3[\]\)]?|^N3H$)', 'N=-3;4;-2', |
|
1826
|
|
|
|
|
|
|
'^(?:a~3\(N2\)2|a~3N4)$', 'a~Ca=2_N=-2;-2;-2;0', # OSE ? |
|
1827
|
|
|
|
|
|
|
# diimide |
|
1828
|
|
|
|
|
|
|
'^N2H2$', 'H=1_N=-2;0', # OSE ? |
|
1829
|
|
|
|
|
|
|
# nitrosyl- group | ion |
|
1830
|
|
|
|
|
|
|
'(?:[\[\(]NO[\]\)])', 'N=2!3_O=-2', |
|
1831
|
|
|
|
|
|
|
'^a~(?:[\[\(]NO[\]\)])\d*$', 'a~Fe,Ru,Cr=0_N=2_O=-2', |
|
1832
|
|
|
|
|
|
|
# hydroxylamine & its salts |
|
1833
|
|
|
|
|
|
|
'NH[23]O.', 'H=1_N=-1_O=-2', |
|
1834
|
|
|
|
|
|
|
# ammonia, amide |
|
1835
|
|
|
|
|
|
|
'NH[234]', 'H=1_N=-3', |
|
1836
|
|
|
|
|
|
|
|
|
1837
|
|
|
|
|
|
|
'.BF4', 'B=3_F=-1', |
|
1838
|
|
|
|
|
|
|
# hypophosphorous |
|
1839
|
|
|
|
|
|
|
'.PO2', 'P=1_O=-2', |
|
1840
|
|
|
|
|
|
|
# polyphosphates |
|
1841
|
|
|
|
|
|
|
'.P2O4', 'P=2_O=-2', |
|
1842
|
|
|
|
|
|
|
'.P2O5', 'P=3;3!2;4_O=-2', |
|
1843
|
|
|
|
|
|
|
'.P2O6', 'P=4;4!3;5_O=-2', |
|
1844
|
|
|
|
|
|
|
'.P3O8', 'P=3;4;4_O=-2', |
|
1845
|
|
|
|
|
|
|
'.P6O12', 'P=3_O=-2', |
|
1846
|
|
|
|
|
|
|
|
|
1847
|
|
|
|
|
|
|
# Neutral ligands |
|
1848
|
|
|
|
|
|
|
'CO\(NH2\)2', 'C=4_H=1_N=-3_O=-2', |
|
1849
|
|
|
|
|
|
|
'H2O(?=[^2O]|Os|$)', 'H=1_O=-2', |
|
1850
|
|
|
|
|
|
|
'C2H4', 'H=1_C=-2', |
|
1851
|
|
|
|
|
|
|
# metal ammiakaty |
|
1852
|
|
|
|
|
|
|
'^a~\(NH3\)\d*$', 'a~Ca=0_H=1_N=-3', |
|
1853
|
|
|
|
|
|
|
|
|
1854
|
|
|
|
|
|
|
'^(?:HOF|HFO|OFH|FOH)$', 'H=1_F=1_O=-2', |
|
1855
|
|
|
|
|
|
|
|
|
1856
|
|
|
|
|
|
|
'^Bi2O4$', 'Bi=3;5_O=-2', |
|
1857
|
|
|
|
|
|
|
'^B4H10$', 'B=2;2;3;3_H=-1', |
|
1858
|
|
|
|
|
|
|
'^Fe3C$', 'Fe=2;2;0_C=-4', |
|
1859
|
|
|
|
|
|
|
'^Fe3P$', 'Fe=3;0;0_P=-3', |
|
1860
|
|
|
|
|
|
|
'^P4S3$', 'P=1_S=-2;-2;0', |
|
1861
|
|
|
|
|
|
|
'^P4S7$', 'P=1_S=-2;-2;0;0;0;0;0', |
|
1862
|
|
|
|
|
|
|
'^P4S10$', 'P=1_S=-2;-2;0;0;0;0;0;0;0;0', |
|
1863
|
|
|
|
|
|
|
'^P12H6$', 'H=1_P=-3;-3;0;0;0;0;0;0;0;0;0;0', |
|
1864
|
|
|
|
|
|
|
# compound oxide |
|
1865
|
|
|
|
|
|
|
'^U3O8$', 'U=5;5;6_O=-2', # triuranium octoxide |
|
1866
|
|
|
|
|
|
|
'^Pb2O3$', 'Pb=2;4_O=-2', |
|
1867
|
|
|
|
|
|
|
'^Sb2O4$', 'Sb=3;5_O=-2', |
|
1868
|
|
|
|
|
|
|
'^Ag2O2$', 'Ag=1;3_O=-2', # silver peroxide |
|
1869
|
|
|
|
|
|
|
'^a~3O4$', 'a~Pb,Pt=2;2;4_O=-2', |
|
1870
|
|
|
|
|
|
|
'^a~3O4$', 'a~Fe,Co,Mn=2;3;3_O=-2', |
|
1871
|
|
|
|
|
|
|
# carbonyls |
|
1872
|
|
|
|
|
|
|
'^a~\d*\(CO\)\d*$', 'a~V,W,Cr,Ir,Mn,Fe,Co,Ni,Mo,Tc,Re,Ru,Rh,Os=0_C=2_O=-2', |
|
1873
|
|
|
|
|
|
|
# alkaline metals and others |
|
1874
|
|
|
|
|
|
|
'^a~2O2', 'a~H,Li,Na,K,Rb,Cs,Fr,Hg=1_O=-1', # peroxides |
|
1875
|
|
|
|
|
|
|
'^(?:a~O2|a~2O4)', 'a~Li,Na,K,Rb,Cs,Fr=1_O=-1;0', # superoxides |
|
1876
|
|
|
|
|
|
|
'^a~O3', 'a~Li,Na,K,Rb,Cs,Fr=1_O=-1;0;0', # ozonide |
|
1877
|
|
|
|
|
|
|
# alkaline-earth metals and others |
|
1878
|
|
|
|
|
|
|
'^a~O2', 'a~Mg,Ca,Sr,Ba,Ra,Zn,Cd,Hg,Cu=2_O=-1', # peroxides |
|
1879
|
|
|
|
|
|
|
'^(?:a~\(O2\)2|a~O4)', 'a~Mg,Ca,Sr,Ba,Ra=2_O=-1;0', # superoxides |
|
1880
|
|
|
|
|
|
|
'^(?:a~\(O3\)2|a~O6)', 'a~Mg,Ca,Sr,Ba,Ra=2_O=-1;0;0', # ozonide |
|
1881
|
|
|
|
|
|
|
# all peroxides |
|
1882
|
|
|
|
|
|
|
'.\(O2\)', 'O=-1', |
|
1883
|
|
|
|
|
|
|
# dioxygenils, O2PtF6 ... (except O2F2) |
|
1884
|
|
|
|
|
|
|
'^(?:\(O2\)|O2)(?![F])', 'O=1;0', |
|
1885
|
|
|
|
|
|
|
# chromium peroxide |
|
1886
|
|
|
|
|
|
|
'^CrO5$', 'Cr=6_O=-2;-1;-1;-1;-1', |
|
1887
|
|
|
|
|
|
|
'^Cr2O8$', 'Cr=6_O=-2;-2;-2;-2;-1;-1;-1;-1', |
|
1888
|
|
|
|
|
|
|
# rhenium, iodine, chlorine peroxide |
|
1889
|
|
|
|
|
|
|
'^a~2O8$', 'a~Re,I,Cl=7_O=-2;-2;-2;-2;-2;-2;-1;-1', |
|
1890
|
|
|
|
|
|
|
# sulfur peroxide |
|
1891
|
|
|
|
|
|
|
'^SO4$', 'S=6_O=-2;-2;-1;-1', |
|
1892
|
|
|
|
|
|
|
'^S2O7$', 'S=6_O=-2;-2;-2;-2;-2;-1;-1', |
|
1893
|
|
|
|
|
|
|
# peroxymonosulfuric | persulfuric | Caro's acid |
|
1894
|
|
|
|
|
|
|
'.SO5', 'S=6_O=-2;-2;-2;-1;-1', |
|
1895
|
|
|
|
|
|
|
# per-carbonates (percarbonic acid) |
|
1896
|
|
|
|
|
|
|
'.C2O6', 'C=4_O=-2;-2;-2;-2;-1;-1', |
|
1897
|
|
|
|
|
|
|
# acid chlorine peroxide ? |
|
1898
|
|
|
|
|
|
|
'.ClO5', 'Cl=7_O=-2;-2;-2;-1;-1', |
|
1899
|
|
|
|
|
|
|
# dioxodifluorochlorate |
|
1900
|
|
|
|
|
|
|
'.ClO2F2', 'Cl=5_O=-2_F=-1', |
|
1901
|
|
|
|
|
|
|
# oxotetrafluorochlorate |
|
1902
|
|
|
|
|
|
|
'.ClOF4', 'Cl=5_O=-2_F=-1', |
|
1903
|
|
|
|
|
|
|
# oxofluorides |
|
1904
|
|
|
|
|
|
|
'.ClO3F2', 'Cl=7_O=-2_F=-1', |
|
1905
|
|
|
|
|
|
|
'.ClO2F4', 'Cl=7_O=-2_F=-1', |
|
1906
|
|
|
|
|
|
|
# platinum hexafluoride (strongest oxidizer) |
|
1907
|
|
|
|
|
|
|
'.PtF[6-9][\]\)]?$', 'Pt=5_F=-1', |
|
1908
|
|
|
|
|
|
|
# chlorine nitrides |
|
1909
|
|
|
|
|
|
|
'^(?:Cl3N|NCl3)$', 'Cl=1_N=-3', |
|
1910
|
|
|
|
|
|
|
'.(?:ClN|NCl)', 'Cl=1_N=-3', |
|
1911
|
|
|
|
|
|
|
|
|
1912
|
|
|
|
|
|
|
'^Fe2P', 'P=5_Fe=-2;-3', |
|
1913
|
|
|
|
|
|
|
# exotic |
|
1914
|
|
|
|
|
|
|
'^FNO3$', 'F=1_N=5_O=-2', |
|
1915
|
|
|
|
|
|
|
] |
|
1916
|
|
|
|
|
|
|
} |
|
1917
|
|
|
|
|
|
|
|
|
1918
|
|
|
|
|
|
|
|
|
1919
|
|
|
|
|
|
|
1; |
|
1920
|
|
|
|
|
|
|
__END__ |