Skip to content
Draft
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
2 changes: 1 addition & 1 deletion feectools
Submodule feectools updated 48 files
+92 −86 feectools/core/bsplines.py
+46 −42 feectools/core/bsplines_kernels.py
+228 −228 feectools/core/field_evaluation_kernels.py
+34 −34 feectools/core/tests/test_bsplines.py
+8 −8 feectools/core/tests/test_bsplines_kernel.py
+180 −180 feectools/core/tests/test_bsplines_pyccel.py
+17 −17 feectools/ddm/blocking_data_exchanger.py
+39 −34 feectools/ddm/cart.py
+32 −16 feectools/ddm/nonblocking_data_exchanger.py
+12 −12 feectools/ddm/partition.py
+4 −4 feectools/ddm/petsc.py
+4 −4 feectools/ddm/tests/test_cart_1d.py
+3 −3 feectools/ddm/tests/test_cart_2d.py
+3 −3 feectools/ddm/tests/test_cart_3d.py
+7 −7 feectools/ddm/tests/test_multicart_2d.py
+6 −6 feectools/feec/derivatives.py
+84 −72 feectools/feec/global_geometric_projectors.py
+1 −1 feectools/fem/grid.py
+2 −2 feectools/fem/partitioning.py
+6 −6 feectools/fem/projectors.py
+29 −11 feectools/fem/splines.py
+29 −29 feectools/fem/tensor.py
+4 −4 feectools/fem/tests/analytical_profiles_1d.py
+14 −14 feectools/fem/tests/test_spline_histopolation.py
+11 −11 feectools/fem/tests/test_spline_interpolation.py
+3 −3 feectools/fem/tests/utilities.py
+2 −2 feectools/fem/vector.py
+14 −13 feectools/linalg/basic.py
+17 −13 feectools/linalg/block.py
+28 −10 feectools/linalg/direct_solvers.py
+5 −5 feectools/linalg/fft.py
+36 −29 feectools/linalg/kron.py
+6 −6 feectools/linalg/solvers.py
+146 −122 feectools/linalg/stencil.py
+116 −116 feectools/linalg/tests/test_block.py
+7 −7 feectools/linalg/tests/test_fft.py
+3 −3 feectools/linalg/tests/test_kron_stencil_matrix.py
+78 −78 feectools/linalg/tests/test_linalg.py
+14 −14 feectools/linalg/tests/test_matrix_free.py
+15 −15 feectools/linalg/tests/test_solvers.py
+8 −8 feectools/linalg/tests/test_stencil_interface_matrix.py
+57 −57 feectools/linalg/tests/test_stencil_vector.py
+3 −3 feectools/linalg/tests/test_stencil_vector_space.py
+49 −49 feectools/linalg/topetsc.py
+11 −11 feectools/linalg/utilities.py
+8 −8 feectools/utilities/quadratures.py
+14 −14 feectools/utilities/utils.py
+1 −0 pyproject.toml
116 changes: 116 additions & 0 deletions params_LinearMHDDriftkineticCC.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
from struphy import main
from struphy.fields_background import equils
from struphy.geometry import domains
from struphy.initial import perturbations
from struphy.io.options import BaseUnits, DerhamOptions, EnvironmentOptions, FieldsBackground, Time
from struphy.kinetic_background import maxwellians

# import model, set verbosity
from struphy.models.hybrid import LinearMHDDriftkineticCC
from struphy.pic.utilities import (
BinningPlot,
BoundaryParameters,
KernelDensityPlot,
LoadingParameters,
WeightsParameters,
)
from struphy.topology import grids

# environment options
env = EnvironmentOptions()

# units
base_units = BaseUnits()

# time stepping
time_opts = Time()

# geometry
domain = domains.Cuboid()

# fluid equilibrium (can be used as part of initial conditions)
equil = equils.HomogenSlab()

# grid
grid = grids.TensorProductGrid(Nel=(16, 16, 16))

