Skip to content
Open
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
161 changes: 84 additions & 77 deletions bout-particle-push.cxx

Large diffs are not rendered by default.

35 changes: 16 additions & 19 deletions bout-particle-push.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ using namespace VANTAGE::Reactions;

/// @brief Data struct to hold information about a reaction source.
/// @param reaction_name Name of the reaction, e.g. "ionistaion"
/// @param source_name Name of the source, e.g. Siz (ion density source due to ionisation).
/// @param source_name Name of the source, e.g. Siz (ion density source due to
/// ionisation).
/// @param accumulator CellwiseAccumulator to use to accumulate the source term for this
/// reaction.
/// @param particle_group ParticleGroup to which this source applies.
Expand All @@ -31,8 +32,7 @@ struct VantageSource {
class VantageSourceManager {
public:
VantageSourceManager(std::shared_ptr<PetscInterface::DMPlexInterface>& neso_mesh,
Mesh* bout_mesh,
const std::map<std::string, BoutReal>& norms);
Mesh* bout_mesh, const std::map<std::string, BoutReal>& norms);

Mesh* bout_mesh;

Expand Down Expand Up @@ -70,8 +70,6 @@ private:
*
*/



/**
* @brief Function to calculate particle positions and velocities from a Maxwellian.
*
Expand All @@ -87,10 +85,12 @@ private:
*/

template <size_t ndim>
inline ParticleSet uniform_cellwise_maxwellian(
SYCLTargetSharedPtr sycl_target, std::shared_ptr<PetscInterface::DMPlexInterface> mesh,
const ParticleSpec &particle_spec, const INT &npart_per_cell,
const REAL &weight, const REAL &std_dev, const INT &species_id) {
inline ParticleSet
uniform_cellwise_maxwellian(SYCLTargetSharedPtr sycl_target,
std::shared_ptr<PetscInterface::DMPlexInterface> mesh,
const ParticleSpec& particle_spec, const INT& npart_per_cell,
const REAL& weight, const REAL& std_dev,
const INT& species_id) {

const int rank = sycl_target->comm_pair.rank_parent;
const int size = sycl_target->comm_pair.size_parent;
Expand All @@ -101,12 +101,11 @@ inline ParticleSet uniform_cellwise_maxwellian(
std::vector<std::vector<double>> positions;
std::vector<int> cell_ids;
PetscInterface::uniform_within_dmplex_cells(mesh, npart_per_cell, positions, cell_ids,
&rng_pos);
&rng_pos);

const int N = cell_ids.size();

auto velocities =
NESO::Particles::normal_distribution(N, ndim, 0.0, std_dev, rng_vel);
auto velocities = NESO::Particles::normal_distribution(N, ndim, 0.0, std_dev, rng_vel);

ParticleSet maxwellian(N, particle_spec);

Expand All @@ -129,14 +128,13 @@ inline ParticleSet uniform_cellwise_maxwellian(
* in recombination and charge exchange.
*/

inline auto get_uniform_rng_kernel(SYCLTargetSharedPtr sycl_target,
std::size_t n_samples,
inline auto get_uniform_rng_kernel(SYCLTargetSharedPtr sycl_target, std::size_t n_samples,
std::uint64_t root_seed = 141351) {

const int rank = sycl_target->comm_pair.rank_parent;

std::uint64_t seed = NESO::RNGToolkit::create_seeds(
sycl_target->comm_pair.size_parent, rank, root_seed);
std::uint64_t seed =
NESO::RNGToolkit::create_seeds(sycl_target->comm_pair.size_parent, rank, root_seed);

auto rng_normal = NESO::RNGToolkit::create_rng<REAL>(
NESO::RNGToolkit::Distribution::Uniform<REAL>{
Expand All @@ -146,12 +144,11 @@ inline auto get_uniform_rng_kernel(SYCLTargetSharedPtr sycl_target,
// Create an interface between NESO-RNG-Toolkit and NESO-Particles KernelRNG
auto rng_interface =
make_rng_generation_function<GenericDeviceRNGGenerationFunction, REAL>(
[=](REAL *d_ptr, const std::size_t num_samples) -> int {
[=](REAL* d_ptr, const std::size_t num_samples) -> int {
return rng_normal->get_samples(d_ptr, num_samples);
});

auto rng_kernel =
host_atomic_block_kernel_rng<REAL>(rng_interface, n_samples);
auto rng_kernel = host_atomic_block_kernel_rng<REAL>(rng_interface, n_samples);

return rng_kernel;
}
4 changes: 1 addition & 3 deletions scripts/dmplex_tools_for_particle_pusher/density_history.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@


def plot(case_path):

ds = xbout.load.open_boutdataset(
datapath=case_path / "BOUT.dmp.*.nc",
inputfilepath=case_path / "BOUT.inp",
Expand All @@ -27,7 +26,7 @@ def plot(case_path):
Ni_avg.plot(ax=ax, marker="o")
ax.set_ylabel("Normalised density")
ax.set_title("Mean ion density")

ax = axes[1]
Nn_avg.plot(ax=ax, marker="o")
ax.set_ylabel("Normalised density")
Expand All @@ -45,7 +44,6 @@ def plot(case_path):
ax.set_ylabel("-")
ax.set_title("Density volume integrals")


for ax in axes:
ax.set_xlabel("time")

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
from plot_corners_functions import plot_corners_get_dmplex_data
import argparse
parser = argparse.ArgumentParser(description="Process a Hypnotoad mesh file to produce a modified mesh file and a file containing the global list of vertices of the mesh. Produce plots of cell vertices.")
parser.add_argument("hypnotoad_nc_file_path", type=str, help="The path to the Hypnotoad netCDF file representing the mesh.")

parser = argparse.ArgumentParser(
description="Process a Hypnotoad mesh file to produce a modified mesh file and a file containing the global list of vertices of the mesh. Produce plots of cell vertices."
)
parser.add_argument(
"hypnotoad_nc_file_path",
type=str,
help="The path to the Hypnotoad netCDF file representing the mesh.",
)
args = parser.parse_args()
file_path = args.hypnotoad_nc_file_path
print(f"Processing Hypnotoad mesh from {args.hypnotoad_nc_file_path}")

Nx,Ny,cell_vertices,vertex_list,boundary_vertex_info = plot_corners_get_dmplex_data(file_path,interactive_plot=True,print_cells_to_screen_output=False)
Nx, Ny, cell_vertices, vertex_list, boundary_vertex_info = plot_corners_get_dmplex_data(
file_path, interactive_plot=True, print_cells_to_screen_output=False
)
27 changes: 16 additions & 11 deletions scripts/dmplex_tools_for_particle_pusher/load_and_plot_dm.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
from petsc4py import PETSc
import argparse

parser = argparse.ArgumentParser(description="Plot the edges of a DMPlex mesh.")
parser.add_argument("dmplex_h5_file_path", type=str, help="The path to the HDF5 file representing the DMPlex data")
parser.add_argument(
"dmplex_h5_file_path",
type=str,
help="The path to the HDF5 file representing the DMPlex data",
)

args = parser.parse_args()
print(f"Plotting: {args.dmplex_h5_file_path}")
file_path = args.dmplex_h5_file_path

dm = PETSc.DMPlex().create()
viewer = PETSc.Viewer().createHDF5(file_path, 'r')
viewer = PETSc.Viewer().createHDF5(file_path, "r")
dm.load(viewer)
viewer.destroy()
dm.setFromOptions()
Expand All @@ -25,23 +30,23 @@
# Get all edges (cone of each edge cell)
edges = []
for p in range(dm.getChart()[0], dm.getChart()[1]):
#if dm.getLabelValue("celltype", p) == PETSc.DMPlex.CellType.EDGE:
# if dm.getLabelValue("celltype", p) == PETSc.DMPlex.CellType.EDGE:
cone = dm.getCone(p)
if len(cone) == 2:
v0, v1 = cone
x0 = coords[section.getOffset(v0):section.getOffset(v0)+dim]
x1 = coords[section.getOffset(v1):section.getOffset(v1)+dim]
x0 = coords[section.getOffset(v0) : section.getOffset(v0) + dim]
x1 = coords[section.getOffset(v1) : section.getOffset(v1) + dim]
edges.append((x0, x1))

# Plot using object-oriented matplotlib
fig, ax = plt.subplots()
for x0, x1 in edges:
ax.plot([x0[0], x1[0]], [x0[1], x1[1]], color='k', linewidth=0.5)
ax.plot([x0[0], x1[0]], [x0[1], x1[1]], color="k", linewidth=0.5)

ax.set_aspect('equal')
ax.set_title('DMPlex Mesh Edges')
ax.set_xlabel('x')
ax.set_ylabel('y')
output_path = file_path[:-3]+'.pdf'
ax.set_aspect("equal")
ax.set_title("DMPlex Mesh Edges")
ax.set_xlabel("x")
ax.set_ylabel("y")
output_path = file_path[:-3] + ".pdf"
plt.savefig(output_path)
print(f"Saving file to: {output_path}")
79 changes: 50 additions & 29 deletions scripts/dmplex_tools_for_particle_pusher/particle_animator.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,37 @@
from matplotlib.animation import FuncAnimation
from petsc4py import PETSc
import argparse
parser = argparse.ArgumentParser(description="Animate particles moving on a DMPlex mesh.")
parser.add_argument("dmplex_h5_file_path", type=str, help="The path to the HDF5 file representing the DMPlex data")
parser.add_argument("particle_trajectory_h5_file_path", type=str, help="The path to the HDF5 file representing the particle data")

parser = argparse.ArgumentParser(
description="Animate particles moving on a DMPlex mesh."
)
parser.add_argument(
"dmplex_h5_file_path",
type=str,
help="The path to the HDF5 file representing the DMPlex data",
)
parser.add_argument(
"particle_trajectory_h5_file_path",
type=str,
help="The path to the HDF5 file representing the particle data",
)

args = parser.parse_args()
print(f"Animating particle paths from {args.particle_trajectory_h5_file_path} on DMPlex edges from {args.dmplex_h5_file_path}")
print(
f"Animating particle paths from {args.particle_trajectory_h5_file_path} on DMPlex edges from {args.dmplex_h5_file_path}"
)


def load_dmplex(file_path):
dm = PETSc.DMPlex().create()
viewer = PETSc.Viewer().createHDF5(file_path, 'r')
viewer = PETSc.Viewer().createHDF5(file_path, "r")
dm.load(viewer)
viewer.destroy()
dm.setFromOptions()
dm.setUp()
return dm


def get_mesh_edges(dm):
# Get coordinates
section = dm.getCoordinateSection()
Expand All @@ -33,45 +48,49 @@ def get_mesh_edges(dm):
cone = dm.getCone(p)
if len(cone) == 2:
v0, v1 = cone
x0 = coords[section.getOffset(v0):section.getOffset(v0)+dim]
x1 = coords[section.getOffset(v1):section.getOffset(v1)+dim]
x0 = coords[section.getOffset(v0) : section.getOffset(v0) + dim]
x1 = coords[section.getOffset(v1) : section.getOffset(v1) + dim]
edges.append((x0, x1))
return edges


dm = load_dmplex(args.dmplex_h5_file_path)
#dm = load_dmplex('dmplex/expected_nonorthogonal.grd.nc.mesh.h5')
# dm = load_dmplex('dmplex/expected_nonorthogonal.grd.nc.mesh.h5')
edges = get_mesh_edges(dm)

# Plot using object-oriented matplotlib
fig, ax = plt.subplots()


def load_particle_data(file_path):
particle_data = h5py.File(file_path,"r")
particle_data = h5py.File(file_path, "r")
data_all_timesteps = list(particle_data.keys())
nstep = len(data_all_timesteps)

particle_positions = []
for it in range(0,nstep):
for it in range(0, nstep):
try:
group = particle_data[f"Step#{it}"]
#print(list(group.keys()))
# print(list(group.keys()))
P_0 = group["POSITION_0"]
P_1 = group["POSITION_1"]
nparticles = len(P_0)
pdata = np.zeros((nparticles,2))
pdata[:,0] = P_0
pdata[:,1] = P_1
pdata = np.zeros((nparticles, 2))
pdata[:, 0] = P_0
pdata[:, 1] = P_1
particle_positions.append(pdata)
except (KeyError) as error:
except KeyError as error:
print(f"No particles at time step {it}: {error}")
# assign empty particle data
pdata = np.empty((0,2))
pdata = np.empty((0, 2))
particle_positions.append(pdata)
return particle_positions


def update_plot(i, data, scat):
scat.set_offsets(data[i])
return scat,
return (scat,)


particle_positions = load_particle_data(args.particle_trajectory_h5_file_path)
nstep = len(particle_positions)
Expand All @@ -80,23 +99,25 @@ def update_plot(i, data, scat):
fig, ax = plt.subplots()
# Plot DMPlex edges
for x0, x1 in edges:
ax.plot([x0[0], x1[0]], [x0[1], x1[1]], color='k', linewidth=0.5)
ax.plot([x0[0], x1[0]], [x0[1], x1[1]], color="k", linewidth=0.5)
# Animate particles
scat = ax.scatter(particle_positions[0][:,0], particle_positions[0][:,1], c='b',s=1.0, marker='.')
ax.set_title('Particle Positions')
ax.set_xlabel('R')
ax.set_ylabel('Z')
scat = ax.scatter(
particle_positions[0][:, 0], particle_positions[0][:, 1], c="b", s=1.0, marker="."
)
ax.set_title("Particle Positions")
ax.set_xlabel("R")
ax.set_ylabel("Z")


def update(frame):
scat.set_offsets(np.c_[particle_positions[frame][:,0], particle_positions[frame][:,1]])
return scat,
scat.set_offsets(
np.c_[particle_positions[frame][:, 0], particle_positions[frame][:, 1]]
)
return (scat,)


ani = FuncAnimation(fig, update, frames=nstep, interval=50, blit=True)
output_path = args.particle_trajectory_h5_file_path + ".animation.gif"
ani.save(output_path)
print(f"Saving animation of particle paths to {output_path}")
#plt.show()




# plt.show()
Loading
Loading