Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
86a9550
First commit for 2x OAP for mirrors. Major changes are made to how th…
Maxwell-Rosen Dec 10, 2025
913f20a
Add peak finding functionality for DG fields
Maxwell-Rosen Dec 11, 2025
220fdbb
Add a project on peaks function to array_dg_find_peaks, which evaluat…
Maxwell-Rosen Dec 11, 2025
9665556
Add a method to only evaluate the array at one peak, reducing the amm…
Maxwell-Rosen Dec 11, 2025
aa4afa0
Remove some memory allocation during the advance methods and evaluati…
Maxwell-Rosen Dec 11, 2025
976b6bd
Remove old elements from gk_geometry. Add a agkyl_array_dg_reduce_dir…
Maxwell-Rosen Dec 11, 2025
61fa5ca
Merge branch 'main' into gk-oap-2x-multispecies
Maxwell-Rosen Jan 7, 2026
3b933bb
Implement kinetic electrons into the POA scheme. The unit tests run a…
Maxwell-Rosen Jan 7, 2026
79133e7
Add support for symmetric tandem mirrors. Unit tests pass and are va…
Maxwell-Rosen Jan 8, 2026
4229238
Refactor loss cone mask gyrokinetic code for improved clarity and per…
Maxwell-Rosen Jan 8, 2026
aa8b733
Update gk_species_damping to match the new capabilities of fdot_multi…
Maxwell-Rosen Jan 9, 2026
a6bff16
gk_species_damping is working on this branch too now. I needed to rem…
Maxwell-Rosen Jan 9, 2026
e2bc28f
Add another unit test to the loss cone mask
Maxwell-Rosen Jan 9, 2026
fe0e3ed
Merge branch 'main' into gk-oap-2x-tandem-multispecies
Maxwell-Rosen Feb 18, 2026
1fb0516
Update variable name
Maxwell-Rosen Feb 19, 2026
ce57b6a
GPU unit tests all pass. It's compute sanitizer clean. I will have to…
Maxwell-Rosen Feb 20, 2026
a3f949e
rework array find peaks to have a full GPU implementation because the…
Maxwell-Rosen Feb 20, 2026
017e360
Wrap the array_find_peaks into the loss cone mask. I had an issue wit…
Maxwell-Rosen Feb 20, 2026
f3977bf
Merge branch 'main' into gk-oap-2x-tandem-multispecies
Maxwell-Rosen Feb 20, 2026
909d741
Fix loss cone mask unit test. Someone didn't run make check when comm…
Maxwell-Rosen Feb 20, 2026
c689992
fdot multiplier works in parallel. Unit test fixed
Maxwell-Rosen Feb 20, 2026
eed58bc
Refactor global potential handling in damping modules to use shared p…
Maxwell-Rosen Feb 24, 2026
0821a27
Fix missing semicolon in gk_species_damping_release function for prop…
Maxwell-Rosen Feb 24, 2026
dec21d3
remove the array_reduce_dir object. This is leftover from an old vers…
Maxwell-Rosen Feb 24, 2026
a807e79
Merge branch 'main' into gk-oap-2x-tandem-multispecies
Maxwell-Rosen Feb 24, 2026
6a4931a
Uncrustify format the files this PR modifies and also depricate all p…
Maxwell-Rosen Feb 24, 2026
34d6229
Merge branch 'main' into gk-oap-2x-tandem-multispecies
Maxwell-Rosen Mar 5, 2026
740cf5a
Merge branch 'main' into gk-oap-2x-tandem-multispecies
Maxwell-Rosen Mar 6, 2026
062d869
Fix an issue with the non-uniform grids in the 2x2v nonuniform wham r…
Maxwell-Rosen Mar 6, 2026
5eb57ae
Merge branch 'main' into gk-oap-2x-tandem-multispecies
Maxwell-Rosen Mar 12, 2026
d687d0f
Fix two egregious mistakes in using the gk_run methods for the POA sc…
Maxwell-Rosen Mar 12, 2026
2d39244
More dramatic potential for this regression test
Maxwell-Rosen Mar 12, 2026
724fb7f
Add commented out calls to c2p_pos in loss_cone_mask_gyrokinetic kernels
Maxwell-Rosen Mar 12, 2026
6ae3332
Update the 1x2v boltz elc mirror poa to resemble the 2x2v case for de…
Maxwell-Rosen Mar 12, 2026
baad16f
I found a parallelism bug. I was passing the global allgathered phi i…
Maxwell-Rosen Mar 13, 2026
153d7b2
Merge branch 'main' into gk-oap-2x-tandem-multispecies
Maxwell-Rosen Mar 13, 2026
6d95ed7
Reduce the number of frames in the regression tests
Maxwell-Rosen Mar 13, 2026
443c76c
Add sprintf to the app name
Maxwell-Rosen Mar 13, 2026
122f3be
Remove c2p from the loss cone mask, as it shouldn't be there since ev…
Maxwell-Rosen Mar 13, 2026
f8f799b
Remove c2p context from damping
Maxwell-Rosen Mar 14, 2026
92a3c05
Merge branch 'main' into gk-oap-2x-tandem-multispecies
Maxwell-Rosen Mar 24, 2026
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
1,192 changes: 1,192 additions & 0 deletions core/unit/ctest_array_dg_find_peaks.c

