Skip to content

Commit

Permalink
instrument holdConstantProperty only in relevant screens, make heatCo…
Browse files Browse the repository at this point in the history
…olFactorProperty readonly only in screens that have the Hold Constant feature, #30
  • Loading branch information
pixelzoom committed May 1, 2024
1 parent 2042cfa commit e9ba186
Show file tree
Hide file tree
Showing 13 changed files with 97 additions and 70 deletions.
13 changes: 7 additions & 6 deletions js/common/model/BaseModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ import optionize from '../../../../phet-core/js/optionize.js';
import ModelViewTransform2 from '../../../../phetcommon/js/view/ModelViewTransform2.js';
import Stopwatch from '../../../../scenery-phet/js/Stopwatch.js';
import TimeSpeed from '../../../../scenery-phet/js/TimeSpeed.js';
import Tandem from '../../../../tandem/js/Tandem.js';
import gasProperties from '../../gasProperties.js';
import GasPropertiesConstants from '../GasPropertiesConstants.js';
import TimeTransform from './TimeTransform.js';
import PickRequired from '../../../../phet-core/js/types/PickRequired.js';
import { PhetioObjectOptions } from '../../../../tandem/js/PhetioObject.js';

// constants
const MODEL_VIEW_SCALE = 0.040; // number of pixels per pm
Expand All @@ -41,7 +42,7 @@ type SelfOptions = {
stopwatchPosition?: Vector2;
};

export type BaseModelOptions = SelfOptions;
export type BaseModelOptions = SelfOptions & PickRequired<PhetioObjectOptions, 'tandem'>;

