Skip to content

3/initiliaze from mesh#613

Open
malamast wants to merge 2 commits into
masterfrom
3/initiliaze-from-mesh
Open

3/initiliaze from mesh#613
malamast wants to merge 2 commits into
masterfrom
3/initiliaze-from-mesh

Conversation

@malamast

@malamast malamast commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Purpose

Added a functionality to initialize number density and pressure from grid variables with names varName_init.
You can set up 2D profiles in the grid e.g. Nd+_init from example from EFIT files (1D omp profiles and no polidal variation) and then in the input file you set:
[Nd+]
initialize_from_mesh = true # Should be in SI units with name: _init

Change Summary

I changed the isothermal component as well. I made the T variable a Field3D var instead of BoutReal so that it can be set up from grid.

Validation

I tested it with my cases for 2D and 3D.

AI Assistance

No.

Documentation

None

Review Notes

None

malamast added 2 commits July 8, 2026 14:48
…er density and pressure from grid variables with names varName_init.

fixed_density and isothermal: Added a functionality to read the fixed denstiy or temperature from grid variables with names varName_init
@malamast
malamast requested review from bendudson and mikekryjak July 8, 2026 22:03
@codecov

codecov Bot commented Jul 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 60.00000% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 56.92%. Comparing base (1d23bd6) to head (d362cb4).

Files with missing lines Patch % Lines
include/fixed_density.hxx 57.14% 2 Missing and 1 partial ⚠️
src/evolve_density.cxx 57.14% 2 Missing and 1 partial ⚠️
src/evolve_pressure.cxx 66.66% 2 Missing and 1 partial ⚠️
src/isothermal.cxx 57.14% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##           master     #613   +/-   ##
=======================================
  Coverage   56.92%   56.92%           
=======================================
  Files          97       97           
  Lines       10092    10120   +28     
  Branches     1462     1466    +4     
=======================================
+ Hits         5745     5761   +16     
- Misses       3757     3765    +8     
- Partials      590      594    +4     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@mikekryjak mikekryjak left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @malamast, this is really useful work. I left a few comments and suggestions for typo fixes.

Can you also please add a docs section on this on the https://hermes3.readthedocs.io/en/latest/execution.html page as a new subsection called Initialising from known profiles? Let me know if you need any help with this.

Comment thread src/evolve_density.cxx
// Try to read the initial field from the mesh
mesh->get(N, std::string("N") + name + "_init"); // Units: [m^-3/s]
N /= Nnorm; // Normalization
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will cause a bug when evolve_log is true as logN would not be populated, causing an issue here:

if (evolve_log) {
// Evolving logN, but most calculations use N
N = exp(logN);
}

Here is where logN is calculated:

if (evolve_log) {
// Evolve logarithm of density
solver->add(logN, std::string("logN") + name);
// Save the density to the restart file
// so the simulation can be restarted evolving density
// get_restart_datafile()->addOnce(N, std::string("N") + name);
if (!alloptions["hermes"]["restarting"]) {
// Set logN from N input options
initial_profile(std::string("N") + name, N);
logN = log(N);
} else {
// Ignore these settings
Options::root()[std::string("N") + name].setConditionallyUsed();
}
} else {
// Evolve the density in time
solver->add(N, std::string("N") + name);
}

I think all that's needed here is to make sure it's calculated from the grid value:

if (evolve_log && !alloptions["hermes"]["restarting"]) {
  logN = log(N);
}

Comment thread src/evolve_pressure.cxx
if (initialize_from_mesh) {
// Try to read the initial field from the mesh
mesh->get(P, std::string("P") + name + "_init"); // Units: Pascal [Pa]
P /= Pnorm; // Normalization

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment https://github.com/boutproject/hermes-3/pull/613/changes#r3569745560. Need to calculate logP if evolve_log is true.

Comment thread src/evolve_density.cxx

if (initialize_from_mesh) {
// Try to read the initial field from the mesh
mesh->get(N, std::string("N") + name + "_init"); // Units: [m^-3/s]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the variable isn't in the grid, it will be set to zero. This makes it quite annoying if you misspell the variable or forget to put it in and don't check the console dump which shows the warning.

My LLM suggests that this can be overcome because get() gives a return status you can use:

std::string variable = std::string("N") + name + "_init"
if (mesh->get(N, variable) != 0) {
  throw BoutException("Could not load '{}' from the mesh", variable);
}

You can see the return status for mesh->get() defined here - if the value isn't found, it will be set to default and it will return 1:
https://github.com/boutproject/BOUT-dev/blob/9eb94c7c9d9539c1e4e60ec84377a48d5ab50b22/src/mesh/mesh.cxx#L231-L236

This needs to be applied to every place a variable is read from the grid.

Comment thread include/fixed_density.hxx

if (initialize_from_mesh) {
// Try to read the initial field from the mesh
mesh->get(N, std::string("N") + name + "_init"); // Units: [m^-3/s]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/evolve_pressure.cxx

if (initialize_from_mesh) {
// Try to read the initial field from the mesh
mesh->get(P, std::string("P") + name + "_init"); // Units: Pascal [Pa]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/evolve_density.cxx
// Initilize the Field3D N from 2D profiles stored in the mesh file.
initialize_from_mesh =
n_options["initialize_from_mesh"]
.doc("Initilize field from 2D profiles stored in the mesh file?")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.doc("Initilize field from 2D profiles stored in the mesh file?")
.doc("Initialize field from 2D profiles stored in the mesh file?")

Comment thread src/evolve_pressure.cxx
// Initilize the Field3D P from 2D profiles stored in the mesh file.
initialize_from_mesh =
p_options["initialize_from_mesh"]
.doc("Initilize field from 2D profiles stored in the mesh file?")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.doc("Initilize field from 2D profiles stored in the mesh file?")
.doc("Initialize field from 2D profiles stored in the mesh file?")

Comment thread src/isothermal.cxx
// Initilize the Field3D T from 2D profiles stored in the mesh file.
initialize_from_mesh =
options["initialize_from_mesh"]
.doc("Initilize field from 2D profiles stored in the mesh file?")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.doc("Initilize field from 2D profiles stored in the mesh file?")
.doc("Initialize field from 2D profiles stored in the mesh file?")

Comment thread include/fixed_density.hxx

if (initialize_from_mesh) {
// Try to read the initial field from the mesh
mesh->get(N, std::string("N") + name + "_init"); // Units: [m^-3/s]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
mesh->get(N, std::string("N") + name + "_init"); // Units: [m^-3/s]
mesh->get(N, std::string("N") + name + "_init"); // Units: [m^-3]

Comment thread src/evolve_density.cxx

if (initialize_from_mesh) {
// Try to read the initial field from the mesh
mesh->get(N, std::string("N") + name + "_init"); // Units: [m^-3/s]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
mesh->get(N, std::string("N") + name + "_init"); // Units: [m^-3/s]
mesh->get(N, std::string("N") + name + "_init"); // Units: [m^-3]

@mikekryjak mikekryjak mentioned this pull request Jul 16, 2026
10 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants