-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PhET-iO instrumentation #83
Comments
Benchmark sim prior to instrumentation: https://phet-dev.colorado.edu/html/blackbody-spectrum/1.0.0-dev.14/phet/blackbody-spectrum_en_phet.html |
… all of the displayed parts, see #83
@arnabp the instrumentation process required a non-trivial refactor for item number 5 on the list in #36 (comment). The relevant changes are in 1dc0c91, could you please review? |
@chrisklus reviewed BGRAndStarDisplay. I put the node's initial layout placement back in BlackbodySpectrumScreenView, everything else looks good. |
@arnabp sounds good, thanks. |
Before instrumenting
whether the user created a parallel circuit), for events that are useful, easy to compute in simulation code and difficult to compute in wrapper code. Or a simulation may need to be configurable in a way that is not already supported by the instrumentation you have already completed. These features should be determined in the PhET-iO design meeting.
Code Review
A high-quality Code Review will make instrumentation easier, promote long term maintainability for the
simulation, and protect the simulation from a volatile API. If the simulation is already in good shape, the review will not take too long. If the simulation is not in good shape, then it needs your help.
Instrumentation
Now that the simulation is in good shape and the PhET-iO design meeting is complete, we are ready to instrument the simulation. Follow the checklist below, and if you have questions you can review Faraday's Law and its PhET-iO instrumentation or reach out to teammates who may have come this way before.
Initial Setup
tandem
s to each screen usingtandem.createTandem(...)
Visit Objects that Should be Instrumented
Consult the PhET-iO design issue to see what features the sim should support. See
https://github.com/phetsims/tandem/tree/master/js/PhetioObject.js for the
supported PhetioObject options. Not every node in the hierarchy must be instrumented, but every leaf is instrumented. For example the
view
is rarely instrumented.tandem
s and otherPhetioObject
options into objects that should be instrumented. Do not instrument objects that are "implementation details" and do not over-instrument.units
inNumberProperty
for example, and should be passed where appropriate.)Creating and Naming Tandems
Well-designed tandem names are important. Once the PhET-iO simulation is published, the API becomes public and therefore difficult to change. Sometimes PhET-iO design meetings can also help come up tandem names. NOTE: "Tandem" is a PhET internal name, publicly to clients the full strings are known as "phetioIDs."
Screen
tandems should end with aScreen
suffix.Property
suffix.model
andview
.Tandem.required
for constructors that already have an options parameter. This default can be helpful for identifying cases where you have neglected to pass a tandem in (becauseTandem.required
will error loudly if validating tandems).createGroupTandem
for arrays or otherwise numbered tandems. See usages for examples.Feature Support
Property
instances to make it possible to get/set a value, so value changes will appear on the data stream and so the item can be stored and restored in save/load.Property
orEmitter
elements by composition, or subclassPhetioObject
.Run phetmarks=>aqua=>Test Sims(Fast Build) with PhET-iO checked. This will help catch any simulations using the component you just instrumented.
tandem: Tandem.required
ortandem: Tandem.optional
to the options accordingly. Here are some conventions to guide this decision:Tandem.required
tandem: Tandem.required
to default options wherever you intend to pass tandem via options.mutate
but not both.phetioPrintMissingTandems
flag if you want to collect a list of all required, optional, and uninstrumented common code classes instead of erroring out on the first missing tandem. Each occurrence is numbered to give a better idea of how many the sim has to do.phetioDocumentation
:phetioDocumentation
that is client facing to start with a capital letter.parameters support tambo but not vibe.
DEFAULT_OPTIONS
or at least be very careful about how it is done, see the concernsmentioned in https://github.com/phetsims/phet-io/issues/1179
Create new IO types
If necessary, create new IO types to support desired feature set. Generally we don't want to be locked in to coupling IO Types to sim types. Instead, we decided that we want the PhET-iO API to be able to vary independently from the sim implementation instead of leaking sim implementation details. Still, for a well-designed simulation, IO Types will often match closely with the sim types. To ensure good IO type inheritance hierarchies follow these principles:
See sloppy TTypes beers-law-lab#213 for more context on prior problems in this area and discussion about it.
The Data Stream
Emitter
instances as appropriate to augment the data stream.Emitters
andProperty
instances naturally emit to a structured data stream and are probably what you need. If you need something more custom, you can callphetioStartEvent
andphetioEndEvent
directly.See https://github.com/phetsims/phet-io/issues/282
Emitter.addListener
instead ofEvents.onStatic
Emitter.emitN
argument, you may specifyVoidIO
for its type, see PressListener.jsphetioEventType: 'user'
for pointer events, keyboard events and UI events(like checkbox toggled, button pressed), and
phetioEventType: 'model'
for model actions/responses. This is easiest to test in the console: colorized wrapper. Model events will be logged in black, and user events will be logged blue. You can also go to the data-stream wrapper to see events in JSON form. If your simulation only leverages existing model types (like Property/Emitter) and UI types (like sun components), then you will not be instrumenting new types.Post Instrumentation and Checks
dispose
d, which unregisters the tandem.dt
values are used instead of Date.now() or other Date functions. This is necessary for reproducible playback via input events. Perhaps tryphet.joist.elapsedTime
.phet.joist.random
, and all doing so after modules are declared (non-statically)? For example, the following methods (and perhaps others) should not be used:Math.random
,_.shuffle
,_.sample
,_.random
.undefined
values are omitted in the state--consider this when determining whether toStateObject should use null or undefined values.http://localhost/phet-io-wrappers/index/?sim={{simulation-name}} and test all the links. To further understand what each wrapper exemplifies, read the description for it in the wrapper index, and launch that wrapper with a sim already completely PhET-iO instrumented like Faraday's Law.
grunt --brands=phet-io
and test the built version by launching build/wrappers/index and testing all the links.?ea&brand=phet-io&phetioStandalone&fuzz
to run with assertions, PhET-iO brand and fuzzing.Support dynamic state
For simulations that have static content (such as a fixed number of objects and properties), instrumentation is complete after you have completed the preceding steps. For simulations that have a dynamic number of objects, such as Circuit Construction Kit circuits or Molecules and Light photons, the containers and elements must be instrumented. This is currently tricky with PhET-iO. Some sims may wish to avoid this entire hassle by pre-allocating all of the instrumented instances. Consider adding flags to indicate whether the objects are "alive" or "in the pool".
Details about how to support dynamic state.
Beer's Law Lab and Charges and Fields demonstrates how this may be done. A container class defines two methods:
clearChildInstances
which empties a container andaddChildInstance
which repopulates a container one element at atime. For example, see ShakerParticlesIO in the beers-law-lab instrumentation.
When state is set, first the container is cleared, then children are created. Child states can be obtained from
toStateObject
and set back with
fromStateObject
, with an additional call tosetValue
in case additional data is supplied, or customcode can be used.
Dispose must be implemented properly on all dynamic instances, or else it will result in stale values in the playback sim.
For example, if a simulation is sending the position of a particle as a property, if the particle position property
hasn't been disposed of, the simulation will try to create a new property with the same id and hence throw an assertion
error because that tandem is already registered.
On January 11, 2017 ControlPoints were not being disposed correctly in Energy-skate-park-basics, causing a mysterious bug
(impossible set state), make sure that children are being disposed correctly before creating them in the downstream sim!
Other tips and tricks for "impossible set state":
can be addressed the same way
Dispose functions must be added to types that are instrumented. But that's only half of the memory management issue. The
other half is revisiting memory management for all instances that don't exist for the lifetime of the sim, and verifying
that tandems are properly cleaned up.
Tips, Tricks, Notes, Misc
phetmarks --> index --> desired wrapper
. Instead you can use phetmarks to launch any individual wrapper. Note that the wrapper index in the build version is at the top level of the build dir (build/phet-io/
).Two types of serialization
Data type serialization For example, numbers, strings, Vector2 instances fall into this category. These values are instantiated by
fromStateObject
.Reference type serialization For example, Nodes and Properties. For example, if a simulation has one
heightProperty
that exists for the lifetime of the sim then when we save the state of the sim, we save the dynamic characteristics of theheightProperty
(rather than trying to serialize the entire list of listeners and phet-io metadata. Then the PhET-iO library callssetValue()
to update the dynamic characteristics of theheightProperty
without dealing with all of Property's many attributes. The staticsetValue
methods on IO Types are automatically called by PhET-iO to restore dynamic characteristics of reference-type serialized instances. Search for toStateObject in *IO.js files for examples.Review and Publication
Happy instrumenting!
The text was updated successfully, but these errors were encountered: