Skip to content

New model VlasovPoissonElectrostaticAdiabatic (full-orbit ions, adiabatic electrons) and fixes of the full-f Poisson background - #800

Merged
spossann merged 12 commits into
develfrom
vlasov-poisson-adiabatic
Oct 20, 2026
Merged

spossann merged 12 commits into
develfrom
vlasov-poisson-adiabatic

Conversation

@spossann

@spossann spossann commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

Summary

New model VlasovPoissonElectrostaticAdiabatic

The full-orbit (6D) counterpart of DriftKineticElectrostaticAdiabatic: Vlasov ions in the electrostatic potential and a static B0, electrons through the linearized Boltzmann response.

df/dt + v . grad f + (1/eps) (-grad phi + v x B0) . df/dv = 0
-(eps/alpha^2) Delta phi + n0/(Z eps T0) (phi - <phi>) = int f d^3v - n0
  • New propagator AdiabaticPoissonSolve (subclass of ImplicitDiffusion):
    • quasi_neutral=True (default) drops the vacuum term, so the solve is a weighted mass-matrix solve;
    • which_geometry adds the optional flux-surface average phi - <phi>, as in the drift-kinetic model;
    • stab_mat="M0ad_withT" (weight n0/T0).
  • ImplicitDiffusion now allows stab_mat="M0ad_withT" and diffusion_mat=None (no diffusion term), with option checks.
  • Propagator order push_eta, poisson, push_v_E, push_vxb: with Strang splitting both E-kicks use the potential of the current marker positions (drift-kick-kick-drift). This is the same reasoning as DriftKineticElectrostaticAdiabatic: Poisson solve between the two guiding-center pushers #799 for the drift-kinetic model.
  • Tests:
    • manufactured solutions for the Poisson solve, including the zonal average;
    • option checks;
    • verification: ion-acoustic Landau damping along B0, quasi-neutral (gamma -0.168 vs -0.153) and with the vacuum term (-0.179 vs -0.194).
  • Example slab_drift_wave: a drift wave in a density gradient.
    • Equilibrium: the initial state must be the exact Vlasov equilibrium f0(x + eps v_y), here a Maxwellian shifted by the ion diamagnetic velocity.
    • Time step: in the quasi-neutral limit the explicit splitting needs dt c_s pi/h <~ 2, since the ion-acoustic branch has no Debye cutoff.
    • Result: measured omega = 0.262, against 0.262 from the full-orbit dispersion relation and 0.287 from the drift-kinetic one (the O(k_perp^2 rho_i^2) gap).

Example slab_drift_wave for DriftKineticElectrostaticAdiabatic

The same physical setup as the full-orbit example (box, eps = 0.1, kappa_n = 1, T_i = T_e = 1, mode k = (pi/2, 3, 0.05)), for a direct comparison:

  • drift-kinetic ions with the guiding-center Maxwellian n0(X) M (an exact equilibrium);
  • explicit guiding-center pushers, dt = 0.25;
  • LoadingParameters and GyroMaxwellian2D with B0 = 1 (both default to 2);
  • Same electron model as the full-orbit example: Boltzmann response for all modes, i.e. no flux-surface average. For this, GyrokineticPoissonSolve gets the new option which_geometry=None; the default stays "cylindrical".
    • In the shearless slab the physical choice would be the average along the field lines (over z, "cylindrical"), which removes the electron response of the k_z = 0 modes.
    • That is not possible in the quasi-neutral full-orbit model, where the field equation has no polarization term to determine , and it is not needed for the studied mode, which has k_z != 0.
    • With "cylindrical", the ion convective cells of the k_z = 0 modes (omega ~ 3) also made the explicit push unstable at dt = 0.25.
  • Result: measured omega = 0.291 against 0.287 from the drift-kinetic dispersion relation; the full-orbit example gives 0.262 for a predicted 0.262. pproc_slab_drift_wave.py --compare <full-orbit run> overlays both modes.

