def explicit_relay(): """Intermediate component with explicit settings. Sends and receives overlay settings explicitly, rather than having MUSCLE handle them. This just passes all information on. """ instance = Instance({ Operator.F_INIT: ['in[]'], Operator.O_F: ['out[]']}) while instance.reuse_instance(False): # f_init assert instance.get_setting('test2', 'float') == 13.3 assert instance.get_port_length('in') == instance.get_port_length( 'out') msgs = list() for slot in range(instance.get_port_length('in')): msg = instance.receive_with_settings('in', slot) assert msg.data.startswith('testing') assert msg.settings['test2'] == 14.4 msgs.append(msg) assert instance.get_setting('test2') == 13.3 # o_f for slot in range(instance.get_port_length('out')): instance.send('out', msgs[slot], slot)
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
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()
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()