Skip to content

Commit

Permalink
improve comments and code style, see #93
Browse files Browse the repository at this point in the history
  • Loading branch information
jbphet committed Feb 13, 2025
1 parent b179f22 commit a807a73
Show file tree
Hide file tree
Showing 17 changed files with 127 additions and 102 deletions.
2 changes: 0 additions & 2 deletions js/spin/model/BlockingMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ import quantumMeasurement from '../../quantumMeasurement.js';
export class BlockingMode extends EnumerationValue {

public static readonly NO_BLOCKER = new BlockingMode( 'noBlocker' );

public static readonly BLOCK_UP = new BlockingMode( 'blockingUp' );

public static readonly BLOCK_DOWN = new BlockingMode( 'blockingDown' );

public static readonly enumeration = new Enumeration( BlockingMode );
Expand Down
10 changes: 5 additions & 5 deletions js/spin/model/MeasurementDevice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,19 @@ export type MeasurementDeviceOptions = SelfOptions & AbstractBlochSphereOptions;

export default class MeasurementDevice {

// The bloch sphere representation of the spin state
// Bloch sphere representation of the spin state
public readonly simpleBlochSphere: AbstractBlochSphere;

// The spin state of the particle that last crossed the measurement line
// spin state of the particle that last crossed the measurement line
public readonly spinStateProperty: Vector2Property;

// The position of the device in the model
// position of the device in the model
public readonly positionProperty: Vector2Property;

// Emitter that informs that there has been a measurement
// emitter that fires when a measurement is made
public readonly measurementEmitter: Emitter;

// Flag to indicate if the line is active
// flag to indicate if the line is active
public readonly isActiveProperty: BooleanProperty;

public constructor( position: Vector2, originallyActive: boolean, providedOptions: MeasurementDeviceOptions ) {
Expand Down
1 change: 0 additions & 1 deletion js/spin/model/SimpleBlochSphere.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ export default class SimpleBlochSphere extends AbstractBlochSphere {

}


/**
* Abstract method that should run calculations to update the Bloch Sphere representation.
*/
Expand Down
8 changes: 3 additions & 5 deletions js/spin/model/SingleParticleCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@ import SpinModel from './SpinModel.js';

export class SingleParticleCollection extends ParticleCollection {

public constructor(
model: SpinModel,
maxParticles: number,
tandem: Tandem
) {
public constructor( model: SpinModel,
maxParticles: number,
tandem: Tandem ) {
super( model, maxParticles, tandem );
}

Expand Down
1 change: 0 additions & 1 deletion js/spin/model/SourceMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import QuantumMeasurementStrings from '../../QuantumMeasurementStrings.js';
export class SourceMode extends EnumerationValue {

public static readonly SINGLE = new SourceMode( QuantumMeasurementStrings.singleParticleStringProperty, 'singleParticle' );

public static readonly CONTINUOUS = new SourceMode( QuantumMeasurementStrings.continuousStringProperty, 'continuous' );

public static readonly enumeration = new Enumeration( SourceMode );
Expand Down
3 changes: 2 additions & 1 deletion js/spin/model/SpinDirection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ export class SpinDirection extends EnumerationValue {
}

public static spinToVector( spin: SpinDirection | null ): Vector2 {
// Since X_MINUS is not a valid initial state, we support null here to represent that case as a vector

// Since X_MINUS is not a valid initial state, we support null here to represent that case as a vector.
return spin === SpinDirection.Z_PLUS ? new Vector2( 0, 1 ) :
spin === SpinDirection.Z_MINUS ? new Vector2( 0, -1 ) :
spin === SpinDirection.X_PLUS ? new Vector2( 1, 0 ) : new Vector2( -1, 0 );
Expand Down
6 changes: 3 additions & 3 deletions js/spin/model/SpinExperiment.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// Copyright 2024-2025, University of Colorado Boulder

/**
* SpinExperiment contains the details for all posisble Stern-Gerlach configurations of the Spin Screen.
* SpinExperiment is an enumeration that contains the details for all possible Stern-Gerlach configurations used on the
* Spin Screen.
*
* @author Agustín Vallejo
*/
Expand All @@ -16,7 +17,6 @@ import quantumMeasurement from '../../quantumMeasurement.js';
import QuantumMeasurementStrings from '../../QuantumMeasurementStrings.js';
import { BlockingMode } from './BlockingMode.js';


type SternGerlachExperimentSetting = {
isZOriented: boolean;
};
Expand Down Expand Up @@ -63,7 +63,7 @@ export default class SpinExperiment extends EnumerationValue {

public readonly usingSingleApparatus: boolean;

// Wether the blocker is blocking the up or down exit, if applicable
// whether the blocker is blocking the up or down exit, if applicable
public readonly blockingModeProperty: Property<BlockingMode>;

public constructor(
Expand Down
23 changes: 13 additions & 10 deletions js/spin/model/SpinModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,7 @@ export default class SpinModel implements TModel {
tandem: providedOptions.tandem.createTandem( 'alphaSquaredProperty' )
} );

// Since both alpha and beta can be controlled via the slider
// they have to be derived manually from eachother below
// Since both alpha and beta can be controlled via the slider they must be derived manually.
this.betaSquaredProperty = new NumberProperty( 1 - this.alphaSquaredProperty.value );

this.currentExperimentProperty = new Property<SpinExperiment>( SpinExperiment.EXPERIMENT_1, {
Expand Down Expand Up @@ -279,7 +278,6 @@ export default class SpinModel implements TModel {
this.sternGerlachs[ index ].isZOrientedProperty.value = setting.isZOriented;
} );


// Set the probabilities of the experiment. In the continuous case, this immediately alters the shown rays
// In the single case, this prepares the probabilities for the particle that will be shot
this.prepare();
Expand All @@ -294,34 +292,39 @@ export default class SpinModel implements TModel {
}

public prepare(): void {
// Measure on the first SG, this will change its upProbabilityProperty

// Measure on the first SG, this will change its upProbabilityProperty.
this.sternGerlachs[ 0 ].updateProbability( this.derivedSpinStateProperty.value );

if ( !this.currentExperimentProperty.value.usingSingleApparatus ) {
// Measure on the second SG according to the orientation of the first one

// Measure on the second SG according to the orientation of the first one.
this.sternGerlachs[ 1 ].updateProbability(
// SG0 passes the up-spin particles to SG1

// SG0 passes the up-spin particles to SG1.
SpinDirection.spinToVector( this.sternGerlachs[ 0 ].isZOrientedProperty.value ? SpinDirection.Z_PLUS : SpinDirection.X_PLUS )
);

this.sternGerlachs[ 2 ].updateProbability(
// SG0 passes the down-spin particles to SG2, and because X- is not in the initial spin values, we pass null

// SG0 passes the down-spin particles to SG2, and because X- is not in the initial spin values, we pass null.
SpinDirection.spinToVector( this.sternGerlachs[ 0 ].isZOrientedProperty.value ? SpinDirection.Z_MINUS : null )
);

}
}

public step( dt: number ): void {
// Stepping the Stern Gerlachs so their counters average over time

// Step each of the Stern Gerlach devices so their counters average over time.
this.sternGerlachs.forEach( sternGerlach => sternGerlach.step( dt ) );

// Step the particle collections, which is how they move forward in time.
this.singleParticlesCollection.step( dt );
this.multipleParticlesCollection.step( dt );
}

/**
* Resets the model.
* Reset the model.
*/
public reset(): void {
this.measurementDevices.forEach( device => device.reset() );
Expand Down
7 changes: 4 additions & 3 deletions js/spin/model/SternGerlach.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ export default class SternGerlach extends PhetioObject {
// Position of the Stern Gerlach (SG) apparatus in the model coordinates
public readonly positionProperty: Vector2Property;

// Wether the SG measures in the Z or X direction
// Whether the SG measures in the Z or X direction
public readonly isZOrientedProperty: BooleanProperty;

// Wether the direction of the SG is controllable
// Whether the direction of the SG is controllable
public readonly isDirectionControllableProperty: BooleanProperty;

// Visibility of the SG apparatus
Expand Down Expand Up @@ -145,7 +145,7 @@ export default class SternGerlach extends PhetioObject {

}

// Updates the counters so they average properly
// Updates the counters so they average properly.
public step( dt: number ): void {
this.upCounterProperty.step( dt );
this.downCounterProperty.step( dt );
Expand All @@ -157,6 +157,7 @@ export default class SternGerlach extends PhetioObject {
* through the apparatus.
*/
public calculateProbability( incomingStateVector: Vector2 ): number {

// Using a XZ vector to calculate the projected probability.
// The experiment has a measurement vector and the incoming state has a spin vector
// Based on the dot product we'll obtain the probability
Expand Down
3 changes: 1 addition & 2 deletions js/spin/view/ManyParticlesCanvasNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@ export default class ManyParticlesCanvasNode extends CanvasNode {
}

/**
* Paints the grid lines on the canvas node.
* Paint the grid lines on the canvas node.
*/
public paintCanvas( context: CanvasRenderingContext2D ): void {

context.fillStyle = QuantumMeasurementColors.particleColorProperty.value.toCSS();
for ( let i = 0; i < this.particles.length; i++ ) {
const position = this.modelViewTransform.modelToViewPosition( this.particles[ i ].position );
Expand Down
9 changes: 5 additions & 4 deletions js/spin/view/MeasurementDeviceNode.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Copyright 2024-2025, University of Colorado Boulder

/**
* MeasurementDeviceNode contains the UI elements of the single particle measurement zone. It includes a simple bloch sphere,
* and a camera node which lights on trigger.
* MeasurementDeviceNode contains the UI elements of the single particle measurement zone. It includes a simple bloch
* sphere, and a camera node which lights on trigger.
*
* @author Agustín Vallejo
*/
Expand Down Expand Up @@ -33,7 +33,9 @@ export default class MeasurementDeviceNode extends VBox {

private readonly simpleBlochSphereNode: BlochSphereNode;

public constructor( measurementLine: MeasurementDevice, modelViewTransform: ModelViewTransform2, providedOptions: MeasurementDeviceNodeOptions ) {
public constructor( measurementLine: MeasurementDevice,
modelViewTransform: ModelViewTransform2,
providedOptions: MeasurementDeviceNodeOptions ) {

const simpleBlochSphereNode = new BlochSphereNode( measurementLine.simpleBlochSphere, {
tandem: Tandem.OPT_OUT,
Expand Down Expand Up @@ -71,7 +73,6 @@ export default class MeasurementDeviceNode extends VBox {
}, 500 );
} );


const options = optionize<MeasurementDeviceNodeOptions, SelfOptions, VBoxOptions>()( {
children: [
simpleBlochSphereNode,
Expand Down
65 changes: 40 additions & 25 deletions js/spin/view/ParticleSourceNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,41 +41,51 @@ export default class ParticleSourceNode extends Node {
modelViewTransform: ModelViewTransform2,
tandem: Tandem ) {

// Constants
// constants
const PARTICLE_SOURCE_WIDTH = modelViewTransform.modelToViewDeltaX( ParticleSourceModel.PARTICLE_SOURCE_WIDTH );
const PARTICLE_SOURCE_HEIGHT = modelViewTransform.modelToViewDeltaY( -ParticleSourceModel.PARTICLE_SOURCE_HEIGHT ); // Minus because of inverted Y
const PARTICLE_SOURCE_CORNER_RADIUS = modelViewTransform.modelToViewDeltaX( ParticleSourceModel.PARTICLE_SOURCE_CORNER_RADIUS );

// Main shape of the component
const particleSourceRectangle = new Path( new Shape()
.roundRect( 0, 0, PARTICLE_SOURCE_WIDTH, PARTICLE_SOURCE_HEIGHT, PARTICLE_SOURCE_CORNER_RADIUS, PARTICLE_SOURCE_CORNER_RADIUS ),
// main shape of the component
const particleSourceRectangle = new Path(
new Shape().roundRect(
0, 0, PARTICLE_SOURCE_WIDTH, PARTICLE_SOURCE_HEIGHT, PARTICLE_SOURCE_CORNER_RADIUS, PARTICLE_SOURCE_CORNER_RADIUS
),
{
stroke: 'black',
lineWidth: 0.5,
fill: new LinearGradient( 0, 0, 0, 100 )
.addColorStop( 0, '#88f' )
.addColorStop( 0.2, 'white' )
.addColorStop( 1, 'blue' )
} );
}
);

const particleSourceBarrelWidth = PARTICLE_SOURCE_WIDTH / 5;
const particleSourceBarrel = new Path( new Shape()
.roundRect( PARTICLE_SOURCE_WIDTH - particleSourceBarrelWidth / 2,
PARTICLE_SOURCE_HEIGHT / 2 - particleSourceBarrelWidth / 2, particleSourceBarrelWidth, particleSourceBarrelWidth, 4, 4 ),
const particleSourceBarrel = new Path(
new Shape().roundRect(
PARTICLE_SOURCE_WIDTH - particleSourceBarrelWidth / 2,
PARTICLE_SOURCE_HEIGHT / 2 - particleSourceBarrelWidth / 2,
particleSourceBarrelWidth,
particleSourceBarrelWidth,
4,
4
),
{
stroke: 'black',
lineWidth: 0.5,
fill: new LinearGradient( 0, 0, 0, PARTICLE_SOURCE_WIDTH / 10 )
.addColorStop( 0, '#88f' )
.addColorStop( 0.2, 'white' )
.addColorStop( 1, 'blue' )
} );
}
);
particleSourceBarrel.rotateAround( particleSourceBarrel.center, Math.PI / 4 );
particleSourceBarrel.center.y = particleSourceRectangle.center.y;

const currentlyShootingParticlesProperty = new BooleanProperty( false );

// Button for 'single' mode
// button for 'single' mode
const shootParticleButtonTandem = tandem.createTandem( 'shootParticleButton' );
const shootParticleButton = new RoundMomentaryButton<boolean>(
currentlyShootingParticlesProperty, false, true, {
Expand All @@ -84,15 +94,16 @@ export default class ParticleSourceNode extends Node {
visibleProperty: new GatedVisibleProperty( DerivedProperty.not( particleSourceModel.isContinuousModeProperty ), shootParticleButtonTandem ),
center: particleSourceRectangle.center,
tandem: shootParticleButtonTandem
} );
}
);

currentlyShootingParticlesProperty.link( shooting => {
if ( shooting ) {
singleParticlesCollection.shootSingleParticle();
}
} );

// Slider for 'continuous' mode
// slider for 'continuous' mode
const sliderRange = particleSourceModel.particleAmountProperty.range;
const particleAmountSliderTandem = tandem.createTandem( 'particleAmountSlider' );
const particleAmountSlider = new HSlider( particleSourceModel.particleAmountProperty, sliderRange, {
Expand Down Expand Up @@ -122,19 +133,23 @@ export default class ParticleSourceNode extends Node {

particleSourceApparatus.center = modelViewTransform.modelToViewPosition( particleSourceModel.positionProperty.value );

const sourceModeRadioButtonGroup = new AquaRadioButtonGroup( particleSourceModel.sourceModeProperty, SourceMode.enumeration.values.map( sourceMode => {
return {
value: sourceMode,
createNode: () => new Text( sourceMode.sourceName, { font: new PhetFont( 15 ), maxWidth: 150 } ),
options: {
accessibleName: sourceMode.sourceName
},
tandemName: `${sourceMode.tandemName}RadioButton`
};
} ), {
tandem: tandem.createTandem( 'sourceModeRadioButtonGroup' ),
spacing: SPACING
} );
const sourceModeRadioButtonGroup = new AquaRadioButtonGroup(
particleSourceModel.sourceModeProperty,
SourceMode.enumeration.values.map( sourceMode => {
return {
value: sourceMode,
createNode: () => new Text( sourceMode.sourceName, { font: new PhetFont( 15 ), maxWidth: 150 } ),
options: {
accessibleName: sourceMode.sourceName
},
tandemName: `${sourceMode.tandemName}RadioButton`
};
} ),
{
tandem: tandem.createTandem( 'sourceModeRadioButtonGroup' ),
spacing: SPACING
}
);
const sourceModeTitle = new RichText( QuantumMeasurementStrings.sourceModeStringProperty, {
font: new PhetFont( { size: 20, weight: 'bold' } ),
maxWidth: 200,
Expand Down
9 changes: 5 additions & 4 deletions js/spin/view/ParticleSprites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
* Understanding this implementation requires an understanding of the scenery Sprites API. In a nutshell: Sprites has an
* array of Sprite and an array of SpriteInstance. The array of Sprite is the complete unique set of images used to
* render all SpriteInstances. Each SpriteInstance has a reference to a Sprite (which determines what it looks like) and
* a Matrix3 (which determines how it's transformed). At each model step, the positions of the ParticleInstance instances
* are updated by adjusting their matrix, and then invalidatePaint is called to re-render the sprites.
* a Matrix3 (which determines how it's transformed). At each model step, the positions of the ParticleInstance
* instances are updated by adjusting their matrix, and then invalidatePaint is called to re-render the sprites.
*
* @author John Blanco (PhET Interactive Simulations)
*/
Expand All @@ -31,7 +31,7 @@ export default class ParticleSprites extends Sprites {
private readonly particles: ParticleWithSpin[];
private readonly modelViewTransform: ModelViewTransform2;

// The sprite used to render the particles
// the sprite used to render the particles
private particleSprite: Sprite | null = null;

public constructor( particles: ParticleWithSpin[], modelViewTransform: ModelViewTransform2, canvasBounds: Bounds2 ) {
Expand All @@ -51,7 +51,8 @@ export default class ParticleSprites extends Sprites {
new ShadedSphereNode( 15, {
mainColor: QuantumMeasurementColors.particleColorProperty,
highlightColor: 'white'
} ).toCanvas( ( canvas, x, y ) => {
} ).toCanvas( canvas => {

// Create the sprite that will be used to represent the particles.
particleSprite = new Sprite( new SpriteImage(
canvas,
Expand Down
Loading

0 comments on commit a807a73

Please sign in to comment.