Large diffs are not rendered by default.

739 changes: 739 additions & 0 deletions core/zero/array_dg_find_peaks.c

Large diffs are not rendered by default.

540 changes: 540 additions & 0 deletions core/zero/array_dg_find_peaks_cu.cu

Large diffs are not rendered by default.

314 changes: 314 additions & 0 deletions core/zero/gkyl_array_dg_find_peaks.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,314 @@
#pragma once

#include <gkyl_array.h>
#include <gkyl_basis.h>
#include <gkyl_range.h>
#include <gkyl_rect_grid.h>

/**
* Find all peaks (local maxima, local minima, and boundary values) of a DG
* field along one direction.
*
* For a 2D input array f(psi, z), finding peaks along z (dir=1) gives arrays:
* out_val[k](psi) = value of k-th peak along z for each psi
* out_coord[k](psi) = z-coordinate of k-th peak for each psi
*
* For a 1D input array f(z), finding peaks along z (dir=0) gives scalars:
* out_val[k] = value of k-th peak
* out_coord[k] = z-coordinate of k-th peak
*
* Peaks are detected by sampling the field at nodal points along the search
* direction and identifying:
* - EDGE_LO: Value at the lower boundary of the domain
* - LOCAL_MAX: Points where f increases then decreases
* - LOCAL_MIN: Points where f decreases then increases
* - EDGE_HI: Value at the upper boundary of the domain
*
* The number of peaks is determined by scanning along the search direction
* at a middle preserved-direction coordinate.
*/
typedef struct gkyl_array_dg_find_peaks gkyl_array_dg_find_peaks;

/** Types of peaks that can be found. */
enum gkyl_peak_type {
GKYL_PEAK_EDGE_LO, // Value at lower boundary
GKYL_PEAK_LOCAL_MAX, // Local maximum
GKYL_PEAK_LOCAL_MIN, // Local minimum
GKYL_PEAK_EDGE_HI, // Value at upper boundary
};

/** Input parameters for dg_find_peaks updater. */
struct gkyl_array_dg_find_peaks_inp {
const struct gkyl_basis *basis; // Input basis (N-dimensional)
const struct gkyl_rect_grid *grid; // Input grid
const struct gkyl_range *range; // Input range (local)
const struct gkyl_range *range_ext; // Input extended range
int search_dir; // Direction to search for peaks (0-indexed)
bool use_gpu; // Whether to run on GPU
};

/**
* Create a new peak finder updater. The number of peaks is determined by
* scanning the input field along the search direction at a middle coordinate.
* This must be called AFTER the input field is initialized, as it scans the
* field to determine the number of peaks.
*
* @param inp Input parameters
* @param field Input field to scan for peak count determination
* @return New updater pointer
*/
struct gkyl_array_dg_find_peaks* gkyl_array_dg_find_peaks_new(
const struct gkyl_array_dg_find_peaks_inp *inp, const struct gkyl_array *field);

/**
* Compute the peaks. For each point along the preserved dimensions,
* find all peaks along the search direction.
*
* @param up Updater object
* @param in Input array (N-dimensional DG field)
*/
void gkyl_array_dg_find_peaks_advance(struct gkyl_array_dg_find_peaks *up,
const struct gkyl_array *in);

/**
* Get the number of peaks found.
*
* @param up Updater object
* @return Number of peaks
*/
int gkyl_array_dg_find_peaks_num_peaks(const struct gkyl_array_dg_find_peaks *up);

/**
* Get the type of a specific peak (EDGE_LO, LOCAL_MAX, LOCAL_MIN, EDGE_HI).
*
* @param up Updater object
* @param peak_idx Index of the peak (0 to num_peaks-1)
* @return Type of the peak
*/
enum gkyl_peak_type gkyl_array_dg_find_peaks_get_type(const struct gkyl_array_dg_find_peaks *up,
int peak_idx);

/**
* Get the output basis ((N-1)-dimensional, or p=0 1D for 1D->0D).
*
* @param up Updater object
* @return Pointer to output basis
*/
const struct gkyl_basis* gkyl_array_dg_find_peaks_get_basis(
const struct gkyl_array_dg_find_peaks *up);

