Beispiel #1
0
    def assemble_HJBi(self, t=None):
        """ Assembly matrix discretizing second order terms after diffusion
        moved to the explicit operator is subtracted. Whenever amount of
        diffusion used to make some row of an explicit operator monotonic
        exceeds the amount of natural diffusion at that node we call it
        artificial diffusion. In such case, this row of the implicit operator
        is multiplied by zero
        """
        print('Assembling implicit operators')
        self.implicit_matrices = np.empty([self.csize_beta, self.csize_alpha],
                                          dtype=object)
        remaining_diffusion = Function(self.V)
        max_art_dif = 0.0
        max_art_dif_loc = None
        diffusion_matrix = self.diag_matrix.copy()
        for ind_a, alpha in enumerate(self.ctrset_alpha):
            for ind_b, beta in enumerate(self.ctrset_beta):
                # TODO: Include assert making sure that diffusion is
                #  non-negative on all of the internal nodes
                diffusion = self.parameters.diffusion(alpha, beta)
                if t is not None:
                    diffusion.t = t
                diff = interpolate(diffusion, self.V).vector()
                if not np.all(diff >= 0):
                    raise Exception("Choose non-negative diffusion")

                diff_vec = np.array([
                    diff[i] if i not in self.boundary_nodes_list else 0.0
                    for i in range(self.dim)
                ])

                artdif = self.explicit_diffusion[ind_b][ind_a] - diff_vec
                if np.amax(artdif) > max_art_dif:
                    max_art_dif = np.amax(artdif)
                    max_art_dif_loc = self.coords[np.argmax(artdif)]

                # discretise second order terms
                remaining_diffusion.vector()[:] = np.maximum(
                    -artdif, [0] * self.dim)
                diffusion_matrix.set_diagonal(remaining_diffusion.vector())

                Iab = matmult(diffusion_matrix, self.laplacian)
                self.implicit_matrices[ind_b][ind_a] = self.timestep_size * \
                    Iab + self.mass_matrix

        self.scipy_implicit_matrices = [[toscipy(mat) for mat in Ialist]
                                        for Ialist in self.implicit_matrices]
        print('Checking if the implicit operators satisfy'
              ' monotonicity conditions')
        for matrix_list in self.scipy_implicit_matrices:
            for matrix in matrix_list:
                implicit_check(matrix)

        with open(self.ad_data_path + '/ad.txt', 'a') as f:
            time_str = f' at time {t}\n' if t is not None else '\n'
            f.write(f'For mesh {self.mesh_name} max value of artificial'
                    ' diffusion coefficient was'
                    f' {max_art_dif} at {max_art_dif_loc}' + time_str)
Beispiel #2
0
    def assemble_lumpedmm(self):
        """ Assembly lumped mass matrix - plays role of identity matrix
        """
        print("Assembling lumped mass matrix")
        mass_form = self.w * self.u * dx
        self.mass_matrix = assemble(mass_form)

        mass_action_form = action(mass_form, Constant(1))
        self.MM_terms = assemble(mass_action_form)

        self.mass_matrix.zero()
        self.mass_matrix.set_diagonal(self.MM_terms)
        self.scipy_mass_matrix = toscipy(self.mass_matrix)
Beispiel #3
0
    def assemble_lumpedmm(self):
        """ Assembly lumped mass matrix - equal to 0 on robin boundary since
            there is no time derivative there.
        """
        print("Assembling lumped mass matrix")
        mass_form = self.w * self.u * dx
        mass_action_form = action(mass_form, Constant(1))
        self.MM_terms = assemble(mass_action_form)

        for n in self.robint_nodes_list:
            self.MM_terms[n] = 1.0
        for n in self.robin_nodes_list:
            self.MM_terms[n] = 0.0

        self.mass_matrix = assemble(mass_form)
        self.mass_matrix.zero()
        self.mass_matrix.set_diagonal(self.MM_terms)
        self.scipy_mass_matrix = toscipy(self.mass_matrix)
