Skip to content

Commit c2aac83

Browse files
authored
implement constants for cleaner symbolic equations (#60)
1 parent 66a6ee6 commit c2aac83

File tree

7 files changed

+58
-18
lines changed

7 files changed

+58
-18
lines changed

demo/STGneuron.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ dynamics = HodgkinHuxley(channels, gradients);
2626
@named neuron = CompartmentSystem(Vₘ, dynamics;
2727
geometry = geo,
2828
extensions = [calcium_conversion]);
29-
t_total = 5000.0
30-
sim = Simulation(neuron, t_total * ms)
29+
t_total = 4000.0ms
30+
sim = Simulation(neuron, t_total)
3131
solution = solve(sim, Rosenbrock23());
3232

3333
# Plot at 5kHz sampling

demo/hodgkinhuxley.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# Classic Hodgkin Huxley neuron with a "current pulse" stimulus
22
using Conductor, Unitful, ModelingToolkit, OrdinaryDiffEq, Plots
33
import Unitful: mV, mS, cm, µm, pA, nA, mA, µA, ms
4-
import Conductor: Na, K # shorter aliases for Sodium/Potassium
54

65
Vₘ = ParentScope(MembranePotential(-65mV))
76

@@ -24,7 +23,7 @@ kdr_kinetics = [
2423
@named leak = IonChannel(Leak, max_g = 0.3mS / cm^2)
2524

2625
channels = [NaV, Kdr, leak];
27-
reversals = Equilibria([Na => 50.0mV, K => -77.0mV, Leak => -54.4mV])
26+
reversals = Equilibria([Sodium => 50.0mV, Potassium => -77.0mV, Leak => -54.4mV])
2827

2928
@named pulse_stim = PulseTrain(amplitude = 400.0pA, duration = 100ms, delay = 100ms)
3029

demo/prinz_kinetics.jl

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
using Conductor, Unitful, ModelingToolkit
2-
import Unitful: mV, mS, cm, µm, ms, mM, µM, µA
3-
import Conductor: Na, K, Ca, Cation, Leak
2+
import Unitful: mV, mS, cm, µm, ms, mM, µM, µA, nM, K
3+
import Conductor: mR, ℱ
44

55
Vₘ = ParentScope(MembranePotential(-50mV))
6+
67
Caᵢ = Concentration(Calcium, 0.05µM, dynamic = true)
8+
Caₒ = Concentration(Calcium, 3.0mM, location = Conductor.Outside)
9+
minCa = Concentration(Calcium, 1.0nM, name=:minCa)
710
ICa = IonCurrent(Calcium, aggregate = true)
811

12+
T = Temperature(283.15K)
13+
914
nav_kinetics = [Gate(SteadyStateTau,
1015
1.0 / (1.0 + exp((Vₘ + 25.5) / -5.29)),
1116
2.64 - (2.52 / (1 + exp((Vₘ + 120.0) / -25.0))),
@@ -57,21 +62,14 @@ h_kinetics = [
5762
1.0 / (1.0 + exp((Vₘ + 75.0) / 5.5)),
5863
2 / (exp((Vₘ + 169.7) / (-11.6)) + exp((Vₘ - 26.7) / (14.3))), name = :m)]
5964

60-
Ca_Nernst(Ca) = 1000 * ((-8.314 * 283.15) / (2 * 96485.365)) * log(max(Ca, 0.001) / 3000.0)
61-
@register_symbolic Ca_Nernst(Ca)
62-
ModelingToolkit.get_unit(op::typeof(Ca_Nernst), args) = mV
63-
6465
gradients = Equilibria(Pair[Sodium => 50.0mV,
6566
Potassium => -80.0mV,
6667
Cation => (-20mV, :H),
6768
Leak => -50mV,
68-
# x1000 for mV; thresholding Cai in case negative conc
69-
# TODO: write nernst function + use Unitful constants (RT/zℱ)
70-
Calcium => Ca_Nernst(Caᵢ)]);
69+
Calcium => (-mR*T/2ℱ) * log(max(Caᵢ, minCa) / Caₒ)]);
7170

7271
# Reported area value in Prinz 2003; the area of a cylinder without the ends (2πrh).
7372
# Dimensions r = 25µm, h = 400µm given by Liu et al 1998.
74-
7573
#r = 25µm; h = 400µm; area = round(ustrip(Float64, cm^2, 2π*r*h), sigdigits=3)
7674

7775
geo = Cylinder(radius = 25µm, height = 400µm)

docs/src/core/primitives.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ ExtrinsicPotential
1212
IonConcentration
1313
IonCurrent
1414
EquilibriumPotential
15+
Conductor.Temperature
1516
```
1617

1718
## Constants
@@ -21,6 +22,8 @@ Conductor.t
2122
Conductor.D
2223
Conductor.ℱ
2324
Conductor.IonSpecies
25+
Conductor.R
26+
Conductor.mR
2427
```
2528
### Quantities
2629

src/Conductor.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ export Simulation
9595
export @named
9696

9797
export Calcium, Sodium, Potassium, Chloride, Cation, Anion, Leak, Ion, NonIonic
98-
98+
export Temperature
9999
export t
100100

101101
export CompartmentSystem, Compartment, ConductanceSystem, Conductance,

src/primitives.jl

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,25 @@ julia> Conductor.ℱ
1919
96485.33212331001 C mol^-1
2020
```
2121
"""
22-
const= Unitful.q * Unitful.Na # Faraday's constant
22+
const= let name = :ℱ
23+
only(@constants $name=ustrip(Unitful.q * Unitful.Na) [unit = Unitful.C*Unitful.mol^-1])
24+
end
25+
26+
"""
27+
Universal Gas Constant (base units)
28+
"""
29+
const R = let name = :R
30+
only(@constants $name=ustrip(Unitful.R) [unit = Unitful.unit(Unitful.R)])
31+
end
32+
33+
"""
34+
Universal Gas Constant (milli-)
35+
36+
Scaled by 1000x. Results in output
37+
"""
38+
const mR = let name = :mR
39+
only(@constants $name=(ustrip(Unitful.R)*1000) [unit = u"mJ*K^-1*mol^-1"])
40+
end
2341

2442
"""
2543
The independent variable for time, ``t``.
@@ -278,6 +296,28 @@ function EquilibriumPotential(ion::IonSpecies, eqv::Union{Nothing, Real, Voltage
278296
return setmetadata(ret, EquilibriumPotential, EquilibriumPotential(ion))
279297
end
280298

299+
"""
300+
Temperature(temp; <keyword arguments>)
301+
302+
Temperature (in Kelvin)
303+
304+
# Arguments
305+
- `dynamic::Bool = false`: a dynamic `Temperature` is assumed to vary with time.
306+
- `name::Symbol = :T`: the symbol to use for the symbolic variable.
307+
"""
308+
function Temperature(temp::Union{Nothing, Real, Unitful.Temperature};
309+
dynamic::Bool = false, name::Symbol = :T)
310+
temp_val = temp isa Unitful.Temperature ? ustrip(Unitful.K, temp) : temp
311+
if isnothing(temp_val)
312+
ret = dynamic ? only(@variables $name(t) [unit = Unitful.K]) :
313+
only(@parameters $name [unit = Unitful.K])
314+
else
315+
ret = dynamic ? only(@variables($name(t)=temp_val, [unit = Unitful.K])) :
316+
only(@parameters($name=temp_val, [unit = Unitful.K]))
317+
end
318+
return ret
319+
end
320+
281321
# Internal API: EquilibriumPotential trait queries
282322
isreversal(x) = hasmetadata(value(x), EquilibriumPotential)
283323
getreversal(x) = isreversal(x) ? getmetadata(value(x), EquilibriumPotential) : nothing

test/prinzneuron.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ include(normpath(@__DIR__, "..", "demo", "prinz_kinetics.jl"))
2222
extensions = [calcium_conversion]);
2323
@test length.([equations(neuron),
2424
states(neuron),
25-
parameters(neuron)]) == [31, 31, 17]
25+
parameters(neuron)]) == [31, 31, 20]
2626

2727
time = 2000
2828
simul_sys = Simulation(neuron, time * ms; return_system = true)
2929

3030
@test length.([equations(simul_sys),
3131
states(simul_sys),
32-
parameters(simul_sys)]) == [13, 13, 17]
32+
parameters(simul_sys)]) == [13, 13, 20]
3333

3434
# Prinz STG neuron hand-written reference implementation
3535

0 commit comments

Comments
 (0)