Skip to content

Commit 6be5e72

Browse files
committed
Corrected domain issues
Added a `ProblemDomain` type and a domain check function the generalize the GaussianPlumeSolution. Previously it was ignoring the mixing layer when deciding on the domain of the problem. Added a limiter to plume rise, forcing plume rise below the mixing layer.
1 parent 25ac410 commit 6be5e72

5 files changed

Lines changed: 59 additions & 16 deletions

File tree

src/models/gaussian_mixing_layer.jl

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ function plume(scenario::Scenario, ::Type{GaussianMixingLayer}, eqs=DefaultSet()
107107
error("Unknown mixing layer method: $method")
108108
end
109109

110+
# domain
111+
dom = ProblemDomain(0.0, Inf, -Inf, Inf, 0.0, hₘ)
112+
110113
return GaussianPlumeSolution(
111114
scenario, # scenario::Scenario
112115
:simplemixinglayer, # model::Symbol
@@ -119,8 +122,8 @@ function plume(scenario::Scenario, ::Type{GaussianMixingLayer}, eqs=DefaultSet()
119122
ml,
120123
NoPlumeRise(), # plume rise model
121124
_stability(scenario), # stability class
122-
eqs # equation set
123-
)
125+
eqs, # equation set
126+
dom) # problem domain
124127
end
125128

126129
@doc doc"""
@@ -200,6 +203,10 @@ function plume(scenario::Scenario{<:AbstractSubstance,<:VerticalJet,<:Atmosphere
200203
if plumerise == true
201204
Tᵣ = _release_temperature(scenario)
202205
plume = plume_rise(Dⱼ,uⱼ,Tᵣ,u,Tₐ,Γ,stab)
206+
if plume.final_rise > hₘ-hᵣ
207+
@warn "Plume rise $(plume.final_rise) exceeds mixing height $hₘ, plume rise is limited to the mixing height."
208+
plume = _new_plume_rise(plume, hₘ)
209+
end
203210
else
204211
plume = NoPlumeRise()
205212
end
@@ -217,6 +224,9 @@ function plume(scenario::Scenario{<:AbstractSubstance,<:VerticalJet,<:Atmosphere
217224
error("Unknown mixing layer method: $method")
218225
end
219226

227+
# domain
228+
dom = ProblemDomain(0.0, Inf, -Inf, Inf, 0.0, hₘ)
229+
220230
return GaussianPlumeSolution(
221231
scenario, #scenario::Scenario
222232
:simplemixinglayer, #model::Symbol
@@ -229,6 +239,6 @@ function plume(scenario::Scenario{<:AbstractSubstance,<:VerticalJet,<:Atmosphere
229239
ml,
230240
plume, #plume rise model
231241
stab, #stability class
232-
eqs #equation set
233-
)
242+
eqs, #equation set
243+
dom) #problem domain
234244
end

src/models/gaussian_plume.jl

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ abstract type GaussianVerticalTerm end
66
struct GaussianPlume <: PlumeModel end
77

88
# Solution to the gaussian plume
9-
struct GaussianPlumeSolution{F<:Number,C<:GaussianCrossTerm,V<:GaussianVerticalTerm,P<:PlumeRise,S<:StabilityClass,E<:EquationSet} <: Plume
9+
struct GaussianPlumeSolution{F<:Number,C<:GaussianCrossTerm,V<:GaussianVerticalTerm,P<:PlumeRise,S<:StabilityClass,E<:EquationSet,D<:ProblemDomain} <: Plume
1010
scenario::Scenario
1111
model::Symbol
1212
rate::F
@@ -19,8 +19,9 @@ struct GaussianPlumeSolution{F<:Number,C<:GaussianCrossTerm,V<:GaussianVerticalT
1919
plumerise::P
2020
stability::Type{S}
2121
equationset::E
22+
domain::D
2223
end
23-
GaussianPlumeSolution(s,m,Q,c,ρ,u,h_eff,cross,vert,pr,stab,es) = GaussianPlumeSolution(s,m,promote(Q,c,ρ,u,h_eff)...,cross,vert,pr,stab,es)
24+
GaussianPlumeSolution(s,m,Q,c,ρ,u,h_eff,cross,vert,pr,stab,es,dom) = GaussianPlumeSolution(s,m,promote(Q,c,ρ,u,h_eff)...,cross,vert,pr,stab,es,dom)
2425

2526
struct SimpleCrossTerm <: GaussianCrossTerm end
2627
cross_term(y, σy, ::SimpleCrossTerm) = exp(-0.5*(y/σy)^2)/((2π)*σy)
@@ -67,20 +68,23 @@ function plume(scenario::Scenario, ::Type{GaussianPlume}, eqs=DefaultSet(); h_mi
6768
c_max = m/Qᵒ
6869
c_max = c_max/ρₐ
6970

71+
# domain
72+
dom = ProblemDomain(0.0, Inf, -Inf, Inf, 0.0, Inf)
73+
7074
return GaussianPlumeSolution(
7175
scenario, # scenario::Scenario
7276
:gaussian, # model::Symbol
7377
m, # mass emission rate
7478
c_max, # max_concentration
75-
ρₐ, # mass concentration to vol concentration
76-
windspeed(scenario,max(hᵣ,h_min),eqs), # windspeed
79+
ρₐ, # mass concentration to vol concentration
80+
windspeed(scenario,max(hᵣ,h_min),eqs), # windspeed
7781
hᵣ, # effective_stack_height::Number
7882
SimpleCrossTerm(),
7983
SimpleVerticalTerm(),
8084
NoPlumeRise(), # plume rise model
8185
_stability(scenario), # stability class
82-
eqs # equation set
83-
)
86+
eqs, # equation set
87+
dom) # problem domain
8488
end
8589

8690
@doc doc"""
@@ -151,6 +155,9 @@ function plume(scenario::Scenario{<:AbstractSubstance,<:VerticalJet,<:Atmosphere
151155
plume = NoPlumeRise()
152156
end
153157

158+
# domain
159+
dom = ProblemDomain(0.0, Inf, -Inf, Inf, 0.0, Inf)
160+
154161
return GaussianPlumeSolution(
155162
scenario, #scenario::Scenario
156163
:gaussian, #model::Symbol
@@ -163,16 +170,16 @@ function plume(scenario::Scenario{<:AbstractSubstance,<:VerticalJet,<:Atmosphere
163170
SimpleVerticalTerm(),
164171
plume, #plume rise model
165172
stab, #stability class
166-
eqs #equation set
167-
)
173+
eqs, #equation set
174+
dom) #problem domain
168175
end
169176

170177
function (g::GaussianPlumeSolution{F,C,V,NoPlumeRise,S,E})(x, y, z, t=0) where {F,C,V,S,E}
171178
# domain check
172179
h = g.effective_stack_height
173180
if (x==0)&&(y==0)&&(z==h)
174181
return g.max_concentration
175-
elseif (x0)||(z<0)
182+
elseif _in_domain(x,y,z,g.domain) == false
176183
return zero(F)
177184
else
178185
G = g.rate
@@ -197,7 +204,7 @@ function (g::GaussianPlumeSolution{F,C,V,<:BriggsModel,S,E})(x, y, z, t=0) where
197204
h = g.effective_stack_height
198205
if (x==0)&&(y==0)&&(z==h)
199206
return g.max_concentration
200-
elseif (x0)||(z<0)
207+
elseif _in_domain(x,y,z,g.domain) == false
201208
return zero(F)
202209
else
203210
G = g.rate

src/utils/plume_rise.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ Base.isapprox(a::MomentumPlume, b::MomentumPlume) = all([
3131
if typeof(getproperty(a,k))<:Number ])
3232

3333

34+
# some helper functions to limit the plume rise, e.g. when a mixing layer prevents the plume from rising too high
35+
"""
36+
_new_plume_rise(plume::BriggsModel, max_rise::Number)
37+
Creates a new plume rise model with the same parameters as `plume`, but limits the final
38+
rise to `max_rise`. This is useful when the plume rise exceeds the mixing height or
39+
other constraints in the model.
40+
"""
41+
_new_plume_rise(plume::BuoyantPlume, max_rise::Number) = BuoyantPlume(plume.Fb, plume.xf, plume.u, max_rise)
42+
_new_plume_rise(plume::MomentumPlume, max_rise::Number) = MomentumPlume(plume.Fm, plume.xf, plume.β, plume.u, plume.s, max_rise, plume.stab)
43+
3444
"""
3545
plume_rise(Dⱼ,uⱼ,Tᵣ,a::Atmosphere)
3646
Implements the Briggs plume rise equations for buoyancy and momentum driven

src/utils/utils.jl

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,20 @@ include("equation_sets/isc3.jl")
2727

2828
# Default correlations
2929
DefaultSet = BasicEquationSet{DefaultWind,Nothing,Defaultσy,Defaultσz}
30-
DefaultPuffSet = BasicEquationSet{DefaultWind,CCPSPuffσx,CCPSPuffσy,CCPSPuffσz}
30+
DefaultPuffSet = BasicEquationSet{DefaultWind,CCPSPuffσx,CCPSPuffσy,CCPSPuffσz}
31+
32+
# a lazy check for if x,y,z are in the domain
33+
struct ProblemDomain{F<:Number}
34+
xmin::F
35+
xmax::F
36+
ymin::F
37+
ymax::F
38+
zmin::F
39+
zmax::F
40+
end
41+
42+
function _in_domain(x::Number, y::Number, z::Number, domain::ProblemDomain)
43+
return x domain.xmin && x domain.xmax &&
44+
y domain.ymin && y domain.ymax &&
45+
z domain.zmin && z domain.zmax
46+
end

test/models/gaussian_plume_tests.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
pl = plume(scn)
3131

3232
# test default behaviour and type inheritance
33-
@test GasDispersion.GaussianPlumeSolution(scn,:test,1.0,2,3,4,5,GasDispersion.SimpleCrossTerm(),GasDispersion.SimpleVerticalTerm(),GasDispersion.NoPlumeRise(),ClassA,DefaultSet()) isa GasDispersion.GaussianPlumeSolution{Float64, GasDispersion.SimpleCrossTerm, GasDispersion.SimpleVerticalTerm, GasDispersion.NoPlumeRise, ClassA, GasDispersion.BasicEquationSet{GasDispersion.DefaultWind, Nothing, GasDispersion.Defaultσy, GasDispersion.Defaultσz}}
33+
@test GasDispersion.GaussianPlumeSolution(scn,:test,1.0,2,3,4,5,GasDispersion.SimpleCrossTerm(),GasDispersion.SimpleVerticalTerm(),GasDispersion.NoPlumeRise(),ClassA,DefaultSet(),GasDispersion.ProblemDomain(0.0,Inf,-Inf,Inf,0.0,Inf)) isa GasDispersion.GaussianPlumeSolution{Float64, GasDispersion.SimpleCrossTerm, GasDispersion.SimpleVerticalTerm, GasDispersion.NoPlumeRise, ClassA, GasDispersion.BasicEquationSet{GasDispersion.DefaultWind, Nothing, GasDispersion.Defaultσy, GasDispersion.Defaultσz}, GasDispersion.ProblemDomain{Float64}}
3434
@test pl isa GasDispersion.GaussianPlumeSolution
3535
@test pl isa Plume
3636
@test pl(-1,0,0) == 0.0

0 commit comments

Comments
 (0)