Beispiel #4
0
    def assemble_HJBe(self, t=None):
        """ Assembly explicit operator for every control in the control set,
        then apply artificial diffusion to all of them. Note that artificial
        diffusion is calculated differently on the boundary nodes.
        """
        self.explicit_matrices = np.empty([self.csize_beta, self.csize_alpha],
                                          dtype=object)
        self.explicit_diffusion = np.empty([self.csize_beta, self.csize_alpha],
                                           dtype=object)
        diag_vector = Vector(self.mesh.mpi_comm(), self.dim)
        global_min_timestep = float('inf')
        # Create explicit operator for each control in control set
        for ind_a, a in enumerate(self.ctrset_alpha):
            for ind_b, b in enumerate(self.ctrset_beta):
                if (ind_a * self.csize_beta + ind_b) % 10 == 0:
                    print(f'Assembling explicit matrix under control '
                          f'{ind_a*self.csize_beta + ind_b} out of '
                          f'{self.csize_alpha*self.csize_beta}')
                # coefficients in the interior
                advection_x = self.parameters.adv_x(a, b)
                advection_y = self.parameters.adv_y(a, b)
                reaction = self.parameters.lin(a, b)

                if t is not None:
                    advection_x.t = t
                    advection_y.t = t
                    reaction.t = t

                # Discretize PDE (set values on boundary rows to zero)
                b = np.array([advection_x, advection_y])
                E_int_form = (np.dot(b, grad(self.w)) +
                              reaction * self.w) * self.u * dx
                explicit_matrix = assemble(E_int_form)

                # Calculate nodewise minimum diffusion required to
                # impose monotonicity
                min_diffusion = [0] * explicit_matrix.size(0)
                for rows, row_num in getrows(explicit_matrix,
                                             self.laplacian,
                                             ignore=self.boundary_nodes_list):
                    min_diffusion[row_num] = calc_ad(rows, row_num)
                self.explicit_diffusion[ind_b][ind_a] = min_diffusion

                diffusion_matrix = apply_ad(self.laplacian, min_diffusion)
                explicit_matrix += diffusion_matrix

                explicit_matrix.get_diagonal(diag_vector)
                current_min_timestep = get_min_timestep(
                    diag_vector, self.MM_terms, self.boundary_nodes_list)

                global_min_timestep = min(current_min_timestep,
                                          global_min_timestep)
                self.explicit_matrices[ind_b][ind_a] = toscipy(explicit_matrix)

        #######################################################################
        min_timesteps = int(self.T / global_min_timestep) + 1
        if not self.timesteps or self.timesteps < min_timesteps:
            self.timesteps = min_timesteps
            try:
                filename = (f'meshes/{self.parameters.domain}/'
                            f'Mvalues-{self.parameters.experiment}.json')
                with open(filename, 'r') as f:
                    min_timesteps_dict = json.load(f)
            except FileNotFoundError:
                min_timesteps_dict = {}
            min_timesteps_dict[self.parameters.mesh_name] = self.timesteps
            with open(filename, 'w') as f:
                json.dump(min_timesteps_dict, f)

        self.timestep_size = self.T / self.timesteps  # time step size
        self.parameters.calculate_save_interval()
        self.explicit_matrices = [[
            self.timestep_size * E - self.scipy_mass_matrix for E in Elist
        ] for Elist in self.explicit_matrices]

        print('Checking if the explicit operators satisfy'
              ' monotonicity conditions')
        for matrix_list in self.explicit_matrices:
            for matrix in matrix_list:
                explicit_check(matrix, self.boundary_nodes_list)
Beispiel #5
0
    def assemble_HJBi(self, t=None):
        """ Assembly matrix discretizing second order terms after diffusion
        moved to the explicit operator is subtracted. Whenever amount of
        diffusion used to make some row of an explicit operator monotonic
        exceeds the amount of natural diffusion at that node we call it
        artificial diffusion. In such case, this row of the implicit operator
        is multiplied by zero
        """
        print('Assembling implicit operators')
        self.implicit_matrices = []
        remaining_diffusion = Function(self.V)
        max_art_dif = 0.0
        max_art_dif_loc = None
        diffusion_matrix = self.diag_matrix.copy()
        for explicit_diffusion, alpha in \
                zip(self.explicit_diffusion, self.control_set):

            diffusion = self.parameters.diffusion(alpha)
            if t is not None:
                diffusion.t = t

            diff = interpolate(diffusion, self.V).vector()
            if not np.all(diff >= 0):
                raise Exception("Choose non-negative diffusion")
            diff_vec = np.array([
                diff[i] if i not in self.boundary_nodes_list else 0.0
                for i in range(self.dim)
            ])

            artificial_diffusion = explicit_diffusion - diff_vec
            if np.amax(artificial_diffusion) > max_art_dif:
                max_art_dif = np.amax(artificial_diffusion)
                max_art_dif_loc = self.coords[np.argmax(artificial_diffusion)]

            # discretise second order terms
            remaining_diffusion.vector()[:] = np.maximum(
                -artificial_diffusion, [0] * self.dim)
            diffusion_matrix.set_diagonal(remaining_diffusion.vector())
            implicit_matrix = matmult(diffusion_matrix, self.laplacian)

            for j in self.parameters.regions['Robin']:
                self.set_directional_derivative(implicit_matrix,
                                                region=j,
                                                nodes=self.robin_nodes_dict[j],
                                                control=alpha,
                                                time=t)

            self.implicit_matrices.append(self.timestep_size *
                                          implicit_matrix + self.mass_matrix)

        self.scipy_implicit_matrices = [
            toscipy(mat) for mat in self.implicit_matrices
        ]
        print('Checking if the implicit operators satisfy'
              ' monotonicity conditions')
        for implicit_matrix in self.scipy_implicit_matrices:
            implicit_check(implicit_matrix)

        with open(self.ad_data_path + '/ad.txt', 'a') as f:
            time_str = f' at time {t}\n' if t is not None else '\n'
            f.write(f'For mesh {self.mesh_name} max value of artificial'
                    ' diffusion coefficient was'
                    f' {max_art_dif} at {max_art_dif_loc}' + time_str)
