Skip to content

Commit

Permalink
Merge pull request #60 from ODINN-SciML/purejulia
Browse files Browse the repository at this point in the history
Migrate to pure julia
  • Loading branch information
albangossard authored Jan 23, 2025
2 parents b13413f + 2413919 commit 1b5618b
Show file tree
Hide file tree
Showing 16 changed files with 76 additions and 151 deletions.
53 changes: 14 additions & 39 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,42 +22,14 @@ jobs:
fail-fast: false
matrix:
version:
- '1.10'
python: [3.9]
- '1.11'
os:
- ubuntu-latest
- macos-latest
arch:
- x64
steps:
- uses: actions/checkout@v2
- name: Set up Python 🐍 ${{ matrix.python }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python }}
- name: Create environment with micromamba 🐍🖤
uses: mamba-org/setup-micromamba@v1
with:
micromamba-version: '1.5.6-0'
environment-file: ./environment.yml
environment-name: oggm_env # it is recommendable to add both name and yml file.
init-shell: bash
cache-environment: true
# condarc-file: ./condarc.yml # If necessary, we can include .condarc to configure environment
- name: Test creation of environment with micromamba 🔧🐍🖤
run: |
which python
conda env export
shell: bash -el {0}
- name: Update certifi
run: |
pip install --upgrade certifi
shell: bash -el {0}
# - name: Test OGGM installation 🔧🌎
# run: pytest.oggm
# shell: bash -el {0}
- name: Set ENV Variables for PyCall.jl 🐍 📞
run: export PYTHON=/home/runner/micromamba/envs/oggm_env/bin/python
shell: bash -el {0}
- uses: julia-actions/setup-julia@v1
with:
version: ${{ matrix.version }}
Expand All @@ -69,15 +41,18 @@ jobs:
with:
cache-registries: "true"
cache-compiled: "true"
- uses: julia-actions/julia-buildpkg@v1
env:
PYTHON : /home/runner/micromamba/envs/oggm_env/bin/python
# The SSL certificate path can be readed from the action "Check Julia SSL certifications"
SSL_CERT_FILE: /etc/ssl/certs/ca-certificates.crt
- uses: julia-actions/julia-runtest@v1
env:
PYTHON : /home/runner/micromamba/envs/oggm_env/bin/python
SSL_CERT_FILE: /etc/ssl/certs/ca-certificates.crt
- name: Build Julia packages in Ubuntu
uses: julia-actions/julia-buildpkg@v1
if: matrix.os == 'ubuntu-latest'
- name: Build Julia packages in MacOS
uses: julia-actions/julia-buildpkg@v1
if: matrix.os == 'macos-latest'
- name: Run tests in Ubuntu
uses: julia-actions/julia-runtest@v1
if: matrix.os == 'ubuntu-latest'
- name: Run tests in MacOS
uses: julia-actions/julia-runtest@v1
if: matrix.os == 'macos-latest'
- uses: julia-actions/julia-processcoverage@v1
- uses: codecov/codecov-action@v3
with:
Expand Down
10 changes: 4 additions & 6 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Huginn"
uuid = "9cb796e9-d0ea-421b-b37d-eb97bc1add55"
authors = ["Jordi Bolibar <[email protected]>", "Facundo Sapienza <[email protected]>"]
version = "0.6.0"
version = "0.7.0"

[deps]
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
Expand All @@ -17,7 +17,6 @@ Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
PlotThemes = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca"
PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
Sleipnir = "f5e6c550-199f-11ee-3608-394420200519"
Expand All @@ -27,19 +26,18 @@ Tullio = "bc48ee85-29a4-5162-ae0b-a64e1601d4bc"
[compat]
BenchmarkTools = "1"
CairoMakie = "0.11, 0.12"
Infiltrator = "1"
Infiltrator = "1.8"
JLD2 = "0.4"
Muninn = "0.3"
Muninn = "0.4.0"
Optimization = "3"
OptimizationOptimJL = "0.3"
OrdinaryDiffEq = "6"
PlotThemes = "3"
Plots = "1"
ProgressMeter = "1"
PyCall = "1"
Reexport = "1"
Revise = "3"
Sleipnir = "0.6"
Sleipnir = "0.7.0"
Tullio = "0.3"
julia = "1.7"

Expand Down
23 changes: 0 additions & 23 deletions src/Huginn.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ using CairoMakie
import Pkg
using Distributed
using ProgressMeter
using PyCall

### ODINN.jl dependencies ###
using Reexport
Expand All @@ -30,28 +29,6 @@ cd(@__DIR__)
const global root_dir::String = dirname(Base.current_project())
const global root_plots::String = joinpath(root_dir, "plots")

# ##############################################
# ############ PYTHON LIBRARIES ##############
# ##############################################

