From a5f9532cecb9f5421984327c06709470af5e5f5e Mon Sep 17 00:00:00 2001 From: marinlauber Date: Fri, 25 Jul 2025 13:41:56 +0200 Subject: [PATCH 1/5] add julia resonant circuit example --- resonant-circuit/capacitor-julia/Project.toml | 3 + resonant-circuit/capacitor-julia/capacitor.jl | 90 +++++++++++++++ resonant-circuit/capacitor-julia/run.sh | 3 + resonant-circuit/coil-julia/Project.toml | 3 + resonant-circuit/coil-julia/coil.jl | 107 ++++++++++++++++++ resonant-circuit/coil-julia/run.sh | 3 + 6 files changed, 209 insertions(+) create mode 100644 resonant-circuit/capacitor-julia/Project.toml create mode 100644 resonant-circuit/capacitor-julia/capacitor.jl create mode 100755 resonant-circuit/capacitor-julia/run.sh create mode 100644 resonant-circuit/coil-julia/Project.toml create mode 100644 resonant-circuit/coil-julia/coil.jl create mode 100755 resonant-circuit/coil-julia/run.sh diff --git a/resonant-circuit/capacitor-julia/Project.toml b/resonant-circuit/capacitor-julia/Project.toml new file mode 100644 index 000000000..8a303cd38 --- /dev/null +++ b/resonant-circuit/capacitor-julia/Project.toml @@ -0,0 +1,3 @@ +[deps] +OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" +PreCICE = "57fbd4af-5cc3-4712-aac0-6930e7658184" diff --git a/resonant-circuit/capacitor-julia/capacitor.jl b/resonant-circuit/capacitor-julia/capacitor.jl new file mode 100644 index 000000000..3e97adbf2 --- /dev/null +++ b/resonant-circuit/capacitor-julia/capacitor.jl @@ -0,0 +1,90 @@ +using PreCICE +using OrdinaryDiffEq +using JLD2 + +# Initialize and configure preCICE +participant = PreCICE.createParticipant("Capacitor", "../precice-config.xml", 0, 1) + +# Geometry IDs. As it is a 0-D simulation, only one vertex is necessary. +mesh_name = "Capacitor-Mesh" + +dimensions = PreCICE.getMeshDimensions(mesh_name) + +vertex_ids = PreCICE.setMeshVertices(mesh_name, [0. 0.]) + +let + # Data IDs + read_data_name = "Current" + write_data_name = "Voltage" + + # Simulation parameters and initial condition + C = 2 # Capacitance of the capacitor + L = 1 # Inductance of the coil + t0 = 0 # Initial simulation time + t_max = 10 # End simulation time + Io = 1 # Initial current + phi = 0 # Phase of the signal + + w0 = 1 / sqrt(L * C) # Resonant frequency + U0 = -w0 * L * Io * sin(phi) # Initial condition for U + + function f_U(u, p, t) + (dt, C, mesh_name, read_data_name, vertex_ids) = p + I = PreCICE.readData(mesh_name, read_data_name, vertex_ids, dt) + return -I[1] / C # Time derivative of U + end + + # Initialize simulation + if PreCICE.requiresInitialData() + @show I0 + PreCICE.writeData(mesh_name, write_data_name, vertex_ids, I0) + end + PreCICE.initialize() + + solver_dt = PreCICE.getMaxTimeStepSize() + + # Start simulation + t = t0 + U0_checkpoint = U0 + t_checkpoint = t + U_store = [[t, U0]] + while PreCICE.isCouplingOngoing() + + + # Record checkpoint if necessary + if PreCICE.requiresWritingCheckpoint() + U0_checkpoint = U0 + t_checkpoint = t + end + + # Make Simulation Step + precice_dt = PreCICE.getMaxTimeStepSize() + dt = min(precice_dt, solver_dt) + t_span = (t, t + dt) + params = (dt, C, mesh_name, read_data_name, vertex_ids) + prob = ODEProblem(f_U, U0, t_span, params) + # https://docs.sciml.ai/DiffEqDocs/stable/basics/common_solver_opts + sol = solve(prob, Tsit5(), reltol=1e-12, abstol=1e-12) + + # Exchange data + evals = max(length(sol.t), 3) # at least do 3 substeps to allow cubic interpolation + for i in range(1,evals) + U0 = sol(t_span[1] + i * dt / evals) + PreCICE.writeData(mesh_name, write_data_name, vertex_ids, fill(U0, (1,1))) + PreCICE.advance(dt / evals) + end + t = t + dt + + # Recover checkpoint if not converged + if PreCICE.requiresReadingCheckpoint() + U0 = U0_checkpoint + t = t_checkpoint + end + if PreCICE.isTimeWindowComplete() + push!(U_store, [t, U0]) + end + end + jldsave("capacitor.jld2", U=U_store) + # Stop coupling + PreCICE.finalize() +end \ No newline at end of file diff --git a/resonant-circuit/capacitor-julia/run.sh b/resonant-circuit/capacitor-julia/run.sh new file mode 100755 index 000000000..b8fad8705 --- /dev/null +++ b/resonant-circuit/capacitor-julia/run.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +julia --project=. capacitor.jl \ No newline at end of file diff --git a/resonant-circuit/coil-julia/Project.toml b/resonant-circuit/coil-julia/Project.toml new file mode 100644 index 000000000..8a303cd38 --- /dev/null +++ b/resonant-circuit/coil-julia/Project.toml @@ -0,0 +1,3 @@ +[deps] +OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" +PreCICE = "57fbd4af-5cc3-4712-aac0-6930e7658184" diff --git a/resonant-circuit/coil-julia/coil.jl b/resonant-circuit/coil-julia/coil.jl new file mode 100644 index 000000000..00c192ec0 --- /dev/null +++ b/resonant-circuit/coil-julia/coil.jl @@ -0,0 +1,107 @@ +using PreCICE +using OrdinaryDiffEq +using Plots +using JLD2 + +# Initialize and configure preCICE +participant = PreCICE.createParticipant("Coil", "../precice-config.xml", 0, 1) + +# Geometry IDs. As it is a 0-D simulation, only one vertex is necessary. +mesh_name = "Coil-Mesh" + +dimensions = PreCICE.getMeshDimensions(mesh_name) + +vertex_ids = PreCICE.setMeshVertices(mesh_name, [0. 0.]) + +let + # Data IDs + read_data_name = "Voltage" + write_data_name = "Current" + + # Simulation parameters and initial condition + C = 2 # Capacitance of the capacitor + L = 1 # Inductance of the coil + t0 = 0 # Initial simulation time + Io = 1 # Initial current + phi = 0 # Phase of the signal + + w0 = 1 / sqrt(L * C) # Resonant frequency + I0 = Io * cos(phi) # Initial condition for I + + # to estimate cost + f_evals = 0 + + function f_I(u, p, t) + f_evals += 1 + (dt, L, mesh_name, read_data_name, vertex_ids) = p + U = PreCICE.readData(mesh_name, read_data_name, vertex_ids, dt) + return U[1] / L # Time derivative of I; ODE determining capacitor + end + + # Initialize simulation + if PreCICE.requiresInitialData() + @show I0 + PreCICE.writeData(mesh_name, write_data_name, vertex_ids, I0) + end + PreCICE.initialize() + + solver_dt = PreCICE.getMaxTimeStepSize() + + # Start simulation + t = t0 + I0_checkpoint = I0 + t_checkpoint = t + I_store = [[t, I0]] + while PreCICE.isCouplingOngoing() + + # Record checkpoint if necessary + if PreCICE.requiresWritingCheckpoint() + I0_checkpoint = I0 + t_checkpoint = t + end + + # Make Simulation Step + precice_dt = PreCICE.getMaxTimeStepSize() + dt = min(precice_dt, solver_dt) + t_span = (t, t + dt) + params = (dt, L, mesh_name, read_data_name, vertex_ids) + prob = ODEProblem(f_I, I0, t_span, params) + # https://docs.sciml.ai/DiffEqDocs/stable/basics/common_solver_opts + sol = solve(prob, Tsit5(), reltol=1e-12, abstol=1e-12) + + # Exchange data + evals = max(length(sol.t), 3) # at least do 3 substeps to allow cubic interpolation + for i in range(1,evals) + I0 = sol(t_span[1] + i * dt / evals) + PreCICE.writeData(mesh_name, write_data_name, vertex_ids, fill(I0, (1,1))) + PreCICE.advance(dt / evals) + end + t = t + dt + + # Recover checkpoint if not converged + if PreCICE.requiresReadingCheckpoint() + I0 = I0_checkpoint + t = t_checkpoint + end + if PreCICE.isTimeWindowComplete() + push!(I_store, [t, I0]) + end + end + jldsave("coil.jld2", U=I_store) + # Stop coupling + PreCICE.finalize() + + # solutions + I_analytical(t) = Io * cos(t * w0 + phi) + U_analytical(t) = -w0 * L * Io * sin(w0 * t + phi); + + # plot + time = getindex.(I_store,1); I_num = getindex.(I_store,2) + plot(time, [I_num, I_analytical.(time), U_analytical.(time)], + label=["Simulated Current" "Analytical Current" "Analytical Voltage"], + xlabel="Time", title="Resonant Circuit Simulation") + U_store = jldopen(joinpath(@__DIR__,"../capacitor-julia/capacitor.jld2")) + time = getindex.(U_store["U"],1); U_num = getindex.(U_store["U"],2) + plot!(time, U_num, label="Simulated Voltage") + savefig("resonant_circuit.png") +end \ No newline at end of file diff --git a/resonant-circuit/coil-julia/run.sh b/resonant-circuit/coil-julia/run.sh new file mode 100755 index 000000000..7d19bd1e8 --- /dev/null +++ b/resonant-circuit/coil-julia/run.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +julia --project=. coil.jl \ No newline at end of file From 114d8115532f453c8fd3c0e34bb2eab54198c9aa Mon Sep 17 00:00:00 2001 From: marinlauber Date: Fri, 25 Jul 2025 14:37:31 +0200 Subject: [PATCH 2/5] update README.md --- resonant-circuit/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resonant-circuit/README.md b/resonant-circuit/README.md index fbbcbc4e9..ca2cb21fd 100644 --- a/resonant-circuit/README.md +++ b/resonant-circuit/README.md @@ -1,7 +1,7 @@ --- title: Resonant Circuit permalink: tutorials-resonant-circuit.html -keywords: MATLAB, Python +keywords: MATLAB, Python, Julia summary: We simulate a two-element LC circuit (one inductor and one capacitor). --- @@ -33,6 +33,7 @@ preCICE configuration (image generated using the [precice-config-visualizer](htt * *MATLAB* A solver using the [MATLAB bindings](https://precice.org/installation-bindings-matlab.html). Before running this tutorial, follow the [instructions](https://precice.org/installation-bindings-matlab.html) to correctly install the MATLAB bindings. * *Python* A solver using the preCICE [Python bindings](https://precice.org/installation-bindings-python.html). +* *Julia* A solver using the preCICE [Julia bindings](https://precice.org/installation-bindings-julia.html). ## Running the simulation From 64889d92ce3426f6537b5e5a41f849c070292d29 Mon Sep 17 00:00:00 2001 From: marinlauber Date: Wed, 6 Aug 2025 09:47:12 +0200 Subject: [PATCH 3/5] tidy scripts and remove plotting from there, fix run.sh --- resonant-circuit/capacitor-julia/capacitor.jl | 10 +------- resonant-circuit/capacitor-julia/run.sh | 11 +++++++-- resonant-circuit/coil-julia/coil.jl | 24 +------------------ resonant-circuit/coil-julia/run.sh | 11 +++++++-- 4 files changed, 20 insertions(+), 36 deletions(-) diff --git a/resonant-circuit/capacitor-julia/capacitor.jl b/resonant-circuit/capacitor-julia/capacitor.jl index 3e97adbf2..175efe88e 100644 --- a/resonant-circuit/capacitor-julia/capacitor.jl +++ b/resonant-circuit/capacitor-julia/capacitor.jl @@ -1,6 +1,5 @@ using PreCICE using OrdinaryDiffEq -using JLD2 # Initialize and configure preCICE participant = PreCICE.createParticipant("Capacitor", "../precice-config.xml", 0, 1) @@ -10,7 +9,7 @@ mesh_name = "Capacitor-Mesh" dimensions = PreCICE.getMeshDimensions(mesh_name) -vertex_ids = PreCICE.setMeshVertices(mesh_name, [0. 0.]) +vertex_ids = PreCICE.setMeshVertices(mesh_name, zeros((1,dimensions))) let # Data IDs @@ -36,7 +35,6 @@ let # Initialize simulation if PreCICE.requiresInitialData() - @show I0 PreCICE.writeData(mesh_name, write_data_name, vertex_ids, I0) end PreCICE.initialize() @@ -47,10 +45,8 @@ let t = t0 U0_checkpoint = U0 t_checkpoint = t - U_store = [[t, U0]] while PreCICE.isCouplingOngoing() - # Record checkpoint if necessary if PreCICE.requiresWritingCheckpoint() U0_checkpoint = U0 @@ -80,11 +76,7 @@ let U0 = U0_checkpoint t = t_checkpoint end - if PreCICE.isTimeWindowComplete() - push!(U_store, [t, U0]) - end end - jldsave("capacitor.jld2", U=U_store) # Stop coupling PreCICE.finalize() end \ No newline at end of file diff --git a/resonant-circuit/capacitor-julia/run.sh b/resonant-circuit/capacitor-julia/run.sh index b8fad8705..4e6b56f7b 100755 --- a/resonant-circuit/capacitor-julia/run.sh +++ b/resonant-circuit/capacitor-julia/run.sh @@ -1,3 +1,10 @@ -#!/bin/sh +#!/usr/bin/env bash +set -e -u -julia --project=. capacitor.jl \ No newline at end of file +. ../../tools/log.sh +exec > >(tee --append "$LOGFILE") 2>&1 + +julia --project=Project.toml -e "using Pkg; Pkg.instantiate();" +julia --project=Project.toml capacitor.jl + +close_log \ No newline at end of file diff --git a/resonant-circuit/coil-julia/coil.jl b/resonant-circuit/coil-julia/coil.jl index 00c192ec0..38549a719 100644 --- a/resonant-circuit/coil-julia/coil.jl +++ b/resonant-circuit/coil-julia/coil.jl @@ -1,7 +1,5 @@ using PreCICE using OrdinaryDiffEq -using Plots -using JLD2 # Initialize and configure preCICE participant = PreCICE.createParticipant("Coil", "../precice-config.xml", 0, 1) @@ -11,7 +9,7 @@ mesh_name = "Coil-Mesh" dimensions = PreCICE.getMeshDimensions(mesh_name) -vertex_ids = PreCICE.setMeshVertices(mesh_name, [0. 0.]) +vertex_ids = PreCICE.setMeshVertices(mesh_name, zeros((1,dimensions))) let # Data IDs @@ -40,7 +38,6 @@ let # Initialize simulation if PreCICE.requiresInitialData() - @show I0 PreCICE.writeData(mesh_name, write_data_name, vertex_ids, I0) end PreCICE.initialize() @@ -51,7 +48,6 @@ let t = t0 I0_checkpoint = I0 t_checkpoint = t - I_store = [[t, I0]] while PreCICE.isCouplingOngoing() # Record checkpoint if necessary @@ -83,25 +79,7 @@ let I0 = I0_checkpoint t = t_checkpoint end - if PreCICE.isTimeWindowComplete() - push!(I_store, [t, I0]) - end end - jldsave("coil.jld2", U=I_store) # Stop coupling PreCICE.finalize() - - # solutions - I_analytical(t) = Io * cos(t * w0 + phi) - U_analytical(t) = -w0 * L * Io * sin(w0 * t + phi); - - # plot - time = getindex.(I_store,1); I_num = getindex.(I_store,2) - plot(time, [I_num, I_analytical.(time), U_analytical.(time)], - label=["Simulated Current" "Analytical Current" "Analytical Voltage"], - xlabel="Time", title="Resonant Circuit Simulation") - U_store = jldopen(joinpath(@__DIR__,"../capacitor-julia/capacitor.jld2")) - time = getindex.(U_store["U"],1); U_num = getindex.(U_store["U"],2) - plot!(time, U_num, label="Simulated Voltage") - savefig("resonant_circuit.png") end \ No newline at end of file diff --git a/resonant-circuit/coil-julia/run.sh b/resonant-circuit/coil-julia/run.sh index 7d19bd1e8..08a42b289 100755 --- a/resonant-circuit/coil-julia/run.sh +++ b/resonant-circuit/coil-julia/run.sh @@ -1,3 +1,10 @@ -#!/bin/sh +#!/usr/bin/env bash +set -e -u -julia --project=. coil.jl \ No newline at end of file +. ../../tools/log.sh +exec > >(tee --append "$LOGFILE") 2>&1 + +julia --project=Project.toml -e "using Pkg; Pkg.instantiate();" +julia --project=Project.toml coil.jl + +close_log \ No newline at end of file From 6d4bae9fcfb42a67e3a90e181fd1e5c02ad298a1 Mon Sep 17 00:00:00 2001 From: marinlauber Date: Wed, 6 Aug 2025 10:36:40 +0200 Subject: [PATCH 4/5] add package install in run and switch OrdinaryDiffEq for DifferentialEquations --- resonant-circuit/capacitor-julia/capacitor.jl | 2 +- resonant-circuit/capacitor-julia/run.sh | 2 +- resonant-circuit/coil-julia/coil.jl | 2 +- resonant-circuit/coil-julia/run.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/resonant-circuit/capacitor-julia/capacitor.jl b/resonant-circuit/capacitor-julia/capacitor.jl index 175efe88e..9219c5cae 100644 --- a/resonant-circuit/capacitor-julia/capacitor.jl +++ b/resonant-circuit/capacitor-julia/capacitor.jl @@ -1,5 +1,5 @@ using PreCICE -using OrdinaryDiffEq +using DifferentialEquations # Initialize and configure preCICE participant = PreCICE.createParticipant("Capacitor", "../precice-config.xml", 0, 1) diff --git a/resonant-circuit/capacitor-julia/run.sh b/resonant-circuit/capacitor-julia/run.sh index 4e6b56f7b..a61d1fa67 100755 --- a/resonant-circuit/capacitor-julia/run.sh +++ b/resonant-circuit/capacitor-julia/run.sh @@ -4,7 +4,7 @@ set -e -u . ../../tools/log.sh exec > >(tee --append "$LOGFILE") 2>&1 -julia --project=Project.toml -e "using Pkg; Pkg.instantiate();" +julia --project=Project.toml -e 'using Pkg; Pkg.add("DifferentialEquations"); Pkg.add("PreCICE"); Pkg.instantiate();' julia --project=Project.toml capacitor.jl close_log \ No newline at end of file diff --git a/resonant-circuit/coil-julia/coil.jl b/resonant-circuit/coil-julia/coil.jl index 38549a719..6cd949ebb 100644 --- a/resonant-circuit/coil-julia/coil.jl +++ b/resonant-circuit/coil-julia/coil.jl @@ -1,5 +1,5 @@ using PreCICE -using OrdinaryDiffEq +using DifferentialEquations # Initialize and configure preCICE participant = PreCICE.createParticipant("Coil", "../precice-config.xml", 0, 1) diff --git a/resonant-circuit/coil-julia/run.sh b/resonant-circuit/coil-julia/run.sh index 08a42b289..6340410ae 100755 --- a/resonant-circuit/coil-julia/run.sh +++ b/resonant-circuit/coil-julia/run.sh @@ -4,7 +4,7 @@ set -e -u . ../../tools/log.sh exec > >(tee --append "$LOGFILE") 2>&1 -julia --project=Project.toml -e "using Pkg; Pkg.instantiate();" +julia --project=Project.toml -e 'using Pkg; Pkg.add("DifferentialEquations"); Pkg.add("PreCICE"); Pkg.instantiate();' julia --project=Project.toml coil.jl close_log \ No newline at end of file From cc4dedf866d04e0117368781c4f8121a6700e226 Mon Sep 17 00:00:00 2001 From: marinlauber Date: Wed, 6 Aug 2025 10:39:49 +0200 Subject: [PATCH 5/5] rm old Project files --- resonant-circuit/capacitor-julia/Project.toml | 3 --- resonant-circuit/coil-julia/Project.toml | 3 --- 2 files changed, 6 deletions(-) delete mode 100644 resonant-circuit/capacitor-julia/Project.toml delete mode 100644 resonant-circuit/coil-julia/Project.toml diff --git a/resonant-circuit/capacitor-julia/Project.toml b/resonant-circuit/capacitor-julia/Project.toml deleted file mode 100644 index 8a303cd38..000000000 --- a/resonant-circuit/capacitor-julia/Project.toml +++ /dev/null @@ -1,3 +0,0 @@ -[deps] -OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" -PreCICE = "57fbd4af-5cc3-4712-aac0-6930e7658184" diff --git a/resonant-circuit/coil-julia/Project.toml b/resonant-circuit/coil-julia/Project.toml deleted file mode 100644 index 8a303cd38..000000000 --- a/resonant-circuit/coil-julia/Project.toml +++ /dev/null @@ -1,3 +0,0 @@ -[deps] -OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" -PreCICE = "57fbd4af-5cc3-4712-aac0-6930e7658184"