Exemple #1
0
class SolverTimeIntegratorParametersGroup(ParametersGroup):
    """Class for defining the solver time integrator parameters for cadet.

    See also
    --------
    ParametersGroup
    """
    abstol = UnsignedFloat(default=1e-8)
    algtol = UnsignedFloat(default=1e-12)
    reltol = UnsignedFloat(default=1e-6)
    reltol_sens = UnsignedFloat(default=1e-12)
    init_step_size = UnsignedFloat(default=1e-6)
    max_steps = UnsignedInteger(default=1000000)
    max_step_size = UnsignedInteger(default=1000000)
    errortest_sens = Bool(default=False)
    max_newton_iter = UnsignedInteger(default=1000000)
    max_errtest_fail = UnsignedInteger(default=1000000)
    max_convtest_fail = UnsignedInteger(default=1000000)
    max_newton_iter_sens = UnsignedInteger(default=1000000)

    _parameters = [
        'abstol', 'algtol', 'reltol', 'reltol_sens', 'init_step_size',
        'max_steps', 'max_step_size', 'errortest_sens', 'max_newton_iter',
        'max_errtest_fail', 'max_convtest_fail', 'max_newton_iter_sens'
    ]
class TrustConstr(SciPyInterface):
    """Class from scipy for optimization with trust-constr as method for the
    solver.

    This class is a wrapper for the method trust-constr from the optimization
    suite of the scipy interface. It defines the solver options in the local
    variable options as a dictionary and implements the abstract method run for
    running the optimization.
    """
    gtol = UnsignedFloat(default=1e-6)
    xtol = UnsignedFloat(default=1e-8)
    barrier_tol = UnsignedFloat(default=1e-8)
    initial_constr_penalty = UnsignedFloat(default=1.0)
    initial_tr_radius = UnsignedFloat(default=1.0)
    initial_barrier_parameter = UnsignedFloat(default=0.01)
    initial_barrier_tolerance = UnsignedFloat(default=0.01)
    factorization_method = None
    maxiter = UnsignedInteger(default=1000)
    verbose = UnsignedInteger(default=0)
    disp = Bool(default=False)
    _options = [
        'gtol', 'xtol', 'barrier_tol', 'finite_diff_rel_step',
        'initial_constr_penalty',
        'initial_tr_radius', 'initial_barrier_parameter',
        'initial_barrier_tolerance', 'factorization_method',
        'maxiter','verbose', 'disp'
    ]

    jac = Switch(default='3-point', valid=['2-point', '3-point', 'cs'])

    def __str__(self):
        return 'trust-constr'
Exemple #3
0
class ReturnParametersGroup(ParametersGroup):
    """Class for defining the return parameters for cadet.

    See also
    --------
    ParametersGroup
    """
    write_solution_times = Bool(default=True)
    write_solution_last = Bool(default=True)
    write_sens_last = Bool(default=True)
    split_components_data = Bool(default=False)
    split_ports_data = Bool(default=False)

    _parameters = [
        'write_solution_times', 'write_solution_last', 'write_sens_last',
        'split_components_data', 'split_ports_data'
    ]
class LRMDiscretizationFV(DiscretizationParametersBase):
    ncol = UnsignedInteger(default=100)
    use_analytic_jacobian = Bool(default=True)
    reconstruction = Switch(default='WENO', valid=['WENO'])
    
    _parameters = DiscretizationParametersBase._parameters + [
        'ncol', 'use_analytic_jacobian', 'reconstruction',
    ]
    _dimensionality = ['ncol']
class NelderMead(SciPyInterface):
    """
    """
    maxiter = UnsignedInteger()
    maxfev = UnsignedInteger()
    initial_simplex = None
    xatol = UnsignedFloat(default=0.01)
    fatol = UnsignedFloat(default=0.01)
    adaptive = Bool(default=True)
    _options = [
        'maxiter', 'maxfev', 'initial_simplex', 'xatol', 'fatol', 'adaptive'
    ]
class LRMPDiscretizationFV(DiscretizationParametersBase):
    ncol = UnsignedInteger(default=100)

    par_geom = Switch(
        default='SPHERE', 
        valid=['SPHERE', 'CYLINDER', 'SLAB']
    )

    use_analytic_jacobian = Bool(default=True)
    reconstruction = Switch(default='WENO', valid=['WENO'])
    
    gs_type = Bool(default=True)
    max_krylov = UnsignedInteger(default=0)
    max_restarts = UnsignedInteger(default=10)
    schur_safety = UnsignedFloat(default=1.0e-8)
    
    _parameters = DiscretizationParametersBase._parameters + [
        'ncol', 'par_geom', 
        'use_analytic_jacobian', 'reconstruction', 
        'gs_type', 'max_krylov', 'max_restarts', 'schur_safety'
    ]
    _dimensionality = ['ncol']
class SLSQP(SciPyInterface):
    """Class from scipy for optimization with SLSQP as method for the
    solver.

    This class is a wrapper for the method SLSQP from the optimization
    suite of the scipy interface. It defines the solver options in the local
    variable options as a dictionary and implements the abstract method run for
    running the optimization.
    """
    ftol = UnsignedFloat(default=1e-2)
    eps = UnsignedFloat(default=1e-6)
    disp = Bool(default=False)
    _options = ['ftol', 'eps', 'disp']
class GRMDiscretizationFV(DiscretizationParametersBase):
    ncol = UnsignedInteger(default=100)
    npar = UnsignedInteger(default=5)

    par_geom = Switch(
        default='SPHERE', 
        valid=['SPHERE', 'CYLINDER', 'SLAB']
    )
    par_disc_type = Switch(
        default='EQUIDISTANT_PAR', 
        valid=['EQUIDISTANT_PAR', 'EQUIVOLUME_PAR', 'USER_DEFINED_PAR']
    )
    par_disc_vector = DependentlySizedRangedList(lb=0, ub=1, dep='par_disc_vector_length')
    
    par_boundary_order = RangedInteger(lb=1, ub=2, default=2)

    use_analytic_jacobian = Bool(default=True)
    reconstruction = Switch(default='WENO', valid=['WENO'])
    
    gs_type = Bool(default=True)
    max_krylov = UnsignedInteger(default=0)
    max_restarts = UnsignedInteger(default=10)
    schur_safety = UnsignedFloat(default=1.0e-8)

    fix_zero_surface_diffusion = Bool(default=False)
    
    _parameters = DiscretizationParametersBase._parameters + [
        'ncol', 'npar', 
        'par_geom', 'par_disc_type', 'par_disc_vector', 'par_boundary_order', 
        'use_analytic_jacobian', 'reconstruction', 
        'gs_type', 'max_krylov', 'max_restarts', 'schur_safety',
        'fix_zero_surface_diffusion',
    ]
    _dimensionality = ['ncol', 'npar']
        
    @property
    def par_disc_vector_length(self):
        return self.npar + 1
class COBYLA(SciPyInterface):
    """Class from scipy for optimization with COBYLA as method for the
    solver.

    This class is a wrapper for the method COBYLA from the optimization
    suite of the scipy interface. It defines the solver options in the local
    variable options as a dictionary and implements the abstract method run for
    running the optimization.
    """
    rhobeg = UnsignedFloat(default=1)
    maxiter = UnsignedInteger(default=1000)
    disp = Bool(default=False)
    catol = UnsignedFloat(default=0.0002)
    _options = ['rhobeg', 'maxiter', 'disp', 'catol']
Exemple #10
0
class UnitReturnParametersGroup(ParametersGroup):
    """Class for defining the unit return parameters for cadet.

    The class defines several parameters for the unit return parameters as
    boolean for cadet. The names are saved as strings in the parameters list.
    Only the WRITE_SOLUTION_OUTLET ans WRITE_SOLUTION_INLET are set True as
    default value. The remaining unit return parameters are set False for
    default value.

    See also
    --------
    ParametersGroup
    """
    write_coordinates = Bool(default=True)
    write_solution_inlet = Bool(default=True)
    write_solution_outlet = Bool(default=True)
    write_solution_bulk = Bool(default=False)
    write_solution_particle = Bool(default=False)
    write_solution_solid = Bool(default=False)
    write_solution_flux = Bool(default=False)
    write_solution_volume = Bool(default=True)
    write_soldot_inlet = Bool(default=False)
    write_soldot_outlet = Bool(default=False)
    write_soldot_bulk = Bool(default=False)
    write_soldot_particle = Bool(default=False)
    write_soldot_solid = Bool(default=False)
    write_soldot_flux = Bool(default=False)
    write_soldot_volume = Bool(default=False)
    write_sens_inlet = Bool(default=False)
    write_sens_outlet = Bool(default=False)
    write_sens_bulk = Bool(default=False)
    write_sens_particle = Bool(default=False)
    write_sens_solid = Bool(default=False)
    write_sens_flux = Bool(default=False)
    write_sens_volume = Bool(default=False)
    write_sensdot_inlet = Bool(default=False)
    write_sensdot_outlet = Bool(default=False)
    write_sensdot_bulk = Bool(default=False)
    write_sensdot_particle = Bool(default=False)
    write_sensdot_solid = Bool(default=False)
    write_sensdot_flux = Bool(default=False)
    write_sensdot_volume = Bool(default=False)
    write_solution_last_unit = Bool(default=False)

    _parameters = [
        'write_coordinates',
        'write_solution_inlet', 'write_solution_outlet', 'write_solution_bulk',
        'write_solution_particle', 'write_solution_solid', 'write_solution_flux',
        'write_solution_volume', 
        'write_soldot_inlet', 'write_soldot_outlet', 'write_soldot_bulk', 
        'write_soldot_particle', 'write_soldot_solid', 'write_soldot_flux', 
        'write_soldot_volume', 
        'write_sens_inlet', 'write_sens_outlet', 'write_sens_bulk', 
        'write_sens_particle', 'write_sens_solid', 'write_sens_flux', 
        'write_sens_volume',
        'write_sensdot_inlet', 'write_sensdot_outlet', 'write_sensdot_bulk',
        'write_sensdot_particle', 'write_sensdot_solid', 'write_sensdot_flux',
        'write_sensdot_volume'
    ]
