Skip to content

Commit

Permalink
add system-under-test area to 4th screen, see #54
Browse files Browse the repository at this point in the history
  • Loading branch information
jbphet committed Jan 15, 2025
1 parent 5d3602d commit f94055d
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 55 deletions.
12 changes: 6 additions & 6 deletions js/bloch-sphere/model/BlochSphereModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const MAX_OBSERVATION_TIME = 2 * Math.PI / QuantumMeasurementConstants.MAX_PRECE

class BlochSphereModel implements TModel {

public readonly showMagneticFieldProperty: BooleanProperty;
public readonly magneticFieldEnabledProperty: BooleanProperty;

// Bloch Spheres shown in the screen
public readonly preparationBlochSphere: ComplexBlochSphere;
Expand Down Expand Up @@ -75,8 +75,8 @@ class BlochSphereModel implements TModel {

public constructor( providedOptions: QuantumMeasurementModelOptions ) {

this.showMagneticFieldProperty = new BooleanProperty( false, {
tandem: providedOptions.tandem.createTandem( 'showMagneticFieldProperty' ),
this.magneticFieldEnabledProperty = new BooleanProperty( false, {
tandem: providedOptions.tandem.createTandem( 'magneticFieldEnabledProperty' ),
phetioFeatured: true
} );

Expand Down Expand Up @@ -192,7 +192,7 @@ class BlochSphereModel implements TModel {

// Set the precession rate of the Bloch sphere based on the magnetic field strength and the selected scene.
Multilink.multilink(
[ this.magneticFieldStrengthProperty, this.showMagneticFieldProperty ],
[ this.magneticFieldStrengthProperty, this.magneticFieldEnabledProperty ],
( magneticFieldStrength, showMagneticField ) => {
this.singleMeasurementBlochSphere.rotatingSpeedProperty.value = showMagneticField ?
magneticFieldStrength :
Expand Down Expand Up @@ -267,7 +267,7 @@ class BlochSphereModel implements TModel {
'The model should be prepared for measurement prior to calling this method.'
);

if ( this.showMagneticFieldProperty.value ) {
if ( this.magneticFieldEnabledProperty.value ) {

// Transition to the state where the model is waiting to take a measurement.
this.measurementStateProperty.value = 'timingObservation';
Expand Down Expand Up @@ -316,7 +316,7 @@ class BlochSphereModel implements TModel {
public reset(): void {
this.resetCounts();
this.preparationBlochSphere.reset();
this.showMagneticFieldProperty.reset();
this.magneticFieldEnabledProperty.reset();
this.measurementStateProperty.reset();
this.magneticFieldStrengthProperty.reset();
this.measurementBasisProperty.reset();
Expand Down
66 changes: 47 additions & 19 deletions js/bloch-sphere/view/BlochSphereMeasurementArea.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
// Copyright 2025, University of Colorado Boulder

/**
* BlochSphereMeasurementArea is the node that contains the measurement area for the Bloch Sphere screen. It contains the
* UI elements for controlling magnetic field and basis of measurements...
* BlochSphereMeasurementArea is the node that contains the measurement area for the Bloch Sphere screen. It contains
* the UI elements for controlling various aspects of the measurement that is to be performed.
*
* @author Agustín Vallejo
* @author John Blanco (PhET Interactive Simulations)
*/

import DerivedProperty from '../../../../axon/js/DerivedProperty.js';
import DerivedStringProperty from '../../../../axon/js/DerivedStringProperty.js';
import Dimension2 from '../../../../dot/js/Dimension2.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';
import { HBox, Node, NodeOptions, RichText, RichTextOptions, Text, VBox } from '../../../../scenery/js/imports.js';
import AquaRadioButtonGroup from '../../../../sun/js/AquaRadioButtonGroup.js';
import RectangularRadioButtonGroup from '../../../../sun/js/buttons/RectangularRadioButtonGroup.js';
import TextPushButton from '../../../../sun/js/buttons/TextPushButton.js';
import Checkbox from '../../../../sun/js/Checkbox.js';
import Panel from '../../../../sun/js/Panel.js';
import QuantumMeasurementColors from '../../common/QuantumMeasurementColors.js';
import QuantumMeasurementConstants from '../../common/QuantumMeasurementConstants.js';
Expand All @@ -28,8 +30,8 @@ import BlochSphereModel from '../model/BlochSphereModel.js';
import { MeasurementBasis } from '../model/MeasurementBasis.js';
import BlochSphereNumericalEquationNode from './BlochSphereNumericalEquationNode.js';
import MagneticFieldControl from './MagneticFieldControl.js';
import MagneticFieldNode from './MagneticFieldNode.js';
import MeasurementTimerControl from './MeasurementTimerControl.js';
import SystemUnderTestNode from './SystemUnderTestNode.js';

type SelfOptions = EmptySelfOptions;

Expand All @@ -40,20 +42,16 @@ export default class BlochSphereMeasurementArea extends Node {
public constructor( model: BlochSphereModel, providedOptions: BlochSphereMeasurementAreaOptions ) {

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

const magneticFieldNode = new MagneticFieldNode( model.magneticFieldStrengthProperty, {
visibleProperty: model.showMagneticFieldProperty
tandem: providedOptions.tandem.createTandem( 'equationNode' )
} );

const singleMeasurementBlochSphereNode = new BlochSphereNode( model.singleMeasurementBlochSphere, {
tandem: providedOptions.tandem.createTandem( 'singleMeasurementBlochSphereNode' ),
drawTitle: false,
drawKets: false,
drawAngleIndicators: true,
center: magneticFieldNode.center,
top: equationNode.bottom + 50,
left: equationNode.left,
visibleProperty: model.isSingleMeasurementModeProperty
} );

Expand Down Expand Up @@ -83,7 +81,8 @@ export default class BlochSphereMeasurementArea extends Node {
currentRow++;
}
} );
multipleMeasurementBlochSpheresNode.center = magneticFieldNode.center.plusXY( 0, 30 );
multipleMeasurementBlochSpheresNode.centerX = singleMeasurementBlochSphereNode.centerX;
multipleMeasurementBlochSpheresNode.top = 70;

const spinUpLabelStringProperty = new DerivedStringProperty(
[ model.measurementBasisProperty ],
Expand Down Expand Up @@ -122,6 +121,7 @@ export default class BlochSphereMeasurementArea extends Node {
font: new PhetFont( 18 ),
fill: 'black'
};

// Create and add the radio buttons that select the chart type view in the nuclideChartAccordionBox.
const basisRadioButtonGroupTandem = providedOptions.tandem.createTandem( 'basisRadioButtonGroup' );

Expand Down Expand Up @@ -151,7 +151,7 @@ export default class BlochSphereMeasurementArea extends Node {

const measurementTimerControl = new MeasurementTimerControl( model.timeToMeasurementProperty, model.measurementTimeProperty, {
tandem: providedOptions.tandem.createTandem( 'measurementTimerControl' ),
visibleProperty: model.showMagneticFieldProperty
visibleProperty: model.magneticFieldEnabledProperty
} );

const measurementControlPanel = new Panel( new VBox( {
Expand Down Expand Up @@ -200,7 +200,7 @@ export default class BlochSphereMeasurementArea extends Node {

const measurementControls = new VBox( {
left: singleMeasurementBlochSphereNode.right + 20,
top: magneticFieldNode.top - 50,
top: equationNode.bottom + 10,
spacing: 10,
children: [
measurementResultHistogram,
Expand All @@ -209,21 +209,49 @@ export default class BlochSphereMeasurementArea extends Node {
]
} );

const magneticFieldCheckbox = new Checkbox(
model.magneticFieldEnabledProperty,
// TODO: This text should be localized, see https://github.com/phetsims/quantum-measurement/issues/54
new Text( 'Enable Magnetic Field', { font: new PhetFont( { size: 16 } ) } ),
{
spacing: 10,
centerX: multipleMeasurementBlochSpheresNode.centerX,
bottom: QuantumMeasurementConstants.LAYOUT_BOUNDS.bottom - 55,
tandem: providedOptions.tandem.createTandem( 'magneticFieldCheckbox' )
}
);

const magneticFieldControl = new MagneticFieldControl( model.magneticFieldStrengthProperty, {
centerX: singleMeasurementBlochSphereNode.centerX,
top: magneticFieldNode.bottom + 10,
visibleProperty: model.showMagneticFieldProperty,
visibleProperty: model.magneticFieldEnabledProperty,
tandem: providedOptions.tandem.createTandem( 'magneticFieldControl' )
} );

const systemUnderTestNode = new SystemUnderTestNode(
new Dimension2( 150, 180 ),
model.magneticFieldEnabledProperty,
model.magneticFieldStrengthProperty,
model.isSingleMeasurementModeProperty
);

const magneticFieldAndStrengthControl = new HBox( {
children: [ magneticFieldControl, systemUnderTestNode ],
spacing: 12,
centerX: singleMeasurementBlochSphereNode.centerX,
bottom: magneticFieldCheckbox.top - 20
} );

magneticFieldAndStrengthControl.localBoundsProperty.link( () => {
magneticFieldAndStrengthControl.centerX = singleMeasurementBlochSphereNode.centerX;
} );

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

Expand Down
25 changes: 6 additions & 19 deletions js/bloch-sphere/view/BlochSphereScreenView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,14 @@
*/

import BlochSphereModel from 'model/BlochSphereModel.js';
import PhetFont from '../../../../scenery-phet/js/PhetFont.js';
import { Color, Line, Text } from '../../../../scenery/js/imports.js';
import Checkbox from '../../../../sun/js/Checkbox.js';
import { Color, Line } from '../../../../scenery/js/imports.js';
import Tandem from '../../../../tandem/js/Tandem.js';
import QuantumMeasurementScreenView from '../../common/view/QuantumMeasurementScreenView.js';
import quantumMeasurement from '../../quantumMeasurement.js';
import BlochSphereMeasurementArea from './BlochSphereMeasurementArea.js';
import BlochSpherePreparationArea from './BlochSpherePreparationArea.js';

export default class BlochSphereScreenView extends QuantumMeasurementScreenView {
class BlochSphereScreenView extends QuantumMeasurementScreenView {

private readonly model: BlochSphereModel;

Expand All @@ -42,28 +40,15 @@ export default class BlochSphereScreenView extends QuantumMeasurementScreenView
} );
this.addChild( dividingLine );

const showMagneticFieldCheckbox = new Checkbox(
model.showMagneticFieldProperty,
new Text( 'Show Magnetic Field', { font: new PhetFont( { size: 16 } ) } ),
{
tandem: tandem.createTandem( 'showMagneticFieldCheckbox' ),
spacing: 10,
centerX: this.layoutBounds.centerX + 150,
top: this.layoutBounds.top + 20
} );
this.addChild( showMagneticFieldCheckbox );


const measurementArea = new BlochSphereMeasurementArea( model, {
tandem: tandem.createTandem( 'measurementArea' ),
left: dividingLineX + 20,
top: showMagneticFieldCheckbox.bottom + 20
top: this.layoutBounds.top + 40
} );
this.addChild( measurementArea );

this.pdomPlayAreaNode.pdomOrder = [
preparationArea,
showMagneticFieldCheckbox,
measurementArea
];

Expand All @@ -78,4 +63,6 @@ export default class BlochSphereScreenView extends QuantumMeasurementScreenView
}
}

quantumMeasurement.register( 'BlochSphereScreenView', BlochSphereScreenView );
quantumMeasurement.register( 'BlochSphereScreenView', BlochSphereScreenView );

export default BlochSphereScreenView;
2 changes: 1 addition & 1 deletion js/bloch-sphere/view/MagneticFieldControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default class MagneticFieldControl extends Panel {
fill: QuantumMeasurementColors.controlPanelFillColorProperty,
stroke: null,
xMargin: 10,
yMargin: 10
yMargin: 20
}, providedOptions );

const magneticFieldIndicator = new Node( {
Expand Down
27 changes: 17 additions & 10 deletions js/bloch-sphere/view/MagneticFieldNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,39 @@
*/

import NumberProperty from '../../../../axon/js/NumberProperty.js';
import Dimension2 from '../../../../dot/js/Dimension2.js';
import { combineOptions } from '../../../../phet-core/js/optionize.js';
import { Node, NodeOptions } from '../../../../scenery/js/imports.js';
import quantumMeasurement from '../../quantumMeasurement.js';
import MagneticFieldArrowNode from './MagneticFieldArrowNode.js';

export default class MagneticFieldNode extends Node {
const SIZE = new Dimension2( 150, 170 );

public constructor( magneticFieldStrength: NumberProperty, providedOptions: NodeOptions ) {
export default class MagneticFieldNode extends Node {

super( providedOptions );
public constructor( magneticFieldStrength: NumberProperty, providedOptions?: NodeOptions ) {

const columns = 8;
const rows = 7;
const separationX = 300 / columns;
const separationY = 300 / rows;
const columns = 5;
const rows = 5;
const separationX = SIZE.width / columns;
const separationY = SIZE.height / rows;
const arrowNodes: MagneticFieldArrowNode[] = [];

for ( let i = 0; i < columns; i++ ) {
for ( let j = 0; j < rows; j++ ) {
const magneticFieldArrowNode = new MagneticFieldArrowNode( magneticFieldStrength, 30 );
magneticFieldStrength.link( strength => {
const magneticFieldArrowNode = new MagneticFieldArrowNode( magneticFieldStrength, 20 );
magneticFieldStrength.link( () => {
magneticFieldArrowNode.centerX = i * separationX;
magneticFieldArrowNode.centerY = j * separationY;
} );

this.addChild( magneticFieldArrowNode );
arrowNodes.push( magneticFieldArrowNode );
}
}

const options = combineOptions<NodeOptions>( { children: arrowNodes }, providedOptions );

super( options );
}
}

Expand Down
Loading

0 comments on commit f94055d

Please sign in to comment.