Beispiel #1
0
def setup_multi_level_advection_diffusion_benchmark(
        nvars, corr_len, max_eval_concurrency=1):
    r"""
    Compute functionals of the transient advection-diffusion (with 1 configure variables which controls the two spatial mesh resolutions and the timestep). An integer increase in the configure variable value will raise the 3 numerical discretiation paramaters by the same integer.

    See :func:`pyapprox_dev.advection_diffusion_wrappers.setup_advection_diffusion_benchmark` for details on function arguments and output.
    """
    from scipy import stats
    from pyapprox.models.wrappers import TimerModelWrapper, PoolModel, \
        WorkTrackingModel
    from pyapprox.models.wrappers import PoolModel
    from pyapprox.variables import IndependentMultivariateRandomVariable
    from pyapprox.benchmarks.benchmarks import Benchmark
    from pyapprox.models.wrappers import MultiLevelWrapper
    univariate_variables = [stats.uniform(-np.sqrt(3), 2*np.sqrt(3))]*nvars
    variable = IndependentMultivariateRandomVariable(univariate_variables)
    final_time, degree = 1.0, 1
    options = {'corr_len': corr_len}
    base_model = AdvectionDiffusionModel(
        final_time, degree, qoi_functional_misc,
        second_order_timestepping=False, options=options)
    multilevel_model = MultiLevelWrapper(
        base_model, base_model.num_config_vars)
    # add wrapper to allow execution times to be captured
    timer_model = TimerModelWrapper(multilevel_model, base_model)
    pool_model = PoolModel(
        timer_model, max_eval_concurrency, base_model=base_model)
    model = WorkTrackingModel(
        pool_model, base_model, multilevel_model.num_config_vars)
    attributes = {'fun': model, 'variable': variable,
                  'multi_level_model': multilevel_model}
    return Benchmark(attributes)
def setup_model(num_vars, max_eval_concurrency):
    corr_len = 1 / 10
    second_order_timestepping = False

    qoi_functional = qoi_functional_misc
    degree = 1
    base_model = AdvectionDiffusionModel(
        num_vars,
        corr_len,
        1.0e-0,
        degree,
        qoi_functional,
        add_work_to_qoi=False,
        boundary_condition_type=None,
        second_order_timestepping=second_order_timestepping)
    timer_model = TimerModelWrapper(base_model, base_model)
    model = PoolModel(timer_model, max_eval_concurrency, base_model=base_model)
    model = WorkTrackingModel(model, model.base_model)
    return model
