def _test_patch_ghost_on_refined_level_case(self, dim, has_patch_ghost,
                                                **kwargs):
        import pyphare.pharein as ph

        from pyphare.simulator.simulator import startMPI

        startMPI()

        out = "phare_outputs"

        test_id = self.ddt_test_id()

        refinement_boxes = {"L0": [nDBox(dim, 10, 19)]}

        kwargs["interp_order"] = kwargs.get("interp_order", 1)
        local_out = f"{out}/dim{dim}_interp{kwargs['interp_order']}_mpi_n_{cpp.mpi_size()}_id{test_id}/{str(has_patch_ghost)}"
        kwargs["diag_outputs"] = local_out
        datahier = self.getHierarchy(refinement_boxes=refinement_boxes,
                                     qty="particles_patch_ghost",
                                     ndim=dim,
                                     **kwargs)

        self.assertTrue(
            any([
                diagInfo.quantity.endswith("patchGhost")
                for diagInfo in ph.global_vars.sim.diagnostics
            ]))
        self.assertTrue((1 in datahier.levels()) == has_patch_ghost)
    def _test_nbr_particles_per_cell_is_as_provided(self,
                                                    dim,
                                                    interp_order,
                                                    default_ppc=100):
        ddt_test_id = self.ddt_test_id()
        datahier = self.getHierarchy(
            interp_order, {"L0": {
                "B0": nDBox(dim, 10, 20)
            }},
            "particles",
            ndim=dim,
            diag_outputs=f"ppc/{dim}/{interp_order}/{ddt_test_id}")

        for patch in datahier.level(0).patches:
            pd = patch.patch_datas["protons_particles"]
            icells = pd.dataset[patch.box].iCells
            H, edges = np.histogramdd(icells)
            self.assertTrue((H == default_ppc).all())
    def _test_density_is_as_provided_by_user(self, dim, interp_order):

        empirical_dim_devs = {
            1: 6e-3,
            2: 3e-2,
        }

        nbParts = {1: 10000, 2: 1000}
        print("test_density_is_as_provided_by_user : interp_order : {}".format(
            interp_order))
        hier = self.getHierarchy(
            interp_order, {"L0": {
                "B0": nDBox(dim, 10, 20)
            }},
            qty="moments",
            nbr_part_per_cell=nbParts[dim],
            beam=True,
            ndim=dim,
            diag_outputs=
            f"test_density/{dim}/{interp_order}/{self.ddt_test_id()}")

        from pyphare.pharein import global_vars
        model = global_vars.sim.model
        proton_density_fn = model.model_dict["protons"]["density"]
        beam_density_fn = model.model_dict["beam"]["density"]

        for ilvl, level in hier.levels().items():
            print("checking density on level {}".format(ilvl))
            for ip, patch in enumerate(level.patches):
                print("patch {}".format(ip))

                ion_density = patch.patch_datas["rho"].dataset[:]
                proton_density = patch.patch_datas["protons_rho"].dataset[:]
                beam_density = patch.patch_datas["beam_rho"].dataset[:]
                x = patch.patch_datas["rho"].x

                layout = patch.patch_datas["rho"].layout
                centering = layout.centering["X"][
                    patch.patch_datas["rho"].field_name]
                nbrGhosts = layout.nbrGhosts(interp_order, centering)

                if dim == 1:
                    protons_expected = proton_density_fn(
                        x[nbrGhosts:-nbrGhosts])
                    beam_expected = beam_density_fn(x[nbrGhosts:-nbrGhosts])
                    ion_expected = protons_expected + beam_expected

                    ion_actual = ion_density[nbrGhosts:-nbrGhosts]
                    beam_actual = beam_density[nbrGhosts:-nbrGhosts]
                    protons_actual = proton_density[nbrGhosts:-nbrGhosts]

                if dim == 2:
                    y = patch.patch_datas["rho"].y
                    xx, yy = np.meshgrid(x, y, indexing="ij")

                    x0 = xx[nbrGhosts:-nbrGhosts, nbrGhosts:-nbrGhosts]
                    y0 = yy[nbrGhosts:-nbrGhosts, nbrGhosts:-nbrGhosts]

                    protons_expected = proton_density_fn(x0, y0)
                    beam_expected = beam_density_fn(x0, y0)
                    ion_expected = protons_expected + beam_expected

                    ion_actual = ion_density[nbrGhosts:-nbrGhosts,
                                             nbrGhosts:-nbrGhosts]
                    beam_actual = beam_density[nbrGhosts:-nbrGhosts,
                                               nbrGhosts:-nbrGhosts]
                    protons_actual = proton_density[nbrGhosts:-nbrGhosts,
                                                    nbrGhosts:-nbrGhosts]

                names = ("ions", "protons", "beam")
                expected = (ion_expected, protons_expected, beam_expected)
                actual = (ion_actual, protons_actual, beam_actual)
                devs = {
                    name: np.std(expected - actual)
                    for name, expected, actual in zip(names, expected, actual)
                }

                for name, dev in devs.items():
                    print(f"sigma(user density - {name} density) = {dev}")
                    self.assertLess(dev, empirical_dim_devs[dim],
                                    f'{name} has dev = {dev}')
    def _test_bulkvel_is_as_provided_by_user(self, dim, interp_order):
        hier = self.getHierarchy(
            interp_order,
            {"L0": {
                "B0": nDBox(dim, 10, 19)
            }},
            "moments",
            nbr_part_per_cell=100,
            beam=True,
            ndim=dim,  # ppc needs to be 10000?
            diag_outputs=f"test_bulkV/{dim}/{interp_order}/{self.ddt_test_id()}"
        )

        from pyphare.pharein import global_vars
        model = global_vars.sim.model
        # protons and beam have same bulk vel here so take only proton func.
        vx_fn = model.model_dict["protons"]["vx"]
        vy_fn = model.model_dict["protons"]["vy"]
        vz_fn = model.model_dict["protons"]["vz"]
        nprot = model.model_dict["protons"]["density"]
        nbeam = model.model_dict["beam"]["density"]

        for ilvl, level in hier.levels().items():
            print("checking density on level {}".format(ilvl))
            for ip, patch in enumerate(level.patches):
                print("patch {}".format(ip))

                layout = patch.patch_datas["protons_Fx"].layout
                centering = layout.centering["X"][
                    patch.patch_datas["protons_Fx"].field_name]
                nbrGhosts = layout.nbrGhosts(interp_order, centering)

                if dim == 1:
                    x = patch.patch_datas["protons_Fx"].x[nbrGhosts:-nbrGhosts]

                    fpx = patch.patch_datas["protons_Fx"].dataset[
                        nbrGhosts:-nbrGhosts]
                    fpy = patch.patch_datas["protons_Fy"].dataset[
                        nbrGhosts:-nbrGhosts]
                    fpz = patch.patch_datas["protons_Fz"].dataset[
                        nbrGhosts:-nbrGhosts]

                    fbx = patch.patch_datas["beam_Fx"].dataset[
                        nbrGhosts:-nbrGhosts]
                    fby = patch.patch_datas["beam_Fy"].dataset[
                        nbrGhosts:-nbrGhosts]
                    fbz = patch.patch_datas["beam_Fz"].dataset[
                        nbrGhosts:-nbrGhosts]

                    ni = patch.patch_datas["rho"].dataset[nbrGhosts:-nbrGhosts]

                    vxact = (fpx + fbx) / ni
                    vyact = (fpy + fby) / ni
                    vzact = (fpz + fbz) / ni

                    vxexp = (nprot(x) * vx_fn(x) +
                             nbeam(x) * vx_fn(x)) / (nprot(x) + nbeam(x))
                    vyexp = (nprot(x) * vy_fn(x) +
                             nbeam(x) * vy_fn(x)) / (nprot(x) + nbeam(x))
                    vzexp = (nprot(x) * vz_fn(x) +
                             nbeam(x) * vz_fn(x)) / (nprot(x) + nbeam(x))

                    for vexp, vact in zip((vxexp, vyexp, vzexp),
                                          (vxact, vyact, vzact)):
                        std = np.std(vexp - vact)
                        print("sigma(user v - actual v) = {}".format(std))
                        self.assertTrue(
                            std < 1e-2
                        )  # empirical value obtained from print just above

                def reshape(patch_data, nGhosts):
                    return patch_data.dataset[:].reshape(patch.box.shape +
                                                         (nGhosts * 2) + 1)

                if dim == 2:
                    xx, yy = np.meshgrid(patch.patch_datas["protons_Fx"].x,
                                         patch.patch_datas["protons_Fx"].y,
                                         indexing="ij")

                    density = reshape(patch.patch_datas["rho"], nbrGhosts)

                    protons_Fx = reshape(patch.patch_datas["protons_Fx"],
                                         nbrGhosts)
                    protons_Fy = reshape(patch.patch_datas["protons_Fy"],
                                         nbrGhosts)
                    protons_Fz = reshape(patch.patch_datas["protons_Fz"],
                                         nbrGhosts)

                    beam_Fx = reshape(patch.patch_datas["beam_Fx"], nbrGhosts)
                    beam_Fy = reshape(patch.patch_datas["beam_Fy"], nbrGhosts)
                    beam_Fz = reshape(patch.patch_datas["beam_Fz"], nbrGhosts)

                    x = xx[nbrGhosts:-nbrGhosts, nbrGhosts:-nbrGhosts]
                    y = yy[nbrGhosts:-nbrGhosts, nbrGhosts:-nbrGhosts]

                    fpx = protons_Fx[nbrGhosts:-nbrGhosts,
                                     nbrGhosts:-nbrGhosts]
                    fpy = protons_Fy[nbrGhosts:-nbrGhosts,
                                     nbrGhosts:-nbrGhosts]
                    fpz = protons_Fz[nbrGhosts:-nbrGhosts,
                                     nbrGhosts:-nbrGhosts]

                    fbx = beam_Fx[nbrGhosts:-nbrGhosts, nbrGhosts:-nbrGhosts]
                    fby = beam_Fy[nbrGhosts:-nbrGhosts, nbrGhosts:-nbrGhosts]
                    fbz = beam_Fz[nbrGhosts:-nbrGhosts, nbrGhosts:-nbrGhosts]

                    ni = density[nbrGhosts:-nbrGhosts, nbrGhosts:-nbrGhosts]

                    vxact = (fpx + fbx) / ni
                    vyact = (fpy + fby) / ni
                    vzact = (fpz + fbz) / ni

                    vxexp = (nprot(x, y) * vx_fn(x, y) + nbeam(x, y) *
                             vx_fn(x, y)) / (nprot(x, y) + nbeam(x, y))
                    vyexp = (nprot(x, y) * vy_fn(x, y) + nbeam(x, y) *
                             vy_fn(x, y)) / (nprot(x, y) + nbeam(x, y))
                    vzexp = (nprot(x, y) * vz_fn(x, y) + nbeam(x, y) *
                             vz_fn(x, y)) / (nprot(x, y) + nbeam(x, y))

                    for vexp, vact in zip((vxexp, vyexp, vzexp),
                                          (vxact, vyact, vzact)):
                        self.assertTrue(np.std(vexp - vact) < 1e-2)