Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor How UQTestFuns Should Handle Parameters #351

Closed
damar-wicaksono opened this issue May 31, 2024 · 1 comment
Closed

Refactor How UQTestFuns Should Handle Parameters #351

damar-wicaksono opened this issue May 31, 2024 · 1 comment
Assignees
Labels
core Core functionality of the package
Milestone

Comments

@damar-wicaksono
Copy link
Owner

Currently, arbitrary parameters may be assigned to a property of UQTestFuns instances. If the underlying function supports it, then they will be consumed accordingly. The responsibility about how to consume the parameters is delegated to the actual implementation of the test function (i.e., inside the respective module). Users may change the value of the parameters directly on the instance.

However, the current implementation is not safe as there is no guarantee that user will supply the correct parameters, in particular, their types as a value of the parameter can be anything. Semantically, the parameters being arbitrary has no structure from one test function implementation to another.

Some refactoring is thus needed.

Refactoring idea

I would like for test function parameters to be encapsulated inside its own class, say, Parameters.
The class has the following main properties:

  • name or perhaps, id
  • _original_entries: the parameters created at the beginning
  • description
  • _dict: storing the simply the keywords and values of parameter entries. If the parameter value is modified on the fly (on the instance) then only the value here changes. An instance may be reset to the original value because we have to storages.

With the following methods:

  • add_parameter(keyword, symbol, valu, type, optional, description)
  • as_dict(): returns the dict
  • reset(): return all values to the original entries.
  • __getitem__()
  • __setitem__()
  • __contains__()
  • __str__()
  • __deepcopy__()
  • __copy__()
  • __len__()

Each parameter must have the following properties:

  • keyword: keyword as appears in the test function implementation signature
  • value: the value of the parameter
  • type: the type of the parameter value (for checking)
  • optional: whether this parameter is optional
  • symbol: the symbol as appear in the equation
  • description: the description the parameter

So the parameters for the circular pipe crack problem can be constructed as follows:

params = Parameters()
params.add_parameter(
  keyword="pipe_radius",
  symbol="t",
  value=3.377e-1,
  type=float,
  description="Radius of the pipe [m]",
)
params.add_parameter(
  keyword="pipe_thickness",
  symbol="R",
  value=3.377e-2,
  type=float,
  description="Thickness of the pipe [m]",
)
params.add_parameter(
  keyword="bending_moment",
  symbol="M",
  value=3.0,
  type=float,
  description="Applied bending moment [MNm]",
)

We can update the value as long as the assigned value is of consistent type. For instance:

params["bending_moment"] = 2.0  # Okay
params["bending_moment"] = "a"  # Raise an exception!

The top-level signature of eval_ method is now will be:

def eval_(xx: np.ndarray, **kwargs):

instead of

def eval_(*args):

This method is called by the evaluate() method:

def evaluate(self, *args):
  ...
  else:
      return self.__class__.eval_(xx, **self.parameters.as_dict())

Note that parameters will be assigned in the call to the actual function as keyword arguments.
Now instead of:

def evaluate(
    xx: np.ndarray, parameters: Tuple[float, float, float]
) -> np.ndarray:

we write the signature as:

def evaluate(
      xx: np.ndarray, pipe_radius: float, pipe_thickness: float, bending_moment: float,
) -> np.ndarray:

which is now more self-explanatory and much less cryptic.

The method as_dict() will return a dictionary whose values are each of the entries value; the key of this dictionary must match with the keyword arguments defined in the underlying function.
Furthermore, the number of entries in each Parameters must match with the declared keyword arguments, no more and no less.
That's why the keyword specified in the Parameters instance must be correct otherwise the function cannot find them.

The output of print() is as follows:

Name            : Parameters-CircularPipeCrack-Verma2015
# of Parameters : 3
Description     : Set of parameters for the circular pipe crack problem
                  used in Verma et al. (2015)

  No.  Symbol     Keyword          Value         Type             Description                  
                                                                                                     
-----  ------  --------------  --------------   ------   --------------------------------
    1    r       pipe_radius      3.377e-1       float       Radius of the pipe [m]
    2    t     pipe_thickness     3.377e-2       float      Thickness of the pipe [m]
    3    M     bending_moment        3.0         float     Applied bending moment [MNm]
@damar-wicaksono damar-wicaksono added the core Core functionality of the package label May 31, 2024
@damar-wicaksono damar-wicaksono added this to the 0.5.0 Release milestone May 31, 2024
@damar-wicaksono damar-wicaksono self-assigned this May 31, 2024
damar-wicaksono added a commit that referenced this issue Oct 30, 2024
Introduce the FunParams class to handle UQ
test function parameters.
Updated class usage across the module
to ensure proper handling of parameters.
The test suite has been updated
to test latest changes.

This commit should resolve Issue #351.
@damar-wicaksono
Copy link
Owner Author

This issue has been resolved by PR #360.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Core functionality of the package
Projects
None yet
Development

No branches or pull requests

1 participant