/**
* Get the output grid.
*
* @param up Updater object
* @return Pointer to output grid
*/
const struct gkyl_rect_grid* gkyl_array_dg_find_peaks_get_grid(
const struct gkyl_array_dg_find_peaks *up);

/**
* Get the output range.
*
* @param up Updater object
* @return Pointer to output range
*/
const struct gkyl_range* gkyl_array_dg_find_peaks_get_range(
const struct gkyl_array_dg_find_peaks *up);

/**
* Get the output extended range.
*
* @param up Updater object
* @return Pointer to output extended range
*/
const struct gkyl_range* gkyl_array_dg_find_peaks_get_range_ext(
const struct gkyl_array_dg_find_peaks *up);

/**
* Get the output nodal range.
*
* @param up Updater object
* @return Pointer to output nodal range
*/
const struct gkyl_range*
gkyl_array_dg_find_peaks_get_nodal_range(const struct gkyl_array_dg_find_peaks *up);

/**
* Get the output array containing peak values for a specific peak.
*
* @param up Updater object
* @param peak_idx Index of the peak (0 to num_peaks-1)
* @return Pointer to output values array (modal DG expansion)
*/
const struct gkyl_array* gkyl_array_dg_find_peaks_acquire_vals(
const struct gkyl_array_dg_find_peaks *up, int peak_idx);

/**
* Get the output array containing peak values in nodal basis for a specific peak.
*
* @param up Updater object
* @param peak_idx Index of the peak (0 to num_peaks-1)
* @return Pointer to output values array (nodal DG expansion)
*/
const struct gkyl_array* gkyl_array_dg_find_peaks_acquire_vals_nodal(
const struct gkyl_array_dg_find_peaks *up, int peak_idx);

/**
* Get the output array containing coordinates of a specific peak.
*
* @param up Updater object
* @param peak_idx Index of the peak (0 to num_peaks-1)
* @return Pointer to output coordinates array (modal DG expansion)
*/
const struct gkyl_array* gkyl_array_dg_find_peaks_acquire_coords(
const struct gkyl_array_dg_find_peaks *up, int peak_idx);

/**
* Get the output array containing coordinates in nodal basis of a specific peak.
*
* @param up Updater object
* @param peak_idx Index of the peak (0 to num_peaks-1)
* @return Pointer to output coordinates array (nodal DG expansion)
*/
const struct gkyl_array* gkyl_array_dg_find_peaks_acquire_coords_nodal(
const struct gkyl_array_dg_find_peaks *up, int peak_idx);

/**
* Project (evaluate) an arbitrary array onto the peak locations previously
* found by gkyl_array_dg_find_peaks_advance.
*
* For a 1D case with 5 peaks, this evaluates the input array at those 5 peak
* locations and returns the values.
*
* For a 2D case with peaks along lines (e.g., psi vs z with peaks in z),
* this evaluates the input array along the contours defined by the peak
* locations for each psi.
*
* The peak locations must have been previously computed via
* gkyl_array_dg_find_peaks_advance. This method evaluates the provided array
* at those same locations.
*
* Example usage:
* @code
* // 1. Find peaks in bmag along z direction
* struct gkyl_array_dg_find_peaks *peak_finder = gkyl_array_dg_find_peaks_new(&inp, bmag);
* gkyl_array_dg_find_peaks_advance(peak_finder, bmag);
*
* // 2. Get bmag_max (LOCAL_MAX peak) location and value
* int num_peaks = gkyl_array_dg_find_peaks_num_peaks(peak_finder);
* int bmag_max_idx = -1;
* for (int p = 0; p < num_peaks; p++) {
* if (gkyl_array_dg_find_peaks_get_type(peak_finder, p) == GKYL_PEAK_LOCAL_MAX) {
* bmag_max_idx = p;
* break;
* }
* }
* const struct gkyl_array *bmag_max = gkyl_array_dg_find_peaks_acquire_vals(peak_finder, bmag_max_idx);
* const struct gkyl_array *z_max = gkyl_array_dg_find_peaks_acquire_coords(peak_finder, bmag_max_idx);
*
* // 3. Evaluate phi at the same locations where bmag has peaks
* struct gkyl_array *phi_at_peaks[num_peaks];
* for (int p = 0; p < num_peaks; p++) {
* phi_at_peaks[p] = gkyl_array_new(GKYL_DOUBLE, out_basis.num_basis, out_range_ext.volume);
* }
* gkyl_array_dg_find_peaks_project_on_peaks(peak_finder, phi, phi_at_peaks);
*
* // 4. Now phi_at_peaks[bmag_max_idx] contains phi evaluated at the mirror throat
* @endcode
*
* @param up Updater object (must have run advance first)
* @param in_array Array to evaluate at peak locations (same grid/basis as original field)
* @param out_vals Output: array of evaluated values for each peak
* (must be pre-allocated with num_peaks elements, each matching out_range_ext)
*/
void gkyl_array_dg_find_peaks_project_on_peaks(struct gkyl_array_dg_find_peaks *up,
const struct gkyl_array *in_array, struct gkyl_array **out_vals);

