Exemplo n.º 1
0
    def __init__(
        self,
        workdir,
        fmu_path,
        inp,
        known,
        est,
        ideal,
        lp_n=None,
        lp_len=None,
        lp_frame=None,
        vp=None,
        ic_param=None,
        methods=("MODESTGA", "PS"),
        ga_opts={},
        ps_opts={},
        scipy_opts={},
        modestga_opts={},
        ftype="RMSE",
        default_log=True,
        logfile="modestpy.log",
    ):

        # Default logging configuration?
        if default_log:
            config_logger(filename=logfile, level="WARNING")

        self.logger = logging.getLogger(type(self).__name__)

        # Sanity checks
        assert inp.index.equals(
            ideal.index), "inp and ideal indexes are not matching"

        init, lo, hi = 0, 1, 2  # Init. value, lower bound, upper bound indices
        for v in est:
            assert (est[v][init] >= est[v][lo]) and (
                est[v][init] <=
                est[v][hi]), "Initial value out of limits ({})".format(v)

        # Input data
        self.workdir = workdir
        self.fmu_path = fmu_path
        self.inp = inp
        self.known = known
        self.est = est
        self.ideal = ideal
        self.methods = methods
        self.ftype = ftype

        # Results placeholders
        self.best_per_run = pd.DataFrame()
        self.final = pd.DataFrame()

        # Estimation options
        # GA options
        self.GA_OPTS = {
            "maxiter": 50,
            "pop_size": max((4 * len(est.keys()), 20)),
            "tol": 1e-6,
            "mut": 0.10,
            "mut_inc": 0.33,
            "uniformity": 0.5,
            "look_back": 50,
            "lhs": False,
            "ftype": ftype,
        }  # Default

        # Default
        self.GA_OPTS["trm_size"] = max(self.GA_OPTS["pop_size"] // 6, 2)
        # User options
        self.GA_OPTS = self._update_opts(self.GA_OPTS, ga_opts, "GA_LEGACY")

        # PS options
        self.PS_OPTS = {
            "maxiter": 500,
            "rel_step": 0.02,
            "tol": 1e-11,
            "try_lim": 1000,
            "ftype": ftype,
        }  # Default

        # User options
        self.PS_OPTS = self._update_opts(self.PS_OPTS, ps_opts, "PS")

        # SCIPY options
        self.SCIPY_OPTS = {
            "solver": "L-BFGS-B",
            "options": {
                "disp": True,
                "iprint": 2,
                "maxiter": 150,
                "full_output": True
            },
            "ftype": ftype,
        }  # Default

        # User options
        self.SCIPY_OPTS = self._update_opts(self.SCIPY_OPTS, scipy_opts,
                                            "SCIPY")

        # MODESTGA options
        self.MODESTGA_OPTS = {
            "workers": 3,  # CPU cores to use
            "generations": 50,  # Max. number of generations
            "pop_size": 30,  # Population size
            "mut_rate": 0.01,  # Mutation rate
            "trm_size": 3,  # Tournament size
            "tol": 1e-3,  # Solution tolerance
            "inertia": 100,  # Max. number of non-improving generations
            "ftype": ftype,
        }  # Default

        # User options
        self.MODESTGA_OPTS = self._update_opts(self.MODESTGA_OPTS,
                                               modestga_opts, "MODESTGA")

        # Method dictionary
        self.method_dict = {
            "MODESTGA": (MODESTGA, self.MODESTGA_OPTS),
            "GA_LEGACY": (GA, self.GA_OPTS),
            "PS": (PS, self.PS_OPTS),
            "SCIPY": (SCIPY, self.SCIPY_OPTS),
        }  # Key -> method name, value -> (method class, method options)

        # List of learning periods (tuples with start, stop)
        self.lp = self._select_lp(lp_n, lp_len, lp_frame)

        # Validation period (a tuple with start, stop)
        if vp is not None:
            self.vp = vp
        else:
            self.vp = (ideal.index[0], ideal.index[-1])

        # Initial condition parameters
        # Take first value from time series from 'ideal' column
        self.ic_param = ic_param  # dict (par_name: ideal_column_name)
Exemplo n.º 2
0
#!/usr/bin/env python
from modestpy.test import run
from modestpy.loginit import config_logger

if __name__ == "__main__":
    config_logger(filename='unit_tests.log', level='DEBUG')
    run.tests()
Exemplo n.º 3
0
        random.seed(1)
        np.random.seed(1)
        ga = GA(
            self.fmu_path,
            self.inp,
            self.known,
            self.est,
            self.ideal,
            maxiter=self.gen,
            lhs=True,
        )
        indiv = ga.pop.individuals
        par2 = list()
        for i in indiv:
            par2.append(i.get_estimates(as_dict=True))

        for d1, d2 in zip(par1, par2):
            self.assertDictEqual(d1, d2)


def suite():
    suite = unittest.TestSuite()
    suite.addTest(TestGA("test_ga"))
    suite.addTest(TestGA("test_init_pop"))
    return suite


if __name__ == "__main__":
    config_logger(filename="unit_tests.log", level="DEBUG")
    unittest.main()
Exemplo n.º 4
0
    def __init__(self,
                 workdir,
                 fmu_path,
                 inp,
                 known,
                 est,
                 ideal,
                 lp_n=None,
                 lp_len=None,
                 lp_frame=None,
                 vp=None,
                 ic_param=None,
                 methods=('MODESTGA', 'PS'),
                 ga_opts={},
                 ps_opts={},
                 scipy_opts={},
                 modestga_opts={},
                 ftype='RMSE',
                 default_log=True,
                 logfile='modestpy.log'):

        # Default logging configuration?
        if default_log:
            config_logger(filename=logfile, level='WARNING')

        self.logger = logging.getLogger(type(self).__name__)

        # Sanity checks
        assert inp.index.equals(ideal.index), \
            'inp and ideal indexes are not matching'

        init, lo, hi = 0, 1, 2  # Init. value, lower bound, upper bound indices
        for v in est:
            assert (est[v][init] >= est[v][lo])  \
                and (est[v][init] <= est[v][hi]), \
                'Initial value out of limits ({})'.format(v)

        # Input data
        self.workdir = workdir
        self.fmu_path = fmu_path
        self.inp = inp
        self.known = known
        self.est = est
        self.ideal = ideal
        self.methods = methods
        self.ftype = ftype

        # Results placeholders
        self.best_per_run = pd.DataFrame()
        self.final = pd.DataFrame()

        # Estimation options
        # GA options
        self.GA_OPTS = {
            'maxiter': 50,
            'pop_size': max((4 * len(est.keys()), 20)),
            'tol': 1e-6,
            'mut': 0.10,
            'mut_inc': 0.33,
            'uniformity': 0.5,
            'look_back': 50,
            'lhs': False,
            'ftype': ftype
        }  # Default

        # Default
        self.GA_OPTS['trm_size'] = max(self.GA_OPTS['pop_size'] // 6, 2)
        # User options
        self.GA_OPTS = self._update_opts(self.GA_OPTS, ga_opts, 'GA_LEGACY')

        # PS options
        self.PS_OPTS = {
            'maxiter': 500,
            'rel_step': 0.02,
            'tol': 1e-11,
            'try_lim': 1000,
            'ftype': ftype
        }  # Default

        # User options
        self.PS_OPTS = self._update_opts(self.PS_OPTS, ps_opts, 'PS')

        # SCIPY options
        self.SCIPY_OPTS = {
            'solver': 'L-BFGS-B',
            'options': {
                'disp': True,
                'iprint': 2,
                'maxiter': 150,
                'full_output': True
            },
            'ftype': ftype
        }  # Default

        # User options
        self.SCIPY_OPTS = \
            self._update_opts(self.SCIPY_OPTS, scipy_opts, 'SCIPY')

        # MODESTGA options
        self.MODESTGA_OPTS = {
            'workers': 3,  # CPU cores to use
            'generations': 50,  # Max. number of generations
            'pop_size': 30,  # Population size
            'mut_rate': 0.01,  # Mutation rate
            'trm_size': 3,  # Tournament size
            'tol': 1e-3,  # Solution tolerance
            'inertia': 100,  # Max. number of non-improving generations
            'ftype': ftype
        }  # Default

        # User options
        self.MODESTGA_OPTS = \
            self._update_opts(self.MODESTGA_OPTS, modestga_opts, 'MODESTGA')

        # Method dictionary
        self.method_dict = {
            'MODESTGA': (MODESTGA, self.MODESTGA_OPTS),
            'GA_LEGACY': (GA, self.GA_OPTS),
            'PS': (PS, self.PS_OPTS),
            'SCIPY': (SCIPY, self.SCIPY_OPTS)
        }  # Key -> method name, value -> (method class, method options)

        # List of learning periods (tuples with start, stop)
        self.lp = self._select_lp(lp_n, lp_len, lp_frame)

        # Validation period (a tuple with start, stop)
        if vp is not None:
            self.vp = vp
        else:
            self.vp = (ideal.index[0], ideal.index[-1])

        # Initial condition parameters
        # Take first value from time series from 'ideal' column
        self.ic_param = ic_param  # dict (par_name: ideal_column_name)
Exemplo n.º 5
0
    def __init__(self,
                 workdir,
                 fmu_path,
                 inp,
                 known,
                 est,
                 ideal,
                 lp_n=None,
                 lp_len=None,
                 lp_frame=None,
                 vp=None,
                 ic_param=None,
                 methods=('GA', 'PS'),
                 ga_opts={},
                 ps_opts={},
                 scipy_opts={},
                 fmi_opts={},
                 ftype='RMSE',
                 seed=None,
                 default_log=True,
                 logfile='modestpy.log'):
        """
        Index in DataFrames ``inp`` and ``ideal`` must be named 'time'
        and given in seconds. The index name assertion check is
        implemented to avoid situations in which a user reads DataFrame
        from a csv and forgets to use ``DataFrame.set_index(column_name)``
        (it happens quite often...). TODO: Check index name assertion.

        Currently available estimation methods:
            - GA    - genetic algorithm
            - PS    - pattern search (Hooke-Jeeves)
            - SCIPY - interface to algorithms available through
                      scipy.optimize.minimize()

        Parameters:
        -----------
        workdir: str
            Output directory, must exist
        fmu_path: str
            Absolute path to the FMU
        inp: pandas.DataFrame
            Input data, index given in seconds and named ``time``
        known: dict(str: float)
            Dictionary with known parameters (``parameter_name: value``)
        est: dict(str: tuple(float, float, float))
            Dictionary defining estimated parameters,
            (``par_name: (guess value, lo limit, hi limit)``)
        ideal: pandas.DataFrame
            Ideal solution (usually measurements),
            index in seconds and named ``time``
        lp_n: int or None
            Number of learning periods, one if ``None``
        lp_len: float or None
            Length of a single learning period, entire ``lp_frame`` if ``None``
        lp_frame: tuple of floats or None
            Learning period time frame, entire data set if ``None``
        vp: tuple(float, float) or None
            Validation period, entire data set if ``None``
        ic_param: dict(str, str) or None
            Mapping between model parameters used for IC and variables from
            ``ideal``
        methods: tuple(str, str)
            List of methods to be used in the pipeline
        ga_opts: dict
            Genetic algorithm options
        ps_opts: dict
            Pattern search options
        scipy_opts: dict
            SciPy solver options
        fmi_opts: dict
            Additional options to be passed to the FMI model
            (e.g. solver tolerance)
        ftype: string
            Cost function type. Currently 'NRMSE' (advised for multi-objective
            estimation) or 'RMSE'.
        seed: None or int
            Random number seed. If None, current time or OS specific
            randomness is used.
        default_log: bool
            If true, use default logging settings. Use false if you want to
            use own logging.
        logfile: str
            If default_log=True, this argument can be used to specify the log
            file name
        """
        # Default logging configuration?
        if default_log:
            config_logger(filename=logfile, level='DEBUG')

        self.logger = logging.getLogger(type(self).__name__)

        # Sanity checks
        assert inp.index.equals(ideal.index), \
            'inp and ideal indexes are not matching'

        init, lo, hi = 0, 1, 2  # Init. value, lower bound, upper bound indices
        for v in est:
            assert (est[v][init] >= est[v][lo])  \
                and (est[v][init] <= est[v][hi]), \
                'Initial value out of limits ({})'.format(v)

        # Random seed
        if seed is not None:
            self.logger.info('Setting random seed: {}'.format(seed))
            random.seed(seed)
            np.random.seed(seed)  # Important for other libraries, like pyDOE

        # Input data
        self.workdir = workdir
        self.fmu_path = fmu_path
        self.inp = inp
        self.known = known
        self.est = est
        self.ideal = ideal
        self.methods = methods
        self.ftype = ftype

        # Results placeholders
        self.best_per_run = pd.DataFrame()
        self.final = pd.DataFrame()

        # Estimation options
        # GA options
        self.GA_OPTS = {
            'maxiter': 50,
            'pop_size': max((4 * len(est.keys()), 20)),
            'tol': 1e-6,
            'mut': 0.10,
            'mut_inc': 0.33,
            'uniformity': 0.5,
            'look_back': 50,
            'lhs': False,
            'ftype': ftype,
            'fmi_opts': fmi_opts
        }  # Default

        # Default
        self.GA_OPTS['trm_size'] = max(self.GA_OPTS['pop_size'] // 6, 2)
        # User options
        self.GA_OPTS = self._update_opts(self.GA_OPTS, ga_opts, 'GA')

        # PS options
        self.PS_OPTS = {
            'maxiter': 500,
            'rel_step': 0.02,
            'tol': 1e-11,
            'try_lim': 1000,
            'ftype': ftype,
            'fmi_opts': fmi_opts
        }  # Default

        # User options
        self.PS_OPTS = self._update_opts(self.PS_OPTS, ps_opts, 'PS')

        # SCIPY options
        self.SCIPY_OPTS = {
            'solver': 'L-BFGS-B',
            'options': {
                'disp': True,
                'iprint': 2,
                'maxiter': 150,
                'full_output': True
            },
            'ftype': ftype,
            'fmi_opts': fmi_opts
        }  # Default

        # User options
        self.SCIPY_OPTS = \
            self._update_opts(self.SCIPY_OPTS, scipy_opts, 'SCIPY')

        # Method dictionary
        self.method_dict = {
            'GA': (GA, self.GA_OPTS),
            'PS': (PS, self.PS_OPTS),
            'SCIPY': (SCIPY, self.SCIPY_OPTS)
        }  # Key -> method name, value -> (method class, method options)

        # List of learning periods (tuples with start, stop)
        self.lp = self._select_lp(lp_n, lp_len, lp_frame)

        # Validation period (a tuple with start, stop)
        if vp is not None:
            self.vp = vp
        else:
            self.vp = (ideal.index[0], ideal.index[-1])

        # Initial condition parameters
        # Take first value from time series from 'ideal' column
        self.ic_param = ic_param  # dict (par_name: ideal_column_name)
Exemplo n.º 6
0
This code is licensed under BSD 2-clause license.
See LICENSE file in the project root for license terms.
"""
import json
import os
import pandas as pd
from modestpy import Estimation
from modestpy.utilities.sysarch import get_sys_arch
from modestpy.loginit import config_logger

if __name__ == "__main__":
    """
    This file is supposed to be run from the root directory.
    Otherwise the paths have to be corrected.
    """
    config_logger(filename='simple.log', level='DEBUG')

    # DATA PREPARATION ==============================================
    # Resources
    platform = get_sys_arch()
    assert platform, 'Unsupported platform type!'
    fmu_file = 'Simple2R1C_ic_' + platform + '.fmu'

    fmu_path = os.path.join('examples', 'simple', 'resources', fmu_file)
    inp_path = os.path.join('examples', 'simple', 'resources', 'inputs.csv')
    ideal_path = os.path.join('examples', 'simple', 'resources', 'result.csv')
    est_path = os.path.join('examples', 'simple', 'resources', 'est.json')
    known_path = os.path.join('examples', 'simple', 'resources', 'known.json')

    # Working directory
    workdir = os.path.join('examples', 'simple', 'workdir')
Exemplo n.º 7
0
"""
import json
import os

import pandas as pd

from modestpy import Estimation
from modestpy.loginit import config_logger
from modestpy.utilities.sysarch import get_sys_arch

if __name__ == "__main__":
    """
    This file is supposed to be run from the root directory.
    Otherwise the paths have to be corrected.
    """
    config_logger(filename="simple.log", level="DEBUG")

    # DATA PREPARATION ==============================================
    # Resources
    platform = get_sys_arch()
    assert platform, "Unsupported platform type!"
    fmu_file = "Simple2R1C_ic_" + platform + ".fmu"

    fmu_path = os.path.join("examples", "simple", "resources", fmu_file)
    inp_path = os.path.join("examples", "simple", "resources", "inputs.csv")
    ideal_path = os.path.join("examples", "simple", "resources", "result.csv")
    est_path = os.path.join("examples", "simple", "resources", "est.json")
    known_path = os.path.join("examples", "simple", "resources", "known.json")

    # Working directory
    workdir = os.path.join("examples", "simple", "workdir")