Beispiel #6
0
    def assemble_HJBe(self, t=None):
        """ Assembly explicit operator for every control in the control set,
        then apply artificial diffusion to all of them. Note that artificial
        diffusion is calculated differently on the boundary nodes.
        """
        self.explicit_matrices = np.empty(self.control_set_size, dtype=object)
        self.explicit_diffusion = np.empty([self.control_set_size, self.dim])
        diagonal_vector = Vector(self.mesh.mpi_comm(), self.dim)
        global_min_timestep = float('inf')
        # Create explicit operator for each control in control set
        for k, alpha in enumerate(self.control_set):
            if k % 10 == 0:
                print(f'Assembling explicit matrix under control {k}'
                      f' out of {self.control_set_size}')
            # coefficients in the interior
            advection_x = self.parameters.adv_x(alpha)
            advection_y = self.parameters.adv_y(alpha)
            reaction = self.parameters.lin(alpha)

            if t is not None:
                advection_x.t = t
                advection_y.t = t
                reaction.t = t

            # Discretize PDE (set values on boundary rows to zero)
            b = np.array([advection_x, advection_y])
            E_interior_form = (np.dot(b, grad(self.w)) +
                               reaction * self.w) * self.u * dx
            explicit_matrix = assemble(E_interior_form)
            set_zero_rows(explicit_matrix, self.boundary_nodes_list)

            # Calculate diffusion necessary to make explicit operator monotone
            min_diffusion = np.zeros(explicit_matrix.size(0))
            for rows, row_num in getrows(explicit_matrix,
                                         self.laplacian,
                                         ignore=self.boundary_nodes_list):
                min_diffusion[row_num] = calc_ad(rows, row_num)
            self.explicit_diffusion[k] = min_diffusion

            discrete_diffusion = apply_ad(self.laplacian, min_diffusion)
            explicit_matrix += discrete_diffusion

            for j in self.parameters.regions['RobinTime']:
                self.set_directional_derivative(
                    explicit_matrix,
                    region=j,
                    nodes=self.robint_nodes_dict[j],
                    control=alpha,
                    time=t)

            explicit_matrix.get_diagonal(diagonal_vector)
            current_min_timestep = get_min_timestep(
                diagonal_vector, self.MM_terms,
                self.dirichlet_nodes_list | self.robin_nodes_list)
            global_min_timestep = min(current_min_timestep,
                                      global_min_timestep)
            self.explicit_matrices[k] = toscipy(explicit_matrix)

        #######################################################################
        min_timesteps = int(self.T / global_min_timestep) + 1
        if not self.timesteps or self.timesteps < min_timesteps:
            self.timesteps = min_timesteps
        try:
            filename = (f'meshes/{self.parameters.domain}/'
                        f'Mvalues-{self.parameters.experiment}.json')
            with open(filename, 'r') as f:
                min_timesteps_dict = json.load(f)
        except FileNotFoundError:
            min_timesteps_dict = {}
        min_timesteps_dict[self.parameters.mesh_name] = self.timesteps
        with open(filename, 'w') as f:
            json.dump(min_timesteps_dict, f)

        self.timestep_size = self.T / self.timesteps  # time step size
        self.parameters.calculate_save_interval()
        self.explicit_matrices = self.timestep_size * self.explicit_matrices - \
            np.repeat(self.scipy_mass_matrix, self.control_set_size)

        print('Checking if the explicit operators satisfy'
              ' monotonicity conditions')
        for explicit_matrix in self.explicit_matrices:
            explicit_check(explicit_matrix, self.dirichlet_nodes_list)