示例#1
0
        def _init_offline(self):
            # Call parent to initialize inner product and reduced problem
            output = DifferentialProblemReductionMethod_DerivedClass._init_offline(
                self)

            # Declare a new POD for each basis component
            if len(self.truth_problem.components) > 1:
                self.POD = dict()
                for component in self.truth_problem.components:
                    assert len(
                        self.truth_problem.inner_product[component]) == 1
                    # the affine expansion storage contains only the inner product matrix
                    inner_product = self.truth_problem.inner_product[
                        component][0]
                    self.POD[component] = ProperOrthogonalDecomposition(
                        self.truth_problem.V, inner_product)
            else:
                assert len(self.truth_problem.inner_product) == 1
                # the affine expansion storage contains only the inner product matrix
                inner_product = self.truth_problem.inner_product[0]
                self.POD = ProperOrthogonalDecomposition(
                    self.truth_problem.V, inner_product)

            # Return
            return output
        def _init_offline(self):
            # Call parent to initialize inner product
            output = DifferentialProblemReductionMethod_DerivedClass._init_offline(
                self)

            if self.nested_POD:
                # Declare new POD object(s)
                if len(self.truth_problem.components) > 1:
                    self.POD_time_trajectory = dict()
                    for component in self.truth_problem.components:
                        assert len(
                            self.truth_problem.inner_product[component]
                        ) == 1  # the affine expansion storage contains only the inner product matrix
                        inner_product = self.truth_problem.inner_product[
                            component][0]
                        self.POD_time_trajectory[
                            component] = ProperOrthogonalDecomposition(
                                self.truth_problem.V, inner_product)
                else:
                    assert len(
                        self.truth_problem.inner_product
                    ) == 1  # the affine expansion storage contains only the inner product matrix
                    inner_product = self.truth_problem.inner_product[0]
                    self.POD_time_trajectory = ProperOrthogonalDecomposition(
                        self.truth_problem.V, inner_product)

            # Return
            return output
 def _init_offline(self):
     # Call parent to initialize inner product
     output = DifferentialProblemReductionMethod_DerivedClass._init_offline(self)
     
     # Check admissible values of POD_greedy_basis_extension
     assert self.POD_greedy_basis_extension in ("orthogonal", "POD")
     
     # Declare new POD object(s)
     if len(self.truth_problem.components) > 1:
         self.POD_time_trajectory = dict()
         if self.POD_greedy_basis_extension == "POD":
             self.POD_basis = dict()
         for component in self.truth_problem.components:
             assert len(self.truth_problem.inner_product[component]) == 1 # the affine expansion storage contains only the inner product matrix
             inner_product = self.truth_problem.inner_product[component][0]
             self.POD_time_trajectory[component] = ProperOrthogonalDecomposition(self.truth_problem.V, inner_product)
             if self.POD_greedy_basis_extension == "POD":
                 self.POD_basis[component] = ProperOrthogonalDecomposition(self.truth_problem.V, inner_product)
     else:
         assert len(self.truth_problem.inner_product) == 1 # the affine expansion storage contains only the inner product matrix
         inner_product = self.truth_problem.inner_product[0]
         self.POD_time_trajectory = ProperOrthogonalDecomposition(self.truth_problem.V, inner_product)
         if self.POD_greedy_basis_extension == "POD":
             self.POD_basis = ProperOrthogonalDecomposition(self.truth_problem.V, inner_product)
     
     # Return
     return output
    def _init_offline(self):
        # We cannot use the standard initialization provided by PODGalerkinReduction because
        # supremizer POD requires a custom initialization. We thus duplicate here part of its code

        # Call parent of parent (!) to initialize inner product and reduced problem
        output = StokesOptimalControlPODGalerkinReduction_Base._init_offline(self)

        # Declare a new POD for each basis component
        self.POD = dict()
        for component in ("v", "p", "u", "w", "q"):
            inner_product = self.truth_problem.inner_product[component][0]
            self.POD[component] = ProperOrthogonalDecomposition(
                self.truth_problem.V, inner_product)
        for component in ("s", "r"):
            inner_product = self.truth_problem.inner_product[component][0]
            self.POD[component] = ProperOrthogonalDecomposition(
                self.truth_problem.V, inner_product, component=component)

        # Return
        return output
        def _init_offline(self):
            # Call parent to initialize
            output = AbstractCFDUnsteadyPODGalerkinReduction_Base._init_offline(
                self)

            if self.nested_POD:
                # Declare new POD object(s)
                self.POD_time_trajectory = dict()
                for component in ("u", "p"):
                    inner_product = self.truth_problem.inner_product[
                        component][0]
                    self.POD_time_trajectory[
                        component] = ProperOrthogonalDecomposition(
                            self.truth_problem.V, inner_product)
                for component in ("s", ):
                    inner_product = self.truth_problem.inner_product[
                        component][0]
                    self.POD_time_trajectory[
                        component] = ProperOrthogonalDecomposition(
                            self.truth_problem.V, inner_product, component="s")

            # Return
            return output
