diff --git a/src/CryoGrid.jl b/src/CryoGrid.jl index 534709d4de6930e86cf1ca7e0af11189d184e2c0..dc5c3ae822b82fe81dd737c2a5582035c2366a26 100755 --- a/src/CryoGrid.jl +++ b/src/CryoGrid.jl @@ -11,7 +11,7 @@ using Reexport # Common types and methods export Layer, SubSurface, Top, Bottom -export Process, SubSurfaceProcess, BoundaryProcess, CompoundProcess, Coupled +export Process, SubSurfaceProcess, BoundaryProcess, CoupledProcesses, Coupled export BoundaryStyle, Dirichlet, Neumann export Callback, CallbackStyle include("types.jl") diff --git a/src/Drivers/Drivers.jl b/src/Drivers/Drivers.jl index 4f99e9db4fd1637a8a42ba7e1de85b1f20f5c176..733695e515359d40b16a3aa6c218bf1caa21ffb1 100644 --- a/src/Drivers/Drivers.jl +++ b/src/Drivers/Drivers.jl @@ -3,7 +3,7 @@ Module containing types and functions for enabling time-integration of a CryoGri """ module Drivers -using CryoGrid: Land, SubSurface, CompoundProcess, Callback, CallbackStyle, Discrete, Continuous +using CryoGrid: Land, SubSurface, CoupledProcesses, Callback, CallbackStyle, Discrete, Continuous using CryoGrid.InputOutput using CryoGrid.Numerics using CryoGrid.Physics: Heat @@ -40,7 +40,7 @@ JacobianStyle(::Type{<:Tile}) = DefaultJac() # Auto-detect Jacobian sparsity for problems with one or more heat-only layers. # Note: This assumes that the processes/forcings on the boundary layers do not violate the tridiagonal structure! # Unfortunately, the Stratigraphy type signature is a bit nasty to work with :( -const HeatOnlyTile = Tile{<:Stratigraphy{N,<:Tuple{TTop,Vararg{<:Union{<:StratComponent{<:SubSurface, <:CompoundProcess{<:Tuple{<:Heat}}},TBot}}}}} where {N,TTop,TBot} +const HeatOnlyTile = Tile{<:Stratigraphy{N,<:Tuple{TTop,Vararg{<:Union{<:StratComponent{<:SubSurface, <:CoupledProcesses{<:Tuple{<:Heat}}},TBot}}}}} where {N,TTop,TBot} JacobianStyle(::Type{<:HeatOnlyTile}) = TridiagJac() # DiffEq/SciML driver diff --git a/src/Land/Land.jl b/src/Land/Land.jl index 4eaed980d955bde2a79de254a2c8388a2e813efe..97dbadf7711a4a08995fd3a4c41ceb84ba1c70d5 100644 --- a/src/Land/Land.jl +++ b/src/Land/Land.jl @@ -1,6 +1,6 @@ module Land -import CryoGrid: Layer, Top, Bottom, SubSurface, Process, SubSurfaceProcess, BoundaryProcess, CompoundProcess +import CryoGrid: Layer, Top, Bottom, SubSurface, Process, SubSurfaceProcess, BoundaryProcess, CoupledProcesses import CryoGrid: variables, initialcondition!, prognosticstep!, diagnosticstep!, interact!, observe using CryoGrid.Layers diff --git a/src/Land/stratigraphy.jl b/src/Land/stratigraphy.jl index 0306b34db0a81c61188afd05ed9fb5675ca34092..281cc2e9212b7ffd39f89777d98cb416ccb9bfe7 100644 --- a/src/Land/stratigraphy.jl +++ b/src/Land/stratigraphy.jl @@ -6,7 +6,7 @@ Represents a single component (layer + processes) in the stratigraphy. struct StratComponent{TLayer,TProcess,name} layer::TLayer process::TProcess - StratComponent(name::Symbol, layer::TLayer, process::TProcess) where {TLayer<:Layer,TProcess<:CompoundProcess} = + StratComponent(name::Symbol, layer::TLayer, process::TProcess) where {TLayer<:Layer,TProcess<:CoupledProcesses} = new{TLayer,TProcess,name}(layer,process) end ConstructionBase.constructorof(::Type{StratComponent{TLayer,TProcess,name}}) where {TLayer,TProcess,name} = (layer,process) -> StratComponent(name, layer, process) @@ -19,9 +19,9 @@ componentname(::Type{<:StratComponent{L,P,name}}) where {L,P,name} = name Base.show(io::IO, node::StratComponent{L,P,name}) where {L,P,name} = print(io, "$name($L,$P)") # Constructors for stratigraphy nodes -top(bcs::BoundaryProcess...) = StratComponent(:top, Top(), CompoundProcess(bcs...)) -bottom(bcs::BoundaryProcess...) = StratComponent(:bottom, Bottom(), CompoundProcess(bcs...)) -subsurface(name::Symbol, layer::SubSurface, processes::SubSurfaceProcess...) = StratComponent(name, layer, CompoundProcess(processes...)) +top(bcs::BoundaryProcess...) = StratComponent(:top, Top(), CoupledProcesses(bcs...)) +bottom(bcs::BoundaryProcess...) = StratComponent(:bottom, Bottom(), CoupledProcesses(bcs...)) +subsurface(name::Symbol, layer::SubSurface, processes::SubSurfaceProcess...) = StratComponent(name, layer, CoupledProcesses(processes...)) """ Stratigraphy{N,TComponents,Q} diff --git a/src/Physics/Physics.jl b/src/Physics/Physics.jl index 7df1eb3ef4f6539779c99dd54de6a89edb2c3aa5..75fa839d7a03059986dbbb3579146d2f47fbc8f3 100644 --- a/src/Physics/Physics.jl +++ b/src/Physics/Physics.jl @@ -1,6 +1,6 @@ module Physics -import CryoGrid: Process, CompoundProcess, Coupled, Layer, Top, Bottom, SubSurface +import CryoGrid: Process, CoupledProcesses, Coupled, Layer, Top, Bottom, SubSurface import CryoGrid: diagnosticstep!, initialcondition!, interact!, prognosticstep!, variables, callbacks, observe using CryoGrid.Layers diff --git a/src/Physics/compound.jl b/src/Physics/coupled.jl similarity index 58% rename from src/Physics/compound.jl rename to src/Physics/coupled.jl index 0091bfc11edcab3e88417ce61f459f66ded9359d..6a135b613de46a86c395b06a10a3f4fb6e21cbbd 100644 --- a/src/Physics/compound.jl +++ b/src/Physics/coupled.jl @@ -1,19 +1,19 @@ # Default empty implementations of diagnostic_step! and prognostic_step! for boundary layers -diagnosticstep!(::Top, ::CompoundProcess, state) = nothing -prognosticstep!(::Top, ::CompoundProcess, state) = nothing -diagnosticstep!(::Bottom, ::CompoundProcess, state) = nothing -prognosticstep!(::Bottom, ::CompoundProcess, state) = nothing -variables(layer::Layer, ps::CompoundProcess) = tuplejoin((variables(layer,p) for p in ps.processes)...) -callbacks(layer::Layer, ps::CompoundProcess) = tuplejoin((callbacks(layer,p) for p in ps.processes)...) +diagnosticstep!(::Top, ::CoupledProcesses, state) = nothing +prognosticstep!(::Top, ::CoupledProcesses, state) = nothing +diagnosticstep!(::Bottom, ::CoupledProcesses, state) = nothing +prognosticstep!(::Bottom, ::CoupledProcesses, state) = nothing +variables(layer::Layer, ps::CoupledProcesses) = tuplejoin((variables(layer,p) for p in ps.processes)...) +callbacks(layer::Layer, ps::CoupledProcesses) = tuplejoin((callbacks(layer,p) for p in ps.processes)...) """ - interact!(l1::Layer, ps1::CompoundProcess{P1}, l2::Layer, ps2::CompoundProcess{P2}, s1, s2) where {P1,P2} + interact!(l1::Layer, ps1::CoupledProcesses{P1}, l2::Layer, ps2::CoupledProcesses{P2}, s1, s2) where {P1,P2} -Default implementation of `interact!` for multi-process (CompoundProcess) types. Generates a specialized implementation that calls +Default implementation of `interact!` for multi-process (CoupledProcesses) types. Generates a specialized implementation that calls `interact!` on all pairs of processes between the two layers. Since it is a generated function, the process matching occurs at compile-time and the emitted code will simply be a sequence of `interact!` calls. Pairs of processes which lack a definition of `interact!` should be automatically omitted by the compiler. """ -@generated function interact!(l1::Layer, ps1::CompoundProcess{P1}, l2::Layer, ps2::CompoundProcess{P2}, s1, s2) where {P1,P2} +@generated function interact!(l1::Layer, ps1::CoupledProcesses{P1}, l2::Layer, ps2::CoupledProcesses{P2}, s1, s2) where {P1,P2} p1types = Tuple(P1.parameters) p2types = Tuple(P2.parameters) crossprocesses = [(i,j) for (i,p1) in enumerate(p1types) for (j,p2) in enumerate(p2types)] @@ -26,11 +26,11 @@ lack a definition of `interact!` should be automatically omitted by the compiler return expr end """ - diagnosticstep!(l::Layer, ps::CompoundProcess{P}, state) where {P} + diagnosticstep!(l::Layer, ps::CoupledProcesses{P}, state) where {P} Default implementation of `diagnosticstep!` for multi-process types. Calls each process in sequence. """ -@generated function diagnosticstep!(l::Layer, ps::CompoundProcess{P}, state) where {P} +@generated function diagnosticstep!(l::Layer, ps::CoupledProcesses{P}, state) where {P} expr = Expr(:block) for i in 1:length(P.parameters) @>> quote @@ -40,11 +40,11 @@ Default implementation of `diagnosticstep!` for multi-process types. Calls each return expr end """ - prognosticstep!(l::Layer, ps::CompoundProcess{P}, state) where {P} + prognosticstep!(l::Layer, ps::CoupledProcesses{P}, state) where {P} Default implementation of `prognosticstep!` for multi-process types. Calls each process in sequence. """ -@generated function prognosticstep!(l::Layer, ps::CompoundProcess{P}, state) where {P} +@generated function prognosticstep!(l::Layer, ps::CoupledProcesses{P}, state) where {P} expr = Expr(:block) for i in 1:length(P.parameters) @>> quote @@ -54,11 +54,11 @@ Default implementation of `prognosticstep!` for multi-process types. Calls each return expr end """ - initialcondition!(l::Layer, ps::CompoundProcess{P}, state) where {P} + initialcondition!(l::Layer, ps::CoupledProcesses{P}, state) where {P} Default implementation of `initialcondition!` for multi-process types. Calls each process in sequence. """ -@generated function initialcondition!(l::Layer, ps::CompoundProcess{P}, state) where {P} +@generated function initialcondition!(l::Layer, ps::CoupledProcesses{P}, state) where {P} expr = Expr(:block) for i in 1:length(P.parameters) @>> quote @@ -68,11 +68,11 @@ Default implementation of `initialcondition!` for multi-process types. Calls eac return expr end """ - initialcondition!(l::Layer, ps::CompoundProcess{P}, state) where {P} + initialcondition!(l::Layer, ps::CoupledProcesses{P}, state) where {P} Default implementation of `initialcondition!` for multi-process types. Calls each process in sequence. """ -@generated function initialcondition!(l1::Layer, ps1::CompoundProcess{P1}, l2::Layer, ps2::CompoundProcess{P2}, s1, s2) where {P1,P2} +@generated function initialcondition!(l1::Layer, ps1::CoupledProcesses{P1}, l2::Layer, ps2::CoupledProcesses{P2}, s1, s2) where {P1,P2} p1types = Tuple(P1.parameters) p2types = Tuple(P2.parameters) crossprocesses = [(i,j) for (i,p1) in enumerate(p1types) for (j,p2) in enumerate(p2types)] @@ -85,11 +85,11 @@ Default implementation of `initialcondition!` for multi-process types. Calls eac return expr end """ - observe(::Val{name}, l::Layer, ps::CompoundProcess{P}, state) where {P} + observe(::Val{name}, l::Layer, ps::CoupledProcesses{P}, state) where {P} Default implementation of `observe` for multi-process types. Calls each process in sequence. """ -@generated function observe(val::Val{name}, l::Layer, ps::CompoundProcess{P}, state) where {name,P} +@generated function observe(val::Val{name}, l::Layer, ps::CoupledProcesses{P}, state) where {name,P} expr = Expr(:block) for i in 1:length(P.parameters) @>> quote diff --git a/src/types.jl b/src/types.jl index a8c983e52e513fe752801478f28e113adff0416a..1975aa700ea49691f17b4c5cde33bf26f194c0da 100644 --- a/src/types.jl +++ b/src/types.jl @@ -43,35 +43,35 @@ but may include its own diagnostic (or even prognostic) variables, if necessary. """ abstract type BoundaryProcess <: Process end """ - CompoundProcess{TProcs} <: Process + CoupledProcesses{TProcs} <: Process Represents an explicitly or implicitly coupled system of processes. `TProcs` is always a `Tuple` of other processes. """ -struct CompoundProcess{TProcs} <: Process +struct CoupledProcesses{TProcs} <: Process processes::TProcs - CompoundProcess(processes::Tuple{Vararg{Process}}) = new{typeof(processes)}(processes) - CompoundProcess(processes::SubSurfaceProcess...) = new{typeof(processes)}(processes) - CompoundProcess(processes::BoundaryProcess...) = new{typeof(processes)}(processes) + CoupledProcesses(processes::Tuple{Vararg{Process}}) = new{typeof(processes)}(processes) + CoupledProcesses(processes::SubSurfaceProcess...) = new{typeof(processes)}(processes) + CoupledProcesses(processes::BoundaryProcess...) = new{typeof(processes)}(processes) end -Base.iterate(cp::CompoundProcess) = Base.iterate(cp.processes) -Base.iterate(cp::CompoundProcess, state) = Base.iterate(cp.processes, state) +Base.iterate(cp::CoupledProcesses) = Base.iterate(cp.processes) +Base.iterate(cp::CoupledProcesses, state) = Base.iterate(cp.processes, state) """ - Coupled{P1,P2} = CompoundProcess{Tuple{T1,T2}} where {T1,T2} + Coupled{P1,P2} = CoupledProcesses{Tuple{T1,T2}} where {T1,T2} -Represents an explicitly coupled pair processes. Alias for `CompoundProcess{Tuple{P1,P2}}`. +Represents an explicitly coupled pair processes. Alias for `CoupledProcesses{Tuple{P1,P2}}`. `Coupled` provides a simple mechanism for defining new behaviors on multi-processes systems. """ -const Coupled{P1,P2} = CompoundProcess{Tuple{T1,T2}} where {T1,T2} +const Coupled{P1,P2} = CoupledProcesses{Tuple{T1,T2}} where {T1,T2} """ Coupled(p1,p2) -Alias for `CompoundProcess(p1,p2)`. +Alias for `CoupledProcesses(p1,p2)`. """ -Coupled(p1::P1, p2::P2) where {P1<:Process,P2<:Process} = CompoundProcess(p1,p2) +Coupled(p1::P1, p2::P2) where {P1<:Process,P2<:Process} = CoupledProcesses(p1,p2) # Base methods -Base.show(io::IO, ps::CompoundProcess{T}) where T = print(io, "$T") -@propagate_inbounds @inline Base.getindex(ps::CompoundProcess, i) = ps.processes[i] +Base.show(io::IO, ps::CoupledProcesses{T}) where T = print(io, "$T") +@propagate_inbounds @inline Base.getindex(ps::CoupledProcesses, i) = ps.processes[i] # allow broadcasting of Process types Base.Broadcast.broadcastable(p::Process) = Ref(p) diff --git a/test/Land/stratigraphy_tests.jl b/test/Land/stratigraphy_tests.jl index 90ac66d4adf0ed328fe3d4b61e7958b268cba2d0..ee0450e9e62cf08b4e480ed6b6849abef7f2036f 100644 --- a/test/Land/stratigraphy_tests.jl +++ b/test/Land/stratigraphy_tests.jl @@ -18,15 +18,15 @@ include("../types.jl") if i == 1 @test CryoGrid.componentname(component) == :top @test typeof(component.layer) <: Top - @test typeof(component.process) <: CompoundProcess{Tuple{TestBoundary}} + @test typeof(component.process) <: CoupledProcesses{Tuple{TestBoundary}} elseif i == 2 @test CryoGrid.componentname(component) == :testground @test typeof(component.layer) <: TestGroundLayer - @test typeof(component.process) <: CompoundProcess{Tuple{TestGroundProcess}} + @test typeof(component.process) <: CoupledProcesses{Tuple{TestGroundProcess}} elseif i == 3 @test CryoGrid.componentname(component) == :bottom @test typeof(component.layer) <: Bottom - @test typeof(component.process) <: CompoundProcess{Tuple{TestBoundary}} + @test typeof(component.process) <: CoupledProcesses{Tuple{TestBoundary}} end end end @@ -46,19 +46,19 @@ include("../types.jl") if i == 1 @test CryoGrid.componentname(component) == :top @test typeof(component.layer) <: Top - @test typeof(component.process) <: CompoundProcess{Tuple{TestBoundary}} + @test typeof(component.process) <: CoupledProcesses{Tuple{TestBoundary}} elseif i == 2 @test CryoGrid.componentname(component) == :testground1 @test typeof(component.layer) <: TestGroundLayer - @test typeof(component.process) <: CompoundProcess{Tuple{TestGroundProcess}} + @test typeof(component.process) <: CoupledProcesses{Tuple{TestGroundProcess}} elseif i == 3 @test CryoGrid.componentname(component) == :testground2 @test typeof(component.layer) <: TestGroundLayer - @test typeof(component.process) <: CompoundProcess{Tuple{TestGroundProcess}} + @test typeof(component.process) <: CoupledProcesses{Tuple{TestGroundProcess}} elseif i == 4 @test CryoGrid.componentname(component) == :bottom @test typeof(component.layer) <: Bottom - @test typeof(component.process) <: CompoundProcess{Tuple{TestBoundary}} + @test typeof(component.process) <: CoupledProcesses{Tuple{TestBoundary}} end end end