Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ jobs:
with:
use_coverage: true
use_FuseRegistry: false
upload_artifact: true
artifact_name: test_result_images
artifact_path: test/*.pdf
# Optional inputs for artifact uploading
# For example, uncomment the following 4 lines to upload test result images that
# will be generated by test/runtests.jl in test directory
Expand Down
13 changes: 3 additions & 10 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
name = "SOLPS2ctrl"
uuid = "a531d12f-ac8a-43e8-b6d9-bd121431dd49"
authors = ["David Eldon <eldond@fusion.gat.com>"]
version = "2.2.0"
version = "2.2.1"

[deps]
ArgParse = "c7e460c6-2fb9-53a9-8c5b-16f535851c63"
Contour = "d38c429a-6771-53c6-b99e-75d170b6e991"
ControlSystemIdentification = "3abffc1c-5106-53b7-b354-a47bfc086282"
ControlSystemsBase = "aaaaaaaa-a6ca-5380-bf3e-84a91bcd477e"
DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
EFIT = "cda752c5-6b03-55a3-9e33-132a441b0c17"
IMAS = "13ead8c1-b7d1-41bb-a6d0-5b8b65ed587a"
IMASggd = "b7b5e640-9b39-4803-84eb-376048795def"
Expand All @@ -17,19 +16,15 @@ JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
LsqFit = "2fda8390-95c7-5789-9bda-21331edee243"
PhysicalConstants = "5ad8b20f-a522-5ce9-bfc9-ddf1d5bda6ab"
PlotUtils = "995b91a9-d308-5afd-9ec6-746e21dbc043"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
SOLPS2imas = "09becab6-0636-4c23-a92a-2b3723265c31"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"

[compat]
ArgParse = "1"
Contour = "0.6"
ControlSystemIdentification = "2"
ControlSystemsBase = "1"
DelimitedFiles = "1"
DataStructures = "0.18.22"
EFIT = "1"
IMAS = "1, 2, 3, 4, 5"
IMASggd = "3.3"
Expand All @@ -38,8 +33,6 @@ JSON = "0.21"
LinearAlgebra = "1"
LsqFit = "0.15.1"
PhysicalConstants = "0.2"
PlotUtils = "1"
Plots = "1"
SOLPS2imas = "2.2"
Statistics = "1"
Unitful = "1"
Expand Down
58 changes: 58 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,61 @@ Pkg.add("SOLPS2ctrl")
## Examples

Refer to the instructions on this [wiki page](https://github.com/ProjectTorreyPines/SOLPS2ctrl.jl/wiki/Demo) to see how to run `examples/demo.ipynb`.

## For developers

If you are contributing to this project, you would need to install [dvc](https://dvc.org/) to fetch sample files for testing. Once installed, please configure your ssh so that you can ssh into omega tunneling through cybele without requiring to enter password. This is optional but will make it much easier for you.

Once you have completed above steps, inside the git repo, simply do:
```bash
dvc pull
```

This would download the sample files in the `samples` directory. Then to run tests, you would first need to instantiate the project:
```bash
julia --project
```
Then press `]`:
```julia
_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.11.5 (2025-04-14)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |

julia> ]
```
Then type:
```julia
(SOLPS2ctrl) pkg> instantiate
```
Once the package has been instantiated, you can run the tests using:
```julia
(SOLPS2ctrl) pkg> test
```
This would run all the tests though. To run specific tests, you can do following from the command line to see help options (this works after you ahve instantiated the project like mentioned above):
```bash
% julia --project test/test.jl help
Usage (from inside SOLPS2ctrl.jl):
julia --project test/test.jl [units] [core] [edge] [heavy] [repair] [geqdsk] [prep] [sysid] [state] [controller] [h] [help]

Run tests. Default is all tests.

Optional arguments:
units Test unit conversion utilities
core Test core profile extension
edge Test edge profile extension
heavy Test heavy utilities
repair Test repair_eq
geqdsk Test geqdsk_to_imas
prep Test preparation
sysid Test system id
state Test state prediction
controller Test linear and PVLC controllers
h Show this help message and exit
help Show this help message and exit

```
185 changes: 184 additions & 1 deletion docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,193 @@ cached_mesh_extension!
offset_scale
unscale_unoffset
system_id
system_id_optimal_input_cond
system_id_optimal_inp_cond
model_evolve
```

## Actuators

```@docs
Actuator
DelayedActuator
```
For example:
```@example
using SOLPS2ctrl: DelayedActuator
# Actuator with delay of 3 steps
dact = DelayedActuator(3; default_output=[0.0, 0.0])
inp_series = [ones(2) * i * 0.1 for i in 1:6]
for (i, inp) in enumerate(inp_series)
println("Calling $(i)th time, return value is $(dact(inp))")
end
```

## Controllers

```@docs
Controller
```

### Linear Controller

```@docs
LinearController
```

### Predicted Variable Linear Controller

```@docs
PVLC
state_prediction_matrices
```

#### State Prediction Matrix Algebra

At step k:

```math
\begin{split}
y_k &= C x_k + D u_k\\
x_k &= A x_{k-1} + B u_{k-1}\\
x_{k+1} &= A x_{k} + B u_{k}
\end{split}
```

Therefore to h steps in history:

For all output estimates:

```math
\begin{split}
y_k & = C x_k + D u_k \\
& = C (A x_{k-1} + B u_{k-1}) + D u_k \\
& = C (A (A x_{k-2} + B u_{k-2}) + B u_{k-1}) + D u_k \\
& = ... \\
& = C A^{h-1} x_{k-(h-1)} + C A^{h-2} B u_{k-(h-1)} + C A^{h-3} B u_{k-(h-2)} + ... + CAB u_{k-2} + CB u_{k-1} + D u_k \\
\end{split}
```

```math
\begin{split}
y_k &= C A^{h-1} x_{k-(h-1)} + C A^{h-2} B u_{k-(h-1)} + C A^{h-3} B u_{k-(h-2)} + ... + CAB u_{k-2} + CB u_{k-1} + D u_k \\
y_{k-1} &= C A^{h-2} x_{k-(h-1)} + C A^{h-3} B u_{k-(h-1)} + C A^{h-4} B u_{k-(h-2)} + ... + CAB u_{k-3} + CB u_{k-2} + D u_{k-1} \\

... &= ... \\
y_{k-i} &= C A^{h-1-i} x_{k-(h-1)} + C A^{h-2-i} B u_{k-(h-1)} + C A^{h-3-i} B u_{k-(h-2)} + ... + CB u_{k-i-1} + D u_{k-i} \\
... &= ... \\
y_{k-(h-3)} &= C A^2 x_{k-(h-1)} + CAB u_{k-(h-1)}+ CB u_{k-(h-2)} + D u_{k-(h-3)} \\
y_{k-(h-2)} &= C A x_{k-(h-1)} + CB u_{k-(h-1)} + D u_{k-(h-2)} \\
y_{k-(h-1)} &= C x_{k-(h-1)} + D u_{k-(h-1)}
\end{split}
```

For predicted next state:

```math
\begin{split}
x_{k+1} & = A x_{k} + B u_{k} \\
& = A (A x_{k-1} + B u_{k-1}) + B u_{k} \\
& = A (A (A x_{k-2} + B u_{k-2}) + B u_{k-1}) + B u_{k} \\
& = ... \\
& = A^h x_{k-(h-1)} + A^{h-1} B u_{k-(h-1)} + A^{h-2} B u_{k-(h-2)} + ... + A^2 B u_{k-2} + A B u_{k-1} + B u_{k} \\
\end{split}
```

In terms of mega-matrices, define mega-vectors of inputs and outputs:

```math
\vec{Y} = \begin{bmatrix}
y_{k-(h-1)} \\
y_{k-(h-2)} \\
... \\
y_{k-1} \\
y_{k}
\end{bmatrix}
```

Note that for multiple outputs, each output vector will be stacked vertically to create a single column.

```math
\vec{U} = \begin{bmatrix}
u_{k-(h-1)} \\
u_{k-(h-2)} \\
... \\
u_{k-1} \\
u_{k}
\end{bmatrix}
```

Note that for multiple inputs, each input vector will be stacked vertically to create a single column.

Then, from $x_{k-(h-1)}$ and $\vec{U}$, we get $\vec{Y}$ and predicted state $x_{k+1}$:
```math
\vec{Y} = \mathcal{L} x_{k-(h-1)} + \mathcal{M} \vec{U}
```
```math
x_{k+1} = \mathcal{N} x_{k-(h-1)} + \mathcal{O} \vec{U}
```

Where the mega-matrices $\mathcal{L}$, $\mathcal{M}$, $\mathcal{N}$, $\mathcal{O}$ are:

``\mathcal{L}`` is a matrix with (h x no. of outputs) rows and state-space order columns:

```math
\mathcal{L} = \begin{bmatrix}
C... \\
CA... \\
CA^2... \\
... \\
CA^{h-2}... \\
CA^{h-1}...
\end{bmatrix}
```

``\mathcal{M}`` is a matrix with (h x no. of outputs) rows and (h x no. of inputs) columns:

```math
\mathcal{M} = \begin{bmatrix}
D & 0 & 0 & ... & 0 & 0 & 0 & 0 & \\
CB & D & 0 & ... & 0 & 0 & 0 & 0 & \\
CAB & CB & D & ... & 0 & 0 & 0 & 0 & \\
... & ... & ... & ... & ... & ... & ... & ... & ... \\
C A^{h-4} B & C A^{h-5} B & C A^{h-6} B & ... & CAB & CB & D & 0 & 0 \\
C A^{h-3} B & C A^{h-4} B & C A^{h-5} B & ... & CA^2B & CAB & CB & D & 0 \\
C A^{h-2} B & C A^{h-3} B & C A^{h-4} B & ... & CA^3B & CA^2B & CAB & CB & D \\
\end{bmatrix}
```

``\mathcal{N}`` is a square matrix with state-space order columns and rows:

```math
\mathcal{N} = A^{h}
```

``\mathcal{O}`` is a matrix with state-space order rows and (h x no. of inputs) columns:

```math
\mathcal{O} = \begin{bmatrix} A^{h-1} B & A^{h-2} B & A^{h-3} B & ... & A^2 B & AB & B \end{bmatrix}
```

Then, future state can be predicted by:

```math
x_{k+1} = \mathcal{N} \mathcal{L}^{-1} (\vec{Y} - \mathcal{M} \vec{U}) + \mathcal{O} \vec{U}
```

### Model Predictive Controller

```@docs
MPC
```

## Closed loop simulations

```@docs
lsim_step
model_step
run_closed_loop_sim
```

## Unit conversion utilities

```@docs
Expand Down
1 change: 1 addition & 0 deletions src/SOLPS2ctrl.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ include("$(@__DIR__)/supersize_profile.jl")
include("$(@__DIR__)/repair_eq.jl")
include("$(@__DIR__)/unit_utils.jl")
include("$(@__DIR__)/system_id.jl")
include("$(@__DIR__)/controllers.jl")

"""
find_files_in_allowed_folders(
Expand Down
Loading
Loading