# We either retrieve the reexported Python libraries from Sleipnir or we start from scratch
const netCDF4::PyObject = isdefined(Sleipnir, :netCDF4) ? Sleipnir.netCDF4 : PyNULL()
const cfg::PyObject = isdefined(Sleipnir, :cfg) ? Sleipnir.cfg : PyNULL()
const utils::PyObject = isdefined(Sleipnir, :utils) ? Sleipnir.utils : PyNULL()
const workflow::PyObject = isdefined(Sleipnir, :workflow) ? Sleipnir.workflow : PyNULL()
const tasks::PyObject = isdefined(Sleipnir, :tasks) ? Sleipnir.tasks : PyNULL()
const global_tasks::PyObject = isdefined(Sleipnir, :global_tasks) ? Sleipnir.global_tasks : PyNULL()
const graphics::PyObject = isdefined(Sleipnir, :graphics) ? Sleipnir.graphics : PyNULL()
const bedtopo::PyObject = isdefined(Sleipnir, :bedtopo) ? Sleipnir.bedtopo : PyNULL()
const millan22::PyObject = isdefined(Sleipnir, :millan22) ? Sleipnir.millan22 : PyNULL()
const MBsandbox::PyObject = isdefined(Sleipnir, :MBsandbox) ? Sleipnir.MBsandbox : PyNULL()
const salem::PyObject = isdefined(Sleipnir, :salem) ? Sleipnir.salem : PyNULL()

# Essential Python libraries
const xr::PyObject = isdefined(Sleipnir, :xr) ? Sleipnir.xr : PyNULL()
const rioxarray::PyObject = isdefined(Sleipnir, :rioxarray) ? Sleipnir.rioxarray : PyNULL()
const pd::PyObject = isdefined(Sleipnir, :pd) ? Sleipnir.pd : PyNULL()

# ##############################################
# ############ HUGINN LIBRARIES ##############
# ##############################################
Expand Down
16 changes: 6 additions & 10 deletions src/parameters/SolverParameters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,40 +38,36 @@ function SolverParameters(;
return solver_parameters
end

Base.:(==)(a::SolverParameters, b::SolverParameters) = a.solver == b.solver && a.reltol == b.reltol && a.step == b.step &&
Base.:(==)(a::SolverParameters, b::SolverParameters) = a.solver == b.solver && a.reltol == b.reltol && a.step == b.step &&
a.tstops == b.tstops && a.save_everystep == b.save_everystep && a.progress == b.progress &&
a.progress_steps == b.progress_steps

"""
Parameters(;
simulation::SimulationParameters = SimulationParameters()
physical::PhysicalParameters = PhysicalParameters()
OGGM::OGGMparameters = OGGMparameters(),
physical::PhysicalParameters = PhysicalParameters(),
simulation::SimulationParameters = SimulationParameters(),
solver::SolverParameters = SolverParameters()
)
Initialize Huginn parameters
Keyword arguments
=================
"""

function Parameters(;
physical::PhysicalParameters = PhysicalParameters(),
simulation::SimulationParameters = SimulationParameters(),
OGGM::OGGMparameters = OGGMparameters(),
solver::SolverParameters = SolverParameters()
)
)

