Skip to content

Commit

Permalink
Cleanup and documentation
Browse files Browse the repository at this point in the history
* core_profiles_2d has been removed as GGDUtils.interp provides the same functionality
* The actuator_model.jl has been moved to unit_utils.jl with only unit conversion utilities. SynthDiag.compute_gas_injection provides gas actuation model directly from IMAS dd now.
* All functions have strict input and output types defined.
* All docstrings have been updated to be more informative.
* Tests have been updated and cleaned up a bit.
  • Loading branch information
anchal-physics committed May 9, 2024
1 parent 615820f commit 2ccac22
Show file tree
Hide file tree
Showing 10 changed files with 477 additions and 374 deletions.
40 changes: 40 additions & 0 deletions .github/workflows/make_docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Make Docs
on:
pull_request:
branches: ["master", "dev"]
push:
branches:
- master
- dev
- docs
paths:
- '.github/workflows/make_docs.yml'
- 'src/'
- 'docs/**'
tags: '*'
workflow_dispatch:

jobs:
make_docs:
permissions:
actions: write
contents: write
statuses: write
name: Documentation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: julia-actions/setup-julia@latest
- uses: julia-actions/cache@v1
- name: Extract branch name
shell: bash
run: echo "branch=${GITHUB_BASE_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT
id: extract_branch
- name: Install dependencies
run: |
julia --project=docs/ -e 'using Pkg; Pkg.add(; url="https://github.com/ProjectTorreyPines/IMASDD.jl.git"); Pkg.add(; url="https://github.com/ProjectTorreyPines/GGDUtils.jl.git", rev="${{ steps.extract_branch.outputs.branch }}"); Pkg.add(; url="https://github.com/ProjectTorreyPines/SOLPS2IMAS.jl.git", rev="${{ steps.extract_branch.outputs.branch }}"); Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()'
- name: Build and deploy
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }}
run: julia --project=docs/ docs/make.jl
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
Manifest.toml
sd_input_data.json
example/Project.toml
docs/build
2 changes: 2 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[deps]
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
17 changes: 17 additions & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Documenter
using SD4SOLPS

makedocs(;
modules=[SD4SOLPS],
format=Documenter.HTML(),
sitename="SD4SOLPS",
checkdocs=:none,
)

deploydocs(;
repo="github.com/ProjectTorreyPines/SD4SOLPS.jl.git",
target="build",
branch="gh-pages",
devbranch="dev",
versions=["stable" => "v^", "v#.#"],
)
98 changes: 98 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@

# SD4SOLPS.jl

```@contents
Pages = ["index.md"]
Depth = 3
```

This repository serves as the top most workflow manager with helpful utilities to use other repositories in this project.

## Documentation of other repositories in this project

### [GGDUtils.jl](https://projecttorreypines.github.io/GGDUtils.jl/stable)

### [SOLPS2IMAS.jl](https://projecttorreypines.github.io/SOLPS2IMAS.jl/stable)

### [SynthDiag.jl](https://projecttorreypines.github.io/SynthDiag.jl/stable)

## Installation

### Using make:
After cloning this repo, check the make menu:
```
SD4SOLPS.jl % make help
Help Menu
make env_with_cloned_repo (or make r): Creates a Julia environment with the cloned repositories
make env_with_git_url (or make u): Creates a Julia environment with the git urls without creating local clones
make clean: Deletes Project.toml and Manifest.toml for a fresh start
```

#### make r
This option creates local copies of required private repositories at the same level as current repository and uses them in develop mode to create a Manifest.toml

#### make u
This option uses url of required private repositories to create a static Manifest.toml attached to current master branches of these repositories.

#### make clean
Deletes Manifest.toml so that environment can be recreated, to update or change the last used method.

### Using Julia REPL and installing using Github url

Or, in julia REPL:
```julia
julia> using Pkg;
julia> Pkg.add(; url="https://github.com/ProjectTorreyPines/IMASDD.jl.git");
julia> Pkg.add(; url="https://github.com/ProjectTorreyPines/GGDUtils.jl.git");
julia> Pkg.add(; url="https://github.com/ProjectTorreyPines/SOLPS2IMAS.jl.git");
julia> Pkg.add(; url="https://github.com/ProjectTorreyPines/SD4SOLPS.jl.git");
julia> Pkg.instantiate()
```

## Top file handling functions

```@docs
find_files_in_allowed_folders
geqdsk_to_imas!
preparation
```

## Repairing/filling out partial equilibrium files

Tools for repairing/filling out partial equilibrium files.

Some of the added fields may not be totally accurate, so it is recommended to
use this tool mainly for test cases, as a utility. For a real equilibrium,
problems should be fixed properly.

```@docs
add_rho_to_equilibrium!
check_rho_1d
```

## Extrapolations

Utilities for extrapolating profiles

