def _assign_data(self, u_bot, u_top):
        """
        u_bot and u_top are the u_h in the neighbouring cells on the two sides of the fracture.
        Ordering is hard-coded according to the grids defined in _make_grid
        """
        u_h = np.zeros(self.nd * self.g_h.num_cells)
        if self.nd == 3:
            u_h[0:6] = u_bot.ravel(order="f")
            u_h[12:18] = u_top.ravel(order="f")
        else:
            u_h[2:6] = u_bot.ravel(order="f")
            u_h[10:14] = u_top.ravel(order="f")

        # Project to interface
        e = (self.g_h, self.g_l)
        d_j = self.gb.edge_props(e)
        mg = d_j["mortar_grid"]
        trace = np.abs(pp.fvutils.vector_divergence(self.g_h)).T
        u_j = mg.primary_to_mortar_avg(nd=self.nd) * trace * u_h
        pp.set_iterate(d_j, {self.model.mortar_displacement_variable: u_j})

        # Parameters used by the propagation class
        for g, d in self.gb:
            if g.dim == self.nd:
                param = {"shear_modulus": self.mu, "poisson_ratio": self.poisson}
            else:
                param = {"SIFs_critical": np.ones((self.nd, g.num_faces))}
            pp.initialize_data(g, d, self.model.mechanics_parameter_key, param)
Beispiel #2
0
    def initial_condition(self) -> None:
        """
        In addition to the values set by the parent class, we set initial value for the
        temperature variable, and a previous iterate value for the scalar value. The
        latter is used for computation of Darcy fluxes, needed for the advective term of
        the energy equation.
        """
        super().initial_condition()

        for g, d in self.gb:
            # Initial value for the scalar variable.
            cell_zeros = np.zeros(g.num_cells)
            state = {self.temperature_variable: cell_zeros}
            iterate = {self.scalar_variable: cell_zeros}  # For initial flux
            d[pp.STATE].update(state)
            pp.set_iterate(d, iterate)

        for _, d in self.gb.edges():
            mg = d["mortar_grid"]
            cell_zeros = np.zeros(mg.num_cells)
            state = {
                self.mortar_temperature_variable: cell_zeros,
                self.mortar_temperature_advection_variable: cell_zeros,
            }
            iterate = {self.mortar_scalar_variable: cell_zeros}
            d[pp.STATE].update(state)

            pp.set_iterate(d, iterate)
Beispiel #3
0
    def initial_condition(self) -> None:
        """
        Initial value for the Darcy fluxes. TODO: Add to THM.
        """
        for g, d in self.gb:
            d[pp.PARAMETERS] = pp.Parameters()
            d[pp.PARAMETERS].update_dictionaries(
                [self.mechanics_parameter_key, self.scalar_parameter_key,]
            )
        self.update_all_apertures(to_iterate=False)
        self.update_all_apertures()
        super().initial_condition()

        for g, d in self.gb:

            d[pp.STATE]["cell_centers"] = g.cell_centers.copy()
            p0 = self.initial_scalar(g)
            state = {
                self.scalar_variable: p0,
                "u_exp_0": np.zeros(g.num_cells),
                "aperture_0": self.aperture(g) * self.length_scale,
            }
            iterate = {
                self.scalar_variable: p0,
            }  # For initial flux

            pp.set_state(d, state)
            pp.set_iterate(d, iterate)
 def test_add_empty_iterate(self, empty_dict):
     """ Add an empty iterate dictionary
     """
     d = empty_dict
     pp.set_iterate(d)
     assert pp.STATE in d
     assert pp.ITERATE in d[pp.STATE]
Beispiel #5
0
    def _initial_condition(self) -> None:
        """
        In addition to the values set by the parent class, we set initial value for the
        temperature variable, and a previous iterate value for the scalar value. The
        latter is used for computation of Darcy fluxes, needed for the advective term of
        the energy equation. The Darcy flux parameter is also initialized.
        """
        super()._initial_condition()

        for g, d in self.gb:
            # Initial value for the scalar variable.
            cell_zeros = np.zeros(g.num_cells)
            state = {self.temperature_variable: cell_zeros}
            iterate = {self.scalar_variable: cell_zeros}  # For initial flux
            pp.set_state(d, state)
            pp.set_iterate(d, iterate)
            # Initial Darcy fluxes for advective flux.
            pp.initialize_data(
                g,
                d,
                self.temperature_parameter_key,
                {
                    "darcy_flux": np.zeros(g.num_faces),
                },
            )

        for e, d in self.gb.edges():
            mg = d["mortar_grid"]
            cell_zeros = np.zeros(mg.num_cells)
            state = {
                self.mortar_temperature_variable: cell_zeros,
                self.mortar_temperature_advection_variable: cell_zeros,
            }
            iterate = {self.mortar_scalar_variable: cell_zeros}

            pp.set_state(d, state)
            pp.set_iterate(d, iterate)
            # Initial Darcy fluxes for advective flux.
            d = pp.initialize_data(
                e,
                d,
                self.temperature_parameter_key,
                {
                    "darcy_flux": np.zeros(mg.num_cells),
                },
            )
    def test_add_iterate_twice_and_state(self, empty_dict):
        """Add two state dictionaries.

        The existing foo value should be overwritten, while bar should be kept.
        Setting values in pp.STATE should not affect the iterate values.
        """
        d = empty_dict
        d1 = {"foo": 1, "bar": 2}
        d2 = {"foo": 3, "spam": 4}

        pp.set_iterate(d, d1)
        pp.set_iterate(d, d2)
        pp.set_state(d, {"foo": 5})
        for key, val in zip(["foo", "bar", "spam"], [3, 2, 4]):
            assert key in d[pp.STATE][pp.ITERATE]
            assert d[pp.STATE][pp.ITERATE][key] == val
        assert d[pp.STATE]["foo"] == 5
    def _initial_condition(self):
        """Set initial guess for the variables.

        The displacement is set to zero in the Nd-domain, and at the fracture interfaces
        The displacement jump is thereby also zero.

        The contact pressure is set to zero in the tangential direction,
        and -1 (that is, in contact) in the normal direction.

        """

        for g, d in self.gb:
            if g.dim == self._Nd:
                # Initialize displacement variable
                state = {
                    self.displacement_variable:
                    np.zeros(g.num_cells * self._Nd)
                }

            elif g.dim == self._Nd - 1:
                # Initialize contact variable
                traction = np.vstack(
                    (np.zeros((g.dim, g.num_cells)),
                     -1 * np.ones(g.num_cells))).ravel(order="F")
                state = {
                    self.contact_traction_variable: traction,
                }
                pp.set_iterate(d, {self.contact_traction_variable: traction})
            else:
                state = {}
            pp.set_state(d, state)

        for _, d in self.gb.edges():
            mg = d["mortar_grid"]

            if mg.dim == self._Nd - 1:
                size = mg.num_cells * self._Nd
                state = {self.mortar_displacement_variable: np.zeros(size)}
                iterate = {self.mortar_displacement_variable: np.zeros(size)}
                pp.set_iterate(d, iterate)
            else:
                state = {}
            pp.set_state(d, state)
        "mass_weight": phi * np.ones(g.num_cells),
    }
    
    # Assing (or update) parameters
    if time == 0:
        pp.initialize_data(g, d, param_key, specified_data)
    else:
        d[pp.PARAMETERS][param_key]["bc_values"] = bc_values
        d[pp.PARAMETERS][param_key]["source"] = source_term


