Conversation
Various other wip refactoring
Runners are now generic wrt to the state type they accept
nptyping doesn't work with numpy 2
doc tests still fail
You need to be able to report the type of the object you would produce as a factory. So add that to an explicit interface and implement in all factories.
The scalar values like energy and time were not being wrapped in the appropriate number of dimensions and were giving errors when added to the HDF5. Fix this in the reporter and add tests explicitly to exercise this. Adds some more fields to the realistic test to show doing this as well.
There is a problem when running realistic simulations in which you want to save something like energy. The problem is that previously when saving the initial walkers to the HDF5 it would enforce that they also have energy. This is burdensome and not necessary to the application user and would likely cause more problems. So to work around this this change adds an additional option to the `WepyHDF5Reporter` `init_walker_save_fields` which lets you customize this. In default usage it does default to having the same fields as the `save_fields` (what will show up in the trajectory data). But you can then provide only the fields you want, e.g. just positions and box_vectors as most initial states have.
There were too many dimensions on the REVO resampling records and not enough for the NoResampler. Straighten that out.
Use sparse fields, main reps, all atom save freqs, and alt reps in examples to exercise these parts of the interface.
Write down an idea for a general resource allocation system between components that has a start in the ResamplerFactory
move the data folder
- Reworked the records passed around for the resampling and decision records used in the parent tables etc. - Relaxed the requirements in the incoming records to be wrapped in so many layers. HDF5 now does this for you to maintain the data compatibility. THe outgoing data works the same.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is a beta release of v2 of wepy which introduces breaking changes to APIs.
For a complete and realistic example for users writing scripts/applications see:
tests/integration/test_openmm/test_realistic.pyThe primary short term goals of these changes were:
REVOResamplerand work mappers for running OpenMM simulationsSome changes in focus were also made. Primarily, that current maintainence effort in core wepy (and this repo) will be on MD simulations and OpenMM in specific.
To that end the generic work mappers have been removed and replaced by purpose built implementations that work very well for OpenMM specifically.
See below for a breakdown of the breaking changes as well as some non-breaking improvements.
A key non-interface improvement is the inclusion of a fairly comprehensive test suite of the core components. This will expand to the analysis modules in the future.
Breaking Changes
General Changes
attrspytest_wepymoduleorchestrationandutil/kv.pymodules removedwepy_tools.wepy_toolswas never intended to follow the same API stability guarantees but is worth mentioning that there are breakages.Simulation Manager
Previously the interfaces between the simulation manager and the components (resamplers, runners, and boundary conditions) were only ambiently defined and difficult to understand for new implementations of components. These interfaces have been completely reified and typed to make them explicit and clear. This includes the
CycleReportDictwhich is handed off to reporters and theRunSegmentDatawhich is produced by runners.Because the simulation manager is effectively a fairly complicated state machine this was made explicit with the introduction of a
ManagerStateMachine, a state transition tableMANAGER_STATE_TRANSITION_TABLE, and associatedManagerStatusandManagerEventtypes. The state machine does not drive actual state transitions but does track them and prevent invalid transitions, which makes it much easier to validate and test.The
Managerclass itself is now explicitly generic over theWalkerStatebeing used in the simulation from a typing perspective.Another pattern was also adopted to make polymorphic configuration/construction of components possible without littering the simulation manager with specific arguments for a component (e.g. resampler) that are only used in certain implementations. The simulation manager now accepts "factories" for runners, resamplers, and work mappers (and will soon accept for boundary conditions, monitors, and reporters). A factory is a function that generates a component conditioned only on a tighter interface inside the simulation manager. Additional arguments must be folded into the factory creation. Factories are simply functions and you are free to implement them however you please but most components provide factories for themselves. The factory objects themselves should be plain data and amenable to simple serialization. The "runtime" objects generated by them are then completely managed by the
Managerobject.Concretely, previously you would construct a stateful
Resamplerand then pass it to theManager:The state of the
resamplerwas then not owned by the manager. Now themanageris responsible for creating and calling hooks during the simulation lifecycle based only upon a static, stateless, factory input. E.g.:Then
manager.resampleris the stateful runtime object.This architecture (and implementation) thus does not have problems with ownership requiring judicious use of
deepcopyforManagerinputs, nowManagerwill always have complete ownership what it needs and will not effect the application calling environment.Runners
The base
Runnerclass is now a generic protocol over theWalkerStateand the segment data.All runners must implement this interface.
Runners are now split up into "runtime" and "static" classes in accordance with the object lifecycles in the simulation manager.
The "runtime" component manages the state of the runs in a simulation while the static version (often a "factory" class) is more decoupled and should contain data only that can be used in serialization, etc.
To make managing state for the runners a state machine was created to aid in implementation:
RunnerStateMachine. This is not required for implementation and only provides checks on explicit opt-in. However the newRunnerprotocol does require astatusproperty to return the correct state as defined inRunnerStatus.The
NoRunnershows a minimal implementation. When transitioning between states viaself.state_machine.send(RunnerEvent.INIT)etc. the state machine will verify that the transition is valid. This also helps in validation that new implementations are correct.The
randomwalk.pymodule was removed.A
MockRunnerand associated classes are defined inrunners/mock.py. This is useful in testing and for a reference implementation.OpenMM Runner
The OpenMM runner was refactored heavily. Firstly it is split up into multiple sub-modules.
OpenMM Simulation State
Previously the
OpenMMStatewas used as aWalkerStatein simulations. This class was a wrapper around theopenmm.Stateobject to avoid unnecessary copies. However, there was a number of issues surrounding the statefulness ofopenmm.Stateobjects and their serializability that was causing subtle issues with threads and processes leading to instabilities in the simulations.In this release the original
OpenMMStatehas now been replaced by both anOpenMMStateWrapperwhich is used to wrap theopenmm.Stateand facilitate Pythonic and simple access to the underlying data and conversion to simpler pure-data representations better suited for serialization etc. The newOpenMMStateis such a pure-data implementation and does not wrap theopenmm.State. There are a variety of methods available for interconverting between these two kinds of objects.In general the workflow would be to:
OpenMMStatefrom arbitrary input data (i.e. thefrom_dwim"do what I mean") (skip this if you already have a State XML file)OpenMMStateWrapperwithOpenMMState.to_state_wrapperOpenMMStateWrapper.statefor feedingopenmm.Stateto anopenmm.Contextsimulationopenmm.Contextin a newOpenMMStateWrapper()OpenMMState.from_state_wrapperto convert to a plain-data representation.The
OpenMMRunneritself handles all of this and only acceptsOpenMMStateobjects, but this pattern is useful for generic data conversion workflows.As generation of
openmm.Stateobjects from scratch has always been a persistent problem, requiring anopenmm.Context, we have provided a novel implementation that serializes theOpenMMStateto the State XML format supported by OpenMM (state_to_xml). This avoids generatingopenmm.Contexts which can sometimes cause stateful corruption within a process which causes issues if the same process then later runs a real simulation. TheOpenMMStateWrapper.from_xmlandserialize_xmlprovide conveniences for interconversion.Note, that all fields on these objects are now
openmm.unit.Quantityobjects rather than there being both quantity and plain numpy versions.OpenMM Logging Reporters
Support for logging of MD simulations directly has been enabled.
Support for logging OpenMM reporters was added directly to the OpenMM simulations themselves (this is distinct) from the wepy reporters, via the
openmm_reporter_factoriesargument to theOpenMMRunnerconstructor. These factories must generate concrete reporters that implement the interface defined foropenmm.app.Simulation. Thewepy/runners/openmm/reporter.pymodule provides some concrete definitions of those interfaces to aid in implementation.By default no OpenMM reporter factories are configured by the
OpenMMRunnerclass. However, for convenience theDEFAULT_OPENMM_REPORTER_FACTORIESprovides some preconfigured logging reporters that can be used. Be aware that there really isn't a "good default" for a wide range of applications so you should consider configuring these yourself for your application.To aid in this the
wepy/runners/openmm/logger.pymodule provides both some base classes for aiding in implementing usefulopenmm.app.Simulationreporters. TheLoggingReporterclass provides a base class that accepts alogging.Loggerobject, a loggingcallbackfunction, and the standardstate_includesfor getting state fields. There is also two more specialized genericLoggingReporterclasses:StepIntervalLoggingReporterwhich configures the interval of MD steps for which it should be called.SamplingTimeIntervalLoggingReporterwhich configures a sampling time interval for which logging callback should be executed.There are three concrete loggers that hardcode a useful logging callback of general interest for MD simulations available to use as well:
HeartBeatLoggingReporterrunning on a step-interval that reports: clock time, elapsed time, sim time (in picoseconds), and sim steps (count).EnergyLoggingReporterrunning on a sampling time interval that reports sim steps and time as well as the kinetic, potential, and total energy of the system.UnitCellLoggingReporterrunning on a sampling time interval that reports sim steps and time as well as the box volume and vectors.Resampling
Decision
For applications there shouldn't be anything needed to update.
The base
Decisionclass has been replaced withBaseDecisionABCwhich is a generic ABC class.The "decision records" which were informally defined dictionaries have now been reified as a protocol
DecisionRecordand a base recordBaseDecisionRecordwhich has the minimal data needed. Each decision record supports conversion to a plain dictionary (to_dict) for compatibility with the reporting interfaces.The
Decision.parentsmethod was removed. Implementations of Decisions must implement this now.The
NoDecisionclass was moved to theno_decision.pymodule.The
clone_merge.pymodule was refactored and additional runtime checks were added on construction.Distances
The
Distanceclass is now a generic protocol wrt theImagetype andWalkerStatetype.In practice now designers of distances should explicitly define their
Imagetype specifically for their distance, rather than relying on dynamic typing. Currently, this is completely unconstrained, but will likely add some constraints to support data output.There is now a
DistanceABCthat has the same default implementations forimageanddistance, only requiring implementation ofimage_distance, if you want the previous behavior ofDistance.The example and mock distance metrics were moved into their own submodules
mock.pyandsimple.py.The
mock.pyis written for the newwepy.runners.mockcomponents.The
simple.pydistance shows a more standalone example that does not integrate to any of the runners.The
randomwalk.pydistances were removed.Resamplers
There is now a core
Resamplergeneric protocol which defines the interface. All class constants, methods, etc. are type annotated.There is now a
ResamplerABCfor inheriting the "standard" settings and methods.Adds an additional check that the max and min walkers do not conflict for
ResamplerABCconstruction.Removed
debug_modeas a constructor argument.The
NoResamplerwas moved to thenoresampler.pysubmodule.REVO
The default optional constructor arguments were refined to not be optional and use explicit input types.
Removed acceptance of
**kwargs.The paralellization via multiprocessing in the
_all_to_all_distancefunction was updated. No APIs were changed but you should be aware of the new behavior. The 'spawn' process start method is now required and hard coded (rather than 'fork' as the default).This should be significantly more robust than in the past in which the Pool would deadlock. For each process only a finite number of calculations will be scheduled to avoid potential memory leaks. Additionally logging is configured in the computed image functions.
As before
n_proc=1will not use multiprocessing at all.Adds the
REVOResamplerFactoryin accord with the changes to simulation component lifecycles are used in theSimManager(see above).Walker
Walkerclass is explicitly a generic class type. This interface is used throughout the code to indicate generic walkers. It is a generic class so that applications can specify particularStatetypes as being contained in aWalker.WalkerStateclass is now a protocol to support independent implementations rather than confusing inheritance.Walkerclass useWalkerStateBox.Walkerclass have been pulled out into standalone functions.Work Mappers
To align with the goal of focused support on OpenMM MD the old work generic
WorkerMapperandTaskMapperhave been removed. These were designed to be generic to runners which made them onerous to configure properly and had numerous robustness problems that would cause simulation crashes. These have been replaced by OpenMM specific work mappers in thework_mapper.openmmsubmodule.The generic
SerialMapperremains as its implementation was fine.In addition the work mappers in general were updated to fit the new manner of component lifecycle in the simulation manager with a focus on factories generated from static configurations to live runtime state managing objects.
A
WorkMapperprotocol interface was defined which specifies exactly what a work mapper must implement.As for the openmm work mappers the primary goal was to provide an integrated approach to GPU device and other platform settings baked into their configuration. The
OpenMMSerialWorkMapperprovides a serial implementation and theOpenMMProcPoolWorkMapperprovides a parallel implementation viamultiprocessing.Pool.The
OpenMMProcPoolWorkMapperis the primary production work mapper that should be used in realistic simulations. Its behavior is similar to the previousWorkerMapperin that worker processes receive serialized inputs to run (rather than relying on shared process memory from forking.) This implementation uses the sameutil.multiprocessinginfrastructure to coordinate handling of logs from runner processes which enables log integration of sub-processes for enhanced monitoring.Currently, performance of the
OpenMMProcPoolWorkMapperis worse than the previousTaskMapperbut has significant improvements in robustness and multiple deadlocking scenarios were eliminated. Only the 'spawn' method is supported as forking resulted in bugs related to OpenMM Context memory problems. Additionally, in the process pool only one simulation segment is run per process to avoid similar memory corruption problems and leaks.Overall the new implementation is much simpler and outsources most coordination to
multiprocessing.Poolrather than using lower level primitives.Over time performance improvements can be made alongside more extensive testing and evaluation of robustness.
HDF5 and Storage
The HDF5 on-disk format was not substantially changed to support backwards compatibility, and because it was unnecessary.
One change is the serialization format for dtypes, which was updated and made more robust according to more modern numpy conventions.
An additional
wepy.storagesubmodule was added as a place to define common interfaces for data that can be use both by the generators of data (runners, resamplers, boundary conditions, etc.) and the consumers (reporters and especially HDF5 reporter).Ultimately, the goal is to have a complete interface for the
WepyHDF5format, but agnostic to the underlying storage technology, in this case HDF5. This will allow for implementation of different storage backends such as xarray, zarr, or TileDB.WepyHDF5Reporter
The interface for this has changed to incorporate an explicit
__init__constructor with only the needed information and NOT the components that are typically used where this information can be pulled from. Use the alternate constructorWepyHDF5Reporter.from_componentsto have a similar ergonomic experience as the old constructor.Non-Breaking Changes
Misc
Types have been added to many function signatures to aid in refactoring and increasing maintainability. However, the project is still not type checked and these should be regarded as comments and not checked types.
Added much more extensive logging to the components.
A simulation monitor interface was defined in
wepy/monitor.py, which will be for observability metrics in e.g. Prometheus.Decision class hierarchy was refactored [...]
Reporters
Reporterprotocol type with explicit interfaces for construction arguments (SimComponentArgs), theCycleReportDict(the data that each reporter receives from the sim manager).reporter.fileand created an explicit ABC base class for inheritance.HDF5
WepyHDF5constructor methods were refactored to be much cleaner and easier to testh5pywere identified and fixed.The test suite is currently only partial but covers the key creation and writing methods.
WepyHDF5Reporter
alt_repstrajectory fields.h5py.Filehandles.Multiprocessing Paralellization
In multiple places the use of process parallel computation was needed. This caused a number of problems when used naively. In response a centralized version of a "process pool" has been provided in the
wepy.util.multiprocessingmodule. This provides a context managerqueue_listener_contextthat implements forwarding of logs from subprocesses in a safe manner that also integrates cleanly with the configured logging settings.The
proc_pool_worker_setupfunction is meant to be used in configuring aPoolso as to do initial logging configuration in workers.For example:
This infrastructure is meant only to work with
spawnprocess start method.For Maintainer's
uvfor project mgmt.wepy.analysis.network_layouts.layout_graph.RGBA_to_hexfunctiontasksandtemplatesdirectoriesintegrationteststests/utilsfolder