示例#6
0
def perform_POD(N):
    # export mesh - instead of generating mesh everytime
    (mesh, _, _, restrictions) = read_mesh()
    W = generate_block_function_space(mesh, restrictions)

    # POD objects
    X = get_inner_products(W, "POD")
    POD = {c: ProperOrthogonalDecomposition(W, X[c]) for c in components}

    # Solution storage
    solution = BlockFunction(W)

    # Training set
    training_set = get_set("training_set")

    # Read in snapshots
    for mu in training_set:
        print("Appending solution for mu =", mu, "to snapshots matrix")
        read_solution(mu, "truth_solve", solution)
        for c in components:
            POD[c].store_snapshot(solution, component=c)

    # Compress component by component
    basis_functions_component = dict()
    for c in components:
        _, _, basis_functions_component[c], N_c = POD[c].apply(N, tol=0.)
        assert N_c == N
        print("Eigenvalues for component", c)
        POD[c].print_eigenvalues(N)
        POD[c].save_eigenvalues_file("basis", "eigenvalues_" + c)

    # Collect all components and save to file
    basis_functions = BasisFunctionsMatrix(W)
    basis_functions.init(components)
    for c in components:
        basis_functions.enrich(basis_functions_component[c], component=c)
    basis_functions.save("basis", "basis")
    # Also save components to file, for the sake of the ParaView plugin
    with open(os.path.join("basis", "components"), "w") as file_:
        for c in components:
            file_.write(c + "\n")
