There’s really no good way to initialize simulations without any programming knowledge unless you’re willing to build a GUI, which can be quite expensive and time-consuming. Higher-order functions may work well enough if you provide example scripts and a few geometric primitives (box, circle, line, ellipsoid, …). I’d recommend Unitful.jl to handle different input units on the frontend, with everything converted internally to a consistent unit system on the backend.
As for specification of higher-order functions, the user should provide a function f(x, y)
that’s independent of the grid. If all material interfaces are initially sharp (i.e. materials start unmixed), you could do something like this:
using Unitful
@derived_dimension MassDiffusivity Unitful.𝐋^2/Unitful.𝐓
struct DiffusiveMaterial
D::Float64 # Mass diffusivity
ρ::Float64 # Density
function DiffusiveMaterial(D, ρ)
D < 0 && error("Diffusivity must be positive")
ρ < 0 && error("Density must be positive")
new(D, ρ)
end
end
# Convert to uniform internal units
function DiffusiveMaterial(D::MassDiffusivity, ρ::Unitful.Density)
DiffusiveMaterial(ustrip(u"m^2/s", D), ustrip(u"kg/m^3", ρ))
end
struct Domain{T <: AbstractRange}
x::T
y::T
D::Array{Float64, 2}
ρ::Array{Float64, 2}
materials::Dict{Symbol, DiffusiveMaterial}
function Domain(x::T, y::T, materials) where {T}
return new{T}(x, y,
Array{Float64}(undef, length(x), length(y)),
Array{Float64}(undef, length(x), length(y)),
materials)
end
end
function initialize!(material, d::Domain)
for (j, y) in enumerate(d.y), (i, x) in enumerate(d.x)
m = material(x, y)
d.D[i, j] = d.materials[m].D
d.ρ[i, j] = d.materials[m].ρ
end
end
incircle(x₀, y₀, R) = (x, y) -> hypot(x - x₀, y - y₀) <= R
inrectangle(x₀, y₀, x₁, y₁) = (x, y) -> x₀ <= x <= x₁ && y₀ <= y <= y₁
which would allow the user to initialize a model like this
materials = Dict(:Mud => DiffusiveMaterial(1.0e-7u"cm^2/s", 2.65e3u"kg/m^3"),
:Water => DiffusiveMaterial(1.0e-6u"cm^2/s", 1000u"kg/m^3"),
:Ethanol => DiffusiveMaterial(8.0e-6u"cm^2/s", 800u"kg/m^3"),)
d = Domain(LinRange(0, 100, 512), LinRange(0, 200, 1024), materials)
initialize!(d) do x, y
if incircle(50, 50, 20)(x, y)
:Ethanol
elseif inrectangle(0, 0, 200, 30)(x, y)
:Mud
else
:Water
end
end