def setup_advection_diffusion_benchmark(nvars,
                                        corr_len,
                                        max_eval_concurrency=1):
    r"""
    Compute functionals of the following model of transient advection-diffusion

    .. math::

       \frac{\partial u}{\partial t}(x,t,\rv) + \nabla u(x,t,\rv)-\nabla\cdot\left[k(x,\rv) \nabla u(x,t,\rv)\right] &=g(x,t) \qquad (x,t,\rv)\in D\times [0,1]\times\rvdom\\
       \mathcal{B}(x,t,\rv)&=0 \qquad\qquad (x,t,\rv)\in \partial D\times[0,1]\times\rvdom\\
       u(x,t,\rv)&=u_0(x,\rv) \qquad (x,t,\rv)\in D\times\{t=0\}\times\rvdom

    Following [NTWSIAMNA2008]_, [JEGGIJNME2020]_ we set 

    .. math:: g(x,t)=(1.5+\cos(2\pi t))\cos(x_1),

    the initial condition as :math:`u(x,z)=0`, :math:`B(x,t,z)` to be zero dirichlet boundary conditions.

    and we model the diffusivity :math:`k` as a random field represented by the
    Karhunen-Loeve (like) expansion (KLE)

    .. math::

       \log(k(x,\rv)-0.5)=1+\rv_1\left(\frac{\sqrt{\pi L}}{2}\right)^{1/2}+\sum_{k=2}^d \lambda_k\phi(x)\rv_k,

    with

    .. math::

       \lambda_k=\left(\sqrt{\pi L}\right)^{1/2}\exp\left(-\frac{(\lfloor\frac{k}{2}\rfloor\pi L)^2}{4}\right) k>1,  \qquad\qquad  \phi(x)=
       \begin{cases}
       \sin\left(\frac{(\lfloor\frac{k}{2}\rfloor\pi x_1)}{L_p}\right) & k \text{ even}\,,\\
       \cos\left(\frac{(\lfloor\frac{k}{2}\rfloor\pi x_1)}{L_p}\right) & k \text{ odd}\,.
       \end{cases}

    where :math:`L_p=\max(1,2L_c)`, :math:`L=\frac{L_c}{L_p}`.

    Parameters
    ----------
    nvars : integer
        The number of variables of the KLE

    corr_len : float
        The correlation length :math:`L_c` of the covariance kernel

    max_eval_concurrency : integer
        The maximum number of simulations that can be run in parallel. Should be         no more than the maximum number of cores on the computer being used

    Returns
    --------
    benchmark : pya.Benchmark
       Object containing the benchmark attributes
    
    """

    from scipy import stats
    from pyapprox.models.wrappers import TimerModelWrapper, PoolModel, \
        WorkTrackingModel
    from pyapprox.models.wrappers import PoolModel
    from pyapprox.variables import IndependentMultivariateRandomVariable
    from pyapprox.benchmarks.benchmarks import Benchmark
    univariate_variables = [stats.uniform(-np.sqrt(3), 2 * np.sqrt(3))] * nvars
    variable = IndependentMultivariateRandomVariable(univariate_variables)
    final_time, degree = 1.0, 1
    options = {'corr_len': corr_len}
    base_model = AdvectionDiffusionModel(final_time,
                                         degree,
                                         qoi_functional_misc,
                                         second_order_timestepping=False,
                                         options=options)
    # add wrapper to allow execution times to be captured
    timer_model = TimerModelWrapper(base_model, base_model)
    pool_model = PoolModel(timer_model,
                           max_eval_concurrency,
                           base_model=base_model)
    # add wrapper that tracks execution times.
    model = WorkTrackingModel(pool_model, base_model)
    attributes = {'fun': model, 'variable': variable}
    return Benchmark(attributes)
print(worktracking_fun_ensemble.work_tracker(query_fun_ids))

#%%
#As expected there are 5 samples tracked for each model and the median evaluation time of the second function is about twice as large as for the first function.

#%%
#Evaluating functions at multiple samples in parallel
#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#For expensive models it is often useful to be able to evaluate each model concurrently. This can be achieved using :class:`pyapprox.models.wrappers.PoolModel`. Note this function is not intended for use with distributed memory systems, but rather is intended to use all the threads of a personal computer or compute node. See :class:`pyapprox.models.async_model.AsynchronousEvaluationModel` if you are interested in running multiple simulations in parallel on a distributed memory system.
#
#PoolModel cannot be used to wrap WorkTrackingModel. However it can still
#be used with WorkTrackingModel using the sequence of wrappers below.

max_eval_concurrency = 1  # set higher
# clear WorkTracker counters
pool_model = PoolModel(
    timer_fun_ensemble, max_eval_concurrency, assert_omp=False)
worktracking_fun_ensemble.work_tracker.costs = dict()
worktracking_fun_ensemble = WorkTrackingModel(
    pool_model, num_config_vars=1)

