Skip to content

Commit 2af70fa

Browse files
authored
Merge pull request #174 from ReactionMechanismGenerator/analyzecrash
Analyze Crashes
2 parents 9ceffea + ecb2a21 commit 2af70fa

6 files changed

Lines changed: 2453 additions & 0 deletions

File tree

Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ SmoothingSplines = "102930c3-cf33-599f-b3b1-9a29a5acab30"
2929
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
3030
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
3131
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
32+
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
3233
Sundials = "c3572dad-4567-51f8-b174-8c6c989267f4"
3334
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
3435
Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c"

iJulia/Crash Analysis.ipynb

Lines changed: 2133 additions & 0 deletions
Large diffs are not rendered by default.

src/Debugging.jl

Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
using Parameters
2+
using Statistics
3+
4+
"""
5+
Object for storing useful debugging information about potentially problematic species
6+
tol is the tolerance analyzed at, G is the Gibbs free energy, dy is
7+
the flux to that species and ratio is the ratio between dy and the flux scale
8+
index is the index of the species
9+
"""
10+
@with_kw struct DebugSpecies
11+
name::String
12+
G::Float64 = 0.0
13+
ratio::Float64 = 0.0
14+
dy::Float64 = 0.0
15+
tol::Float64 = 0.0
16+
index::Int64 = 0
17+
end
18+
19+
"""
20+
Object for storing useful debugging information about potentially problematic reactions
21+
tol is the tolerance analyzed at, kf and krev are the forward and reverse rate coefficients
22+
rt is the rate of the reaction, ratio is the ratio between rt and the rate scale
23+
T and P are the temperature and pressure and index is the index of the reaction
24+
"""
25+
@with_kw struct DebugReaction
26+
reactants::Array{DebugSpecies,1}
27+
products::Array{DebugSpecies,1}
28+
rxnstring::String
29+
tol::Float64 = 0.0
30+
kf::Float64 = 0.0
31+
krev::Float64 = 0.0
32+
rt::Float64 = 0.0
33+
ratio::Float64 = 0.0
34+
T::Float64 = 0.0
35+
P::Float64 = 0.0
36+
index::Int64 = 0
37+
end
38+
39+
struct DebugMech
40+
spcs::Array{DebugSpecies,1}
41+
rxns::Array{DebugReaction,1}
42+
end
43+
44+
function getdebugreaction(rxn::ElementaryReaction;tol=0.0,kf=0.0,krev=0.0,rt=0.0,ratio=0.0,T=0.0,P=0.0,index=0)
45+
return DebugReaction([getdebugspecies(spc,T) for spc in rxn.reactants],
46+
[getdebugspecies(spc,T) for spc in rxn.products],
47+
getrxnstr(rxn),tol,kf,krev,rt,ratio,T,P,index)
48+
end
49+
50+
export getdebugreaction
51+
52+
function getdebugspecies(spc::Species,T::Float64;dy=0.0,ratio=0.0,tol=0.0,index=0)
53+
G = getGibbs(spc.thermo,T)
54+
return DebugSpecies(spc.name,G,ratio,dy,tol,index)
55+
end
56+
57+
export getdebugspecies
58+
59+
"""
60+
This function prints a report analyzing rates and dydt to determine reactions
61+
and thermochemistry worth looking at
62+
sim should be a simulation object created from a solution object corresponding to a crash
63+
tol is the ratio relative to the median absolute rate or dn_i/dt value above which reactions
64+
and species will be reported
65+
"""
66+
function analyzecrash(sim::Simulation;tol=1e6)
67+
rxns = Array{DebugReaction,1}()
68+
spcs = Array{DebugSpecies,1}()
69+
t = sim.sol.t[end]
70+
T = getT(sim,t)
71+
rts = rates(sim,t)
72+
rmedian = median(abs.([rt for rt in rts if !isnan(rt) && rt != 0.0]))
73+
dydt = zeros(length(sim.sol.u[end]))
74+
dydtreactor!(dydt,sim.sol.u[end],0.0,sim.domain,sim.interfaces;p=sim.p)
75+
dymedian = median(abs.([dy for dy in dydt if !isnan(dy) && dy != 0.0]))
76+
y = sim.sol(t)
77+
p = sim.domain.p
78+
ns,cs,T,P,V,C,N,mu,kfs,krevs,Hs,Us,Gs,diffs,Cvave,cpdivR = calcthermo(sim.domain,y,t,p)
79+
for (i,rt) in enumerate(rts)
80+
if isnan(rt)
81+
push!(rxns,getdebugreaction(sim.reactions[i];tol=tol,kf=kfs[i],krev=krevs[i],rt=rt,T=T,ratio=NaN,index=i))
82+
elseif abs(rt/rmedian) > tol
83+
ratio = abs(rt/rmedian)
84+
push!(rxns,getdebugreaction(sim.reactions[i];tol=tol,kf=kfs[i],krev=krev[i],rt=rt,T=T,ratio=ratio,index=i))
85+
end
86+
end
87+
for (i,dy) in enumerate(dydt)
88+
if i > length(sim.species)
89+
continue
90+
end
91+
if isnan(dy)
92+
push!(spcs,getdebugspecies(sim.species[i],T;dy=dy,ratio=NaN,tol=tol,index=i))
93+
elseif abs(dy/dymedian) > tol
94+
ratio = abs(dy/dymedian)
95+
push!(spcs,getdebugspecies(sim.species[i],T;dy=dy,ratio=ratio,tol=tol,index=i))
96+
end
97+
end
98+
return DebugMech(spcs,rxns)
99+
end
100+
101+
"""
102+
This function prints a report analyzing rates and dydt to determine reactions
103+
and thermochemistry worth looking at
104+
sim should be a simulation object created from a solution object corresponding to a crash
105+
tol is the ratio relative to the median absolute rate or dn_i/dt value above which reactions
106+
and species will be reported
107+
"""
108+
function analyzecrash(sim::SystemSimulation;tol=1e6)
109+
rxns = Array{DebugReaction,1}()
110+
spcs = Array{DebugSpecies,1}()
111+
t = sim.sol.t[end]
112+
rts = rates(sim,t)
113+
rmedian = median(abs.([rt for rt in rts if !isnan(rt) && rt != 0.0]))
114+
dydt = zeros(length(sim.sol.u[end]))
115+
dydtreactor!(dydt,sim.sol.u[end],0.0,tuple([s.domain for s in sim.sims]),sim.interfaces;p=sim.p)
116+
dymedian = median(abs.([dy for dy in dydt if !isnan(dy) && dy != 0.0]))
117+
y = sim.sol(t)
118+
p = sim.domain.p
119+
ns,cs,T,P,V,C,N,mu,kfs,krevs,Hs,Us,Gs,diffs,Cvave,cpdivR = calcthermo(sim.domain,y,t,p)
120+
for (i,rt) in enumerate(rts)
121+
if isnan(rt)
122+
push!(rxns,getdebugreaction(sim.reactions[i];tol=tol,kf=kfs[i],krev=krevs[i],rt=rt,ratio=NaN,index=i))
123+
elseif abs(rt/rmedian) > tol
124+
ratio = abs(rt/rmedian)
125+
push!(rxns,getdebugreaction(sim.reactions[i];tol=tol,kf=kfs[i],krev=krev[i],rt=rt,ratio=ratio,index=i))
126+
end
127+
end
128+
for (i,dy) in enumerate(dydt)
129+
if i > length(sim.species)
130+
continue
131+
end
132+
if isnan(dy)
133+
push!(spcs,getdebugspecies(sim.species[i];dy=dy,ratio=NaN,tol=tol,index=i))
134+
elseif abs(dy/dymedian) > tol
135+
ratio = abs(dy/dymedian)
136+
push!(spcs,getdebugspecies(sim.species[i];dy=dy,ratio=ratio,tol=tol,index=i))
137+
end
138+
end
139+
return DebugMech(spcs,rxns)
140+
end
141+
export analyzecrash
142+
143+
function getdebugmechstring(mech::DebugMech)
144+
s = "Crash Analysis Report\n"
145+
for rxn in mech.rxns
146+
s *= getdebugrxnstring(rxn)
147+
end
148+
for spc in mech.spcs
149+
s *= getdebugspeciesstring(spc)
150+
end
151+
return s
152+
end
153+
154+
export getdebugmechstring
155+
156+
function getdebugrxnstring(rxn)
157+
s = ""
158+
rt = rxn.rt
159+
tol = rxn.tol
160+
ratio = rxn.ratio
161+
kf = rxn.kf
162+
krev = rxn.krev
163+
index = rxn.index
164+
if isnan(rt)
165+
s *= "NaN for Reaction:\n"
166+
elseif ratio > tol
167+
s *= "rt/rmedian > $tol, rt=$rt, rt/rmedian=$ratio \nReaction:\n"
168+
end
169+
s *= "Index: $index\n"
170+
s *= rxn.rxnstring * "\n"
171+
if length(rxn.reactants) == 1
172+
kunitsf = "s^-1"
173+
elseif length(rxn.reactants) == 2
174+
kunitsf = "m^3/(mol*s)"
175+
elseif length(rxn.reactants) == 3
176+
kunitsf = "m^6/(mol^2*s)"
177+
else
178+
error("cannot accomodate reactants>3")
179+
end
180+
if length(rxn.products) == 1
181+
kunitsr = "s^-1"
182+
elseif length(rxn.products) == 2
183+
kunitsr = "m^3/(mol*s)"
184+
elseif length(rxn.products) == 3
185+
kunitsr = "m^6/(mol^2*s)"
186+
else
187+
error("cannot accomodate products>3")
188+
end
189+
s *= "kf: $kf $kunitsf\n"
190+
s *= "krev: $krev $kunitsr\n"
191+
s *= "Reactants: \n"
192+
for reactant in rxn.reactants
193+
s *= getdebugspeciesstring(reactant)
194+
end
195+
s *= "Products: \n"
196+
for product in rxn.products
197+
s *= getdebugspeciesstring(product)
198+
end
199+
return s
200+
end
201+
202+
export getdebugreactionstring
203+
204+
function getdebugspeciesstring(spc)
205+
s = ""
206+
dy = spc.dy
207+
ratio = spc.ratio
208+
tol = spc.tol
209+
index = spc.index
210+
if isnan(dy)
211+
s *= "NaN for Species net flux:\n"
212+
elseif ratio> tol
213+
s *= "dydt/dydtmedian > $tol, dydt=$dy, dydt/dydtmedian=$ratio \nSpecies:\n"
214+
end
215+
if index != 0
216+
s *= "Index: $index\n"
217+
end
218+
G = spc.G/4184.0
219+
name = spc.name
220+
s *= "\t$name G(T): $G kcal/mol\n"
221+
return s
222+
end
223+
224+
export getdebugspeciesstring
225+
226+
function printcrashanalysis(mech::DebugMech)
227+
println(getdebugmechstring(mech))
228+
end
229+
230+
function printcrashanalysis(sim::Simulation;tol=1e6)
231+
printcrashanalysis(analyzecrash(sim;tol=tol))
232+
end
233+
234+
export printcrashanalysis
235+
236+
"""
237+
This calculates the collision limit of H + H -> H2 as an upper bound
238+
"""
239+
function calccollisionlimit(T)
240+
mu = 0.00050397
241+
sigma = 2.05e-10
242+
epsilon = 1205.6
243+
Tr = T*kB*Na/epsilon
244+
collintegral = 1.16145*Tr^(-0.14874)+0.52487*exp(-0.7732 * Tr)+2.16178*exp(-2.437887*Tr)
245+
kcoll = sqrt(8.0*pi*kB*T*Na/mu)*sigma^2*collintegral*Na
246+
return kcoll
247+
end
248+
249+
export calccollisionlimit
250+
251+
"""
252+
Compares bimolecular and trimolecular reactions with the collision limit for H+H->H2
253+
to check whether they are physical, a report with only a title and kcoll means no violators
254+
"""
255+
function analyzecolllimit(phase,Tmin,Tmax,Pmin,Pmax)
256+
println("Collision Limit Report (Comparisons are done with collision limit for H+H->H2)")
257+
println("kcoll=$kcoll")
258+
for T in [Tmin,Tmax]
259+
for P in [Pmin,Pmax]
260+
kcoll = calccollisionlimit(T)
261+
cpdivR,hdivRT,sdivR = calcHSCpdless(phase.vecthermo,T)
262+
Gs = (hdivRT.-sdivR)*(R*T)
263+
if phase.diffusionlimited
264+
diffs = getfield.(phase.species,:diffusion)(T=T,mu=0.0,P=P)
265+
else
266+
diffs = Array{Float64,1}()
267+
end
268+
kfs,krevs = getkfkrevs(phase,T,P,P/(R*T),1.0,Gs,diffs,V=1.0/C)
269+
for (i,rxn) in enumerate(phase.reactions)
270+
boo = false
271+
if len(rxn.reactants) > 2
272+
if kfs[i] > kcoll
273+
if !boo
274+
println(getrxnstr(rxn))
275+
boo = true
276+
end
277+
kf = kfs[i]
278+
ratio = kfs[i]/kcoll
279+
println("Violated in forward direction kf=$kf ratio=$ratio T=$T P=$P")
280+
end
281+
end
282+
if len(rxn.products) > 2
283+
if krevs[i] > kcoll
284+
if !boo
285+
println(getrxnstr(rxn))
286+
boo = true
287+
end
288+
krev = krevs[i]
289+
ratio = krevs[i]/kcoll
290+
println("Violated in forward direction krev=$krev ratio=$ratio T=$T P=$P")
291+
end
292+
end
293+
end
294+
end
295+
end
296+
end
297+
298+
export analyzecolllimit