Fixes in the full-f Poisson right-hand side (separate commits)

  1. ImplicitDiffusion: the full-f neutralizing background is -n0, not -Z n0.
    • The H1 kernels deposit the particle density, and the charge (number and sign) is in the coefficient (alpha^2/eps, with eps ~ 1/Z).
    • With -Z n0, the right-hand side was n - Z n0, which is wrong for Z != 1. Electrons (e.g. ColdPlasmaVlasov) got n + n0.
    • All existing examples and tests use Z = 1.
  2. Initial Poisson solve: delta-f deposit without double subtraction.
    • VlasovAmpereOneSpecies, VlasovMaxwellOneSpecies and ColdPlasmaVlasov deposited the delta-f weights for the initial solve, and ImplicitDiffusion added the full-f background on top: n - 2 n0. In periodic examples the compatibility projection hid the offset; with Dirichlet BCs or a non-uniform n0 the initial phi was wrong.
    • New constructor argument ImplicitDiffusion(..., delta_f_source=True) (also PoissonSolve): particle sources are deposited with delta-f weights also for full-f markers (weights restored afterwards), and no background source is added. The three models use it for initial_poisson.
    • The delta-f deposit has far less noise than full-f weights minus n0: for a 1 % perturbation the initial phi has a relative error of 1 % instead of 400 % (100 markers per cell).
    • DeltaFParticles6D (LinearVlasovAmpere/MaxwellOneSpecies) no longer gets the -n0 background: their weights are delta-f already.
    • VlasovMaxwellOneSpecies gauss_error for full-f markers: the diagnostic deposits the full-f weights (whose charge the time stepping conserves) minus a cached t = 0 offset alpha^2/eps (rho_full(0) - rho_delta_f(0)). After 20 steps the residual is about 0.1 of the field term instead of about 3 times it (f0 deposit noise).
  3. GyrokineticPoissonSolve docstrings corrected:
    • stab_mat default "M0ad_withT", not "Id";
    • the solved equation includes phi - <phi>, 1/eps and the rho_coeffs;
    • the parameters are those of the constructor.

Each of fixes 1 and 2 comes with tests that fail on the old code: phi_rms 2.0 (Z = 2 background), 0.09 (double subtraction, background for delta-f markers), relative error 4.1 (full-f deposit).

Tests (local)

  • test_adiabatic_poisson.py (serial, 2 ranks); test_poisson.py, test_gyrokinetic_poisson.py (2 ranks, 140 passed)
  • verification tests of VlasovPoissonElectrostaticAdiabatic, VlasovAmpereOneSpecies, VlasovMaxwellOneSpecies (2 ranks)
  • default-params model tests of the new model, DriftKineticElectrostaticAdiabatic, VlasovAmpereOneSpecies, VlasovMaxwellOneSpecies, ColdPlasmaVlasov (4 ranks)
  • example --test-run + pproc, ruff, doc/check_models_doc.py, doc/check_propagator_doc.py

Follow-ups (not in this PR)

  • In the slab drift-wave example the kinetic energy of f - f0 drifts by 1-2 % of the thermal energy over t = 15 (unexplained).

Related: #799 (propagator order of DriftKineticElectrostaticAdiabatic, merged).

🤖 Generated with Claude Code

spossann and others added 12 commits October 20, 2026 08:36
…diabatic electrons

The full-orbit (6D) counterpart of DriftKineticElectrostaticAdiabatic:
Vlasov ions in phi and a static B0, electrons through the linearized Boltzmann
response, optionally with the flux-surface average phi - <phi> (zonal correction,
which_geometry) as in the drift-kinetic model, and optionally with the vacuum
term -(eps/alpha^2) Delta phi (quasi_neutral=False).

- AdiabaticPoissonSolve (subclass of ImplicitDiffusion) for the field equation.
- ImplicitDiffusion: stab_mat "M0ad_withT" (weight n0/T0) and diffusion_mat=None
  (no diffusion term, a weighted L2 projection), with option checks.
- Propagator order push_eta, poisson, push_v_E, push_vxb: with Strang splitting
  both E-kicks use the potential of the current marker positions (leapfrog).