Exemple #11
0
class SolverBase(metaclass=StructMeta):
    """BaseClass for Solver APIs

    Holds the configuration of the individual solvers and gives an interface for
    calling the run method. The class has to convert the process configuration
    into the APIs configuration format and convert the results back to the
    CADETProcess format.

    Attributes
    ----------
    n_cycles : int
        Number of cycles to be simulated
    n_cycles_min : int
        If simulate_to_stationarity: Minimum number of cycles to be simulated.
    n_cycles_max : int
        If simulate_to_stationarity: Maximum number of cycles to be simulated.
    simulate_to_stationarity : bool
        Simulate until stationarity is reached


    See also
    --------
    Process
    StationarityEvaluator
    """
    n_cycles = UnsignedInteger(default=1)
    evaluate_stationarity = Bool(default=False)
    n_cycles_min = UnsignedInteger(default=3)
    n_cycles_max = UnsignedInteger(default=100)

    def __init__(self, stationarity_evaluator=None):
        self.logger = get_logger('Simulation')

        if stationarity_evaluator is None:
            self._stationarity_evaluator = StationarityEvaluator()
        else:
            self.stationarity_evaluator = stationarity_evaluator
            self.evaluate_stationarity = True

    def simulate(self, process, previous_results=None, **kwargs):
        """Simulate process.

        Depending on the state of evaluate_stationarity, the process is
        simulated until termination criterion is reached.

        Parameters
        ----------
        process : Process
            Process to be simulated
        previous_results : SimulationResults
            Results of previous simulation run for initial conditions.

        Returns
        -------
        results : SimulationResults
            Results the final cycle of the simulation.

        Raises
        ------
        TypeError
            If process is not an instance of Process.

        See also
        --------
        simulate_n_cycles
        simulate_to_stationarity
        run
        """
        if not isinstance(process, Process):
            raise TypeError('Expected Process')

        process.lock = True
        if not self.evaluate_stationarity:
            results = self.simulate_n_cycles(process, self.n_cycles,
                                             previous_results, **kwargs)
        else:
            results = self.simulate_to_stationarity(process, previous_results,
                                                    **kwargs)
        process.lock = False

        return results

    @log_time('Simulation')
    @log_results('Simulation')
    @log_exceptions('Simulation')
    def simulate_n_cycles(self,
                          process,
                          n_cyc,
                          previous_results=None,
                          **kwargs):
        """Simulates process for given number of cycles.

        Parameters
        ----------
        process : Process
            Process to be simulated
        n_cyc : float
            Number of cycles
        previous_results : SimulationResults
            Results of previous simulation run.

        Returns
        -------
        results : SimulationResults
            Results the final cycle of the simulation.

        Raises
        ------
        TypeError
            If process is not an instance of Process.

        See also
        --------
        simulate_n_cycles
        simulate_to_stationarity
        StationarityEvaluator
        run
        """
        if not isinstance(process, Process):
            raise TypeError('Expected Process')

        if previous_results is not None:
            self.set_state_from_results(process, previous_results)
        process._n_cycles = n_cyc

        return self.run(process, **kwargs)

    @log_time('Simulation')
    @log_results('Simulation')
    @log_exceptions('Simulation')
    def simulate_to_stationarity(self,
                                 process,
                                 previous_results=None,
                                 **kwargs):
        """Simulate process until stationarity is reached.

        Parameters
        ----------
        process : Process
            Process to be simulated
        previous_results : SimulationResults
            Results of previous simulation run.

        Returns
        -------
        results : SimulationResults
            Results the final cycle of the simulation.

        Raises
        ------
        TypeError
            If process is not an instance of Process.

        See also
        --------
        simulate
        run
        StationarityEvaluator
        """
        if not isinstance(process, Process):
            raise TypeError('Expected Process')

        if previous_results is not None:
            self.set_state_from_results(process, previous_results)

        # Simulate minimum number of cycles
        n_cyc = self.n_cycles_min
        process._n_cycles = n_cyc
        results = self.run(process, **kwargs)
        process._n_cycles = 1

        # Simulate until stataionarity is reached.
        while True:
            n_cyc += 1
            self.set_state_from_results(process, results)

            results_cycle = self.run(process, **kwargs)

            if n_cyc >= self.n_cycles_max:
                self.logger.warning("Exceeded maximum number of cycles")
                break

            stationarity = False
            for chrom_old, chrom_new in zip(results.chromatograms,
                                            results_cycle.chromatograms):
                stationarity = self.stationarity_evaluator.assert_stationarity(
                    chrom_old, chrom_new)

            results.update(results_cycle)

            if stationarity:
                break

        return results

    def set_state_from_results(self, process, results):
        process.system_state = results.system_state['state']
        process.system_state_derivative = results.system_state[
            'state_derivative']
        return process

    @abstractmethod
    def run(process, **kwargs):
        """Abstract Method for running a simulation.

        Parameters
        ----------
        process : Process
            Process to be simulated.

        Returns
        -------
        results : SimulationResults
            Simulation results including process and solver configuration.

        Raises
        ------
        TypeError
            If process is not an instance of Process
        CADETProcessError
            If simulation doesn't terminate successfully
        """
        return

    @property
    def stationarity_evaluator(self):
        """Returns the stationarity evaluator.

        Returns
        ----------
        stationarity_evaluator : StationarityEvaluator
            Evaluator for cyclic stationarity.
        """
        return self._stationarity_evaluator

    @stationarity_evaluator.setter
    def stationarity_evaluator(self, stationarity_evaluator):
        if not isinstance(stationarity_evaluator, StationarityEvaluator):
            raise CADETProcessError('Expected StationarityEvaluator')
        self._stationarity_evaluator = stationarity_evaluator
