Skip to content

Commit c00f878

Browse files
committed
Merge branch 'master' into parallel_environment_return_pids
2 parents 3af11e8 + c2f4747 commit c00f878

File tree

106 files changed

+28000
-1377
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

106 files changed

+28000
-1377
lines changed

.github/workflows/runtests.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,9 @@ jobs:
155155
# Run tests
156156
- uses: julia-actions/julia-runtest@v1
157157

158-
# Code coverage
159-
- uses: julia-actions/julia-processcoverage@v1
160-
- uses: codecov/codecov-action@v5
161-
if: github.ref != 'refs/heads/master'
162-
with:
163-
token: ${{ secrets.CODECOV_TOKEN }}
158+
# # Code coverage
159+
# - uses: julia-actions/julia-processcoverage@v1
160+
# - uses: codecov/codecov-action@v5
161+
# if: github.ref != 'refs/heads/master'
162+
# with:
163+
# token: ${{ secrets.CODECOV_TOKEN }}

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ LocalPreferences.toml
7272
julia-*.out
7373
examples/Untitled.ipynb
7474
tmp.gif
75+
*.pyc
76+
*.log
7577

7678
# Generated knowledge base files
77-
knowledge/actors/
79+
knowledge/actors/
80+
knowledge/mcp_server/start_server.sh

Makefile

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,42 @@ install_playground: .PHONY
692692
if [ -d playground ] && [ ! -f playground/.gitattributes ]; then mv playground playground_private ; fi
693693
if [ ! -d "playground" ]; then git clone https://github.com/ProjectTorreyPines/FusePlayground.git playground ; else cd playground && git pull origin `git rev-parse --abbrev-ref HEAD` ; fi
694694