- Tests: manufactured solutions for the Poisson solve (incl. zonal average),
  ion-acoustic Landau damping along B0 (verification, quasi-neutral and with
  vacuum term).
- Example slab_drift_wave: drift wave in a density gradient with the exact
  equilibrium (Maxwellian shifted by the ion diamagnetic velocity); the measured
  frequency 0.262 matches the full-orbit dispersion relation (drift-kinetic: 0.287).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
For a full-f particle source (no control variate), verify_rhs adds the
neutralizing background with the coefficient of the accumulator. The H1
kernels (charge_density_0form, gc_density_0form) deposit the particle
density (the weights) and the charge number and sign are in that coefficient
(alpha^2/epsilon with epsilon ~ 1/Z), so the background must be -n0. With
-Z n0 the right-hand side was n - Z n0: wrong for Z != 1 and for electrons
(Z = -1 gave n + n0). All existing examples and tests use Z = 1.

New test: a uniform full-f plasma with Z = 2 in VlasovPoissonElectrostaticAdiabatic
must have phi at noise level (the old background gave phi = -2 everywhere).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
VlasovAmpereOneSpecies, VlasovMaxwellOneSpecies and ColdPlasmaVlasov called
update_weights() before the initial Poisson solve and restored the full-f
weights afterwards. Without the control variate the solve then deposited the
delta-f weights (n - n0) and ImplicitDiffusion added its full-f neutralizing
background (-n0) on top: the right-hand side was n - 2 n0. In the periodic
examples the compatibility projection of PoissonSolve removed the constant
offset, but with Dirichlet boundaries or a non-uniform n0 the initial phi was
wrong.

The solve handles both cases itself (update_weights with the control variate,
full-f weights plus the background without it), so the weight juggling is
removed. The Gauss-law diagnostic of VlasovMaxwellOneSpecies now deposits the
same right-hand side (including the background source for full-f).

New test: the initial potential of a neutral full-f plasma with phi = 0 at the
walls is at noise level (before: phi = -x(1-x)/2, rms 0.09).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Options: stab_mat allows "M0ad_withT" and defaults to it (documented as "Id"),
  it is the mass matrix of the adiabatic term (not multiplied by a "stab_eps");
  epsilon, Z, rho and rho_coeffs are constructor arguments, not options;
  "defaults=" typo.
- Class docstring: the solved equation includes the flux-surface average
  phi - <phi> and the factor 1/epsilon on the right-hand side; the matrix is
  M0ad_withT (I - A); the parameters are those of the constructor (no phi,
  stab_eps, stab_mat or solver arguments); "adabatic" typo.

Docstrings only, no change in behavior.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rokineticPoissonSolve, phi of the old Z n0 background

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The same physical setup as the slab_drift_wave example of
VlasovPoissonElectrostaticAdiabatic (box, epsilon = 0.1, exponential density
gradient kappa_n = 1, T_i = T_e = 1, initial mode k = (pi/2, 3, 0.05)), with
drift-kinetic ions: guiding-center Maxwellian n0(X) M (an exact equilibrium),
explicit guiding-center pushers, dt = 0.25 (no cyclotron motion to resolve).

In the slab the flux surfaces are x = const, so the electrons do not respond
to the average over y and z (which_geometry="toroidal"). With the default
"cylindrical" (average over z only), all modes with k_z = 0 lose the electron
response; their ion convective cells (omega ~ k_y kappa_n / (eps k_perp^2) ~ 3)
made the explicit push unstable at this dt.

The measured frequency of the mode is 0.291 (drift-kinetic dispersion relation
0.287; the full-orbit example gives 0.262 for 0.262). The pproc overlays the
mode of a full-orbit run with --compare <its output folder>.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…stead of pointing to the uncommitted design note

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With which_geometry=None there is no average (<phi> = 0, stab_average=None):
the electrons respond adiabatically to all modes, as in the full-orbit model
VlasovPoissonElectrostaticAdiabatic without its zonal correction. The default
stays "cylindrical".