src/ReactionMechanismSimulator.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ module ReactionMechanismSimulator
5757
include("TransitorySensitivities.jl")
5858
include("AutomaticMechanismAnalysis.jl")
5959
include("EdgeAnalysis.jl")
60+
include("Debugging.jl")
6061
include("Plotting.jl")
6162
include("fluxdiagrams.jl")
6263
end

src/TestReactors.jl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,4 +448,23 @@ end;
448448
@test concentrations(ssys,"OX",0.5e-5) 1.9165723392283484e-5 rtol=1e-5
449449
@test molefractions(ssys.sims[1],"H2O",1e-3) 0.12732345278036702 rtol=1e-5
450450
end;
451+
452+
@testset "Test Crash Analysis" begin
453+
#Define the phase (how species thermodynamic and kinetic properties calculated)
454+
phaseDict = readinput("../src/testing/superminimal_broken.rms")
455+
spcs = phaseDict["phase"]["Species"];
456+
rxns = phaseDict["phase"]["Reactions"];
457+
ig = IdealGas(spcs,rxns;name="gas");
458+
initialconds = Dict(["T"=>1000.0,"P"=>1e5,"H2"=>0.67,"O2"=>0.33]) #Set simulation Initial Temp and Pressure
459+
domain,y0,p = ConstantTPDomain(phase=ig,initialconds=initialconds) #Define the domain (encodes how system thermodynamic properties calculated)
460+
461+
react = Reactor(domain,y0,(0.0,150.11094);p=p) #Create the reactor object
462+
sol = solve(react.ode,CVODE_BDF(),abstol=1e-20,reltol=1e-12); #solve the ode associated with the reactor
463+
sim = Simulation(sol,domain,[],p);
464+
465+
dmech = analyzecrash(sim)
466+
@test length(dmech.rxns) == 1
467+
@test length(dmech.spcs) == 4
468+
@test dmech.rxns[1].index == 11
469+
end;
451470
end;

src/rmstest.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ include("Reactor.jl")
2727
include("Simulation.jl")
2828
include("TransitorySensitivities.jl")
2929
include("AutomaticMechanismAnalysis.jl")
30+
include("Debugging.jl")
3031
include("EdgeAnalysis.jl")
3132
include("Plotting.jl")
3233
include("fluxdiagrams.jl")

0 commit comments

Comments
 (0)