695+
# @devs
696+
knowledge: .PHONY
697+
# Extract FUSE actor knowledge base using Claude analysis
698+
@echo "Extracting FUSE actor knowledge base..."
699+
@cd knowledge && julia --threads=$(JULIA_NUM_THREADS) -e 'include("extract_knowledge.jl"); extract_fuse_knowledge_parallel()'
700+
@echo "Knowledge extraction complete! Check knowledge/fuse_knowledge_base.json"
701+
702+
# @devs
703+
knowledge_clean: .PHONY
704+
# Clean up orphaned actor files in knowledge base
705+
@echo "Checking for orphaned actor files..."
706+
@cd knowledge && julia -e 'include("extract_knowledge.jl"); clean_orphaned_fuse_actors()'
707+
708+
# @dev
709+
learn_usage:
710+
# Learn FUSE usage from Jupyter notebooks and update knowledge/how_to_use_fuse.md
711+
cd knowledge ; ./learn_fuse_usage.sh ../examples/tutorial.ipynb ../examples/tutorial_imas.ipynb ../examples/fluxmatcher.ipynb ../examples/study_TGLFdb.ipynb ../examples/time_dependent_d3d.ipynb ../examples/time_dependent_iter.ipynb ../examples/study_database_generator.ipynb ../examples/study_multi_objective_optimizer.ipynb
712+
713+
# @devs
714+
learn_init:
715+
# Create comprehensive guide on how to initialize FUSE by analyzing case files and parameter structures
716+
claude "Write a how_to_init_fuse.md knowledge file, structured for users and LLMs to learn how to define FUSE use cases. You should looking at each individual *.jl files under FUSE/src/cases (don't skip any, they are all important!). Also add a note about the parameters definitions being in FUSE/src/parameters/parameters_inits.jl and use this file to build your .md documentation as necessary."
717+
718+
# @devs
719+
learn_actors_docstrings:
720+
# update actors docstrings
721+
claude "Go through each and every actor file (***_actor.jl) and (in parallel) spawn a claude session to improve the docstring of each. \
722+
Don't add any docstring to the \`@actor_parameters_struct\` or the Actor constructor. \
723+
Instead you should focus on the \`ActorXXX(dd,act)\` function which in the end is what is going to appear in the online documentation. \
724+
You can add some extra details to the docstrings of \`_step()\` and \`_finalize()\`. \
725+
NEVER document boilerplate arguments, like \`dd\`, \`par\`, \`act\`, \`kw...\`. \
726+
To know what an actor does, look at the executable code. \
727+
If there's already a docstring, verify it against the executable code. \
728+
If there's any conflicting information the executable code should take precendence. \
729+
To know what actors need documentation, search for \`actor_parameters_struct\`, and process them in parallel claude sessions."
730+
695731
# @devs
696732
list_open_compats:
697733
# List compat patches PR on GitHub

Project.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "FUSE"
22
uuid = "e64856f0-3bb8-4376-b4b7-c03396503992"
33
authors = ["Orso Meneghini <[email protected]>"]
4-
version = "0.9.1"
4+
version = "0.9.2"
55

66
[deps]
77
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
@@ -67,14 +67,15 @@ TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f"
6767
TroyonBetaNN = "c0158764-c6e1-428b-a545-31826f389bc8"
6868
TurbulentTransport = "9bf5e8f4-5746-4003-bc69-ef83265c10ca"
6969
VacuumFields = "9d9223b5-c5da-4bf4-abee-2a8bb6775a49"
70-
Weave = "44d3d7a6-8a23-5bf8-98c5-b353f8df5ec9"
7170
YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6"
7271

7372
[weakdeps]
7473
ThermalSystemModels = "68b8b4ac-b179-4f07-8ae9-c1f1360acbca"
74+
Weave = "44d3d7a6-8a23-5bf8-98c5-b353f8df5ec9"
7575

7676
[extensions]
7777
ThermalSystemModelsExt = "ThermalSystemModels"
78+
WeaveExt = "Weave"
7879

7980
[compat]
8081
AbstractTrees = "0.4"

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ The figure below is a sneakpeak of the models implemented in FUSE:
1212

1313
Here are some key resources for getting started with FUSE:
1414

15+
* 📨 **[Sign up for more info](https://forms.gle/iQGYKWfgeNkw2fCZ7)**
1516
* 📚 **[Online documentation](https://fuse.help)**
1617
* 🎓 **[Intro tutorial](https://fuse.help/dev/tutorial.html)**
1718
* 🎤 **[Recent presentation](https://github.com/ProjectTorreyPines/FUSE_extra_files/raw/master/2025_D3D/SET_mar_2025.pdf)**

docs/Project.toml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,41 @@
11
[deps]
2+
ADAS = "f4a0d185-1024-41e7-8ef7-3196bb2f6549"
23
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
4+
BalanceOfPlantSurrogate = "001e48cb-5a1e-4e3c-a5d4-cdc3aa14f3de"
5+
BoundaryPlasmaModels = "2da5b0d0-c5e5-4f14-9caf-62d0020df410"
6+
CHEASE = "40781a8e-f1bb-11ec-24ef-0f6bc40c1567"
7+
CoordinateConventions = "7204ce3a-f536-43d2-be4a-fbed74e90d86"
38
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
49
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
10+
EGGO = "25cd7528-e4e3-46fe-8df7-7ec8e1454e14"
11+
EPEDNN = "e64856f0-3bb8-4376-b4b7-c03396503991"
12+
FRESCO = "f2db6eb9-2c54-4c18-912b-ce467796777a"
513
FUSE = "e64856f0-3bb8-4376-b4b7-c03396503992"
14+
FiniteElementHermite = "6ce10167-d368-4c0e-af34-9787cdd175e5"
15+
FuseExchangeProtocol = "43dcb517-7681-482a-b959-351932bd0b36"
16+
FusionMaterials = "4c86da02-02c8-4634-8460-96566129f8e0"
17+
GACODE = "bb074124-7a58-47ce-bd41-6b7098184f23"
18+
HelpPlots = "5880b2e8-ad0a-48c9-bacd-30dc9c1357e0"
619
IMAS = "13ead8c1-b7d1-41bb-a6d0-5b8b65ed587a"
720
IMASdd = "c5a45a97-b3f9-491c-b9a7-aa88c3bc0067"
821
IMASutils = "b8e4ee59-9bed-3a6a-a553-8dd24d6374ad"
922
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
1023
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
1124
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
25+
MXHEquilibrium = "8efa4e5a-7b9a-4eec-876e-01d13d5b5d75"
26+
MillerExtendedHarmonic = "c82744c2-dc08-461a-8c37-87ab04d0f9b8"
27+
NNeutronics = "a9424c20-d414-11ec-167b-9106c24d956c"
28+
NeoclassicalTransport = "e630bb45-bea9-4e62-953e-b44d0741ac01"
1229
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
1330
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
1431
ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca"
32+
QED = "8bcbec86-48c7-11ec-16a6-c1bc83299373"
33+
RABBIT = "98960a00-302f-469e-9595-275b70d10766"
1534
SimulationParameters = "32ab26d3-25d6-405d-a295-367385e16093"
35+
TEQUILA = "a60c9cbd-e72f-4185-96b6-b8fc312c4d37"
36+
TJLF = "12ecd31c-256b-4db5-a799-cd5afeb0bd7d"
37+
TORBEAM = "b9bf819a-2a49-451a-b482-4ce9066e62e1"
38+
ThermalSystemModels = "68b8b4ac-b179-4f07-8ae9-c1f1360acbca"
39+
TroyonBetaNN = "c0158764-c6e1-428b-a545-31826f389bc8"
40+
TurbulentTransport = "9bf5e8f4-5746-4003-bc69-ef83265c10ca"
41+
VacuumFields = "9d9223b5-c5da-4bf4-abee-2a8bb6775a49"

docs/src/cases_docs.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pushfirst!(
2525
CurrentModule = FUSE
2626
```
2727
28-
FUSE comes with a set of pre-cookes used cases.
28+
FUSE comes with a set of pre-cooked use cases.
2929
The `case_parameters(:use_case, ...)` method returns the `ini` and `act` parameters for that specific `use_case`.
3030
These `ini` and `act` can then be further customized before running a FUSE simulation.
3131