New test: manufactured solution independent of eta3, with and without the
average over eta3 (with the average the adiabatic term vanishes for it).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e average

The drift-kinetic slab example now uses which_geometry=None like the full-orbit
example (Boltzmann response for all modes), instead of the average over y and z.
In the shearless slab the physical choice would be the average along the field
lines (over z, "cylindrical"), which removes the electron response of the k_z = 0
modes; it is not possible in the quasi-neutral full-orbit model and not needed
for the studied mode (k_z != 0). Measured omega 0.291 (drift-kinetic theory 0.287).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ackground for delta-f markers

Correction of 7c2a3fc, which removed the delta-f weights from the initial Poisson
solve of full-f models (to avoid subtracting n0 twice). The delta-f deposit has much
less Monte-Carlo noise than the full-f weights minus the background n0 (that of
f - f0 instead of f): for a 1% density perturbation the relative error of the
initial phi is 1% instead of 400% (100 markers per cell).

- ImplicitDiffusion / PoissonSolve: new constructor argument delta_f_source. The
  particle sources are then deposited with the delta-f weights also for full-f
  markers (update_weights before, full-f weights restored after) and no background
  source is added.
- VlasovAmpereOneSpecies, VlasovMaxwellOneSpecies, ColdPlasmaVlasov: initial_poisson
  with delta_f_source=True; the Gauss-law diagnostic deposits the delta-f weights again.
- DeltaFParticles6D (LinearVlasovAmpere/MaxwellOneSpecies): the weights are delta-f
  already, so no background -n0 is added any more (it was, since these markers force
  control_variate=False; hidden by the compatibility projection in periodic runs).

New tests: initial phi of a perturbed full-f plasma against the exact solution
(fails with the full-f deposit: error 4.1), and the initial phi of unperturbed
delta-f markers with phi = 0 at the walls (fails with the background: rms 0.09).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…kers

The initial Poisson solve deposits the delta-f weights (delta_f_source), while the
time stepping of full-f markers conserves the charge of the full-f weights. The
diagnostic deposited the delta-f weights at every save, so for t > 0 its residual
contained the changing Monte-Carlo noise of the f0 deposit (about 3 times the field
term after 20 steps in the test case).

Now post_allocate caches the offset alpha^2/eps (rho_full(0) - rho_delta_f(0)) for
full-f markers, and the diagnostic deposits the full-f weights minus this offset: it
vanishes at t = 0 and then measures the Gauss-law violation of the time stepping
(about 0.1 of the field term after 20 steps, similar to the control-variate case).
With the control variate nothing changes.

Test: test_initial_gauss_error parametrized over control variate and end time; the
full-f case after 20 steps fails with the old diagnostic (0.29 vs field term 0.11).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@spossann
spossann requested a balanced review from Copilot October 20, 2026 08:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

@spossann
spossann merged commit 48d0b41 into devel Oct 20, 2026
28 checks passed
@spossann
spossann deleted the vlasov-poisson-adiabatic branch October 20, 2026 09:09
spossann added a commit that referenced this pull request Oct 21, 2026
…804)

