From 89a6b39bd18fbf486873a0da01ec56964b4c1037 Mon Sep 17 00:00:00 2001 From: giovanni Date: Thu, 13 Mar 2025 12:04:02 +0100 Subject: [PATCH] fix problem doc --- pina/problem/__init__.py | 2 +- pina/problem/abstract_problem.py | 124 ++++++++++++++----------- pina/problem/inverse_problem.py | 34 ++++--- pina/problem/parametric_problem.py | 19 ++-- pina/problem/spatial_problem.py | 14 ++- pina/problem/time_dependent_problem.py | 14 ++- pina/problem/zoo/__init__.py | 2 +- pina/problem/zoo/advection.py | 4 +- pina/problem/zoo/helmholtz.py | 4 +- pina/problem/zoo/supervised_problem.py | 5 +- 10 files changed, 120 insertions(+), 102 deletions(-) diff --git a/pina/problem/__init__.py b/pina/problem/__init__.py index 3174082..e95f997 100644 --- a/pina/problem/__init__.py +++ b/pina/problem/__init__.py @@ -1,4 +1,4 @@ -"""Module for Problems.""" +"""Module for the Problems.""" __all__ = [ "AbstractProblem", diff --git a/pina/problem/abstract_problem.py b/pina/problem/abstract_problem.py index 43058a6..27207ae 100644 --- a/pina/problem/abstract_problem.py +++ b/pina/problem/abstract_problem.py @@ -1,4 +1,4 @@ -"""Module for AbstractProblem class""" +"""Module for the AbstractProblem class""" from abc import ABCMeta, abstractmethod from copy import deepcopy @@ -11,20 +11,16 @@ from ..utils import merge_tensors class AbstractProblem(metaclass=ABCMeta): """ - The abstract `AbstractProblem` class. All the class defining a PINA Problem - should be inherited from this class. + Abstract base class for PINA problems. All specific problem types should + inherit from this class. - In the definition of a PINA problem, the fundamental elements are: - the output variables, the condition(s), and the domain(s) where the - conditions are applied. + A PINA problem is defined by key components, which typically include output + variables, conditions, and domains over which the conditions are applied. """ def __init__(self): """ - TODO - - :return: _description_ - :rtype: _type_ + Initialization of the :class:`AbstractProblem` class. """ self._discretised_domains = {} # create collector to manage problem data @@ -48,20 +44,19 @@ class AbstractProblem(metaclass=ABCMeta): @property def batching_dimension(self): """ - TODO + Get batching dimension. - :return: _description_ - :rtype: _type_ + :return: The batching dimension. + :rtype int """ return self._batching_dimension @batching_dimension.setter def batching_dimension(self, value): """ - TODO + Set the batching dimension. - :return: _description_ - :rtype: _type_ + :param int value: The batching dimension. """ self._batching_dimension = value @@ -69,10 +64,11 @@ class AbstractProblem(metaclass=ABCMeta): @property def input_pts(self): """ - TODO + Return a dictionary mapping condition names to their corresponding + input points. - :return: _description_ - :rtype: _type_ + :return: The input points of the problem. + :rtype: dict """ to_return = {} for cond_name, cond in self.conditions.items(): @@ -85,21 +81,21 @@ class AbstractProblem(metaclass=ABCMeta): @property def discretised_domains(self): """ - TODO + Return a dictionary mapping domains to their corresponding sampled + points. - :return: _description_ - :rtype: _type_ + :return: The discretised domains. + :rtype dict """ return self._discretised_domains def __deepcopy__(self, memo): """ - Implements deepcopy for the - :class:`~pina.problem.abstract_problem.AbstractProblem` class. + Perform a deep copy of the :class:`AbstractProblem` instance. - :param dict memo: Memory dictionary, to avoid excess copy - :return: The deep copy of the - :class:`~pina.problem.abstract_problem.AbstractProblem` class + :param dict memo: A dictionary used to track objects already copied + during the deep copy process to prevent redundant copies. + :return: A deep copy of the :class:`AbstractProblem` instance. :rtype: AbstractProblem """ cls = self.__class__ @@ -114,7 +110,7 @@ class AbstractProblem(metaclass=ABCMeta): """ Check if all the domains are discretised. - :return: True if all the domains are discretised, False otherwise + :return: ``True`` if all domains are discretised, ``False`` otherwise. :rtype: bool """ return all( @@ -124,12 +120,10 @@ class AbstractProblem(metaclass=ABCMeta): @property def input_variables(self): """ - The input variables of the AbstractProblem, whose type depends on the - type of domain (spatial, temporal, and parameter). - - :return: the input variables of self - :rtype: list + Get the input variables of the problem. + :return: The input variables of the problem. + :rtype: list[str] """ variables = [] @@ -144,20 +138,29 @@ class AbstractProblem(metaclass=ABCMeta): @input_variables.setter def input_variables(self, variables): + """ + Set the input variables of the AbstractProblem. + + :param list[str] variables: The input variables of the problem. + :raises RuntimeError: Not implemented. + """ raise RuntimeError @property @abstractmethod def output_variables(self): """ - The output variables of the problem. + Get the output variables of the problem. """ @property @abstractmethod def conditions(self): """ - The conditions of the problem. + Get the conditions of the problem. + + :return: The conditions of the problem. + :rtype: dict """ return self.conditions @@ -165,30 +168,28 @@ class AbstractProblem(metaclass=ABCMeta): self, n=None, mode="random", domains="all", sample_rules=None ): """ - Generate a set of points to span the `Location` of all the conditions of - the problem. + Discretize the problem's domains by sampling a specified number of + points according to the selected sampling mode. - :param n: Number of points to sample, see Note below - for reference. - :type n: int - :param mode: Mode for sampling, defaults to ``random``. + :param int n: The number of points to sample. + :param mode: The sampling method. Default is ``random``. Available modes include: random sampling, ``random``; latin hypercube sampling, ``latin`` or ``lh``; chebyshev sampling, ``chebyshev``; grid sampling ``grid``. - :param variables: variable(s) to sample, defaults to 'all'. - :type variables: str | list[str] - :param domains: Domain from where to sample, defaults to 'all'. + :param domains: The domains from which to sample. Default is ``all``. :type domains: str | list[str] + :param dict sample_rules: A dictionary of custom sampling rules. + :raises RuntimeError: If both ``n`` and ``sample_rules`` are specified. + :raises RuntimeError: If neither ``n`` nor ``sample_rules`` are set. :Example: - >>> pinn.discretise_domain(n=10, mode='grid') - >>> pinn.discretise_domain(n=10, mode='grid', domain=['bound1']) - >>> pinn.discretise_domain(n=10, mode='grid', variables=['x']) + >>> problem.discretise_domain(n=10, mode='grid') + >>> problem.discretise_domain(n=10, mode='grid', domains=['gamma1']) .. warning:: ``random`` is currently the only implemented ``mode`` for all geometries, i.e. ``EllipsoidDomain``, ``CartesianDomain``, - ``SimplexDomain`` and the geometries compositions ``Union``, + ``SimplexDomain``, and geometry compositions ``Union``, ``Difference``, ``Exclusion``, ``Intersection``. The modes ``latin`` or ``lh``, ``chebyshev``, ``grid`` are only implemented for ``CartesianDomain``. @@ -218,12 +219,31 @@ class AbstractProblem(metaclass=ABCMeta): raise RuntimeError("You have to specify either n or sample_rules.") def _apply_default_discretization(self, n, mode, domains): + """ + Apply default discretization to the problem's domains. + + :param int n: The number of points to sample. + :param mode: The sampling method. + :param domains: The domains from which to sample. + :type domains: str | list[str] + """ for domain in domains: self.discretised_domains[domain] = ( self.domains[domain].sample(n, mode).sort_labels() ) def _apply_custom_discretization(self, sample_rules, domains): + """ + Apply custom discretization to the problem's domains. + + :param dict sample_rules: A dictionary of custom sampling rules. + :param domains: The domains from which to sample. + :type domains: str | list[str] + :raises RuntimeError: If the keys of the sample_rules dictionary are not + the same as the input variables. + :raises RuntimeError: If custom discretisation is applied on a domain + that is not a CartesianDomain. + """ if sorted(list(sample_rules.keys())) != sorted(self.input_variables): raise RuntimeError( "The keys of the sample_rules dictionary must be the same as " @@ -247,10 +267,10 @@ class AbstractProblem(metaclass=ABCMeta): def add_points(self, new_points_dict): """ - Add input points to a sampled condition - :param new_points_dict: Dictionary of input points (condition_name: - LabelTensor) - :raises RuntimeError: if at least one condition is not already sampled + Add new points to an already sampled domain. + + :param dict new_points_dict: The dictionary mapping new points to their + corresponding domain. """ for k, v in new_points_dict.items(): self.discretised_domains[k] = LabelTensor.vstack( diff --git a/pina/problem/inverse_problem.py b/pina/problem/inverse_problem.py index bd75701..343626a 100644 --- a/pina/problem/inverse_problem.py +++ b/pina/problem/inverse_problem.py @@ -1,4 +1,4 @@ -"""Module for the ParametricProblem class""" +"""Module for the InverseProblem class""" from abc import abstractmethod import torch @@ -7,19 +7,14 @@ from .abstract_problem import AbstractProblem class InverseProblem(AbstractProblem): """ - The class for the definition of inverse problems, i.e., problems - with unknown parameters that have to be learned during the training process - from given data. - - Here's an example of a spatial inverse ODE problem, i.e., a spatial - ODE problem with an unknown parameter `alpha` as coefficient of the - derivative term. - - :Example: - TODO + Class for defining inverse problems, where the objective is to determine + unknown parameters through training, based on given data. """ def __init__(self): + """ + Initialization of the :class:`InverseProblem` class. + """ super().__init__() # storing unknown_parameters for optimization self.unknown_parameters = {} @@ -33,23 +28,34 @@ class InverseProblem(AbstractProblem): @abstractmethod def unknown_parameter_domain(self): """ - The parameters' domain of the problem. + The domain of the unknown parameters of the problem. """ @property def unknown_variables(self): """ - The parameters of the problem. + Get the unknown variables of the problem. + + :return: The unknown variables of the problem. + :rtype: list[str] """ return self.unknown_parameter_domain.variables @property def unknown_parameters(self): """ - The parameters of the problem. + Get the unknown parameters of the problem. + + :return: The unknown parameters of the problem. + :rtype: torch.nn.Parameter """ return self.__unknown_parameters @unknown_parameters.setter def unknown_parameters(self, value): + """ + Set the unknown parameters of the problem. + + :param torch.nn.Parameter value: The unknown parameters of the problem. + """ self.__unknown_parameters = value diff --git a/pina/problem/parametric_problem.py b/pina/problem/parametric_problem.py index e12c42e..b54f5a8 100644 --- a/pina/problem/parametric_problem.py +++ b/pina/problem/parametric_problem.py @@ -7,26 +7,23 @@ from .abstract_problem import AbstractProblem class ParametricProblem(AbstractProblem): """ - The class for the definition of parametric problems, i.e., problems - with parameters among the input variables. - - Here's an example of a spatial parametric ODE problem, i.e., a spatial - ODE problem with an additional parameter `alpha` as coefficient of the - derivative term. - - :Example: - TODO + Class for defining parametric problems, where certain input variables are + treated as parameters that can vary, allowing the model to adapt to + different scenarios based on the chosen parameters. """ @abstractmethod def parameter_domain(self): """ - The parameters' domain of the problem. + The domain of the parameters of the problem. """ @property def parameters(self): """ - The parameters' variables of the problem. + Get the parameters of the problem. + + :return: The parameters of the problem. + :rtype: list[str] """ return self.parameter_domain.variables diff --git a/pina/problem/spatial_problem.py b/pina/problem/spatial_problem.py index 1e5434e..68a14b6 100644 --- a/pina/problem/spatial_problem.py +++ b/pina/problem/spatial_problem.py @@ -7,13 +7,8 @@ from .abstract_problem import AbstractProblem class SpatialProblem(AbstractProblem): """ - The class for the definition of spatial problems, i.e., for problems - with spatial input variables. - - Here's an example of a spatial 1-dimensional ODE problem. - - :Example: - TODO + Class for defining spatial problems, where the problem domain is defined in + terms of spatial variables. """ @abstractmethod @@ -25,6 +20,9 @@ class SpatialProblem(AbstractProblem): @property def spatial_variables(self): """ - The spatial input variables of the problem. + Get the spatial input variables of the problem. + + :return: The spatial input variables of the problem. + :rtype: list[str] """ return self.spatial_domain.variables diff --git a/pina/problem/time_dependent_problem.py b/pina/problem/time_dependent_problem.py index 3d06b68..df88a3e 100644 --- a/pina/problem/time_dependent_problem.py +++ b/pina/problem/time_dependent_problem.py @@ -7,13 +7,8 @@ from .abstract_problem import AbstractProblem class TimeDependentProblem(AbstractProblem): """ - The class for the definition of time-dependent problems, i.e., for problems - depending on time. - - Here's an example of a 1D wave problem. - - :Example: - TODO + Class for defining time-dependent problems, where the system's behavior + changes with respect to time. """ @abstractmethod @@ -25,6 +20,9 @@ class TimeDependentProblem(AbstractProblem): @property def temporal_variable(self): """ - The time variable of the problem. + Get the time variable of the problem. + + :return: The time variable of the problem. + :rtype: list[str] """ return self.temporal_domain.variables diff --git a/pina/problem/zoo/__init__.py b/pina/problem/zoo/__init__.py index 6e3d58e..e129c2c 100644 --- a/pina/problem/zoo/__init__.py +++ b/pina/problem/zoo/__init__.py @@ -1,4 +1,4 @@ -"""TODO""" +"""Module for implemented problems.""" __all__ = [ "SupervisedProblem", diff --git a/pina/problem/zoo/advection.py b/pina/problem/zoo/advection.py index 32c6afe..1ba777a 100644 --- a/pina/problem/zoo/advection.py +++ b/pina/problem/zoo/advection.py @@ -16,7 +16,7 @@ class AdvectionEquation(Equation): def __init__(self, c): """ - Initialize the advection equation. + Initialization of the :class:`AdvectionEquation`. :param c: The advection velocity parameter. :type c: float | int @@ -80,7 +80,7 @@ class AdvectionProblem(SpatialProblem, TimeDependentProblem): def __init__(self, c=1.0): """ - Initialize the advection problem. + Initialization of the :class:`AdvectionProblem`. :param c: The advection velocity parameter. :type c: float | int diff --git a/pina/problem/zoo/helmholtz.py b/pina/problem/zoo/helmholtz.py index 8564d82..0468a4d 100644 --- a/pina/problem/zoo/helmholtz.py +++ b/pina/problem/zoo/helmholtz.py @@ -16,7 +16,7 @@ class HelmholtzEquation(Equation): def __init__(self, alpha): """ - Initialize the Helmholtz equation. + Initialization of the :class:`HelmholtzEquation` class. :param alpha: Parameter of the forcing term. :type alpha: float | int @@ -75,7 +75,7 @@ class HelmholtzProblem(SpatialProblem): def __init__(self, alpha=3.0): """ - Initialize the Helmholtz problem. + Initialization of the :class:`HelmholtzProblem` class. :param alpha: Parameter of the forcing term. :type alpha: float | int diff --git a/pina/problem/zoo/supervised_problem.py b/pina/problem/zoo/supervised_problem.py index 45c75a1..3fe683f 100644 --- a/pina/problem/zoo/supervised_problem.py +++ b/pina/problem/zoo/supervised_problem.py @@ -2,12 +2,11 @@ from ..abstract_problem import AbstractProblem from ... import Condition -from ... import LabelTensor class SupervisedProblem(AbstractProblem): """ - Definition of a supervised learning problem in PINA. + Definition of a supervised-learning problem. This class provides a simple way to define a supervised problem using a single condition of type @@ -28,7 +27,7 @@ class SupervisedProblem(AbstractProblem): self, input_, output_, input_variables=None, output_variables=None ): """ - Initialize the SupervisedProblem class. + Initialization of the :class:`SupervisedProblem` class. :param input_: Input data of the problem. :type input_: torch.Tensor | LabelTensor | Graph | Data