### Core profile extrapolations

```@docs
extrapolate_core
fill_in_extrapolated_core_profile!
```

### Edge profiles extrapolations

These functions have not been fully tested and/or supported yet.

```@docs
mesh_psi_spacing
cached_mesh_extension!
```

## Unit conversion utilities

```@docs
gas_unit_converter
```
150 changes: 46 additions & 104 deletions src/SD4SOLPS.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,37 @@ using IMASDD: IMASDD
using SOLPS2IMAS: SOLPS2IMAS
using EFIT: EFIT
using Interpolations: Interpolations
#import GGDUtils

export find_files_in_allowed_folders
export geqdsk_to_imas!
export find_files_in_allowed_folders, geqdsk_to_imas!, preparation

include("$(@__DIR__)/supersize_profile.jl")
include("$(@__DIR__)/repair_eq.jl")
include("$(@__DIR__)/actuator_model.jl")

greet() = print("Hello World!")
include("$(@__DIR__)/unit_utils.jl")

"""
find_files_in_allowed_folders()
find_files_in_allowed_folders(
input_dirs::String...;
eqdsk_file::String,
recursive::Bool=true,
)
Searches a list of allowed folders for a set of filenames that will provide information
about the SOLPS case. Returns a list of filenames with complete paths.
Example:
```julia
SD4SOLPS.find_files_in_allowed_folders(
"<your samples folder>/D3D_Ma_184833_03600",
eqdsk_file="g184833.03600",
"<your samples folder>/D3D_Ma_184833_03600";
eqdsk_file="g184833.03600",
)
```
"""
function find_files_in_allowed_folders(
input_dirs...;
eqdsk_file,
recursive=true,
allow_reduced_versions=false,
)
input_dirs::String...;
eqdsk_file::String,
recursive::Bool=true,
)::Vector{String}
files = ["b2fgmtry", "b2time.nc", "b2mn.dat", eqdsk_file]
reduced_files =
["b2fgmtry_red", "b2time_red.nc", "b2mn.dat", eqdsk_file]
Expand All @@ -46,7 +48,7 @@ function find_files_in_allowed_folders(
else
dirs = input_dirs
end
for i 1:length(files)
for i eachindex(files)
for dir dirs
file = dir * "/" * files[i]
reduced_file = dir * "/" * reduced_files[i]
Expand All @@ -63,12 +65,22 @@ function find_files_in_allowed_folders(
end

"""
geqdsk_to_imas!()
Transfers the equilibrium reconstruction in an EFIT-style gEQDSK file into
geqdsk_to_imas!(
eqdsk_file::String,
dd::IMASDD.dd;
set_time::Union{Nothing, Float64}=nothing,
time_index::Int=1,
)
Transfers the equilibrium reconstruction from an EFIT-style gEQDSK file into
the IMAS DD structure.
"""
function geqdsk_to_imas!(eqdsk_file, dd; set_time=nothing, time_index=1)
function geqdsk_to_imas!(
eqdsk_file::String,
dd::IMASDD.dd;
set_time::Union{Nothing, Float64}=nothing,
time_index::Int=1,
)
# https://github.com/JuliaFusion/EFIT.jl/blob/master/src/io.jl
g = EFIT.readg(eqdsk_file; set_time=set_time)
# Copying ideas from OMFIT: omfit/omfit_classes/omfit_eqdsk.py / to_omas()
Expand Down Expand Up @@ -134,7 +146,7 @@ function geqdsk_to_imas!(eqdsk_file, dd; set_time=nothing, time_index=1)
if length(xrs) > 0
bx = eqt.boundary.x_point
resize!(bx, length(xrs))
for i length(xrs)
for i eachindex(xrs)
bx[i].r = xrs[i]
bx[i].z = xzs[i]
end
Expand Down Expand Up @@ -179,98 +191,28 @@ function geqdsk_to_imas!(eqdsk_file, dd; set_time=nothing, time_index=1)
end

"""
core_profile_2d(dd, prof_time_idx, eq_time_idx, quantity)
Reads a 1D core profile and flux map and returns a quantity at requested R,Z points
dd: a data dictionary instance with equilibrium and core profile data loaded
quantity: a string specifying the quantity to fetch
Returns a callable function that takes (r, z) as arguments and returns the quantity
"""
function core_profile_2d(dd, prof_time_idx, eq_time_idx, quantity)
if !check_rho_1d(dd; time_slice=eq_time_idx)
throw(ArgumentError("Equilibrium rho profile in input DD was missing."))
end
prof = dd.core_profiles.profiles_1d[prof_time_idx]
rho_prof = prof.grid.rho_tor_norm
quantity_fields = split(quantity, ".")
p = prof
for field quantity_fields
p = getproperty(p, Symbol(field))
end
eqt = dd.equilibrium.time_slice[eq_time_idx]
p1 = eqt.profiles_1d
p2 = eqt.profiles_2d[1]
gq = eqt.global_quantities
psi_a = gq.psi_axis
psi_b = gq.psi_boundary
rhon_eq = p1.rho_tor_norm
psi_eq = p1.psi
psin_eq = (psi_eq .- psi_a) ./ (psi_b - psi_a)
psirz = p2.psi
psinrz = (psirz .- psi_a) ./ (psi_b - psi_a)
r_eq = p2.grid.dim1
z_eq = p2.grid.dim2
extension = [1.0001, 1.1, 5]
# rho_N isn't defined on open flux surfaces, so it is extended by copying psi_N
psin_eq_ext = copy(psin_eq)
append!(psin_eq_ext, extension)
rhon_eq_ext = copy(rhon_eq)
append!(rhon_eq_ext, extension)
neg_extension = [-5, -0.0001] # I guess this would be at a PF coil or something?
prepend!(psin_eq_ext, neg_extension)
prepend!(rhon_eq_ext, neg_extension)

rho_prof_ext = vcat(rho_prof, extension)
p_ext = vcat(p, zeros(size(extension)))
rho_prof_ext = prepend!(rho_prof_ext, neg_extension)
p_ext = prepend!(p_ext, zeros(size(neg_extension)))

# Data are set up and ready to process

# EDGE PROFILES (the input data):
# rho_prof_ext: rho_N values associated with the profile of some quantity
# p_ext : profile of some quantity vs. rho_prof

# EQUILBRIUM (the connection from rho to R,Z via psi):
# psin_eq_ext : 1D array of psi_N values that corresponds to rhon_eq_ext
# rhon_eq_ext : 1D array of rho_N values that corresponds to psin_eq_ext
# --> connects rho to everything else via psi
# psinrz : 2D array of psi_N values that corresponds to r_eq and z_eq
# r_eq and z_eq : 1D coordinate arrays that correspond to psinrz

# OUTPUT INSTRUCTIONS:
# r and z : coordinates of output points where values of p are desired

# psi_at_requested_points =
# Interpolations.linear_interpolation((r_eq, z_eq), psinrz).(r, z)
# rhonpsi = Interpolations.linear_interpolation(psin_eq_ext, rhon_eq_ext)
# rho_at_requested_points = rhonpsi.(psi_at_requested_points)
# itp = Interpolations.linear_interpolation(rho_prof_ext, p_ext)
# p_at_requested_points = itp.(rho_at_requested_points)
# return p_at_requested_points
rz2psin = Interpolations.linear_interpolation((r_eq, z_eq), psinrz)
psin2rhon = Interpolations.linear_interpolation(psin_eq_ext, rhon_eq_ext)
rhon2prof = Interpolations.linear_interpolation(rho_prof_ext, p_ext)
return (r, z) -> rhon2prof(psin2rhon(rz2psin(r, z)))
end

"""
preparation()
preparation(
eqdsk_file::String,
dirs::String...;
core_method::String="simple",
filename::String="sd_input_data",
output_format::String="json",
eqdsk_set_time::Union{Nothing, Float64}=nothing,
eq_time_index::Int64=1,
)::IMASDD.dd
Gathers SOLPS and EFIT files and loads them into IMAS structure. Extrapolates
profiles as needed to get a complete picture.
"""
function preparation(
eqdsk_file,
dirs...;
eqdsk_file::String,
dirs::Vector{String};
core_method::String="simple",
edge_method::String="simple",
filename::String="sd_input_data",
output_format::String="json",
eqdsk_set_time=nothing,
eq_time_index=1,
)
eqdsk_set_time::Union{Nothing, Float64}=nothing,
eq_time_index::Int64=1,
)::IMASDD.dd
b2fgmtry, b2time, b2mn, eqdsk =
find_files_in_allowed_folders(dirs...; eqdsk_file=eqdsk_file)
println("Found source files:")
Expand Down
12 changes: 10 additions & 2 deletions src/repair_eq.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,19 @@ export add_rho_to_equilibrium!
export check_rho_1d

"""
function check_rho_1d()
check_rho_1d(
dd::IMASDD.dd;
time_slice::Int64=1,
throw_on_fail::Bool=false,
)::Bool
Checks to see if rho exists and is valid in the equilibrium 1d profiles
"""
function check_rho_1d(dd::IMASDD.dd; time_slice::Int64=1, throw_on_fail::Bool=false)
function check_rho_1d(
dd::IMASDD.dd;
time_slice::Int64=1,
throw_on_fail::Bool=false,
)::Bool
rho = dd.equilibrium.time_slice[time_slice].profiles_1d.rho_tor_norm
if length(rho) < 1
rho_okay = false
Expand Down
Loading

0 comments on commit 2ccac22

Please sign in to comment.