Renames the model `VlasovPoissonElectrostaticAdiabatic` (added in #800)
to `VlasovPoissonAdiabatic`: the Poisson equation already says that the
model is electrostatic.

- model module `vlasov_poisson_adiabatic.py`, class, example folder
`examples/VlasovPoissonAdiabatic/` and verification test
`test_verif_VlasovPoissonAdiabatic.py`
- references in `models-all.rst`, `struphy.api.models`, the generated
`models/__init__.py` and the drift-kinetic slab example
- no deprecated alias (the old name was never released)

Tests: the verification test, the default-params model test on 4 ranks,
`doc/check_models_doc.py` and both slab drift-wave examples (and pprocs)
with `--test-run`.

The new model `VlasovPoissonAdiabaticPauli` is stacked on this branch:
#805.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
spossann added a commit that referenced this pull request Oct 21, 2026
…atic electrons) and fixes of the full-f Poisson background (#800)

## Summary

### New model `VlasovPoissonElectrostaticAdiabatic`

The full-orbit (6D) counterpart of `DriftKineticElectrostaticAdiabatic`:
Vlasov ions in the electrostatic potential and a static B0, electrons
through the linearized Boltzmann response.

    df/dt + v . grad f + (1/eps) (-grad phi + v x B0) . df/dv = 0
-(eps/alpha^2) Delta phi + n0/(Z eps T0) (phi - <phi>) = int f d^3v - n0

- New propagator `AdiabaticPoissonSolve` (subclass of
`ImplicitDiffusion`):
- `quasi_neutral=True` (default) drops the vacuum term, so the solve is
a weighted mass-matrix solve;
- `which_geometry` adds the optional flux-surface average `phi - <phi>`,
as in the drift-kinetic model;
  - `stab_mat="M0ad_withT"` (weight n0/T0).
- `ImplicitDiffusion` now allows `stab_mat="M0ad_withT"` and
`diffusion_mat=None` (no diffusion term), with option checks.
- Propagator order `push_eta, poisson, push_v_E, push_vxb`: with Strang
splitting both E-kicks use the potential of the current marker positions
(drift-kick-kick-drift). This is the same reasoning as #799 for the
drift-kinetic model.
- Tests:
- manufactured solutions for the Poisson solve, including the zonal
average;
  - option checks;
- verification: ion-acoustic Landau damping along B0, quasi-neutral
(gamma -0.168 vs -0.153) and with the vacuum term (-0.179 vs -0.194).
- Example `slab_drift_wave`: a drift wave in a density gradient.
- **Equilibrium:** the initial state must be the exact Vlasov
equilibrium f0(x + eps v_y), here a Maxwellian shifted by the ion
diamagnetic velocity.
- **Time step:** in the quasi-neutral limit the explicit splitting needs
`dt c_s pi/h <~ 2`, since the ion-acoustic branch has no Debye cutoff.
- **Result:** measured omega = 0.262, against 0.262 from the full-orbit
dispersion relation and 0.287 from the drift-kinetic one (the O(k_perp^2
rho_i^2) gap).

### Example `slab_drift_wave` for `DriftKineticElectrostaticAdiabatic`

The same physical setup as the full-orbit example (box, eps = 0.1,
kappa_n = 1, T_i = T_e = 1, mode k = (pi/2, 3, 0.05)), for a direct
comparison:

- drift-kinetic ions with the guiding-center Maxwellian n0(X) M (an
exact equilibrium);
- explicit guiding-center pushers, dt = 0.25;
- `LoadingParameters` and `GyroMaxwellian2D` with `B0 = 1` (both default
to 2);
- Same electron model as the full-orbit example: Boltzmann response for
all modes, i.e. no flux-surface average. For this,
`GyrokineticPoissonSolve` gets the new option `which_geometry=None`; the
default stays `"cylindrical"`.
- In the shearless slab the physical choice would be the average along
the field lines (over z, `"cylindrical"`), which removes the electron
response of the k_z = 0 modes.
- That is not possible in the quasi-neutral full-orbit model, where the
field equation has no polarization term to determine <phi>, and it is
not needed for the studied mode, which has k_z != 0.
- With `"cylindrical"`, the ion convective cells of the k_z = 0 modes
(omega ~ 3) also made the explicit push unstable at dt = 0.25.
- **Result:** measured omega = 0.291 against 0.287 from the
drift-kinetic dispersion relation; the full-orbit example gives 0.262
for a predicted 0.262. `pproc_slab_drift_wave.py --compare <full-orbit
run>` overlays both modes.

### Fixes in the full-f Poisson right-hand side (separate commits)

1. **`ImplicitDiffusion`: the full-f neutralizing background is `-n0`,
not `-Z n0`.**
- The H1 kernels deposit the particle density, and the charge (number
and sign) is in the coefficient (`alpha^2/eps`, with eps ~ 1/Z).
- With `-Z n0`, the right-hand side was `n - Z n0`, which is wrong for Z
!= 1. Electrons (e.g. `ColdPlasmaVlasov`) got `n + n0`.
   - All existing examples and tests use Z = 1.
2. **Initial Poisson solve: delta-f deposit without double
subtraction.**
- `VlasovAmpereOneSpecies`, `VlasovMaxwellOneSpecies` and
`ColdPlasmaVlasov` deposited the delta-f weights for the initial solve,
and `ImplicitDiffusion` added the full-f background on top: `n - 2 n0`.
In periodic examples the compatibility projection hid the offset; with
Dirichlet BCs or a non-uniform n0 the initial phi was wrong.
- New constructor argument `ImplicitDiffusion(..., delta_f_source=True)`
(also `PoissonSolve`): particle sources are deposited with delta-f
weights also for full-f markers (weights restored afterwards), and no
background source is added. The three models use it for
`initial_poisson`.
- The delta-f deposit has far less noise than full-f weights minus n0:
for a 1 % perturbation the initial phi has a relative error of 1 %
instead of 400 % (100 markers per cell).
- `DeltaFParticles6D` (`LinearVlasovAmpere/MaxwellOneSpecies`) no longer
gets the `-n0` background: their weights are delta-f already.
- `VlasovMaxwellOneSpecies` `gauss_error` for full-f markers: the
diagnostic deposits the full-f weights (whose charge the time stepping
conserves) minus a cached t = 0 offset `alpha^2/eps (rho_full(0) -
rho_delta_f(0))`. After 20 steps the residual is about 0.1 of the field
term instead of about 3 times it (f0 deposit noise).
3. **`GyrokineticPoissonSolve` docstrings corrected:**
   - `stab_mat` default `"M0ad_withT"`, not `"Id"`;
- the solved equation includes `phi - <phi>`, `1/eps` and the
`rho_coeffs`;
   - the parameters are those of the constructor.

Each of fixes 1 and 2 comes with tests that fail on the old code:
phi_rms 2.0 (Z = 2 background), 0.09 (double subtraction, background for
delta-f markers), relative error 4.1 (full-f deposit).

## Tests (local)

- `test_adiabatic_poisson.py` (serial, 2 ranks); `test_poisson.py`,
`test_gyrokinetic_poisson.py` (2 ranks, 140 passed)
- verification tests of `VlasovPoissonElectrostaticAdiabatic`,
`VlasovAmpereOneSpecies`, `VlasovMaxwellOneSpecies` (2 ranks)
- default-params model tests of the new model,
`DriftKineticElectrostaticAdiabatic`, `VlasovAmpereOneSpecies`,
`VlasovMaxwellOneSpecies`, `ColdPlasmaVlasov` (4 ranks)
- example `--test-run` + pproc, ruff, `doc/check_models_doc.py`,
`doc/check_propagator_doc.py`

## Follow-ups (not in this PR)

- In the slab drift-wave example the kinetic energy of f - f0 drifts by
1-2 % of the thermal energy over t = 15 (unexplained).

Related: #799 (propagator order of `DriftKineticElectrostaticAdiabatic`,
merged).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
spossann added a commit that referenced this pull request Oct 21, 2026
…804)

Renames the model `VlasovPoissonElectrostaticAdiabatic` (added in #800)
to `VlasovPoissonAdiabatic`: the Poisson equation already says that the
model is electrostatic.

- model module `vlasov_poisson_adiabatic.py`, class, example folder
`examples/VlasovPoissonAdiabatic/` and verification test
`test_verif_VlasovPoissonAdiabatic.py`
- references in `models-all.rst`, `struphy.api.models`, the generated
`models/__init__.py` and the drift-kinetic slab example
- no deprecated alias (the old name was never released)

Tests: the verification test, the default-params model test on 4 ranks,
`doc/check_models_doc.py` and both slab drift-wave examples (and pprocs)
with `--test-run`.

The new model `VlasovPoissonAdiabaticPauli` is stacked on this branch:
#805.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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