# Build the parameters based on all the subtypes of parameters
parameters = Sleipnir.Parameters(physical, simulation, OGGM,
parameters = Sleipnir.Parameters(physical, simulation,
nothing, solver, nothing, nothing)

if parameters.simulation.multiprocessing
enable_multiprocessing(parameters)
end

oggm_config(OGGM.working_dir; oggm_processes=OGGM.workers)

return parameters
end
Expand Down
35 changes: 5 additions & 30 deletions src/setup/config.jl
Original file line number Diff line number Diff line change
@@ -1,35 +1,10 @@
function __init__()

# Create structural folders if needed
OGGM_path = joinpath(homedir(), "Python/OGGM_data")
if !isdir(OGGM_path)
mkpath(OGGM_path)
end

try
# Only load Python packages if not previously loaded by Sleipnir
if cfg == PyNULL() && workflow == PyNULL() && utils == PyNULL() && MBsandbox == PyNULL()
println("Initializing Python libraries in Huginn...")
copy!(netCDF4, pyimport("netCDF4"))
copy!(cfg, pyimport("oggm.cfg"))
copy!(utils, pyimport("oggm.utils"))
copy!(workflow, pyimport("oggm.workflow"))
copy!(tasks, pyimport("oggm.tasks"))
copy!(global_tasks, pyimport("oggm.global_tasks"))
copy!(graphics, pyimport("oggm.graphics"))
copy!(bedtopo, pyimport("oggm.shop.bedtopo"))
copy!(millan22, pyimport("oggm.shop.millan22"))
copy!(MBsandbox, pyimport("MBsandbox.mbmod_daily_oneflowline"))
copy!(salem, pyimport("salem"))
copy!(pd, pyimport("pandas"))
copy!(xr, pyimport("xarray"))
copy!(rioxarray, pyimport("rioxarray"))
end
catch e
@warn "It looks like you have not installed and/or activated the virtual Python environment. \n
Please follow the guidelines in: https://github.com/ODINN-SciML/ODINN.jl#readme"
@warn exception=(e, catch_backtrace())
end
# # Create structural folders if needed
# OGGM_path = joinpath(homedir(), "Python/OGGM_data")
# if !isdir(OGGM_path)
# mkpath(OGGM_path)
# end

end

Expand Down
4 changes: 2 additions & 2 deletions src/simulations/predictions/prediction_utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function batch_iceflow_PDE!(glacier_idx::I, simulation::Prediction) where {I <:
params = simulation.parameters
glacier = simulation.glaciers[glacier_idx]

glacier_id = isnothing(glacier.gdir) ? "unnamed" : glacier.rgi_id
glacier_id = isnothing(glacier.rgi_id) ? "unnamed" : glacier.rgi_id
println("Processing glacier: ", glacier_id)

# Initialize glacier ice flow model
Expand Down Expand Up @@ -130,7 +130,7 @@ function batch_iceflow_PDE(glacier_idx::I, simulation::Prediction) where {I <: I
params = simulation.parameters
glacier = simulation.glaciers[glacier_idx]

glacier_id = isnothing(glacier.gdir) ? "unnamed" : glacier.rgi_id
glacier_id = isnothing(glacier.rgi_id) ? "unnamed" : glacier.rgi_id
println("Processing glacier: ", glacier_id)

# Initialize glacier ice flow model (don't needed for out-of-place? maybe a simplified version?)
Expand Down
45 changes: 22 additions & 23 deletions test/PDE_UDE_solve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,32 @@ function pde_solve_test(; rtol::F, atol::F, save_refs::Bool=false, MB::Bool=fals

println("PDE solving with MB = $MB")
working_dir = joinpath(homedir(), "OGGM/Huginn_tests")

params = Parameters(OGGM = OGGMparameters(working_dir=working_dir,
multiprocessing=true,
workers=2,
ice_thickness_source = "Farinotti19"),
simulation = SimulationParameters(use_MB=MB,

rgi_paths = get_rgi_paths()

params = Huginn.Parameters(simulation = SimulationParameters(use_MB=MB,
velocities=false,
tspan=(2010.0, 2015.0),
working_dir = Huginn.root_dir,
test_mode = true),
test_mode = true,
rgi_paths = rgi_paths),
solver = SolverParameters(reltol=1e-12)
)
)

## Retrieving gdirs and climate for the following glaciers
## Fast version includes less glacier to reduce the amount of downloaded files and computation time on GitHub CI
## Fast version includes less glacier to reduce the amount of downloaded files and computation time on GitHub CI
if fast
rgi_ids = ["RGI60-11.03638", "RGI60-11.01450", "RGI60-08.00213", "RGI60-04.04351", "RGI60-01.02170"]
rgi_ids = ["RGI60-11.03638", "RGI60-11.01450"] #, "RGI60-08.00213", "RGI60-04.04351", "RGI60-01.02170"]
else
rgi_ids = ["RGI60-11.03638", "RGI60-11.01450", "RGI60-08.00213", "RGI60-04.04351", "RGI60-01.02170",
"RGI60-02.05098", "RGI60-01.01104", "RGI60-01.09162", "RGI60-01.00570", "RGI60-04.07051",
"RGI60-02.05098", "RGI60-01.01104", "RGI60-01.09162", "RGI60-01.00570", "RGI60-04.07051",
"RGI60-07.00274", "RGI60-07.01323", "RGI60-01.17316"]
end

if MB
model = Model(iceflow = SIA2Dmodel(params), mass_balance = TImodel1(params))
model = Huginn.Model(iceflow = SIA2Dmodel(params), mass_balance = TImodel1(params))
else
model = Model(iceflow = SIA2Dmodel(params), mass_balance = nothing)
model = Huginn.Model(iceflow = SIA2Dmodel(params), mass_balance = nothing)
end

# We retrieve some glaciers for the simulation
Expand All @@ -50,7 +49,7 @@ function pde_solve_test(; rtol::F, atol::F, save_refs::Bool=false, MB::Bool=fals
jldsave(joinpath(Huginn.root_dir, "test/data/PDE/PDE_refs_noMB.jld2"); prediction.results)
end
end

# Load reference values for the simulation
if MB
PDE_refs = load(joinpath(Huginn.root_dir, "test/data/PDE/PDE_refs_MB.jld2"))["results"]
Expand Down Expand Up @@ -86,7 +85,7 @@ function pde_solve_test(; rtol::F, atol::F, save_refs::Bool=false, MB::Bool=fals
@test all(isapprox.(result.H[end], test_ref.H[end], rtol=rtol, atol=atol))
@test all(isapprox.(result.Vx, test_ref.Vx, rtol=rtol, atol=vtol))
@test all(isapprox.(result.Vy, test_ref.Vy, rtol=rtol, atol=vtol))

end # let
end
end
Expand All @@ -95,18 +94,18 @@ end
function TI_run_test!(save_refs::Bool = false; rtol::F, atol::F) where {F <: AbstractFloat}

working_dir = joinpath(homedir(), "OGGM/Huginn_tests")
params = Parameters(OGGM = OGGMparameters(working_dir=working_dir,
multiprocessing=true,
workers=2,
ice_thickness_source = "Farinotti19"),
simulation = SimulationParameters(use_MB=true,

rgi_paths = get_rgi_paths()

params = Huginn.Parameters(simulation = SimulationParameters(use_MB=true,
velocities=false,
tspan=(2010.0, 2015.0),
working_dir = Huginn.root_dir,
test_mode = true),
test_mode = true,
rgi_paths = rgi_paths),
solver = SolverParameters(reltol=1e-8)
)
model = Model(iceflow = SIA2Dmodel(params), mass_balance = TImodel1(params))
)
model = Huginn.Model(iceflow = SIA2Dmodel(params), mass_balance = TImodel1(params))
rgi_ids = ["RGI60-11.03638"]

glacier = initialize_glaciers(rgi_ids, params)[1]
Expand Down
Binary file modified test/data/PDE/H_w_MB_ref.jld2
Binary file not shown.
Binary file modified test/data/PDE/MB_ref.jld2
Binary file not shown.
Binary file modified test/data/PDE/PDE_refs_MB.jld2
Binary file not shown.
Binary file modified test/data/PDE/PDE_refs_noMB.jld2
Binary file not shown.
Binary file modified test/data/params/solver_params_default.jld2
Binary file not shown.
Binary file modified test/data/params/solver_params_specified.jld2
Binary file not shown.
11 changes: 7 additions & 4 deletions test/halfar.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,22 @@ Arguments
"""
function unit_halfar_test(; A, n, t₀, t₁, Δx, Δy, nx, ny, h₀, r₀, rtol=0.02, atol=1.0, distance_to_border=3, save_plot=false, inplace=true)

# Get parameters for a simulation
parameters = Parameters(simulation=SimulationParameters(tspan=(t₀, t₁),
rgi_paths = get_rgi_paths()

# Get parameters for a simulation
parameters = Huginn.Parameters(simulation=SimulationParameters(tspan=(t₀, t₁),
multiprocessing=false,
use_MB=false,
use_iceflow=true,
working_dir=Huginn.root_dir),
working_dir=Huginn.root_dir,
rgi_paths=rgi_paths),
physical=PhysicalParameters(),
solver=SolverParameters(reltol=1e-12))

# Bed (it has to be flat for the Halfar solution)
B = zeros((nx,ny))

model = Model(iceflow = SIA2Dmodel(parameters), mass_balance = nothing)
model = Huginn.Model(iceflow = SIA2Dmodel(parameters), mass_balance = nothing)

# Initial condition of the glacier
R₀ = [sqrt((Δx * (i - nx/2))^2 + (Δy * (j - ny/2))^2) for i in 1:nx, j in 1:ny]
Expand Down
9 changes: 6 additions & 3 deletions test/mass_conservation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,17 @@ Arguments
"""
function unit_mass_test(; H₀, B, A, n, t_sim, Δx, Δy, rtol=0.02, save_plot=false)

rgi_paths = get_rgi_paths()

# Get parameters for a simulation
parameters = Parameters(simulation=SimulationParameters(tspan=(0.0, t_sim),
parameters = Huginn.Parameters(simulation=SimulationParameters(tspan=(0.0, t_sim),
use_MB=false,
use_iceflow=true),
use_iceflow=true,
rgi_paths=rgi_paths),
physical=PhysicalParameters(),
solver=SolverParameters(reltol=1e-12))

model = Model(iceflow = SIA2Dmodel(parameters), mass_balance = nothing)
model = Huginn.Model(iceflow = SIA2Dmodel(parameters), mass_balance = nothing)

# Surface
S = B + H₀
Expand Down
Loading

2 comments on commit 1b5618b

@albangossard
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator register()

Release notes:

Breaking changes

  • Dependencies to PyCall have been removed. All existing Python objects have been replaced by Julia ones, and hence the interface has changed.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/123600

Tagging

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.7.0 -m "<description of version>" 1b5618b4082e0a01c22d938fd447690e986ea048
git push origin v0.7.0

Please sign in to comment.