# derham options
derham_opts = DerhamOptions()

# light-weight model instance
model = LinearMHDDriftkineticCC()

# species parameters
model.mhd.set_phys_params()
model.energetic_ions.set_phys_params()

loading_params = LoadingParameters(ppc=1000)
weights_params = WeightsParameters()
boundary_params = BoundaryParameters()
model.energetic_ions.set_markers(
loading_params=loading_params,
weights_params=weights_params,
boundary_params=boundary_params,
)
model.energetic_ions.set_sorting_boxes()
model.energetic_ions.set_save_data()

# propagator options
model.propagators.push_bxe.options = model.propagators.push_bxe.Options(
b_tilde=model.em_fields.b_field,
)
model.propagators.push_parallel.options = model.propagators.push_parallel.Options(
b_tilde=model.em_fields.b_field,
)
model.propagators.shearalfen_cc5d.options = model.propagators.shearalfen_cc5d.Options(
energetic_ions=model.energetic_ions.var,
)
model.propagators.magnetosonic.options = model.propagators.magnetosonic.Options(
b_field=model.em_fields.b_field,
)
model.propagators.cc5d_density.options = model.propagators.cc5d_density.Options(
energetic_ions=model.energetic_ions.var,
b_tilde=model.em_fields.b_field,
)
model.propagators.cc5d_gradb.options = model.propagators.cc5d_gradb.Options(
b_tilde=model.em_fields.b_field,
)
model.propagators.cc5d_curlb.options = model.propagators.cc5d_curlb.Options(
b_tilde=model.em_fields.b_field,
)

# background, perturbations and initial conditions
model.mhd.velocity.add_background(FieldsBackground())
model.mhd.velocity.add_perturbation(perturbations.TorusModesCos(given_in_basis="v", comp=0))
model.mhd.velocity.add_perturbation(perturbations.TorusModesCos(given_in_basis="v", comp=1))
model.mhd.velocity.add_perturbation(perturbations.TorusModesCos(given_in_basis="v", comp=2))
maxwellian_1 = maxwellians.GyroMaxwellian2D(n=(1.0, None), equil=equil)
maxwellian_2 = maxwellians.GyroMaxwellian2D(n=(0.1, None), equil=equil)
background = maxwellian_1 + maxwellian_2
model.energetic_ions.var.add_background(background)

# if .add_initial_condition is not called, the background is the kinetic initial condition
perturbation = perturbations.TorusModesCos()
maxwellian_1pt = maxwellians.GyroMaxwellian2D(n=(1.0, perturbation), equil=equil)
init = maxwellian_1pt + maxwellian_2
model.energetic_ions.var.add_initial_condition(init)

# optional: exclude variables from saving
# model.energetic_ions.var.save_data = False

if __name__ == "__main__":
# start run
verbose = True

main.run(
model,
params_path=__file__,
env=env,
base_units=base_units,
time_opts=time_opts,
domain=domain,
equil=equil,
grid=grid,
derham_opts=derham_opts,
verbose=verbose,
)
4 changes: 2 additions & 2 deletions src/struphy/bsplines/bsplines.py
Original file line number Diff line number Diff line change
Expand Up @@ -611,8 +611,8 @@ def make_knots(breaks, degree, periodic):

if periodic:
period = breaks[-1] - breaks[0]
T[0:p] = [xi - period for xi in breaks[-p - 1 : -1]]
T[-p:] = [xi + period for xi in breaks[1 : p + 1]]
T[0:p] = xp.asarray([xi - period for xi in breaks[-p - 1 : -1]])
T[-p:] = xp.asarray([xi + period for xi in breaks[1 : p + 1]])
else:
T[0:p] = breaks[0]
T[-p:] = breaks[-1]
Expand Down
6 changes: 2 additions & 4 deletions src/struphy/console/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ def parse_path(directory, verbose: bool = False):
for filename in files:
if re.search(r"__\w+__", root):
continue
if (filename.endswith(".py") or filename.endswith(".ipynb")) and not re.search(r"__\w+__", filename):
if filename.endswith(".py") and not re.search(r"__\w+__", filename):
file_path = os.path.join(root, filename)
python_files.append(file_path)
return python_files
Expand Down Expand Up @@ -489,9 +489,7 @@ def get_python_files(input_type, path=None):