#%% Set initial states
for g, d in gb:
    cc = g.cell_centers
    pp.set_state(d)
    pp.set_iterate(d)
    d[pp.STATE][pressure_var] = p_ex(cc[0], cc[1], time * np.ones_like(cc[0]))
    d[pp.STATE][pp.ITERATE][pressure_var] = d[pp.STATE][pressure_var].copy()

#%% AD variables and manager
grid_list = [g for g, _ in gb]
dof_manager = pp.DofManager(gb)
equation_manager = pp.ad.EquationManager(gb, dof_manager)
p = equation_manager.merge_variables([(g, pressure_var) for g in grid_list])
p_m = p.previous_iteration()
p_n = p.previous_timestep()

#%% We let the density to be a non-linear function of the pressure
def rho(p):
    if isinstance(p, pp.ad.Ad_array):
        return rho_ref * pp.ad.exp(c * (p - p_ref))
Beispiel #9
0
    def update_all_apertures(self, to_iterate=True):
        """
        To better control the aperture computation, it is done for the entire gb by a
        single function call. This also allows us to ensure the fracture apertures
        are updated before the intersection apertures are inherited.
        """
        gb = self.gb
        for g, d in gb:

            apertures = np.ones(g.num_cells)
            if g.dim == (self.Nd - 1):
                # Initial aperture

                apertures *= self.initial_aperture
                # Reconstruct the displacement solution on the fracture
                g_h = gb.node_neighbors(g)[0]
                data_edge = gb.edge_props((g, g_h))
                if pp.STATE in data_edge:
                    u_mortar_local = self.reconstruct_local_displacement_jump(
                        data_edge, from_iterate=to_iterate
                    )
                    apertures -= u_mortar_local[-1].clip(max=0)
            if to_iterate:
                pp.set_iterate(
                    d,
                    {"aperture": apertures.copy(), "specific_volume": apertures.copy()},
                )
            else:
                state = {
                    "aperture": apertures.copy(),
                    "specific_volume": apertures.copy(),
                }
                pp.set_state(d, state)

        for g, d in gb:
            parent_apertures = []
            num_parent = []
            if g.dim < (self.Nd - 1):
                for edges in gb.edges_of_node(g):
                    e = edges[0]
                    g_h = e[0]

                    if g_h == g:
                        g_h = e[1]

                    if g_h.dim == (self.Nd - 1):
                        d_h = gb.node_props(g_h)
                        if to_iterate:
                            a_h = d_h[pp.STATE][pp.ITERATE]["aperture"]
                        else:
                            a_h = d_h[pp.STATE]["aperture"]
                        a_h_face = np.abs(g_h.cell_faces) * a_h
                        mg = gb.edge_props(e)["mortar_grid"]
                        # Assumes g_h is master
                        a_l = (
                            mg.mortar_to_slave_avg()
                            * mg.master_to_mortar_avg()
                            * a_h_face
                        )
                        parent_apertures.append(a_l)
                        num_parent.append(np.sum(mg.mortar_to_slave_int().A, axis=1))
                    else:
                        raise ValueError("Intersection points not implemented in 3d")
                parent_apertures = np.array(parent_apertures)
                num_parents = np.sum(np.array(num_parent), axis=0)

                apertures = np.sum(parent_apertures, axis=0) / num_parents

                specific_volumes = np.power(apertures, self.Nd - g.dim)
                if to_iterate:
                    pp.set_iterate(
                        d,
                        {
                            "aperture": apertures.copy(),
                            "specific_volume": specific_volumes.copy(),
                        },
                    )
                else:
                    state = {
                        "aperture": apertures.copy(),
                        "specific_volume": specific_volumes.copy(),
                    }
                    pp.set_state(d, state)

        return apertures