示例#7
0
    class PODGalerkinReduction_Class(
            DifferentialProblemReductionMethod_DerivedClass):
        """
        Abstract class. The folders used to store the snapshots and for the post processing data,
        the data stracture for the POD algorithm are initialized.

        :param truth_problem: the class of the truth problem to be solved.
        :return: PODGalerkinReduction_Class where all the offline data are stored.
        """
        def __init__(self, truth_problem, **kwargs):
            # Call the parent initialization
            DifferentialProblemReductionMethod_DerivedClass.__init__(
                self, truth_problem, **kwargs)

            # Declare a POD object
            # ProperOrthogonalDecomposition (for problems with one component)
            # or dict of ProperOrthogonalDecomposition (for problem with several components)
            self.POD = None
            # I/O
            self.folder["snapshots"] = os.path.join(self.folder_prefix,
                                                    "snapshots")
            self.folder["post_processing"] = os.path.join(
                self.folder_prefix, "post_processing")
            self.label = "POD-Galerkin"

            # Since we use a POD for each component, it makes sense to possibly have
            # different tolerances for each component.
            if len(self.truth_problem.components) > 1:
                self.tol = {
                    component: 0.
                    for component in self.truth_problem.components
                }
            else:
                self.tol = 0.

        def set_tolerance(self, tol, **kwargs):
            """
            It sets tolerance to be used as stopping criterion.

            :param tol: the tolerance to be used.
            """
            if len(self.truth_problem.components) > 1:
                if tol is None:
                    all_components_in_kwargs = self.truth_problem.components[
                        0] in kwargs
                    for component in self.truth_problem.components:
                        if all_components_in_kwargs:
                            assert component in kwargs, (
                                "You need to specify the tolerance of all components in kwargs"
                            )
                        else:
                            assert component not in kwargs, (
                                "You need to specify the tolerance of all components in kwargs"
                            )
                    assert all_components_in_kwargs
                    tol = dict()
                    for component in self.truth_problem.components:
                        tol[component] = kwargs[component]
                        del kwargs[component]
                else:
                    assert isinstance(tol, Number)
                    tol_number = tol
                    tol = dict()
                    for component in self.truth_problem.components:
                        tol[component] = tol_number
                        assert component not in kwargs, (
                            "You cannot provide both a number and kwargs for components"
                        )
            else:
                if tol is None:
                    assert len(self.truth_problem.components) == 1
                    component_0 = self.truth_problem.components[0]
                    assert component_0 in kwargs
                    tol = kwargs[component_0]
                else:
                    assert isinstance(tol, Number)

            self.tol = tol

        def _init_offline(self):
            # Call parent to initialize inner product and reduced problem
            output = DifferentialProblemReductionMethod_DerivedClass._init_offline(
                self)

            # Declare a new POD for each basis component
            if len(self.truth_problem.components) > 1:
                self.POD = dict()
                for component in self.truth_problem.components:
                    assert len(
                        self.truth_problem.inner_product[component]) == 1
                    # the affine expansion storage contains only the inner product matrix
                    inner_product = self.truth_problem.inner_product[
                        component][0]
                    self.POD[component] = ProperOrthogonalDecomposition(
                        self.truth_problem.V, inner_product)
            else:
                assert len(self.truth_problem.inner_product) == 1
                # the affine expansion storage contains only the inner product matrix
                inner_product = self.truth_problem.inner_product[0]
                self.POD = ProperOrthogonalDecomposition(
                    self.truth_problem.V, inner_product)

            # Return
            return output

        def offline(self):
            """
            It performs the offline phase of the reduced order model.

            :return: reduced_problem where all offline data are stored.
            """
            need_to_do_offline_stage = self._init_offline()
            if need_to_do_offline_stage:
                self._offline()
            self._finalize_offline()
            return self.reduced_problem

        @snapshot_links_to_cache
        def _offline(self):
            print(
                TextBox(self.truth_problem.name() + " " + self.label +
                        " offline phase begins",
                        fill="="))
            print("")

            for (mu_index, mu) in enumerate(self.training_set):
                print(TextLine(str(mu_index), fill="#"))

                self.truth_problem.set_mu(mu)

                print("truth solve for mu =", self.truth_problem.mu)
                snapshot = self.truth_problem.solve()
                self.truth_problem.export_solution(self.folder["snapshots"],
                                                   "truth_" + str(mu_index),
                                                   snapshot)
                snapshot = self.postprocess_snapshot(snapshot, mu_index)

                print("update snapshots matrix")
                self.update_snapshots_matrix(snapshot)

                print("")

            print(TextLine("perform POD", fill="#"))
            self.compute_basis_functions()

            print("")
            print("build reduced operators")
            self.reduced_problem.build_reduced_operators()

            print("")
            print(
                TextBox(self.truth_problem.name() + " " + self.label +
                        " offline phase ends",
                        fill="="))
            print("")

        def update_snapshots_matrix(self, snapshot):
            """
            It updates the snapshots matrix.

            :param snapshot: last offline solution computed.
            """
            if len(self.truth_problem.components) > 1:
                for component in self.truth_problem.components:
                    self.POD[component].store_snapshot(snapshot,
                                                       component=component)
            else:
                self.POD.store_snapshot(snapshot)

        def compute_basis_functions(self):
            """
            It computes basis functions performing POD solving an eigenvalue problem.
            """
            if len(self.truth_problem.components) > 1:
                for component in self.truth_problem.components:
                    print("# POD for component", component)
                    POD = self.POD[component]
                    (_, _, basis_functions,
                     N) = POD.apply(self.Nmax, self.tol[component])
                    self.reduced_problem.basis_functions.enrich(
                        basis_functions, component=component)
                    self.reduced_problem.N[component] += N
                    POD.print_eigenvalues(N)
                    POD.save_eigenvalues_file(self.folder["post_processing"],
                                              "eigs_" + component)
                    POD.save_retained_energy_file(
                        self.folder["post_processing"],
                        "retained_energy_" + component)
                self.reduced_problem.basis_functions.save(
                    self.reduced_problem.folder["basis"], "basis")
            else:
                (_, _, basis_functions,
                 N) = self.POD.apply(self.Nmax, self.tol)
                self.reduced_problem.basis_functions.enrich(basis_functions)
                self.reduced_problem.N += N
                self.POD.print_eigenvalues(N)
                self.POD.save_eigenvalues_file(self.folder["post_processing"],
                                               "eigs")
                self.POD.save_retained_energy_file(
                    self.folder["post_processing"], "retained_energy")
                self.reduced_problem.basis_functions.save(
                    self.reduced_problem.folder["basis"], "basis")

        def error_analysis(self, N_generator=None, filename=None, **kwargs):
            """
            It computes the error of the reduced order approximation with respect to the full order one
            over the testing set

            :param N_generator: generator of dimension of the reduced problem.
            """
            self._init_error_analysis(**kwargs)
            self._error_analysis(N_generator, filename, **kwargs)
            self._finalize_error_analysis(**kwargs)

        def _error_analysis(self, N_generator=None, filename=None, **kwargs):
            if N_generator is None:

                def N_generator():
                    N = self.reduced_problem.N
                    if isinstance(N, dict):
                        N = min(N.values())
                    for n in range(1, N + 1):  # n = 1, ... N
                        yield n

            if "components" in kwargs:
                components = kwargs["components"]
            else:
                components = self.truth_problem.components

            def N_generator_items():
                for n in N_generator():
                    assert isinstance(n, (dict, int))
                    if isinstance(n, int):
                        yield (n, n)
                    elif isinstance(n, dict):
                        assert len(n) == 1
                        (n_int, n_online_size_dict) = n.popitem()
                        assert isinstance(n_int, int)
                        assert isinstance(n_online_size_dict, OnlineSizeDict)
                        yield (n_int, n_online_size_dict)
                    else:
                        raise TypeError(
                            "Invalid item generated by N_generator")

            def N_generator_max():
                *_, Nmax = N_generator_items()
                assert isinstance(Nmax, tuple)
                assert len(Nmax) == 2
                assert isinstance(Nmax[0], int)
                return Nmax[0]

            print(
                TextBox(self.truth_problem.name() + " " + self.label +
                        " error analysis begins",
                        fill="="))
            print("")

            error_analysis_table = ErrorAnalysisTable(self.testing_set)
            error_analysis_table.set_Nmax(N_generator_max())
            for component in components:
                error_analysis_table.add_column("error_" + component,
                                                group_name="solution_" +
                                                component,
                                                operations=("mean", "max"))
                error_analysis_table.add_column("relative_error_" + component,
                                                group_name="solution_" +
                                                component,
                                                operations=("mean", "max"))
            error_analysis_table.add_column("error_output",
                                            group_name="output",
                                            operations=("mean", "max"))
            error_analysis_table.add_column("relative_error_output",
                                            group_name="output",
                                            operations=("mean", "max"))

            for (mu_index, mu) in enumerate(self.testing_set):
                print(TextLine(str(mu_index), fill="#"))

                self.reduced_problem.set_mu(mu)

                for (n_int, n_arg) in N_generator_items():
                    self.reduced_problem.solve(n_arg, **kwargs)
                    error = self.reduced_problem.compute_error(**kwargs)
                    relative_error = self.reduced_problem.compute_relative_error(
                        **kwargs)

                    self.reduced_problem.compute_output()
                    error_output = self.reduced_problem.compute_error_output(
                        **kwargs)
                    relative_error_output = self.reduced_problem.compute_relative_error_output(
                        **kwargs)

                    if len(components) > 1:
                        for component in components:
                            error_analysis_table["error_" + component, n_int,
                                                 mu_index] = error[component]
                            error_analysis_table[
                                "relative_error_" + component, n_int,
                                mu_index] = relative_error[component]
                    else:
                        component = components[0]
                        error_analysis_table["error_" + component, n_int,
                                             mu_index] = error
                        error_analysis_table["relative_error_" + component,
                                             n_int, mu_index] = relative_error

                    error_analysis_table["error_output", n_int,
                                         mu_index] = error_output
                    error_analysis_table["relative_error_output", n_int,
                                         mu_index] = relative_error_output

            # Print
            print("")
            print(error_analysis_table)

            print("")
            print(
                TextBox(self.truth_problem.name() + " " + self.label +
                        " error analysis ends",
                        fill="="))
            print("")

            # Export error analysis table
            error_analysis_table.save(
                self.folder["error_analysis"],
                "error_analysis" if filename is None else filename)

        def speedup_analysis(self, N_generator=None, filename=None, **kwargs):
            """
            It computes the speedup of the reduced order approximation with respect to the full order one
            over the testing set

            :param N_generator: generator of dimension of the reduced problem.
            """
            self._init_speedup_analysis(**kwargs)
            self._speedup_analysis(N_generator, filename, **kwargs)
            self._finalize_speedup_analysis(**kwargs)

        def _speedup_analysis(self, N_generator=None, filename=None, **kwargs):
            if N_generator is None:

                def N_generator():
                    N = self.reduced_problem.N
                    if isinstance(N, dict):
                        N = min(N.values())
                    for n in range(1, N + 1):  # n = 1, ... N
                        yield n

            def N_generator_items():
                for n in N_generator():
                    assert isinstance(n, (dict, int))
                    if isinstance(n, int):
                        yield (n, n)
                    elif isinstance(n, dict):
                        assert len(n) == 1
                        (n_int, n_online_size_dict) = n.popitem()
                        assert isinstance(n_int, int)
                        assert isinstance(n_online_size_dict, OnlineSizeDict)
                        yield (n_int, n_online_size_dict)
                    else:
                        raise TypeError(
                            "Invalid item generated by N_generator")

            def N_generator_max():
                *_, Nmax = N_generator_items()
                assert isinstance(Nmax, tuple)
                assert len(Nmax) == 2
                assert isinstance(Nmax[0], int)
                return Nmax[0]

            print(
                TextBox(self.truth_problem.name() + " " + self.label +
                        " speedup analysis begins",
                        fill="="))
            print("")

            speedup_analysis_table = SpeedupAnalysisTable(self.testing_set)
            speedup_analysis_table.set_Nmax(N_generator_max())
            speedup_analysis_table.add_column("speedup_solve",
                                              group_name="speedup_solve",
                                              operations=("min", "mean",
                                                          "max"))
            speedup_analysis_table.add_column("speedup_output",
                                              group_name="speedup_output",
                                              operations=("min", "mean",
                                                          "max"))

            truth_timer = Timer("parallel")
            reduced_timer = Timer("serial")

            for (mu_index, mu) in enumerate(self.testing_set):
                print(TextLine(str(mu_index), fill="#"))

                self.reduced_problem.set_mu(mu)

                truth_timer.start()
                self.truth_problem.solve(**kwargs)
                elapsed_truth_solve = truth_timer.stop()

                truth_timer.start()
                self.truth_problem.compute_output()
                elapsed_truth_output = truth_timer.stop()

                for (n_int, n_arg) in N_generator_items():
                    reduced_timer.start()
                    solution = self.reduced_problem.solve(n_arg, **kwargs)
                    elapsed_reduced_solve = reduced_timer.stop()

                    reduced_timer.start()
                    output = self.reduced_problem.compute_output()
                    elapsed_reduced_output = reduced_timer.stop()

                    if solution is not NotImplemented:
                        speedup_analysis_table[
                            "speedup_solve", n_int,
                            mu_index] = elapsed_truth_solve / elapsed_reduced_solve
                    else:
                        speedup_analysis_table["speedup_solve", n_int,
                                               mu_index] = NotImplemented
                    if output is not NotImplemented:
                        speedup_analysis_table[
                            "speedup_output", n_int,
                            mu_index] = (elapsed_truth_solve +
                                         elapsed_truth_output) / (
                                             elapsed_reduced_solve +
                                             elapsed_reduced_output)
                    else:
                        speedup_analysis_table["speedup_output", n_int,
                                               mu_index] = NotImplemented

            # Print
            print("")
            print(speedup_analysis_table)

            print("")
            print(
                TextBox(self.truth_problem.name() + " " + self.label +
                        " speedup analysis ends",
                        fill="="))
            print("")

            # Export speedup analysis table
            speedup_analysis_table.save(
                self.folder["speedup_analysis"],
                "speedup_analysis" if filename is None else filename)