# python_files = [f for f in files if f.endswith(".py") and os.path.isfile(f)]
python_files = [
os.path.join(repopath, f)
for f in files
if (f.endswith(".py") or f.endswith(".ipynb")) and os.path.isfile(os.path.join(repopath, f))
os.path.join(repopath, f) for f in files if f.endswith(".py") and os.path.isfile(os.path.join(repopath, f))
]

if not python_files:
Expand Down
86 changes: 42 additions & 44 deletions src/struphy/diagnostics/diagnostics_pic.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@
"outputs": [],
"source": [
"import os\n",
"\n",
"import struphy\n",
"import numpy as np\n",
"from matplotlib import pyplot as plt\n",
"\n",
"import struphy\n",
"\n",
"path_out = os.path.join(struphy.__path__[0], \"io/out\", \"sim_1\")\n",
"path_out = os.path.join(struphy.__path__[0], 'io/out', 'sim_1')\n",
"\n",
"print(path_out)\n",
"os.listdir(path_out)"
Expand All @@ -30,7 +28,7 @@
"metadata": {},
"outputs": [],
"source": [
"data_path = os.path.join(path_out, \"post_processing\")\n",
"data_path = os.path.join(path_out, 'post_processing')\n",
"\n",
"os.listdir(data_path)"
]
Expand All @@ -41,7 +39,7 @@
"metadata": {},
"outputs": [],
"source": [
"t_grid = np.load(os.path.join(data_path, \"t_grid.npy\"))\n",
"t_grid = np.load(os.path.join(data_path, 't_grid.npy'))\n",
"t_grid"
]
},
Expand All @@ -51,7 +49,7 @@
"metadata": {},
"outputs": [],
"source": [
"f_path = os.path.join(data_path, \"kinetic_data\", \"ions\", \"distribution_function\")\n",
"f_path = os.path.join(data_path, 'kinetic_data', 'ions', 'distribution_function')\n",
"\n",
"print(os.listdir(f_path))"
]
Expand All @@ -62,7 +60,7 @@
"metadata": {},
"outputs": [],
"source": [
"path = os.path.join(f_path, \"e1\")\n",
"path = os.path.join(f_path, 'e1')\n",
"print(os.listdir(path))"
]
},
Expand All @@ -72,9 +70,9 @@
"metadata": {},
"outputs": [],
"source": [
"grid = np.load(os.path.join(f_path, \"e1/\", \"grid_e1.npy\"))\n",
"f_binned = np.load(os.path.join(f_path, \"e1/\", \"f_binned.npy\"))\n",
"delta_f_e1_binned = np.load(os.path.join(f_path, \"e1/\", \"delta_f_binned.npy\"))\n",
"grid = np.load(os.path.join(f_path, 'e1/', 'grid_e1.npy'))\n",
"f_binned = np.load(os.path.join(f_path, 'e1/', 'f_binned.npy'))\n",
"delta_f_e1_binned = np.load(os.path.join(f_path, 'e1/', 'delta_f_binned.npy'))\n",
"\n",
"print(grid.shape)\n",
"print(f_binned.shape)\n",
Expand All @@ -89,18 +87,18 @@
"source": [
"steps = list(np.arange(10))\n",
"\n",
"plt.figure(figsize=(12, 5 * len(steps)))\n",
"plt.figure(figsize=(12, 5*len(steps)))\n",
"for n, step in enumerate(steps):\n",
" plt.subplot(len(steps), 2, 2 * n + 1)\n",
" plt.plot(grid, f_binned[step], label=f\"time = {t_grid[step]}\")\n",
" plt.xlabel(\"e1\")\n",
" # plt.ylim([.5, 1.5])\n",
" plt.title(\"full-f\")\n",
" plt.subplot(len(steps), 2, 2 * n + 2)\n",
" plt.plot(grid, delta_f_e1_binned[step], label=f\"time = {t_grid[step]}\")\n",
" plt.xlabel(\"e1\")\n",
" # plt.ylim([-3e-3, 3e-3])\n",
" plt.title(r\"$\\delta f$\")\n",
" plt.subplot(len(steps), 2, 2*n + 1)\n",
" plt.plot(grid, f_binned[step], label=f'time = {t_grid[step]}')\n",
" plt.xlabel('e1')\n",
" #plt.ylim([.5, 1.5])\n",
" plt.title('full-f')\n",
" plt.subplot(len(steps), 2, 2*n + 2)\n",
" plt.plot(grid, delta_f_e1_binned[step], label=f'time = {t_grid[step]}')\n",
" plt.xlabel('e1')\n",
" #plt.ylim([-3e-3, 3e-3])\n",
" plt.title(r'$\\delta f$')\n",
" plt.legend()"
]
},
Expand All @@ -110,7 +108,7 @@
"metadata": {},
"outputs": [],
"source": [
"path = os.path.join(f_path, \"e1_v1\")\n",
"path = os.path.join(f_path, 'e1_v1')\n",
"print(os.listdir(path))"
]
},
Expand All @@ -120,10 +118,10 @@
"metadata": {},
"outputs": [],
"source": [
"grid_e1 = np.load(os.path.join(f_path, \"e1_v1/\", \"grid_e1.npy\"))\n",
"grid_v1 = np.load(os.path.join(f_path, \"e1_v1/\", \"grid_v1.npy\"))\n",
"f_binned = np.load(os.path.join(f_path, \"e1_v1/\", \"f_binned.npy\"))\n",
"delta_f_binned = np.load(os.path.join(f_path, \"e1_v1/\", \"delta_f_binned.npy\"))\n",
"grid_e1 = np.load(os.path.join(f_path, 'e1_v1/', 'grid_e1.npy'))\n",
"grid_v1 = np.load(os.path.join(f_path, 'e1_v1/', 'grid_v1.npy'))\n",
"f_binned = np.load(os.path.join(f_path, 'e1_v1/', 'f_binned.npy'))\n",
"delta_f_binned = np.load(os.path.join(f_path, 'e1_v1/', 'delta_f_binned.npy'))\n",
"\n",
"print(grid_e1.shape)\n",
"print(grid_v1.shape)\n",
Expand All @@ -139,20 +137,20 @@
"source": [
"steps = list(np.arange(10))\n",
"\n",
"plt.figure(figsize=(12, 5 * len(steps)))\n",
"plt.figure(figsize=(12, 5*len(steps)))\n",
"for n, step in enumerate(steps):\n",
" plt.subplot(len(steps), 2, 2 * n + 1)\n",
" plt.pcolor(grid_e1, grid_v1, f_binned[step].T, label=f\"time = {t_grid[step]}\")\n",
" plt.xlabel(\"$e1$\")\n",
" plt.ylabel(r\"$v_\\parallel$\")\n",
" plt.title(\"full-f\")\n",
" plt.subplot(len(steps), 2, 2*n + 1)\n",
" plt.pcolor(grid_e1, grid_v1, f_binned[step].T, label=f'time = {t_grid[step]}')\n",
" plt.xlabel('$e1$')\n",
" plt.ylabel(r'$v_\\parallel$')\n",
" plt.title('full-f')\n",
" plt.legend()\n",
" plt.colorbar()\n",
" plt.subplot(len(steps), 2, 2 * n + 2)\n",
" plt.pcolor(grid_e1, grid_v1, delta_f_binned[step].T, label=f\"time = {t_grid[step]}\")\n",
" plt.xlabel(\"$e1$\")\n",
" plt.ylabel(r\"$v_\\parallel$\")\n",
" plt.title(r\"$\\delta f$\")\n",
" plt.subplot(len(steps), 2, 2*n + 2)\n",
" plt.pcolor(grid_e1, grid_v1, delta_f_binned[step].T, label=f'time = {t_grid[step]}')\n",
" plt.xlabel('$e1$')\n",
" plt.ylabel(r'$v_\\parallel$')\n",
" plt.title(r'$\\delta f$')\n",
" plt.legend()\n",
" plt.colorbar()"
]
Expand All @@ -163,7 +161,7 @@
"metadata": {},
"outputs": [],
"source": [
"fields_path = os.path.join(data_path, \"fields_data\")\n",
"fields_path = os.path.join(data_path, 'fields_data')\n",
"\n",
"print(os.listdir(fields_path))"
]
Expand All @@ -176,7 +174,7 @@
"source": [
"import pickle\n",
"\n",
"with open(os.path.join(fields_path, \"grids_phy.bin\"), \"rb\") as file:\n",
"with open(os.path.join(fields_path, 'grids_phy.bin'), 'rb') as file:\n",
" x_grid, y_grid, z_grid = pickle.load(file)\n",
"\n",
"print(type(x_grid))\n",
Expand All @@ -189,7 +187,7 @@
"metadata": {},
"outputs": [],
"source": [
"with open(os.path.join(fields_path, \"em_fields\", \"phi_phy.bin\"), \"rb\") as file:\n",
"with open(os.path.join(fields_path, 'em_fields', 'phi_phy.bin'), 'rb') as file:\n",
" phi = pickle.load(file)\n",
"\n",
"plt.figure(figsize=(12, 12))\n",
Expand All @@ -199,9 +197,9 @@
" t = t_grid[step]\n",
" print(phi[t][0].shape)\n",
" plt.subplot(2, 2, n + 1)\n",
" plt.plot(x_grid[:, 0, 0], phi[t][0][:, 0, 0], label=f\"time = {t}\")\n",
" plt.xlabel(\"x\")\n",
" plt.ylabel(r\"$\\phi$(x)\")\n",
" plt.plot(x_grid[:, 0, 0], phi[t][0][:, 0, 0], label=f'time = {t}')\n",
" plt.xlabel('x')\n",
" plt.ylabel(r'$\\phi$(x)')\n",
" plt.legend()"
]
},
Expand Down
4 changes: 1 addition & 3 deletions src/struphy/feec/basis_projection_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,7 @@ def __init__(self, derham, domain, verbose=True, **weights):

self._rank = derham.comm.Get_rank() if derham.comm is not None else 0

if xp.any(
[degree == 1 and num_elements > 1 for degree, num_elements in zip(derham.degree, derham.num_elements)]
):
if any(degree == 1 and num_elements > 1 for degree, num_elements in zip(derham.degree, derham.num_elements)):
if MPI.COMM_WORLD.Get_rank() == 0:
logger.info(
f'\nWARNING: Class "BasisProjectionOperators" called with degree={derham.degree} (interpolation of piece-wise constants should be avoided).',
Expand Down
8 changes: 8 additions & 0 deletions src/struphy/feec/preconditioner.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,11 @@ def solver(self):
"""KroneckerLinearSolver or BlockDiagonalSolver for exactly inverting the approximate mass matrix self.matrix."""
return self._solver

@property
def domain(self):
"""The domain of the linear operator - an element of Vectorspace"""
return self._space

@property
def codomain(self):
"""The codomain of the linear operator - an element of Vectorspace"""
Expand Down Expand Up @@ -742,6 +747,9 @@ def matrix(self):
def solver(self):
"""KroneckerLinearSolver or BlockDiagonalSolver for exactly inverting the approximate mass matrix self.matrix."""
return self._solver

@property
def domain(self):
"""The domain of the linear operator - an element of Vectorspace"""
return self._space

Expand Down
Loading
Loading