class BindingBaseClass(metaclass=StructMeta):
    """Abstract base class for parameters of binding models.

    Attributes
    ----------
    n_comp : UnsignedInteger
        number of components.
    parameters : dict
        dict with parameter values.
    name : String
        name of the binding model.
    """
    name = String()
    is_kinetic = Bool(default=True)
    n_states = Integer(lb=1, ub=1, default=1)

    def __init__(self, component_system, name=None):
        self._parameter_names = ['is_kinetic']
        self._parameters = {
            param: getattr(self, param)
            for param in self._parameter_names
        }

        self.component_system = component_system
        self.name = name

    @property
    def model(self):
        return self.__class__.__name__

    @property
    def component_system(self):
        return self._component_system

    @component_system.setter
    def component_system(self, component_system):
        if not isinstance(component_system, ComponentSystem):
            raise TypeError('')
        self._component_system = component_system

    @property
    def n_comp(self):
        return self.component_system.n_comp

    @property
    def parameters(self):
        """dict: Dictionary with parameter values.
        """
        return self._parameters

    @parameters.setter
    def parameters(self, parameters):
        for param, value in parameters.items():
            if param not in self._parameters:
                raise CADETProcessError('Not a valid parameter')
            setattr(self, param, value)

    def __repr__(self):
        return '{}(n_comp={}, name=\'{}\')'.format(self.__class__.__name__,
                                                   self.n_comp, self.name)

    def __str__(self):
        return self.name
