Beispiel #1
0
def initialize(state: State) -> State:
    """Initialize a simulation state."""
    for m in state.config.modules:
        with validation_context(f'{m.name} (initialization)'):
            state = m.initialize(state)

    # run validation after all initialization is done otherwise validation
    # could fail on a module's private state before it can initialize itself
    with validation_context('global initialization'):
        attr.validate(state)
    return state
Beispiel #2
0
    def create(cls, config: 'SimulationConfig'):
        """Generate a new state object from a config."""
        shape = (
            config.getint('simulation', 'nz'),
            config.getint('simulation', 'ny'),
            config.getint('simulation', 'nx'),
        )
        spacing = (
            config.getfloat('simulation', 'dz'),
            config.getfloat('simulation', 'dy'),
            config.getfloat('simulation', 'dx'),
        )
        grid = RectangularGrid.construct_uniform(shape, spacing)
        state = State(time=0.0, grid=grid, config=config)

        for module in state.config.modules:
            if hasattr(state, module.name):
                # prevent modules from overriding existing class attributes
                raise ValueError(
                    f'The name "{module.name}" is a reserved token.')

            with validation_context(f'{module.name} (construction)'):
                state._extra[module.name] = module.StateClass(
                    global_state=state)
                module.construct(state)

        return state
Beispiel #3
0
def advance(state: State, target_time: float) -> Iterator[State]:
    """Advance a simulation to the given target time."""
    initial_time = state.time

    @dataclass(order=True)
    class ModuleUpdateEvent:
        event_time: float
        previous_update: float
        module: ModuleModel = field(compare=False)

    # Create and fill a queue of modules to run. This allows for modules to
    # operate on disparate time scales. Modules which do not have a time step
    # set will not be run.
    queue: PriorityQueue[ModuleUpdateEvent] = PriorityQueue()
    for module in state.config.modules:
        if module.time_step is not None and module.time_step > 0:
            queue.put(
                ModuleUpdateEvent(event_time=initial_time,
                                  previous_update=initial_time,
                                  module=module))

    # run the simulation until we meet or surpass the desired time
    # while-loop conditional is on previous time so that all pending
    # modules are run on final iteration
    previous_time: float = initial_time
    while previous_time < target_time and not queue.empty():
        # fill a list with update events that are concurrent, and randomize their order
        concurrent_update_events = [queue.get()]
        event_time = concurrent_update_events[0].event_time
        while not queue.empty():
            update_event = queue.get()
            if update_event.event_time == event_time:
                concurrent_update_events.append(update_event)
            else:
                queue.put(update_event)
                break
        rg.shuffle(concurrent_update_events)

        for update_event in concurrent_update_events:
            m: ModuleModel = update_event.module
            previous_time = update_event.previous_update
            state.time = update_event.event_time

            with validation_context(m.name):
                state = m.advance(state, previous_time)
                attr.validate(state)

            # reinsert module with updated time
            queue.put(
                ModuleUpdateEvent(event_time=state.time + m.time_step,
                                  previous_update=state.time,
                                  module=m))
        yield state
    def create(cls, config: 'SimulationConfig'):
        """Generate a new state object from a config."""
        voxel_volume = config.getfloat('simulation', 'voxel_volume')
        lung_tissue = get_geometry_file(
            config.get('simulation', 'geometry_path'))

        # python type checker isn't enough to understand this
        assert len(lung_tissue.shape) == 3
        # noinspection PyTypeChecker
        shape: Tuple[int, int, int] = lung_tissue.shape

        space_volume = voxel_volume * np.product(shape)

        spacing = (
            config.getfloat('simulation', 'dz'),
            config.getfloat('simulation', 'dy'),
            config.getfloat('simulation', 'dx'),
        )
        grid = RectangularGrid.construct_uniform(shape, spacing)
        state = State(
            time=0.0,
            grid=grid,
            config=config,
            lung_tissue=lung_tissue,
            voxel_volume=voxel_volume,
            space_volume=space_volume,
        )

        for module in state.config.modules:
            if hasattr(state, module.name):
                # prevent modules from overriding existing class attributes
                raise ValueError(
                    f'The name "{module.name}" is a reserved token.')

            with validation_context(f'{module.name} (construction)'):
                state._extra[module.name] = module.StateClass(
                    global_state=state)
                module.construct(state)

        return state
Beispiel #5
0
def finalize(state: State) -> State:
    for m in state.config.modules:
        with validation_context(m.name):
            state = m.finalize(state)

    return state