docs/src/install.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ For installation start your Julia interpreter by typing `julia` at the terminal,
6868
!!! note
6969
The WebIO jupyter-lab extension is needed for the [`Interact.jl`](https://github.com/JuliaGizmos/Interact.jl?tab=readme-ov-file#usage) package to work.
7070

71-
Make sure WebIO is working with `jupyter labextension list`.
71+
Make sure WebIO is working with `jupyter labextension list`. If it is working properly, you should see something like: webio-jupyterlab-provider v0.1.0 enabled OK (python, webio_jupyter_extension). This can also be checked with `jupyter nbextension list`, which should show something like: webio-jupyter-nbextension/nbextension enabled.
7272

73-
If the extension has compatibility issues, consider installing an older verision of Jupyter (eg. `conda install jupyterlab=3.6.7`).
73+
If the extension has compatibility issues, consider installing an older verision of Jupyter (eg. `conda install jupyterlab=3.6.7`). Also ensure that the WebIO and Interact packages are fully up-to-date, and restart the notebook session before testing that it works. Finally, it may be necessary to downgrade your system's version of Python - the recommended version for compatibility with Interact is 3.11.11.
7474

7575
1. Start a new Jupyter-lab session (this should open a web-browser page with Jupyter running)
7676

docs/src/tutorial.jl

Lines changed: 4 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -210,185 +210,18 @@ FUSE.digest(dd)
210210

211211
@checkin :awf dd ini act
212212

213-
# # Getting into the weeds
213+
# # Working with the IMAS data structure
214214

215-
# ## Saving and loading data
216-
217-
tutorial_temp_dir = tempdir()
218-
filename = joinpath(tutorial_temp_dir, "$(ini.general.casename).json")
219-
220-
# When saving data to be shared outside of FUSE, one can set `freeze=true` so that all expressions in the dd are evaluated and saved to file.
221-
222-
IMAS.imas2json(dd, filename; freeze=false, strict=false);
223-
224-
# Load from JSON
225-
226-
dd1 = IMAS.json2imas(filename);
227-
228-
# ## Exploring the data dictionary
229-
# * FUSE stores data following the IMAS data schema.
230-
# * The root of the data structure is `dd`, which stands for "Data Dictionary".
231-
# * More details are available in the [documentation](https://fuse.help/stable/dd.html).
232-
233-
# Display part of the equilibrium data in `dd`
234-
235-
dd.equilibrium.time_slice[1].boundary
236-
237-
# this can be done up to a certain depth with `print_tree`
238-
239-
print_tree(dd.equilibrium.time_slice[1].boundary; maxdepth=1)
240-
241-
# ## Plotting data from `dd`
242-
# FUSE uses `Plots.jl` recipes for visualizing data from `dd`.
243-
#
244-
# This allows different plots to be shown when calling `plot()` on different items in the data structure.
215+
# See the IMAS tutorial https://github.com/ProjectTorreyPines/FuseExamples/blob/master/tutorial_imas.ipynb
245216
#
246-
# Learn more about Plots.jl [here](https://docs.juliaplots.org)
247-
248-
# For example plotting the equilibrium...
249-
250-
plot(dd.equilibrium)
251-
252-
# ...or the core profiles
253-
254-
plot(dd.core_profiles)
255-
256-
# Whant to know what arguments can be passed? use `help_plot()` function
257-
258-
help_plot(dd.equilibrium; core_profiles_overlay=true, levels_in=21, levels_out=5, show_secondary_separatrix=true, coordinate=:rho_tor_norm)
259-
260-
# These plots can be composed by calling `plot!()` instead of `plot()`
261-
262-
plot(dd.equilibrium; color=:gray, cx=true)
263-
plot!(dd.build.layer)
264-
plot!(dd.pf_active)
265-
plot!(dd.pf_passive)
266-
plot!(dd.pulse_schedule.position_control; color=:red)
267-
268-
# Plotting an array...
269-
270-
plot(dd.core_profiles.profiles_1d[1].pressure_thermal)
271-
272-
# ...is different from plotting a field from the IDS (which plots the quantity against its coordinate and with units)
273-
274-
plot(dd.core_profiles.profiles_1d[1], :pressure_thermal)
275-
276-
# Customizing plot attributes:
277-
278-
plot(dd.core_profiles.profiles_1d[1], :pressure_thermal; label="", linewidth=2, color=:red, labelfontsize=25)
279-
280-
# Use `findall(ids, r"...")` to search for certain fields. In Julia, string starting with `r` are regular expressions.
281-
282-
findall(dd, r"\.psi")
283-
284-
# `findall(ids, r"...")` can be combined with `plot()` to plot multiple fields
285-
286-
plot(findall(dd, r"\.psi"))
287-
288-
# ## Working with time series
289-
290-
# The IMAS data structure supports time-dependent data, and IMAS.jl provides ways to handle time data efficiently.
291-
292-
# Each `dd` has a `global_time` attribute, which is used throughout FUSE and IMAS to indicate the time at which things should be operate.
293-
294-
dd.global_time
295-
296-
# For the sake of demonstrating handling of time, let's add a new time_slice to the equilibrium.
297-
#
298-
# **NOTE:** in addition to the usual `resize!(ids, n::Int)`, time dependent arrays of structures can be resized with:
299-
# * `resize!(ids)` which will add a time-slice at the current global time (this is what you want to use in most cases)
300-
# * `resize!(ids, time0)` which will add a time-slice at `time0` seconds
301-
302-
# resize the time dependent array of structure
303-
resize!(dd.equilibrium.time_slice, 1.0);
304-
305-
# let's just populate it with the data from the previous time slice
306-
dd.equilibrium.time_slice[2] = deepcopy(dd.equilibrium.time_slice[1]);
307-
dd.equilibrium.time_slice[2].time = 1.0
308-
309-
# Here we see that equilibrium has mulitiple time_slices
310-
311-
dd.equilibrium.time
312-
313-
# We can access time-dependent arrays of structures via integer index...
314-
315-
eqt = dd.equilibrium.time_slice[2]
316-
eqt.time
317-
318-
# ...or at a given time, by passing the time as a floating point number (in seconds)
319-
320-
eqt = dd.equilibrium.time_slice[1.0]
321-
eqt.time
322-
323-
# NOTE: If we ask a time that is not exactly in the arrays of structures, we'll get the closest (causal!) time-slice
324-
325-
eqt = dd.equilibrium.time_slice[0.9]
326-
eqt.time
327-
328-
eqt = dd.equilibrium.time_slice[1.1]
329-
eqt.time
330-
331-
# ... or at the current `dd.global_time` by leaving the square brackets empty []
332-
#
333-
# **NOTE:** using `[]` is what you want to use in most situations that involve time-dependent arrays of structures!
334-
335-
dd.global_time = 0.0
336-
eqt = dd.equilibrium.time_slice[]
337-
eqt.time
338-
339-
dd.global_time = 1.0
340-
eqt = dd.equilibrium.time_slice[]
341-
eqt.time
342-
343-
# What we described above was for time-dependent arrays of structures.
344-
#
345-
# The other place where time comes in, is when dealing with time-dependent arrays of data.
346-
#
347-
# In this case, we can use the `@ddtime` macro to manipulate these time-dependent arrays at `dd.global_time`.
348-
#
349-
# NOTE: Also in this case, `@ddtime` will operate on the closest (causal!) time point
350-
351-
dd.equilibrium.vacuum_toroidal_field.b0
352-
353-
dd.global_time = 1.0
354-
@ddtime(dd.equilibrium.vacuum_toroidal_field.b0 = 10.0)
355-
dd.equilibrium.vacuum_toroidal_field.b0
356-
357-
dd.global_time = 0.0
358-
@ddtime(dd.equilibrium.vacuum_toroidal_field.b0)
359-
360-
dd.global_time = 1.0
361-
@ddtime(dd.equilibrium.vacuum_toroidal_field.b0)
362-
363-
# ## Expressions in `dd`
364-
365-
# Some fields in the data dictionary are expressions (ie. Functions).
366-
# For example `dd.core_profiles.profiles_1d[].pressure` is dynamically calculated as the product of thermal densities and temperature with addition of fast ions contributions
367-
368-
dd.global_time = 0.0
369-
print_tree(dd.core_profiles.profiles_1d[]; maxdepth=1)
370-
371-
# accessing a dynamic expression, automatically evaluates it
372-
373-
dd.core_profiles.profiles_1d[].conductivity_parallel
374-
375-
# In addition to evaluating expressions by accessing them, expressions in the tree can be evaluated using `IMAS.freeze(ids)`
376-
#
377-
# NOTE: `IMAS.freeze(ids, field::Symbol)` works on a single field and `IMAS.refreeze!(ids, field)` forces re-evaluation of an expression. Also, `IMAS.empty!(ids, field::Symbol)` can be used to revert a frozen field back into an expression.
378-
379-
print_tree(IMAS.freeze(dd.core_profiles.profiles_1d[1]); maxdepth=1)
380-
381-
# ## Comparing two IDSs
382-
# We can introduce a change in the `dd1` and spot it with the `diff` function
383-
384-
dd1.equilibrium.time_slice[1].time = -100.0
385-
IMAS.diff(dd.equilibrium, dd1.equilibrium)
217+
# Understanding how to work with the IMAS data structure is a must for working within the FUSE ecosystem!
386218

387219
# ## Summary
388220
# Snapshot of `dd` in 0D quantities (evaluated at `dd.global_time`).
389221
#
390222
# Extract + plots saved to PDF (printed to screen if `filename` is omitted). NOTE: For PDF creation to work, one may need to install of `DejaVu Sans Mono` font.
391223

224+
tutorial_temp_dir = tempdir()
392225
filename = joinpath(tutorial_temp_dir, "$(ini.general.casename).pdf")
393226
display(filename)
394227
FUSE.digest(dd)#, filename)

0 commit comments

Comments
 (0)