Source code for gepard.model

"""Base classes for models of "soft" hadronic structure functions.

    * Elastic electromagnetic form factors
    * Generalized parton distribution functions (GPDs)
    * Compton form factors (for DVCS)

Actual implementations are in other files. Here only generic
treatment of generalized parametrized model is coded.

Todo:
    * Model defined by grid of numbers
    * Flavored models

"""
from __future__ import annotations

from math import sqrt
from typing import List

from . import theory
from .constants import tolerance2


[docs] class Model(theory.Theory): """Base class for all models. Instance of this class specifies structure of relevant hadrons. Methods provided are typically GPDs, CFFs, elastic FFs, DVMP transition TFFs, DAs, etc. Main subclasses are: - ParameterModel which depends on real parameters (some of which can be provided by minimization routine in the fitting procedure). - NeuralModel where structure functions are represented as neural nets (not yet implemented) - GridModel where values of structure functions are represented as grids of numbers, which may be interpolated (not yet implemented) These are then further subclassed to model actual structure functions. """
[docs] def __init__(self, **kwargs) -> None: super().__init__(**kwargs)
[docs] class ParameterModel(Model): """Base class for all parametrized models. Attributes: parameters: dict {'par0': float, ...}. Actual value of parameter. parameters_fixed: dict {'par0': bool, ...}. Is parameter value fixed? Considered False if non-existent. Once Fitter object is created, user should manipulate this dict only via Fitter methods. parameters_limits: dict {'par0: (float, float), ...}. Allowed range for fitting. Considered (-inf, inf) if non-existent. Once Fitter object is created, user should manipulate this dict only via Fitter methods. """
[docs] def __init__(self, **kwargs) -> None: # If subclases don't create these dicts, this is the # last chance. They have to exist. for d in ['parameters', 'parameters_fixed', 'parameters_limits']: if not hasattr(self, d): setattr(self, d, {}) # By default, all params are fixed self._fix_parameters('ALL') # print('ParameterModel init done') super().__init__(**kwargs)
[docs] def add_parameters(self, newpars: dict): """Append newpars to parameters.""" # Create parameters dict if it doesn't exist yet try: self.parameters except AttributeError: self.parameters = {} self.parameters.update(newpars)
[docs] def add_parameters_limits(self, newlimits: dict): """Append newlimits to parameters_limits.""" # Create parameters_limits dict if it doesn't exist yet try: self.parameters_limits except AttributeError: self.parameters_limits = {} self.parameters_limits.update(newlimits)
[docs] def _release_parameters(self, *pars: str): """Release parameters for fitting. Args: *pars: Names of parameters to be released Notes: User should relase and fix parameters using methods of Fitter instance. This then calls this private ParameterModel method. """ for par in pars: if par not in self.parameters: raise ValueError('Parameter {} is not defined in model {}'.format( par, self)) self.parameters_fixed[par] = False
[docs] def _fix_parameters(self, *pars: str): """Fix parameters so they are not fitting variables. Args: *pars: Names of parameters to be fixed. If first name is 'ALL' then fix all parameters. Notes: User should relase and fix parameters using methods of Fitter instance. This then calls this private ParameterModel method. """ if pars[0] == 'ALL': # fix 'em all for par in self.parameters: self.parameters_fixed[par] = True else: for par in pars: if par not in self.parameters: raise ValueError('Parameter {} is not defined in model {}'.format( par, self)) self.parameters_fixed[par] = True
[docs] def free_parameters(self) -> List[str]: """Return list of names of free fitting parameters.""" return [p for p in self.parameters if p not in self.parameters_fixed or not self.parameters_fixed[p]]
[docs] def print_parameters(self): """Print fitting parameters and their errors.""" for p in self.free_parameters(): val = self.parameters[p] err = sqrt(tolerance2)*self.parameters_errors[p] print('{:5s} = {:8.3f} +- {:5.3f}'.format(p, val, err))