export default class BaseModel implements TModel {

Expand All @@ -64,7 +65,7 @@ export default class BaseModel implements TModel {

public readonly stopwatch: Stopwatch;

protected constructor( tandem: Tandem, providedOptions?: BaseModelOptions ) {
protected constructor( providedOptions: BaseModelOptions ) {

const options = optionize<BaseModelOptions, SelfOptions>()( {

Expand All @@ -87,11 +88,11 @@ export default class BaseModel implements TModel {
} );

this.isPlayingProperty = new BooleanProperty( true, {
tandem: tandem.createTandem( 'isPlayingProperty' )
tandem: options.tandem.createTandem( 'isPlayingProperty' )
} );

this.timeSpeedProperty = new EnumerationProperty( TimeSpeed.NORMAL, {
tandem: tandem.createTandem( 'timeSpeedProperty' )
tandem: options.tandem.createTandem( 'timeSpeedProperty' )
} );

this.timeTransform = TimeTransform.NORMAL;
Expand All @@ -107,7 +108,7 @@ export default class BaseModel implements TModel {
range: new Range( 0, GasPropertiesConstants.MAX_TIME ),
units: 'ps'
},
tandem: tandem.createTandem( 'stopwatch' )
tandem: options.tandem.createTandem( 'stopwatch' )
} );
}

Expand Down
42 changes: 26 additions & 16 deletions js/common/model/IdealGasLawModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,21 @@ import PressureModel from './PressureModel.js';
import TemperatureModel from './TemperatureModel.js';

type SelfOptions = {
leftWallDoesWork?: boolean; // does the container's left wall do work on particles?
holdConstant?: HoldConstant;

// Does the container's left wall do work on particles?
leftWallDoesWork?: boolean;

// Whether the screen has a collision counter.
hasCollisionCounter?: boolean;

// Whether the screen has the 'Hold Constant' feature.
hasHoldConstantFeature?: boolean;

// Initial value for holdConstantProperty.
holdConstant?: HoldConstant;
};

type IdealGasLawModelOptions = SelfOptions;
export type IdealGasLawModelOptions = SelfOptions & BaseModelOptions;

type OopsEmitters = {

Expand Down Expand Up @@ -99,54 +108,55 @@ export default class IdealGasLawModel extends BaseModel {
// named oopsEmitters.
public readonly oopsEmitters: OopsEmitters;

public constructor( tandem: Tandem, providedOptions?: IdealGasLawModelOptions ) {
public constructor( providedOptions: IdealGasLawModelOptions ) {

const options = optionize<IdealGasLawModelOptions, SelfOptions, BaseModelOptions>()( {

// SelfOptions
leftWallDoesWork: false,
holdConstant: 'nothing',
hasCollisionCounter: true
hasCollisionCounter: true,
hasHoldConstantFeature: false,
holdConstant: 'nothing'
}, providedOptions );

super( tandem );
super( options );

this.holdConstantProperty = new StringUnionProperty( options.holdConstant, {
validValues: HoldConstantValues,
tandem: tandem.createTandem( 'holdConstantProperty' ),
tandem: options.hasHoldConstantFeature ? options.tandem.createTandem( 'holdConstantProperty' ) : Tandem.OPT_OUT,
phetioReadOnly: true,
phetioDocumentation: 'Determines which quantity will be held constant.'
} );

this.heatCoolFactorProperty = new NumberProperty( 0, {
range: new Range( -1, 1 ),
tandem: tandem.createTandem( 'heatCoolFactorProperty' ),
phetioReadOnly: true,
tandem: options.tandem.createTandem( 'heatCoolFactorProperty' ),
phetioReadOnly: options.hasHoldConstantFeature, // With the Hold Constant feature, the sim animates this Property.
phetioDocumentation: 'Amount of heat or cool applied to particles in the container. ' +
'-1 is maximum cooling, +1 is maximum heat, 0 is off'
} );

this.particleParticleCollisionsEnabledProperty = new BooleanProperty( true, {
tandem: tandem.createTandem( 'particleParticleCollisionsEnabledProperty' ),
tandem: options.tandem.createTandem( 'particleParticleCollisionsEnabledProperty' ),
phetioDocumentation: 'Determines whether collisions between particles are enabled.'
} );

this.container = new IdealGasLawContainer( {
leftWallDoesWork: options.leftWallDoesWork,
tandem: tandem.createTandem( 'container' )
tandem: options.tandem.createTandem( 'container' )
} );

this.particleSystem = new ParticleSystem(
() => this.temperatureModel.getInitialTemperature(),
this.particleParticleCollisionsEnabledProperty,
this.container.particleEntryPosition,
tandem.createTandem( 'particleSystem' )
options.tandem.createTandem( 'particleSystem' )
);

this.temperatureModel = new TemperatureModel(
this.particleSystem.numberOfParticlesProperty, // N
() => this.particleSystem.getAverageKineticEnergy(), // KE
tandem.createTandem( 'temperatureModel' )
options.tandem.createTandem( 'temperatureModel' )
);

this.pressureModel = new PressureModel(
Expand All @@ -155,7 +165,7 @@ export default class IdealGasLawModel extends BaseModel {
this.container.volumeProperty, // V
this.temperatureModel.temperatureProperty, // T
() => { this.container.blowLidOff(); },
tandem.createTandem( 'pressureModel' )
options.tandem.createTandem( 'pressureModel' )
);

this.collisionDetector = new CollisionDetector(
Expand All @@ -168,7 +178,7 @@ export default class IdealGasLawModel extends BaseModel {
if ( options.hasCollisionCounter ) {
this.collisionCounter = new CollisionCounter( this.collisionDetector, {
position: new Vector2( 40, 15 ), // view coordinates! determined empirically
tandem: tandem.createTandem( 'collisionCounter' ),
tandem: options.tandem.createTandem( 'collisionCounter' ),
visible: true
} );
}
Expand Down
13 changes: 6 additions & 7 deletions js/common/view/BaseScreenView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ import optionize from '../../../../phet-core/js/optionize.js';
import { Node } from '../../../../scenery/js/imports.js';
import ResetAllButton from '../../../../scenery-phet/js/buttons/ResetAllButton.js';
import TimeControlNode from '../../../../scenery-phet/js/TimeControlNode.js';
import Tandem from '../../../../tandem/js/Tandem.js';
import gasProperties from '../../gasProperties.js';
import GasPropertiesColors from '../GasPropertiesColors.js';
import GasPropertiesConstants from '../GasPropertiesConstants.js';
import BaseModel from '../model/BaseModel.js';
import PickRequired from '../../../../phet-core/js/types/PickRequired.js';

type SelfOptions = {
hasSlowMotion?: boolean;
};

export type BaseScreenViewOptions = SelfOptions;
export type BaseScreenViewOptions = SelfOptions & PickRequired<ScreenViewOptions, 'tandem'>;

export default abstract class BaseScreenView extends ScreenView {

Expand All @@ -33,16 +33,15 @@ export default abstract class BaseScreenView extends ScreenView {
// subclass is responsible for pdomOrder
protected readonly resetAllButton: Node;

protected constructor( model: BaseModel, tandem: Tandem, providedOptions?: BaseScreenViewOptions ) {
protected constructor( model: BaseModel, providedOptions?: BaseScreenViewOptions ) {

const options = optionize<BaseScreenViewOptions, SelfOptions, ScreenViewOptions>()( {

// SelfOptions
hasSlowMotion: false,

// ScreenViewOptions
isDisposable: false,
tandem: tandem
isDisposable: false
}, providedOptions );

super( options );
Expand Down Expand Up @@ -77,7 +76,7 @@ export default abstract class BaseScreenView extends ScreenView {
}
}
},
tandem: tandem.createTandem( 'timeControlNode' ),
tandem: options.tandem.createTandem( 'timeControlNode' ),
phetioEnabledPropertyInstrumented: false // Controlled by the sim.
} );
this.addChild( this.timeControlNode );
Expand All @@ -87,7 +86,7 @@ export default abstract class BaseScreenView extends ScreenView {
listener: () => { this.reset(); },
right: this.layoutBounds.maxX - GasPropertiesConstants.SCREEN_VIEW_X_MARGIN,
bottom: this.layoutBounds.maxY - GasPropertiesConstants.SCREEN_VIEW_Y_MARGIN,
tandem: tandem.createTandem( 'resetAllButton' )
tandem: options.tandem.createTandem( 'resetAllButton' )
} );
this.addChild( this.resetAllButton );
}
Expand Down
23 changes: 11 additions & 12 deletions js/common/view/IdealGasLawScreenView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ export default class IdealGasLawScreenView extends BaseScreenView {
protected constructor( model: IdealGasLawModel,
particleTypeProperty: StringUnionProperty<ParticleType>,
widthVisibleProperty: Property<boolean>,
tandem: Tandem,
providedOptions?: IdealGasLawScreenViewOptions ) {

const options = optionize<IdealGasLawScreenViewOptions, SelfOptions, BaseScreenViewOptions>()( {
Expand All @@ -95,7 +94,7 @@ export default class IdealGasLawScreenView extends BaseScreenView {
oopsDialogsTandem: null
}, providedOptions );

super( model, tandem, options );
super( model, options );

const containerViewPosition = model.modelViewTransform.modelToViewPosition( model.container.position );

Expand Down Expand Up @@ -161,12 +160,12 @@ export default class IdealGasLawScreenView extends BaseScreenView {
model.holdConstantProperty, this.visibleBoundsProperty, {
resizeGripColor: options.resizeGripColor,
resizeHandleIsPressedListener: resizeHandleIsPressedListener,
tandem: tandem.createTandem( 'containerNode' )
tandem: options.tandem.createTandem( 'containerNode' )
} );

// Return Lid button
const returnLidButton = new ReturnLidButton( model.container, {
tandem: tandem.createTandem( 'returnLidButton' )
tandem: options.tandem.createTandem( 'returnLidButton' )
} );
returnLidButton.boundsProperty.link( bounds => {
returnLidButton.right = model.modelViewTransform.modelToViewX( model.container.right - model.container.openingRightInset ) - 30;
Expand All @@ -179,7 +178,7 @@ export default class IdealGasLawScreenView extends BaseScreenView {
visibleProperty: widthVisibleProperty
} );

const bicyclePumpNodeTandem = tandem.createTandem( 'bicyclePumpNode' );
const bicyclePumpNodeTandem = options.tandem.createTandem( 'bicyclePumpNode' );

// Radio buttons for selecting particle type
const particleTypeRadioButtonGroup = new ParticleTypeRadioButtonGroup( particleTypeProperty,
Expand Down Expand Up @@ -234,7 +233,7 @@ export default class IdealGasLawScreenView extends BaseScreenView {

// Thermometer
const thermometerNode = new GasPropertiesThermometerNode( model.temperatureModel.thermometer, thermometerListboxParent, {
tandem: tandem.createTandem( 'thermometerNode' )
tandem: options.tandem.createTandem( 'thermometerNode' )
} );
thermometerNode.boundsProperty.link( bounds => {
thermometerNode.centerX = containerNode.right - 50;
Expand All @@ -246,7 +245,7 @@ export default class IdealGasLawScreenView extends BaseScreenView {

// Pressure Gauge
const pressureGaugeNode = new PressureGaugeNode( model.pressureModel.pressureGauge, pressureGaugeListboxParent, {
tandem: tandem.createTandem( 'pressureGaugeNode' )
tandem: options.tandem.createTandem( 'pressureGaugeNode' )
} );
pressureGaugeNode.boundsProperty.link( bounds => {
pressureGaugeNode.left = containerNode.right - 2;
Expand Down Expand Up @@ -275,14 +274,14 @@ export default class IdealGasLawScreenView extends BaseScreenView {
model.temperatureModel.temperatureProperty, {
left: heaterCoolerNodeLeft,
bottom: this.layoutBounds.bottom - GasPropertiesConstants.SCREEN_VIEW_Y_MARGIN,
tandem: tandem.createTandem( 'heaterCoolerNode' )
tandem: options.tandem.createTandem( 'heaterCoolerNode' )
} );

// Button to erase all particles from container
const eraseParticlesButton = new EraseParticlesButton( model.particleSystem, {
right: containerNode.right,
top: containerWidthNode.bottom + 5,
tandem: tandem.createTandem( 'eraseParticlesButton' )
tandem: options.tandem.createTandem( 'eraseParticlesButton' )
} );

// Common parent for all tools, so we can move the selected tool to the front without affecting other things.
Expand All @@ -293,7 +292,7 @@ export default class IdealGasLawScreenView extends BaseScreenView {
if ( model.collisionCounter ) {
const collisionCounterListboxParent = new Node();
collisionCounterNode = new CollisionCounterNode( model.collisionCounter, collisionCounterListboxParent, this.visibleBoundsProperty, {
tandem: tandem.createTandem( 'collisionCounterNode' )
tandem: options.tandem.createTandem( 'collisionCounterNode' )
} );
toolsParent.addChild( collisionCounterNode );
toolsParent.addChild( collisionCounterListboxParent );
Expand All @@ -302,7 +301,7 @@ export default class IdealGasLawScreenView extends BaseScreenView {
// Stopwatch
const stopwatchNode = new GasPropertiesStopwatchNode( model.stopwatch, {
dragBoundsProperty: this.visibleBoundsProperty,
tandem: tandem.createTandem( 'stopwatchNode' )
tandem: options.tandem.createTandem( 'stopwatchNode' )
} );
toolsParent.addChild( stopwatchNode );

Expand Down Expand Up @@ -346,7 +345,7 @@ export default class IdealGasLawScreenView extends BaseScreenView {

// OopsDialog when maximum temperature is exceeded.
const oopsMaximumTemperatureDialog = new GasPropertiesOopsDialog( GasPropertiesStrings.oopsMaximumTemperatureStringProperty, {
tandem: ( options.oopsDialogsTandem || tandem ).createTandem( 'oopsMaximumTemperatureDialog' ),
tandem: ( options.oopsDialogsTandem || options.tandem ).createTandem( 'oopsMaximumTemperatureDialog' ),
phetioDocumentation: 'Displayed when the maximum Temperature is reached. To recover, all particles are removed. ' +
'If Hold Constant was set to anything other than None or Volume, it is set to None.'
} );
Expand Down
6 changes: 4 additions & 2 deletions js/diffusion/model/DiffusionModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,15 @@ export default class DiffusionModel extends BaseModel {

public constructor( tandem: Tandem ) {

super( tandem, {
super( {

// Offset of the model's origin, in view coordinates. Determines where the container's bottom-right corner is.
modelOriginOffset: new Vector2( 670, 520 ),

// Stopwatch initial position (in view coordinates!), determined empirically.
stopwatchPosition: new Vector2( 60, 50 )
stopwatchPosition: new Vector2( 60, 50 ),

tandem: tandem
} );

this.particles1 = [];
Expand Down
5 changes: 3 additions & 2 deletions js/diffusion/view/DiffusionScreenView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ export default class DiffusionScreenView extends BaseScreenView {

public constructor( model: DiffusionModel, tandem: Tandem ) {

super( model, tandem, {
hasSlowMotion: true // add Normal/Slow radio buttons to the time controls
super( model, {
hasSlowMotion: true, // add Normal/Slow radio buttons to the time controls
tandem: tandem
} );

const viewProperties = new DiffusionViewProperties( tandem.createTandem( 'viewProperties' ) );
Expand Down
5 changes: 3 additions & 2 deletions js/energy/model/EnergyModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ export default class EnergyModel extends IdealGasLawModel {

public constructor( tandem: Tandem ) {

super( tandem, {
super( {
holdConstant: 'volume',
hasCollisionCounter: false
hasCollisionCounter: false,
tandem: tandem
} );

// In case clients attempt to use this feature of the base class
Expand Down
4 changes: 3 additions & 1 deletion js/energy/view/EnergyScreenView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ export default class EnergyScreenView extends IdealGasLawScreenView {
// view-specific Properties
const viewProperties = new EnergyViewProperties( tandem.createTandem( 'viewProperties' ) );

super( model, viewProperties.particleTypeProperty, viewProperties.widthVisibleProperty, tandem );
super( model, viewProperties.particleTypeProperty, viewProperties.widthVisibleProperty, {
tandem: tandem
} );

// Group panels and accordion boxes in the Studio tree.
const panelsTandem = tandem.createTandem( 'panels' );
Expand Down
5 changes: 3 additions & 2 deletions js/explore/model/ExploreModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ export default class ExploreModel extends IdealGasLawModel {

public constructor( tandem: Tandem ) {

super( tandem, {
super( {
holdConstant: 'nothing',
leftWallDoesWork: true // moving the left wall does work on particles
leftWallDoesWork: true, // moving the left wall does work on particles
tandem: tandem
} );

// In case clients attempt to use this feature of the base class
Expand Down
Loading

0 comments on commit e9ba186

Please sign in to comment.