Skip to content

Commit

Permalink
Improvements to precession and phetio fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
AgustinVallejo committed Jan 8, 2025
1 parent 18abaa9 commit a3c09d4
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 52 deletions.
18 changes: 16 additions & 2 deletions js/bloch-sphere/model/BlochSphereModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ export default class BlochSphereModel implements TModel {
// Time to measurement
public timeToMeasurementProperty: NumberProperty;

// Current time
public measurementTimeProperty: NumberProperty;

// Measurement basis
public measurementBasisProperty: Property<MeasurementBasis>;

Expand Down Expand Up @@ -120,14 +123,20 @@ export default class BlochSphereModel implements TModel {
range: new Range( 0, 1 )
} );

this.measurementTimeProperty = new NumberProperty( 0, {
tandem: providedOptions.tandem.createTandem( 'measurementTimeProperty' )
} );

this.measurementBasisProperty = new Property( MeasurementBasis.S_SUB_Z, {
tandem: providedOptions.tandem.createTandem( 'measurementBasisProperty' ),
phetioValueType: EnumerationIO( MeasurementBasis )
phetioValueType: EnumerationIO( MeasurementBasis ),
phetioFeatured: true
} );

this.isSingleMeasurementModeProperty = new BooleanProperty( true, {
tandem: providedOptions.tandem.createTandem( 'isSingleMeasurementModeProperty' ),
phetioReadOnly: true
phetioReadOnly: true,
phetioFeatured: true
} );