Exemple #13
0
class StationarityEvaluator(metaclass=StructMeta):
    """Class for checking two succeding chromatograms for stationarity

    Attributes
    ----------

    Notes
    -----
    !!! Implement check_skewness and width deviation
    """
    check_concentration = Bool(default=True)
    max_concentration_deviation = UnsignedFloat(default=0.1)

    check_area = Bool(default=True)
    max_area_deviation = UnsignedFloat(default=1)

    check_height = Bool(default=True)
    max_height_deviation = UnsignedFloat(default=0.1)

    def __init__(self):
        self.logger = log.get_logger('StationarityEvaluator')

    def assert_stationarity(self, conc_old, conc_new):
        """Check Wrapper function for checking stationarity of two succeeding cycles.

        First the module 'stationarity' is imported, then the concentration
        profiles for the current and the last cycles are defined. After this
        all checking function from module 'stafs = FlowSheet(n_comp=2, name=flow_sheet_name)
        tionarity' are called.

        Parameters
        ----------
        conc_old : TimeSignal
            Concentration profile of previous cycle
        conc_new : TimeSignal
            Concentration profile of current cycle
        """
        if not isinstance(conc_old, TimeSignal):
            raise TypeError('Expcected TimeSignal')
        if not isinstance(conc_new, TimeSignal):
            raise TypeError('Expcected TimeSignal')

        criteria = {}
        if self.check_concentration:
            criterion, value = self.check_concentration_deviation(
                conc_old, conc_new)
            criteria['concentration_deviation'] = {
                'status': criterion,
                'value': value
            }
        if self.check_area:
            criterion, value = self.check_area_deviation(conc_old, conc_new)
            criteria['area_deviation'] = {'status': criterion, 'value': value}
        if self.check_height:
            criterion, value = self.check_height_deviation(conc_old, conc_new)
            criteria['height_deviation'] = {
                'status': criterion,
                'value': value
            }

        self.logger.debug('Stationrity criteria: {}'.format(criteria))

        if all([crit['status'] for crit in criteria.values()]):
            return True

        return False

    def concentration_deviation(self, conc_old, conc_new):
        """Calculate the concentration profile deviation of two succeeding cycles.

        Parameters
        ----------
        conc_old : TimeSignal
            Concentration profile of previous cycle
        conc_new : TimeSignal
            Concentration profile of current cycle

        Returns
        -------
        concentration_deviation : np.array
            Concentration difference of two succeding cycles.
        """
        return np.max(abs(conc_new.signal - conc_old.signal), axis=0)

    def check_concentration_deviation(self, conc_old, conc_new):
        """Check if deviation in concentration profiles is smaller than eps

        Parameters
        ----------
        conc_old : TimeSignal
            Concentration profile of previous cycle
        conc_new : TimeSignal
            Concentration profile of current cycle

        Returns
        -------
        bool
            True, if concentration deviation smaller than eps, False otherwise.
            False
        """
        conc_dev = self.concentration_deviation(conc_old, conc_new)

        if np.any(conc_dev > self.max_concentration_deviation):
            criterion = False
        else:
            criterion = True

        return criterion, np.max(conc_dev)

    def area_deviation(self, conc_old, conc_new):
        """Calculate the area deviation of two succeeding cycles.

        conc_old : TimeSignal
            Concentration profile of previous cycle
        conc_new : TimeSignal
            Concentration profile of current cycle

        Returns
        -------
        area_deviation : np.array
            Area deviation of two succeding cycles.
        """
        area_old = simps(conc_old.signal, conc_old.time, axis=0)
        area_new = simps(conc_new.signal, conc_new.time, axis=0)

        return abs(area_old - area_new)

    def check_area_deviation(self, conc_old, conc_new, eps=1):
        """Check if deviation in concentration profiles is smaller than eps

        Parameters
        ----------
        conc_old : TimeSignal
            Concentration profile of previous cycle
        conc_new : TimeSignal
            Concentration profile of current cycle

        Returns
        -------
        bool
            True, if area deviation is smaller than eps, False otherwise.
        """
        area_dev = self.area_deviation(conc_old, conc_new)

        if np.any(area_dev > self.max_area_deviation):
            criterion = False
        else:
            criterion = True

        return criterion, area_dev

    def height_deviation(self, conc_old, conc_new):
        """Calculate the height deviation of two succeeding cycles.

        conc_old : TimeSignal
            Concentration profile of previous cycle
        conc_new : TimeSignal
            Concentration profile of current cycle

        Returns
        -------
        height_deviation : np.array
            Height deviation of two succeding cycles.
        """
        height_old = np.amax(conc_old.signal, 0)
        height_new = np.amax(conc_new.signal, 0)

        return abs(height_old - height_new)

    def check_height_deviation(self, conc_old, conc_new):
        """Check if deviation in peak heigth is smaller than eps.

        Parameters
        ----------
        conc_old : TimeSignal
            Concentration profile of previous cycle
        conc_new : TimeSignal
            Concentration profile of current cycle

        Returns
        -------
        bool
            True, if height deviation is smaller than eps, False otherwise.
        """
        abs_height_deviation = self.height_deviation(conc_old, conc_new)

        if np.any(abs_height_deviation > self.max_height_deviation):
            criterion = False
        else:
            criterion = True

        return criterion, abs_height_deviation