Skip to content

Commit

Permalink
introduce charge, mass and particle densities
Browse files Browse the repository at this point in the history
  • Loading branch information
rochSmets committed Nov 20, 2024
1 parent e61b34c commit 8473002
Show file tree
Hide file tree
Showing 45 changed files with 726 additions and 268 deletions.
1 change: 1 addition & 0 deletions pyphare/pyphare/pharein/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ def population_in_model(population):
class FluidDiagnostics_(Diagnostics):
fluid_quantities = [
"density",
"charge_density",
"mass_density",
"flux",
"bulkVelocity",
Expand Down
8 changes: 7 additions & 1 deletion pyphare/pyphare/pharesee/hierarchy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@


def hierarchy_from(
simulator=None, qty=None, pop="", h5_filename=None, times=None, hier=None, **kwargs
simulator=None, qty=None, pop="", h5_filename=None, times=None, hier=None, func=None, **kwargs
):
from .fromh5 import hierarchy_fromh5
from .fromsim import hierarchy_from_sim
from .fromfunc import hierarchy_from_func

"""
this function reads an HDF5 PHARE file and returns a PatchHierarchy from
Expand All @@ -39,4 +40,9 @@ def hierarchy_from(
if simulator is not None and qty is not None:
return hierarchy_from_sim(simulator, qty, pop=pop)

if func is not None and hier is not None:
if not callable(func):
raise TypeError("func must be callable")
return hierarchy_from_func(func, hier, **kwargs)

raise ValueError("can't make hierarchy")
63 changes: 63 additions & 0 deletions pyphare/pyphare/pharesee/hierarchy/fromfunc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from pyphare.pharesee.hierarchy.hierarchy_utils import compute_hier_from


def hierarchy_from_func1d(func, hier, **kwargs):
assert hier.ndim == 1

def compute_(patch_datas, **kwargs):
ref_name = next(iter(patch_datas.keys()))
x_ = patch_datas[ref_name].x

return (
{"name": "value", "data": func(x_, **kwargs), "centering": patch_datas[ref_name].centerings},
)

return compute_hier_from(compute_, hier, **kwargs)


def hierarchy_from_func2d(func, hier, **kwargs):
from pyphare.pharesee.hierarchy.hierarchy_utils import compute_hier_from

def compute_(patch_datas, **kwargs):
ref_name = next(iter(patch_datas.keys()))
x_ = patch_datas[ref_name].x
y_ = patch_datas[ref_name].y

return (
{"name": "value", "data": func(x_, y_, **kwargs), "centering": patch_datas[ref_name].centerings},
)

return compute_hier_from(compute_, hier, **kwargs)


def hierarchy_from_func(func, hier, **kwargs):

"""
Route hierarchical computation to appropriate dimension handler.
Parameters
----------
func : callable
Function to apply to coordinates of the hierarchy
hier : Hierarchy
Hierarchy object (1D or 2D)
**kwargs : dict
Additional arguments passed to func
Returns
-------
dict
Computed hierarchical data
Raises
------
ValueError
If hierarchy dimension is not supported
"""

if hier.ndim == 1:
return hierarchy_from_func1d(func, hier, **kwargs)
if hier.ndim == 2:
return hierarchy_from_func2d(func, hier, **kwargs)
else:
raise ValueError(f"Unsupported hierarchy dimension: {hier.ndim}")
64 changes: 40 additions & 24 deletions pyphare/pyphare/pharesee/hierarchy/hierarchy.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,8 @@ def box_to_Rectangle(self, box):
return Rectangle(box.lower, *box.shape)

def plot_2d_patches(self, ilvl, collections, **kwargs):
from matplotlib.patches import Rectangle

if isinstance(collections, list) and all(
[isinstance(el, Box) for el in collections]
):
Expand All @@ -368,35 +370,47 @@ def plot_2d_patches(self, ilvl, collections, **kwargs):
level_domain_box = self.level_domain_box(ilvl)
mi, ma = level_domain_box.lower.min(), level_domain_box.upper.max()

Check notice

Code scanning / CodeQL

Unused local variable Note

Variable mi is not used.

Check notice

Code scanning / CodeQL

Unused local variable Note

Variable ma is not used.

fig, ax = kwargs.get("subplot", plt.subplots(figsize=(6, 6)))
fig, ax = kwargs.get("subplot", plt.subplots(figsize=(16, 16)))

i0, j0 = level_domain_box.lower
i1, j1 = level_domain_box.upper
ij = np.zeros((i1 - i0 + 1, j1 - j0 + 1)) + np.nan
ix = np.arange(i0, i1 + 1)
iy = np.arange(j0, j1 + 1)

for collection in collections:
facecolor = collection.get("facecolor", "none")
edgecolor = collection.get("edgecolor", "purple")
alpha = collection.get("alpha", 1)
rects = [self.box_to_Rectangle(box) for box in collection["boxes"]]

ax.add_collection(
PatchCollection(
rects, facecolor=facecolor, alpha=alpha, edgecolor=edgecolor
)
)
value = collection.get("value", np.nan)
for box in collection["boxes"]:
i0, j0 = box.lower
i1, j1 = box.upper
ij[i0 : i1 + 1, j0 : j1 + 1] = value
if "coords" in collection:
for coords in collection["coords"]:
ij[coords] = collection["value"]

ax.pcolormesh(ix, iy, ij.T, edgecolors="k", cmap="jet")
ax.set_xticks(ix)
ax.set_yticks(iy)

for patch in self.level(ilvl).patches:
box = patch.box
r = Rectangle(box.lower - 0.5, *(box.upper + 0.5))

r.set_edgecolor("r")
r.set_facecolor("none")
r.set_linewidth(2)
ax.add_patch(r)

if "title" in kwargs:
from textwrap import wrap

xfigsize = int(fig.get_size_inches()[0] * 10) # 10 characters per inch
ax.set_title("\n".join(wrap(kwargs["title"], xfigsize)))

major_ticks = np.arange(mi - 5, ma + 5 + 5, 5)
ax.set_xticks(major_ticks)
ax.set_yticks(major_ticks)

minor_ticks = np.arange(mi - 5, ma + 5 + 5, 1)
ax.set_xticks(minor_ticks, minor=True)
ax.set_yticks(minor_ticks, minor=True)

ax.grid(which="both")
if "xlim" in kwargs:
ax.set_xlim(kwargs["xlim"])
if "ylim" in kwargs:
ax.set_ylim(kwargs["ylim"])

return fig

Expand Down Expand Up @@ -431,7 +445,8 @@ def plot1d(self, **kwargs):
qty = pdata_names[0]

layout = patch.patch_datas[qty].layout
nbrGhosts = layout.nbrGhostFor(qty)
# nbrGhosts = layout.nbrGhostFor(qty) # bad !!!
nbrGhosts = patch.patch_datas[qty].ghosts_nbr
val = patch.patch_datas[qty][patch.box]
x = patch.patch_datas[qty].x[nbrGhosts[0] : -nbrGhosts[0]]
label = "L{level}P{patch}".format(level=lvl_nbr, patch=ip)
Expand Down Expand Up @@ -542,9 +557,10 @@ def plot2d(self, **kwargs):
if "ylim" in kwargs:
ax.set_ylim(kwargs["ylim"])

divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.08)
plt.colorbar(im, ax=ax, cax=cax)
if kwargs.get("cbar", True):
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.08)
fig.colorbar(im, ax=ax, cax=cax)

if kwargs.get("legend", None) is not None:
ax.legend()
Expand Down
1 change: 1 addition & 0 deletions pyphare/pyphare/pharesee/hierarchy/hierarchy_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"momentum_tensor_zz": "Mzz",
"density": "rho",
"mass_density": "rho",
"charge_density": "rho",
"tags": "tags",
}

Expand Down
2 changes: 1 addition & 1 deletion pyphare/pyphare/pharesee/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ def finest_field_plot(run_path, qty, **kwargs):
time = times[0]
interpolator, finest_coords = r.GetVi(time, merged=True, interp=interp)[qty]
elif qty == "rho":
file = os.path.join(run_path, "ions_density.h5")
file = os.path.join(run_path, "ions_charge_density.h5")
if time is None:
times = get_times_from_h5(file)
time = times[0]
Expand Down
6 changes: 3 additions & 3 deletions pyphare/pyphare/pharesee/run/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"EM_B": "B",
"EM_E": "E",
"ions_bulkVelocity": "Vi",
"ions_density": "Ni",
"ions_charge_density": "Ni",
"particle_count": "nppc",
}

Expand Down Expand Up @@ -114,7 +114,7 @@ def GetMassDensity(self, time, merged=False, interp="nearest", **kwargs):
return ScalarField(self._get(hier, time, merged, interp))

def GetNi(self, time, merged=False, interp="nearest", **kwargs):
hier = self._get_hierarchy(time, "ions_density.h5", **kwargs)
hier = self._get_hierarchy(time, "ions_charge_density.h5", **kwargs)
return ScalarField(self._get(hier, time, merged, interp))

def GetN(self, time, pop_name, merged=False, interp="nearest", **kwargs):
Expand Down Expand Up @@ -151,7 +151,7 @@ def GetPi(self, time, merged=False, interp="nearest", **kwargs):
return self._get(Pi, time, merged, interp) # should later be a TensorField

def GetPe(self, time, merged=False, interp="nearest", all_primal=True):
hier = self._get_hierarchy(time, "ions_density.h5")
hier = self._get_hierarchy(time, "ions_charge_density.h5")

Te = hier.sim.electrons.closure.Te

Expand Down
10 changes: 5 additions & 5 deletions pyphare/pyphare_tests/test_pharesee/test_geometry_2d.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,11 @@ def test_large_patchoverlaps(self, expected):
collections=[
{
"boxes": overlap_boxes,
"facecolor": "yellow",
"value": 1,
},
{
"boxes": [p.box for p in hierarchy.level(ilvl).patches],
"facecolor": "grey",
"value": 2,
},
],
)
Expand Down Expand Up @@ -390,11 +390,11 @@ def test_level_ghost_boxes(self, refinement_boxes, expected):
collections=[
{
"boxes": ghost_area_box_list,
"facecolor": "yellow",
"value": 1,
},
{
"boxes": [p.box for p in hierarchy.level(ilvl).patches],
"facecolor": "grey",
"value": 2,
},
],
title="".join(
Expand Down Expand Up @@ -502,7 +502,7 @@ def test_patch_periodicity_copy(self, refinement_boxes, expected):
collections=[
{
"boxes": [p.box for p in periodic_list],
"facecolor": "grey",
"value": 2,
},
],
)
Expand Down
2 changes: 1 addition & 1 deletion pyphare/pyphare_tests/test_pharesee/test_hierarchy.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def vthz(x, y):
for quantity in ["E", "B"]:
ph.ElectromagDiagnostics(quantity=quantity, write_timestamps=timestamps)

for quantity in ["density", "bulkVelocity"]:
for quantity in ["charge_density", "bulkVelocity"]:
ph.FluidDiagnostics(quantity=quantity, write_timestamps=timestamps)

return sim
Expand Down
2 changes: 1 addition & 1 deletion src/amr/level_initializer/hybrid_level_initializer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ namespace solver
core::depositParticles(ions, layout, interpolate_, core::LevelGhostDeposit{});
}

ions.computeDensity();
ions.computeChargeDensity();
ions.computeBulkVelocity();
}

Expand Down
11 changes: 6 additions & 5 deletions src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,20 +385,21 @@ namespace amr
{
// first thing to do is to project patchGhostParitcles moments
auto& patchGhosts = pop.patchGhostParticles();
auto& density = pop.density();
auto& particleDensity = pop.particleDensity();
auto& chargeDensity = pop.chargeDensity();
auto& flux = pop.flux();

interpolate_(makeRange(patchGhosts), density, flux, layout);
interpolate_(makeRange(patchGhosts), particleDensity, chargeDensity, flux, layout);

if (level.getLevelNumber() > 0) // no levelGhost on root level
{
// then grab levelGhostParticlesOld and levelGhostParticlesNew
// and project them with alpha and (1-alpha) coefs, respectively
auto& levelGhostOld = pop.levelGhostParticlesOld();
interpolate_(makeRange(levelGhostOld), density, flux, layout, 1. - alpha);
interpolate_(makeRange(levelGhostOld), particleDensity, chargeDensity, flux, layout, 1. - alpha);

auto& levelGhostNew = pop.levelGhostParticlesNew();
interpolate_(makeRange(levelGhostNew), density, flux, layout, alpha);
interpolate_(makeRange(levelGhostNew), particleDensity, chargeDensity, flux, layout, alpha);
}
}
}
Expand Down Expand Up @@ -538,7 +539,7 @@ namespace amr

auto& J = hybridModel.state.J;
auto& Vi = hybridModel.state.ions.velocity();
auto& Ni = hybridModel.state.ions.density();
auto& Ni = hybridModel.state.ions.chargeDensity();

Jold_.copyData(J);
ViOld_.copyData(Vi);
Expand Down
2 changes: 1 addition & 1 deletion src/amr/physical_models/hybrid_model.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ void HybridModel<GridLayoutT, Electromag, Ions, Electrons, AMR_Types, Grid_t>::f

hybridInfo.modelMagnetic = core::VecFieldNames{state.electromag.B};
hybridInfo.modelElectric = core::VecFieldNames{state.electromag.E};
hybridInfo.modelIonDensity = state.ions.densityName();
hybridInfo.modelIonDensity = state.ions.chargeDensityName();
hybridInfo.modelIonBulkVelocity = core::VecFieldNames{state.ions.velocity()};
hybridInfo.modelCurrent = core::VecFieldNames{state.J};

Expand Down
2 changes: 1 addition & 1 deletion src/amr/tagging/default_hybrid_tagger_strategy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void DefaultHybridTaggerStrategy<HybridModel>::tag(HybridModel& model,
auto& By = model.state.electromag.B.getComponent(PHARE::core::Component::Y);
auto& Bz = model.state.electromag.B.getComponent(PHARE::core::Component::Z);

auto& N = model.state.ions.density();
// auto& N = model.state.ions.chargeDensity();

Check notice

Code scanning / CodeQL

Commented-out code Note

This comment appears to contain commented-out code.

// we loop on cell indexes for all qties regardless of their centering
auto const& [start_x, _]
Expand Down
Loading

0 comments on commit 8473002

Please sign in to comment.