/**
* Project (evaluate) an arbitrary array onto a single peak location previously
* found by gkyl_array_dg_find_peaks_advance.
*
* This is a more efficient version of gkyl_array_dg_find_peaks_project_on_peaks
* when you only need the evaluation at one specific peak (e.g., only at the
* mirror throat LOCAL_MAX peak).
*
* Example usage:
* @code
* // 1. Find peaks in bmag along z direction
* struct gkyl_array_dg_find_peaks *peak_finder = gkyl_array_dg_find_peaks_new(&inp, bmag);
* gkyl_array_dg_find_peaks_advance(peak_finder, bmag);
*
* // 2. Find the LOCAL_MAX peak index
* int num_peaks = gkyl_array_dg_find_peaks_num_peaks(peak_finder);
* int bmag_max_idx = num_peaks - 2; // Assuming standard ordering
*
* // 3. Evaluate phi only at the mirror throat (bmag_max location)
* struct gkyl_array *phi_m = gkyl_array_new(GKYL_DOUBLE, out_basis.num_basis, out_range_ext.volume);
* gkyl_array_dg_find_peaks_project_on_peak_idx(peak_finder, phi, bmag_max_idx, phi_m);
*
* // 4. Now phi_m contains phi evaluated at the mirror throat
* @endcode
*
* @param up Updater object (must have run advance first)
* @param in_array Array to evaluate at peak location (same grid/basis as original field)
* @param peak_idx Index of the peak to evaluate at (0 to num_peaks-1)
* @param out_val Output: evaluated values at the specified peak
* (must be pre-allocated to match out_range_ext)
*/
void gkyl_array_dg_find_peaks_project_on_peak_idx(struct gkyl_array_dg_find_peaks *up,
const struct gkyl_array *in_array, int peak_idx, struct gkyl_array *out_val);

/**
* Release the updater and all internal arrays.
*
* @param up Updater to delete
*/
void gkyl_array_dg_find_peaks_release(struct gkyl_array_dg_find_peaks *up);

/**
* Create a new GPU peak finder updater from an already-initialized host object.
* Allocates GPU arrays, copies the struct to device, and returns a host-side
* struct with array pointers referencing device memory. Called internally by
* gkyl_array_dg_find_peaks_new when use_gpu is true.
*
* @param up_ho Host-side updater object (fully initialized)
* @return New updater pointer with GPU arrays
*/
struct gkyl_array_dg_find_peaks* gkyl_array_dg_find_peaks_new_cu(
struct gkyl_array_dg_find_peaks *up_ho);

/**
* GPU implementation of the advance method. Launches a CUDA kernel to find
* peaks for each preserved-direction node, then runs nodal-to-modal transforms
* on device.
*
* @param up Updater object (with GPU arrays)
* @param in Input array (device-side DG field)
*/
void gkyl_array_dg_find_peaks_advance_cu(struct gkyl_array_dg_find_peaks *up,
const struct gkyl_array *in);

/**
* GPU implementation of project_on_peaks. Launches a CUDA kernel to evaluate
* an input array at all peak locations, then runs nodal-to-modal transforms
* on device.
*
* @param up Updater object (with GPU arrays)
* @param in_array Input array (device-side DG field)
* @param out_vals Output: array of evaluated values for each peak (device-side)
*/
void gkyl_array_dg_find_peaks_project_on_peaks_cu(struct gkyl_array_dg_find_peaks *up,
const struct gkyl_array *in_array, struct gkyl_array **out_vals);

/**
* GPU implementation of project_on_peak_idx. Launches a CUDA kernel to evaluate
* an input array at a single peak location, then runs a nodal-to-modal transform
* on device.
*
* @param up Updater object (with GPU arrays)
* @param in_array Input array (device-side DG field)
* @param peak_idx Index of the peak to evaluate at (0 to num_peaks-1)
* @param out_val Output: evaluated values at the specified peak (device-side)
*/
void gkyl_array_dg_find_peaks_project_on_peak_idx_cu(struct gkyl_array_dg_find_peaks *up,
const struct gkyl_array *in_array, int peak_idx, struct gkyl_array *out_val);
Loading
Loading