def test_asymptomatics_add_less_hazard(): # Set up and upload the test data snapshot = Snapshot.random(nplaces, npeople, nslots) people_place_ids = np.full((npeople, nslots), sentinel_value, dtype=np.uint32) people_place_ids[0][0:4] = [0, 5, 7, 3] people_place_ids[1][0:4] = [1, 5, 6, 4] people_place_ids[2][0:4] = [2, 3, 7, 6] people_flows = np.zeros((npeople, nslots), dtype=np.float32) people_flows[0][0:4] = [0.8, 0.1, 0.06, 0.04] people_flows[1][0:4] = [0.7, 0.18, 0.09, 0.03] people_flows[2][0:4] = [0.6, 0.2, 0.16, 0.04] people_statuses = np.full(npeople, DiseaseStatus.Symptomatic.value, dtype=np.uint32) snapshot.buffers.people_flows[:] = people_flows.flatten() snapshot.buffers.people_place_ids[:] = people_place_ids.flatten() snapshot.buffers.people_statuses[:] = people_statuses snapshot.buffers.place_activities[:] = np.random.randint(4, size=nplaces, dtype=np.uint32) params = Params() params.place_hazard_multipliers = np.ones(5, dtype=np.float32) asymptomatic_multiplier = 0.5 params.individual_hazard_multipliers = np.array( [1.0, asymptomatic_multiplier, 1.0]) snapshot.update_params(params) simulator = Simulator(snapshot, gpu=False) simulator.upload_all(snapshot.buffers) # Run the kernel simulator.step_kernel("people_send_hazards") # Download the result place_hazards = np.zeros(nplaces, dtype=np.uint32) simulator.download("place_hazards", place_hazards) place_counts = np.zeros(nplaces, dtype=np.uint32) simulator.download("place_counts", place_counts) # Assert expected results expected_place_hazards_floats = np.array( [0.8, 0.7, 0.6, 0.24, 0.03, 0.28, 0.13, 0.22], dtype=np.float32) expected_place_hazards = (fixed_factor * expected_place_hazards_floats).astype(np.uint32) assert np.allclose(expected_place_hazards, place_hazards) # Change statuses so all people are asymptomatic people_statuses_asymptomatic = np.full(npeople, DiseaseStatus.Asymptomatic.value, dtype=np.uint32) simulator.upload("people_statuses", people_statuses_asymptomatic) # reset place hazards to zero simulator.step_kernel("places_reset") # run kernel with asymptomatic population simulator.step_kernel("people_send_hazards") # Download the result place_hazards_asymptomatic = np.zeros(nplaces, dtype=np.uint32) simulator.download("place_hazards", place_hazards_asymptomatic) # Assert expected results expected_place_hazards_floats_asymptomatic = expected_place_hazards_floats * asymptomatic_multiplier expected_place_hazards_asymptomatic = ( fixed_factor * expected_place_hazards_floats_asymptomatic).astype( np.uint32) assert np.allclose(expected_place_hazards_asymptomatic, place_hazards_asymptomatic) assert place_hazards_asymptomatic.sum() < place_hazards.sum()
def run(self): # If this is the first data assimilation window, we can just run the model as normal if self.start_day == 0: assert self.current_particle_pop_df is None # Shouldn't have any preivously-created particles # load snapshot snapshot = Snapshot.load_full_snapshot(path=self.snapshot_file) # set params snapshot.update_params(self.params) # Can set the random seed to make it deterministic (None means np will choose one randomly) snapshot.seed_prngs(seed=None) # Create a simulator and upload the snapshot data to the OpenCL device simulator = Simulator(snapshot, opencl_dir=self.opencl_dir, gpu=self.use_gpu) simulator.upload_all(snapshot.buffers) if not self.quiet: # print(f"Running simulation {sim_number + 1}.") print(f"Running simulation") params = Params.fromarray( snapshot.buffers.params ) # XX Why extract Params? Can't just use PARAMS? summary = Summary( snapshot, store_detailed_counts=self.store_detailed_counts, max_time=self.run_length # Total length of the simulation ) # only show progress bar in quiet mode timestep_iterator = range(self.run_length) if self.quiet \ else tqdm(range(self.quiet), desc="Running simulation") iter_count = 0 # Count the total number of iterations # Run for iterations days for _ in timestep_iterator: # Update parameters based on lockdown params.set_lockdown_multiplier(snapshot.lockdown_multipliers, iter_count) simulator.upload("params", params.asarray()) # Step the simulator simulator.step() iter_count += 1 # Update the statuses simulator.download("people_statuses", snapshot.buffers.people_statuses) summary.update(iter_count, snapshot.buffers.people_statuses) if not self.quiet: for i in range(self.run_length): print(f"\nDay {i}") summary.print_counts(i) if not self.quiet: print("\nFinished") # Download the snapshot from OpenCL to host memory # XX This is 'None'. final_state = simulator.download_all(snapshot.buffers) pass else: # Otherwise we need to restart previous models stored in the current_particle_pop_df # XXXX CAN GET OLD MODEL STATES, WITH ALL DISEASE STATUSES, FROM THE DF. TWO ISSUES # 1. But need to work out how to draw these appropriately; can't assume they are each as good as # each other. THIS SHOULD BE OK, surely there's a way to go from the final particles and weights # to the DF of state vectors. Particle ID? Just try it out. # 2. Also: what to do about stochasticity. For a given (global) parameter combination, we will # get quite different results depending on the mode state. - I DON'T THINK THIS IS A PROBLEM. # ABC Commonly used with stochastic models. E.g. https://eprints.lancs.ac.uk/id/eprint/80439/1/mainR1.pdf # raise Exception("Not implemented yet") # Return the current state of the model in a dictionary describing what it is #return {"simulator": simulator} return {"simulator": snapshot}