예제 #1
0
def load_balancer() -> None:
    """A proxy which divides many calls over few instances.

    Put this component between a driver and a set of models, or between
    a macro model and a set of micro models. It will let the driver or
    macro-model submit as many calls as it wants, and divide them over
    the available (micro)model instances in a round-robin fashion.

    Assumes a fixed number of micro-model instances.

    Ports:
        front_in: Input for calls, connect to driver/macro-model O_I.
        back_out: Output to workers, connect to F_INIT of instances that
                do the work.
        back_in: Input for results, connect to O_F of instances that do
                the work.
        front_out: Output back to driver/macro-model S.
    """
    instance = Instance({
        Operator.F_INIT: ['front_in[]'],
        Operator.O_I: ['back_out[]'],
        Operator.S: ['back_in[]'],
        Operator.O_F: ['front_out[]']
    })

    while instance.reuse_instance(False):
        # F_INIT
        started = 0  # number started and index of next to start
        done = 0  # number done and index of next to return

        num_calls = instance.get_port_length('front_in')
        num_workers = instance.get_port_length('back_out')

        instance.set_port_length('front_out', num_calls)
        while done < num_calls:
            while started - done < num_workers and started < num_calls:
                msg = instance.receive_with_settings('front_in', started)
                instance.send('back_out', msg, started % num_workers)
                started += 1
            msg = instance.receive_with_settings('back_in', done % num_workers)
            instance.send('front_out', msg, done)
            done += 1
예제 #2
0
def qmc_driver() -> None:
    """A driver for quasi-Monte Carlo Uncertainty Quantification.

    This component attaches to a collection of model instances, and
    feeds in different parameter values generated using a Sobol
    sequence.
    """
    instance = Instance({
            Operator.O_I: ['parameters_out[]'],
            Operator.S: ['states_in[]']})

    while instance.reuse_instance():
        # F_INIT
        # get and check parameter distributions
        n_samples = instance.get_setting('n_samples', 'int')
        d_min = instance.get_setting('d_min', 'float')
        d_max = instance.get_setting('d_max', 'float')
        k_min = instance.get_setting('k_min', 'float')
        k_max = instance.get_setting('k_max', 'float')

        if d_max < d_min:
            instance.error_shutdown('Invalid settings: d_max < d_min')
            exit(1)
        if k_max < k_min:
            instance.error_shutdown('Invalid settings: k_max < k_min')
            exit(1)

        # generate UQ parameter values
        sobol_sqn = sobol_seq.i4_sobol_generate(2, n_samples)
        ds = d_min + sobol_sqn[:, 0] * (d_max - d_min)
        ks = k_min + sobol_sqn[:, 1] * (k_max - k_min)

        # configure output port
        if not instance.is_resizable('parameters_out'):
            instance.error_shutdown('This component needs a resizable'
                                ' parameters_out port, but it is connected to'
                                ' something that cannot be resized. Maybe try'
                                ' adding a load balancer.')
            exit(1)

        instance.set_port_length('parameters_out', n_samples)

        # run ensemble
        Us = None
        # O_I
        for sample in range(n_samples):
            uq_parameters = Settings({
                'd': ds[sample],
                'k': ks[sample]})
            msg = Message(0.0, None, uq_parameters)
            instance.send('parameters_out', msg, sample)

        # S
        for sample in range(n_samples):
            msg = instance.receive_with_settings('states_in', sample)
            U = np.array(msg.data)
            # accumulate
            if Us is None:
                Us = U
            else:
                Us = np.vstack((Us, U))

        mean = np.mean(Us, axis=0)

        # O_F
        if 'DONTPLOT' not in os.environ:
            from matplotlib import pyplot as plt

            t_max = instance.get_setting('t_max', 'float')
            dt = instance.get_setting('dt', 'float')
            x_max = instance.get_setting('x_max', 'float')
            dx = instance.get_setting('dx', 'float')

            plt.figure()
            plt.imshow(
                    np.log(Us + 1e-20),
                    origin='upper',
                    extent=[
                        -0.5*dx, x_max - 0.5*dx,
                        n_samples-0.5, -0.5],
                    interpolation='none',
                    aspect='auto'
                    )
            cbar = plt.colorbar()
            cbar.set_label('log(Concentration)', rotation=270, labelpad=20)
            plt.xlabel('x')
            plt.ylabel('Sample')
            plt.title('Final states')
            plt.show()
예제 #3
0
def qmc_driver() -> None:
    """A driver for quasi-Monte Carlo Uncertainty Quantification.

    This component attaches to a collection of model instances, and
    feeds in different parameter values generated using a Sobol
    sequence.
    """
    instance = Instance({
        Operator.O_I: ['parameters_out[]'],
        Operator.S: ['states_in[]']
    })

    while instance.reuse_instance():
        # F_INIT
        # get and check parameter distributions
        n_samples = instance.get_setting('n_samples', 'int')
        d_min = instance.get_setting('d_min', 'float')
        d_max = instance.get_setting('d_max', 'float')
        k_min = instance.get_setting('k_min', 'float')
        k_max = instance.get_setting('k_max', 'float')

        if d_max < d_min:
            instance.error_shutdown('Invalid settings: d_max < d_min')
            exit(1)
        if k_max < k_min:
            instance.error_shutdown('Invalid settings: k_max < k_min')
            exit(1)

        # generate UQ parameter values
        sobol_sqn = sobol_seq.i4_sobol_generate(2, n_samples)
        ds = d_min + sobol_sqn[:, 0] * (d_max - d_min)
        ks = k_min + sobol_sqn[:, 1] * (k_max - k_min)

        # configure output port
        if not instance.is_resizable('parameters_out'):
            instance.error_shutdown(
                'This component needs a resizable'
                ' parameters_out port, but it is connected to'
                ' something that cannot be resized. Maybe try'
                ' adding a load balancer.')
            exit(1)

        instance.set_port_length('parameters_out', n_samples)

        # run ensemble
        Us = None
        # O_I
        for sample in range(n_samples):
            uq_parameters = Settings({'d': ds[sample], 'k': ks[sample]})
            msg = Message(0.0, None, uq_parameters)
            instance.send('parameters_out', msg, sample)

        # S
        for sample in range(n_samples):
            msg = instance.receive_with_settings('states_in', sample)
            U = np.array(msg.data)
            # accumulate
            if Us is None:
                Us = U
            else:
                Us = np.vstack((Us, U))

        mean = np.mean(Us, axis=0)
        plt.figure()
        plt.imshow(np.log(Us + 1e-20))
        plt.show()