# create more samples to notice improvement in wall time
nsamples = 10
samples = pya.generate_independent_random_samples(variable, nsamples)
fun_ids = np.ones(nsamples)
fun_ids[:nsamples//2] = 0
ensemble_samples = np.vstack([samples, fun_ids])

t0 = time.time()
values = worktracking_fun_ensemble(ensemble_samples)
t1 = time.time()
print(f'With {max_eval_concurrency} threads that took {t1-t0} seconds')
def setup_advection_diffusion_source_inversion_benchmark(
        measurement_times=np.array([0.05, 0.15]),
        source_strength=0.5,
        source_width=0.1,
        true_sample=np.array([[0.25, 0.75, 4, 4, 4]]).T,
        noise_stdev=0.4,
        max_eval_concurrency=1):
    r"""
    Compute functionals of the following model of transient diffusion of 
    a contaminant

    .. math::

       \frac{\partial u}{\partial t}(x,t,\rv) + \nabla u(x,t,\rv)-\nabla\cdot\left[k(x,\rv) \nabla u(x,t,\rv)\right] &=g(x,t) \qquad (x,t,\rv)\in D\times [0,1]\times\rvdom\\
       \mathcal{B}(x,t,\rv)&=0 \qquad\qquad (x,t,\rv)\in \partial D\times[0,1]\times\rvdom\\
       u(x,t,\rv)&=u_0(x,\rv) \qquad (x,t,\rv)\in D\times\{t=0\}\times\rvdom

    Following [MNRJCP2006]_, [LMSISC2014]_ we set 

    .. math:: g(x,t)=\frac{s}{2\pi h^2}\exp\left(-\frac{\lvert x-x_\mathrm{src}\rvert^2}{2h^2}\right)

    the initial condition as :math:`u(x,z)=0`, :math:`B(x,t,z)` to be zero Neumann boundary conditions, i.e.

    .. math:: \nabla u\cdot n = 0 \quad\mathrm{on} \quad\partial D

    and we model the diffusivity :math:`k=1` as a constant.

    The quantities of interest are point observations :math:`u(x_l)` 
    taken at :math:`P` points in time :math:`\{t_p\}_{p=1}^P` at :math:`L` 
    locations :math:`\{x_l\}_{l=1}^L`. The final time :math:`T` is the last 
    observation time.

    These functionals can be used to define the posterior distribution 

    .. math::  \pi_{\text{post}}(\rv)=\frac{\pi(\V{y}|\rv)\pi(\rv)}{\int_{\rvdom} \pi(\V{y}|\rv)\pi(\rv)d\rv}

    where the prior is the tensor product of independent and identically 
    distributed uniform variables on :math:`[0,1]` i.e. 
    :math:`\pi(\rv)=1`, and the likelihood is given by

    .. math:: \pi(\V{y}|\rv)=\frac{1}{(2\pi)^{d/2}\sigma}\exp\left(-\frac{1}{2}\frac{(y-f(\rv))^T(y-f(\rv))}{\sigma^2}\right)

    and :math:`y` are noisy observations of the solution `u` at the 9 
    points of a uniform :math:`3\times 3` grid covering the physical domain 
    :math:`D` at successive times :math:`\{t_p\}_{p=1}^P`. Here the noise is indepenent and Normally distrbuted with mean 
    zero and variance :math:`\sigma^2`.

    Parameters
    ----------
    measurement_times : np.ndarray (P)
        The times :math:`\{t_p\}_{p=1}^P` at which measurements of the 
        contaminant concentration are taken

    source_strength : float
        The source strength :math:`s`

    source_width : float
        The source width :math:`h`

    true_sample : np.ndarray (2)
        The true location of the source used to generate the observations
        used in the likelihood function

    noise_stdev : float
        The standard deviation :math:`sigma` of the observational noise

    max_eval_concurrency : integer
        The maximum number of simulations that can be run in parallel. Should 
        be no more than the maximum number of cores on the computer being used

    Returns
    -------
    benchmark : pya.Benchmark
       Object containing the benchmark attributes documented below

    fun : callable

        The quantity of interest :math:`f(w)` with signature

        ``fun(w) -> np.ndarray``

        where ``w`` is a 2D np.ndarray with shape (nvars+3,nsamples) and the
        output is a 2D np.ndarray with shape (nsamples,1). The first ``nvars`` 
        rows of ``w`` are realizations of the random variables. The last 3 rows
        are configuration variables specifying the numerical discretization of 
        the PDE model. Specifically the first and second configuration variables
        specify the levels :math:`l_{x_1}` and :math:`l_{x_2}` which dictate
        the resolution of the FEM mesh in the directions :math:`{x_1}` and 
        :math:`{x_2}` respectively. The number of cells in the :math:`{x_i}` 
        direction is given by :math:`2^{l_{x_i}+2}`. The third configuration 
        variable specifies the level :math:`l_t` of the temporal discretization.
        The number of timesteps satisfies :math:`2^{l_{t}+2}` so the timestep 
        size is and :math:`T/2^{l_{t}+2}`.

    variable : pya.IndependentMultivariateRandomVariable
        Object containing information of the joint density of the inputs z
        which is the tensor product of independent and identically distributed 
        uniform variables on :math:`[0,1]`.

    Examples
    --------
    >>> from pyapprox_dev.benchmarks.benchmarks import setup_benchmark
    >>> benchmark=setup_benchmark('advection-diffusion',nvars=2)
    >>> print(benchmark.keys())
    dict_keys(['fun', 'variable'])

    References
    ----------
    .. [MNRJCP2006] `Youssef M. Marzouk, Habib N. Najm, Larry A. Rahn, Stochastic spectral methods for efficient Bayesian solution of inverse problems, Journal of Computational Physics, Volume 224, Issue 2, 2007, Pages 560-586, <https://doi.org/10.1016/j.jcp.2006.10.010>`_

    .. [LMSISC2014] `Jinglai Li and Youssef M. Marzouk. Adaptive Construction of Surrogates for the Bayesian Solution of Inverse Problems, SIAM Journal on Scientific Computing 2014 36:3, A1163-A1186 <https://doi.org/10.1137/130938189>`_

    Notes
    -----
    The example from [MNRJCP2006]_ can be obtained by setting `s=0.5`, `h=0.1`,
    `measurement_times=np.array([0.05,0.15])` and `noise_stdev=0.1`

    The example from [LMSISC2014]_ can be obtained by setting `s=2`, `h=0.05`,
    `measurement_times=np.array([0.1,0.2])` and `noise_stdev=0.1`
    """

    from scipy import stats
    from pyapprox.models.wrappers import TimerModelWrapper, PoolModel, \
        WorkTrackingModel
    from pyapprox.models.wrappers import PoolModel
    from pyapprox.variables import IndependentMultivariateRandomVariable
    from pyapprox.benchmarks.benchmarks import Benchmark
    univariate_variables = [stats.uniform(0, 1)] * 2
    variable = IndependentMultivariateRandomVariable(univariate_variables)
    final_time, degree = measurement_times.max(), 2
    options = {
        'intermediate_times': measurement_times[:-1],
        'source_strength': source_strength,
        'source_width': source_width
    }
    base_model = AdvectionDiffusionSourceInversionModel(
        final_time,
        degree,
        qoi_functional_source_inversion,
        second_order_timestepping=False,
        options=options)
    # add wrapper to allow execution times to be captured
    timer_model = TimerModelWrapper(base_model, base_model)
    pool_model = PoolModel(timer_model,
                           max_eval_concurrency,
                           base_model=base_model)

    # add wrapper that tracks execution times.
    model = WorkTrackingModel(pool_model, base_model)

    from pyapprox.bayesian_inference.markov_chain_monte_carlo import \
        GaussianLogLike
    if true_sample.shape != (5, 1):
        msg = 'true_sample must be the concatenation of random sample and the '
        msg += 'configure sample'
        raise Exception(msg)
    noiseless_data = model(true_sample)[0, :]
    noise = np.random.normal(0, noise_stdev, (noiseless_data.shape[0]))
    data = noiseless_data + noise
    loglike = GaussianLogLike(model, data, noise_stdev)

    attributes = {'fun': model, 'variable': variable, 'loglike': loglike}
    return Benchmark(attributes)
def setup_advection_diffusion_benchmark(nvars,
                                        corr_len,
                                        max_eval_concurrency=1):
    r"""
    Compute functionals of the following model of transient advection-diffusion (with 3 configure variables which control the two spatial mesh resolutions and the timestep)

    .. math::

       \frac{\partial u}{\partial t}(x,t,\rv) + \nabla u(x,t,\rv)-\nabla\cdot\left[k(x,\rv) \nabla u(x,t,\rv)\right] &=g(x,t) \qquad (x,t,\rv)\in D\times [0,1]\times\rvdom\\
       \mathcal{B}(x,t,\rv)&=0 \qquad\qquad (x,t,\rv)\in \partial D\times[0,1]\times\rvdom\\
       u(x,t,\rv)&=u_0(x,\rv) \qquad (x,t,\rv)\in D\times\{t=0\}\times\rvdom

    Following [NTWSIAMNA2008]_, [JEGGIJNME2020]_ we set 

    .. math:: g(x,t)=(1.5+\cos(2\pi t))\cos(x_1),

    the initial condition as :math:`u(x,z)=0`, :math:`B(x,t,z)` to be zero dirichlet boundary conditions.

    and we model the diffusivity :math:`k` as a random field represented by the
    Karhunen-Loeve (like) expansion (KLE)

    .. math::

       \log(k(x,\rv)-0.5)=1+\rv_1\left(\frac{\sqrt{\pi L}}{2}\right)^{1/2}+\sum_{k=2}^d \lambda_k\phi(x)\rv_k,

    with

    .. math::

       \lambda_k=\left(\sqrt{\pi L}\right)^{1/2}\exp\left(-\frac{(\lfloor\frac{k}{2}\rfloor\pi L)^2}{4}\right) k>1,  \qquad\qquad  \phi(x)=
       \begin{cases}
       \sin\left(\frac{(\lfloor\frac{k}{2}\rfloor\pi x_1)}{L_p}\right) & k \text{ even}\,,\\
       \cos\left(\frac{(\lfloor\frac{k}{2}\rfloor\pi x_1)}{L_p}\right) & k \text{ odd}\,.
       \end{cases}

    where :math:`L_p=\max(1,2L_c)`, :math:`L=\frac{L_c}{L_p}`.

    The quantity of interest :math:`f(z)` is the measurement of the solution at a location :math:`x_k` at the final time :math:`T=1` obtained via the linear functional

    .. math:: f(z)=\int_D u(x,T,z)\frac{1}{2\pi\sigma^2}\exp\left(-\frac{\lVert x-x_k \rVert^2_2}{\sigma^2}\right) dx


    Parameters
    ----------
    nvars : integer
        The number of variables of the KLE

    corr_len : float
        The correlation length :math:`L_c` of the covariance kernel

    max_eval_concurrency : integer
        The maximum number of simulations that can be run in parallel. Should be         no more than the maximum number of cores on the computer being used

    Returns
    -------
    benchmark : pya.Benchmark
       Object containing the benchmark attributes documented below

    fun : callable

        The quantity of interest :math:`f(w)` with signature

        ``fun(w) -> np.ndarray``

        where ``w`` is a 2D np.ndarray with shape (nvars+3,nsamples) and the
        output is a 2D np.ndarray with shape (nsamples,1). The first ``nvars`` 
        rows of ``w`` are realizations of the random variables. The last 3 rows
        are configuration variables specifying the numerical discretization of 
        the PDE model. Specifically the first and second configuration variables
        specify the levels :math:`l_{x_1}` and :math:`l_{x_2}` which dictate
        the resolution of the FEM mesh in the directions :math:`{x_1}` and 
        :math:`{x_2}` respectively. The number of cells in the :math:`{x_i}` 
        direction is given by :math:`2^{l_{x_i}+2}`. The third configuration 
        variable specifies the level :math:`l_t` of the temporal discretization.
        The number of timesteps satisfies :math:`2^{l_{t}+2}` so the timestep 
        size is and :math:`T/2^{l_{t}+2}`.

    variable : pya.IndependentMultivariateRandomVariable
        Object containing information of the joint density of the inputs z
        which is the tensor product of independent and identically distributed 
        uniform variables on :math:`[-\sqrt{3},\sqrt{3}]`.

    Examples
    --------
    >>> from pyapprox_dev.benchmarks.benchmarks import setup_benchmark
    >>> benchmark=setup_benchmark('advection-diffusion',nvars=2)
    >>> print(benchmark.keys())
    dict_keys(['fun', 'variable'])
    """

    from scipy import stats
    from pyapprox.models.wrappers import TimerModelWrapper, PoolModel, \
        WorkTrackingModel
    from pyapprox.models.wrappers import PoolModel
    from pyapprox.variables import IndependentMultivariateRandomVariable
    from pyapprox.benchmarks.benchmarks import Benchmark
    univariate_variables = [stats.uniform(-np.sqrt(3), 2 * np.sqrt(3))] * nvars
    variable = IndependentMultivariateRandomVariable(univariate_variables)
    final_time, degree = 1.0, 1
    options = {'corr_len': corr_len}
    base_model = AdvectionDiffusionModel(
        final_time,
        degree,
        qoi_functional_misc,
        second_order_timestepping=False,
        options=options,
        qoi_functional_grad=qoi_functional_grad_misc)
    # add wrapper to allow execution times to be captured
    timer_model = TimerModelWrapper(base_model, base_model)
    pool_model = PoolModel(timer_model,
                           max_eval_concurrency,
                           base_model=base_model)

    # add wrapper that tracks execution times.
    model = WorkTrackingModel(pool_model, base_model,
                              base_model.num_config_vars)
    attributes = {'fun': model, 'variable': variable}
    return Benchmark(attributes)