this.upMeasurementCountProperty = new NumberProperty( 0, {
Expand Down Expand Up @@ -264,6 +273,7 @@ export default class BlochSphereModel implements TModel {
this.magneticFieldStrengthProperty.reset();
this.measurementBasisProperty.reset();
this.isSingleMeasurementModeProperty.reset();
this.measurementTimeProperty.reset();
}

/**
Expand All @@ -275,6 +285,10 @@ export default class BlochSphereModel implements TModel {
this.multiMeasurementBlochSpheres.forEach( blochSphere => {
blochSphere.step( dt );
} );
if ( this.selectedSceneProperty.value === BlochSphereScene.PRECESSION ) {
this.measurementTimeProperty.value += dt;
this.measurementTimeProperty.value %= 2;
}
}
}

Expand Down
6 changes: 4 additions & 2 deletions js/bloch-sphere/model/ComplexBlochSphere.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import Utils from '../../../../dot/js/Utils.js';
import optionize from '../../../../phet-core/js/optionize.js';
import { PhetioObjectOptions } from '../../../../tandem/js/PhetioObject.js';
import AbstractBlochSphere, { AbstractBlochSphereOptions } from '../../common/model/AbstractBlochSphere.js';
import QuantumMeasurementConstants from '../../common/QuantumMeasurementConstants.js';
import quantumMeasurement from '../../quantumMeasurement.js';
import { MeasurementBasis } from './MeasurementBasis.js';
import { StateDirection } from './StateDirection.js';
Expand Down Expand Up @@ -46,11 +47,12 @@ export default class ComplexBlochSphere extends AbstractBlochSphere {


/**
* Abstract method that should run calculations to update the Bloch Sphere representation.
* Calculate precession and add it to azimuthal angle, constrained from 0 to 2 PI.
*/
public override step( dt: number ): void {
const precession = this.rotatingSpeedProperty.value * QuantumMeasurementConstants.MAX_PRECESSION_RATE * dt;
this.azimuthalAngleProperty.value = Utils.moduloBetweenDown(
this.azimuthalAngleProperty.value + this.rotatingSpeedProperty.value * dt, 0, 2 * Math.PI
this.azimuthalAngleProperty.value + precession, 0, 2 * Math.PI
);
}

Expand Down
36 changes: 22 additions & 14 deletions js/bloch-sphere/view/BlochSphereMeasurementArea.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import DerivedProperty from '../../../../axon/js/DerivedProperty.js';
import DerivedStringProperty from '../../../../axon/js/DerivedStringProperty.js';
import { EmptySelfOptions } from '../../../../phet-core/js/optionize.js';
import optionize, { EmptySelfOptions } from '../../../../phet-core/js/optionize.js';
import WithRequired from '../../../../phet-core/js/types/WithRequired.js';
import PhetFont from '../../../../scenery-phet/js/PhetFont.js';
import { Node, NodeOptions, RichText, RichTextOptions, Text, VBox } from '../../../../scenery/js/imports.js';
Expand Down Expand Up @@ -40,18 +40,14 @@ export default class BlochSphereMeasurementArea extends Node {

public constructor( model: BlochSphereModel, providedOptions: BlochSphereMeasurementAreaOptions ) {

super( providedOptions );

const equationNode = new BlochSphereNumericalEquationNode( model, {
tandem: providedOptions.tandem.createTandem( 'equationNode' ),
centerY: -50
} );
this.addChild( equationNode );

const magneticFieldNode = new MagneticFieldNode( model.magneticFieldStrengthProperty, {
visibleProperty: DerivedProperty.valueEqualsConstant( model.selectedSceneProperty, BlochSphereScene.PRECESSION )
} );
this.addChild( magneticFieldNode );

const singleMeasurementBlochSphereNode = new BlochSphereNode( model.singleMeasurementBlochSphere, {
tandem: providedOptions.tandem.createTandem( 'singleMeasurementBlochSphereNode' ),
Expand All @@ -61,7 +57,6 @@ export default class BlochSphereMeasurementArea extends Node {
center: magneticFieldNode.center,
visibleProperty: model.isSingleMeasurementModeProperty
} );
this.addChild( singleMeasurementBlochSphereNode );

const multipleMeasurementBlochSpheresTandem = providedOptions.tandem.createTandem( 'multipleMeasurementBlochSpheres' );
const multipleMeasurementBlochSpheresNode = new Node( {
Expand All @@ -81,7 +76,6 @@ export default class BlochSphereMeasurementArea extends Node {
multipleMeasurementBlochSpheresNode.addChild( blochSphereNode );
} );
multipleMeasurementBlochSpheresNode.center = magneticFieldNode.center.plusXY( 0, 30 );
this.addChild( multipleMeasurementBlochSpheresNode );

const spinUpLabelStringProperty = new DerivedStringProperty(
[ model.measurementBasisProperty ],
Expand All @@ -107,10 +101,14 @@ export default class BlochSphereMeasurementArea extends Node {
isSingleMeasurement => {
return {
createNode: () => new Text( isSingleMeasurement ? 'Single' : 'Multiple', { font: new PhetFont( 16 ) } ),
value: isSingleMeasurement
value: isSingleMeasurement,
tandemName: isSingleMeasurement ? 'singleMeasurementRadioButton' : 'multipleMeasurementRadioButton'
};
} );
const singleOrMultipleRadioButtonGroup = new AquaRadioButtonGroup( model.isSingleMeasurementModeProperty, radioButtonItems, { orientation: 'vertical' } );
const singleOrMultipleRadioButtonGroup = new AquaRadioButtonGroup( model.isSingleMeasurementModeProperty, radioButtonItems, {
orientation: 'vertical',
tandem: providedOptions.tandem.createTandem( 'singleOrMultipleRadioButtonGroup' )
} );

const basisRadioButtonTextOptions: RichTextOptions = {
font: new PhetFont( 18 ),
Expand Down Expand Up @@ -143,7 +141,7 @@ export default class BlochSphereMeasurementArea extends Node {
}
);

const measurementTimerControl = new MeasurementTimerControl( model.timeToMeasurementProperty, model.singleMeasurementBlochSphere.azimuthalAngleProperty, {
const measurementTimerControl = new MeasurementTimerControl( model.timeToMeasurementProperty, model.measurementTimeProperty, {
tandem: providedOptions.tandem.createTandem( 'measurementTimerControl' ),
visibleProperty: DerivedProperty.valueEqualsConstant( model.selectedSceneProperty, BlochSphereScene.PRECESSION )
} );
Expand Down Expand Up @@ -199,16 +197,26 @@ export default class BlochSphereMeasurementArea extends Node {
prepareObserveButton
]
} );
this.addChild( measurementControls );

this.addChild( new MagneticFieldControl( model.magneticFieldStrengthProperty, {
const magneticFieldControl = new MagneticFieldControl( model.magneticFieldStrengthProperty, {
centerX: singleMeasurementBlochSphereNode.centerX,
top: magneticFieldNode.bottom + 10,
visibleProperty: DerivedProperty.valueEqualsConstant( model.selectedSceneProperty, BlochSphereScene.PRECESSION ),
tandem: providedOptions.tandem.createTandem( 'magneticFieldControl' )
} ) );
} );

const options = optionize<BlochSphereMeasurementAreaOptions, SelfOptions, NodeOptions>()( {
children: [
equationNode,
magneticFieldNode,
singleMeasurementBlochSphereNode,
multipleMeasurementBlochSpheresNode,
measurementControls,
magneticFieldControl
]
}, providedOptions );

this.mutate( providedOptions );
super( options );

this.pdomOrder = [
measurementControlPanel,
Expand Down
42 changes: 8 additions & 34 deletions js/bloch-sphere/view/MeasurementTimerControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,35 +31,9 @@ export default class MeasurementTimerControl extends Node {

public constructor(
timeToMeasurementProperty: NumberProperty,
azimuthProperty: NumberProperty,
measurementTimeProperty: NumberProperty,
providedOptions: MeasurementTimerControlOptions
) {
//
// new Path( new Shape().moveTo( -SLIDER_TRACK_SIZE.width / 2, 0 ).lineTo( SLIDER_TRACK_SIZE.width / 2, 0 ), {
// stroke: 'grey',
// lineWidth: 1,
// lineDash: [ 2, 2 ]
// } );
//
// // Add horizontal lines to the magnetic field indicator.
// const numberOfIndicatorLines = 5;
// _.times( numberOfIndicatorLines, num => {
// const indicatorLine = new Line( -5, 0, 5, 0, {
// stroke: 'gray',
// centerY: -SLIDER_TRACK_SIZE.height / 2 + num * SLIDER_TRACK_SIZE.height / ( numberOfIndicatorLines - 1 )
// } );
// magneticFieldIndicator.addChild( indicatorLine );
// indicatorLine.moveToBack();
// } );
//
// const labeledMagneticFieldIndicator = new HBox( {
// children: [
// new Text( '0', { font: new PhetFont( 12 ) } ),
// magneticFieldIndicator
// ],
// spacing: 5,
// resize: false
// } );

const thumbOffset = 30;
const thumbDimensions = new Dimension2( 30, 30 );
Expand All @@ -84,17 +58,17 @@ export default class MeasurementTimerControl extends Node {
timeToMeasurementSlider.addMinorTick( 0.6 );
timeToMeasurementSlider.addMinorTick( 0.8 );

const azimuthIndicatorScale = 15;
const azimuthIndicator = new ArrowNode( 0, azimuthIndicatorScale, 0, 0, {
const timeIndicatorScale = 15;
const timeIndicator = new ArrowNode( 0, timeIndicatorScale, 0, 0, {
fill: 'magenta',
stroke: null,
headHeight: azimuthIndicatorScale,
headWidth: azimuthIndicatorScale,
headHeight: timeIndicatorScale,
headWidth: timeIndicatorScale,
tailWidth: 0
} );

azimuthProperty.link( azimuth => {
azimuthIndicator.centerX = azimuth / ( 2 * Math.PI ) * SLIDER_TRACK_SIZE.width;
measurementTimeProperty.link( measurementTime => {
timeIndicator.centerX = measurementTime / 2 * SLIDER_TRACK_SIZE.width;
} );

const thumbLine = new Path( new Shape().circle( 0, 0, 2 ).moveTo( 0, 0 ).lineTo( 0, thumbOffset - thumbDimensions.height / 2 ), {
Expand Down Expand Up @@ -136,7 +110,7 @@ export default class MeasurementTimerControl extends Node {

const options = optionize<MeasurementTimerControlOptions, SelfOptions, PanelOptions>()( {
children: [
azimuthIndicator,
timeIndicator,
timeToMeasurementSlider,
thumbLine,
measurementSymbol
Expand Down
2 changes: 2 additions & 0 deletions js/common/QuantumMeasurementConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ const QuantumMeasurementConstants = {
KET: '\u27e9',
HBAR: '\u210F',

MAX_PRECESSION_RATE: Math.PI, // radians per second

expectedPercentagePathOptions: {
stroke: '#0a0',
lineWidth: 5
Expand Down

0 comments on commit a3c09d4

Please sign in to comment.