Skip to content

Commit

Permalink
handle unpolarized setting in polarization angle indicators, see #52
Browse files Browse the repository at this point in the history
  • Loading branch information
jbphet committed Nov 13, 2024
1 parent 77cd994 commit a08b078
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 39 deletions.
1 change: 1 addition & 0 deletions js/QuantumMeasurementStrings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ type StringsType = {
'blochSphereStringProperty': LocalizedStringProperty;
'representationStringProperty': LocalizedStringProperty;
'unpolarizedStringProperty': LocalizedStringProperty;
'unknownProbabilitySymbolStringProperty': LocalizedStringProperty;
'zProjectionStringProperty': LocalizedStringProperty;
'xProjectionStringProperty': LocalizedStringProperty;
};
Expand Down
8 changes: 5 additions & 3 deletions js/photons/model/Laser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,10 @@ export default class Laser {
// The custom polarization angle for the emitted photons. This is only used when the preset direction is "custom".
public readonly customPolarizationAngleProperty: NumberProperty;

// The polarization angle that is used for emission. This is a derived - and thus read-only - property that is
// derived from the preset polarization direction and the custom polarization angle.
public readonly polarizationAngleProperty: TReadOnlyProperty<number>;
// The polarization angle of the emitted photons. This is a derived - and thus read-only - property that is
// derived from the preset polarization direction and the custom polarization angle. A value of null indicates that
// the emitted photons are unpolarized, meaining that their individual polarization angles are random.
public readonly polarizationAngleProperty: TReadOnlyProperty<number | null>;

// The set of photons that are used for emission. This is a reference to the same array that is used in the scene model.
private readonly photons: Photon[];
Expand Down Expand Up @@ -108,6 +109,7 @@ export default class Laser {
return presetPolarizationDirection === 'vertical' ? 90 :
presetPolarizationDirection === 'horizontal' ? 0 :
presetPolarizationDirection === 'fortyFiveDegrees' ? 45 :
presetPolarizationDirection === 'unpolarized' ? null :
customPolarizationAngle;
}
);
Expand Down
37 changes: 26 additions & 11 deletions js/photons/view/FlatPolarizationAngleIndicator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* @author John Blanco (PhET Interactive Simulations)
*/

import DerivedProperty from '../../../../axon/js/DerivedProperty.js';
import TReadOnlyProperty from '../../../../axon/js/TReadOnlyProperty.js';
import Bounds2 from '../../../../dot/js/Bounds2.js';
import Utils from '../../../../dot/js/Utils.js';
Expand Down Expand Up @@ -44,7 +45,7 @@ const UNIT_LENGTH = AXIS_LENGTH * 0.75;

export default class FlatPolarizationAngleIndicator extends Node {

public constructor( polarizationAngleProperty: TReadOnlyProperty<number>,
public constructor( polarizationAngleProperty: TReadOnlyProperty<number | null>,
providedOptions?: PolarizationPlaneRepresentationOptions ) {

// Create the vertical axis.
Expand All @@ -69,9 +70,17 @@ export default class FlatPolarizationAngleIndicator extends Node {
centerY: horizontalAxis.centerY
} );

// Create a Property for the fill used for the unit circle, since it changes when the photons are unpolarized.
const unitCircleFillProperty = new DerivedProperty(
[ polarizationAngleProperty ],
polarizationAngle => polarizationAngle === null ?
QuantumMeasurementColors.photonBaseColorProperty.value :
Color.LIGHT_GRAY
);

// Create a unit circle.
const unitCircle = new Circle( UNIT_LENGTH, {
fill: Color.GRAY,
fill: unitCircleFillProperty,
opacity: 0.3
} );

Expand Down Expand Up @@ -109,16 +118,22 @@ export default class FlatPolarizationAngleIndicator extends Node {
// Update the positions of the polarization vectors as the polarization angle changes.
polarizationAngleProperty.link( polarizationAngle => {

// Calculate the positions for the two ends of the polarization vector.
const polarizationVectorTipPosition = new Vector2(
Math.cos( -Utils.toRadians( polarizationAngle ) ),
Math.sin( -Utils.toRadians( polarizationAngle ) )
).times( UNIT_LENGTH );
const polarizationVectorTailPosition = polarizationVectorTipPosition.times( -1 );
// Only show the polarization vector if the angle is not null.
polarizationVectorNode.visible = polarizationAngle !== null;

if ( polarizationAngle !== null ) {

// Calculate the positions for the two ends of the polarization vector.
const polarizationVectorTipPosition = new Vector2(
Math.cos( -Utils.toRadians( polarizationAngle ) ),
Math.sin( -Utils.toRadians( polarizationAngle ) )
).times( UNIT_LENGTH );
const polarizationVectorTailPosition = polarizationVectorTipPosition.times( -1 );

// Project the vectors and set the tips of the arrows accordingly.
polarizationVectorNode.setTip( polarizationVectorTipPosition.x, polarizationVectorTipPosition.y );
polarizationVectorNode.setTail( polarizationVectorTailPosition.x, polarizationVectorTailPosition.y );
// Project the vectors and set the tips of the arrows accordingly.
polarizationVectorNode.setTip( polarizationVectorTipPosition.x, polarizationVectorTipPosition.y );
polarizationVectorNode.setTail( polarizationVectorTailPosition.x, polarizationVectorTailPosition.y );
}
} );
}
}
Expand Down
47 changes: 31 additions & 16 deletions js/photons/view/ObliquePolarizationAngleIndicator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* @author John Blanco (PhET Interactive Simulations)
*/

import DerivedProperty from '../../../../axon/js/DerivedProperty.js';
import TReadOnlyProperty from '../../../../axon/js/TReadOnlyProperty.js';
import Bounds2 from '../../../../dot/js/Bounds2.js';
import Utils from '../../../../dot/js/Utils.js';
Expand Down Expand Up @@ -69,7 +70,7 @@ const project3Dto2D = ( x: number, y: number, z: number ): Vector2 => {

export default class ObliquePolarizationAngleIndicator extends Node {

public constructor( polarizationAngleProperty: TReadOnlyProperty<number>,
public constructor( polarizationAngleProperty: TReadOnlyProperty<number | null>,
providedOptions?: PolarizationPlaneRepresentationOptions ) {

// Create the Y axis line with an arrow head. This is pointing directly to the right. We have to do this as a
Expand Down Expand Up @@ -114,6 +115,14 @@ export default class ObliquePolarizationAngleIndicator extends Node {
center: xAxisTipPosition.times( 1.4 )
} );

// Create a Property for the fill used for the unit circle, since it changes when the photons are unpolarized.
const unitCircleFillProperty = new DerivedProperty(
[ polarizationAngleProperty ],
polarizationAngle => polarizationAngle === null ?
QuantumMeasurementColors.photonBaseColorProperty.value :
Color.LIGHT_GRAY
);

// Create a unit circle that is projected into the x-z plane.
const numberOfPoints = 100;
const projectedStartingPoint = project3Dto2D( UNIT_LENGTH, 0, 0 );
Expand All @@ -128,7 +137,7 @@ export default class ObliquePolarizationAngleIndicator extends Node {
segmentedEllipseShape.lineToPoint( projectedStartingPoint );
segmentedEllipseShape.close();
const projectedXZUnitCircle = new Path( segmentedEllipseShape, {
fill: Color.GRAY,
fill: unitCircleFillProperty,
opacity: 0.3
} );

Expand All @@ -142,7 +151,7 @@ export default class ObliquePolarizationAngleIndicator extends Node {
fill: '#0f0',
doubleHead: true
};
const polarizationVector = new ArrowNode( 0, AXIS_LENGTH, 0, -AXIS_LENGTH, polarizationVectorOptions );
const polarizationVectorNode = new ArrowNode( 0, AXIS_LENGTH, 0, -AXIS_LENGTH, polarizationVectorOptions );

const options = optionize<PolarizationPlaneRepresentationOptions, SelfOptions, NodeOptions>()( {

Expand All @@ -155,7 +164,7 @@ export default class ObliquePolarizationAngleIndicator extends Node {
zAxis,
xAxisLabel,
zAxisLabel,
polarizationVector,
polarizationVectorNode,
yAxisArrowHead,
yAxisLine,
yAxisLabel
Expand All @@ -167,18 +176,24 @@ export default class ObliquePolarizationAngleIndicator extends Node {
// Update the positions of the polarization vectors as the polarization angle changes.
polarizationAngleProperty.link( polarizationAngle => {

// Calculate the position of the polarization unit vector in the x-z plane.
const polarizationVectorPlusInXZPlane = new Vector2(
Math.cos( -Utils.toRadians( polarizationAngle ) ),
Math.sin( -Utils.toRadians( polarizationAngle ) )
).times( UNIT_LENGTH );
const polarizationVectorMinusInXZPlane = polarizationVectorPlusInXZPlane.times( -1 );

// Project the vectors and set the tips of the arrows accordingly.
const tip = project3Dto2D( polarizationVectorPlusInXZPlane.x, 0, polarizationVectorPlusInXZPlane.y );
polarizationVector.setTip( tip.x, tip.y );
const tail = project3Dto2D( polarizationVectorMinusInXZPlane.x, 0, polarizationVectorMinusInXZPlane.y );
polarizationVector.setTail( tail.x, tail.y );
// Only show the polarization vector if the angle is not null.
polarizationVectorNode.visible = polarizationAngle !== null;

if ( polarizationAngle !== null ) {

// Calculate the position of the polarization unit vector in the x-z plane.
const polarizationVectorPlusInXZPlane = new Vector2(
Math.cos( -Utils.toRadians( polarizationAngle ) ),
Math.sin( -Utils.toRadians( polarizationAngle ) )
).times( UNIT_LENGTH );
const polarizationVectorMinusInXZPlane = polarizationVectorPlusInXZPlane.times( -1 );

// Project the vectors and set the tips of the arrows accordingly.
const tip = project3Dto2D( polarizationVectorPlusInXZPlane.x, 0, polarizationVectorPlusInXZPlane.y );
polarizationVectorNode.setTip( tip.x, tip.y );
const tail = project3Dto2D( polarizationVectorMinusInXZPlane.x, 0, polarizationVectorMinusInXZPlane.y );
polarizationVectorNode.setTail( tail.x, tail.y );
}
} );
}
}
Expand Down
30 changes: 21 additions & 9 deletions js/photons/view/PhotonDetectionProbabilityPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,26 @@ const BOLD_FONT = new PhetFont( { size: FONT_SIZE, weight: 'bold' } );

export default class PhotonDetectionProbabilityPanel extends Panel {

public constructor( polarizationAngleProperty: TReadOnlyProperty<number>,
public constructor( polarizationAngleProperty: TReadOnlyProperty<number | null>,
providedOptions: PhotonDetectionProbabilityPanelOptions ) {

const options = optionize<PhotonDetectionProbabilityPanelOptions, SelfOptions, PanelOptions>()( {
fill: QuantumMeasurementColors.screenBackgroundColorProperty,
stroke: null
}, providedOptions );

// Calculate the probability of a photon being detected as horizontally polarized.
// Calculate the probability of a photon being detected as horizontally polarized. A null value indicates that the
// probability is unknown.
const probabilityOfHorizontalProperty = new DerivedProperty(
[ polarizationAngleProperty ],
polarizationAngle => Math.cos( Utils.toRadians( polarizationAngle ) ) ** 2
polarizationAngle => polarizationAngle === null ? null : Math.cos( Utils.toRadians( polarizationAngle ) ) ** 2
);

// Calculate the probability of a photon being detected as vertically polarized.
// Calculate the probability of a photon being detected as vertically polarized. A null value indicates that the
// probability is unknown.
const probabilityOfVerticalProperty = new DerivedProperty(
[ probabilityOfHorizontalProperty ],
probabilityOfHorizontal => 1 - probabilityOfHorizontal
probabilityOfHorizontal => probabilityOfHorizontal === null ? null : 1 - probabilityOfHorizontal
);

// Create the string Properties that will be displayed in the panel.
Expand All @@ -54,21 +56,31 @@ export default class PhotonDetectionProbabilityPanel extends Panel {
probabilityOfHorizontalProperty,
QuantumMeasurementStrings.PStringProperty,
QuantumMeasurementStrings.HStringProperty,
QuantumMeasurementStrings.unknownProbabilitySymbolStringProperty,
QuantumMeasurementColors.horizontalPolarizationColorProperty
],
( probabilityOfHorizontal, pString, hString, horizontalColor ) => {
return `${pString}(${getColoredString( hString, horizontalColor )}) = ${Utils.toFixed( probabilityOfHorizontal, 2 )}`;
( probabilityOfHorizontal, pString, hString, unknownProbabilitySymbol, horizontalColor ) => {
const leftSide = `${pString}(${getColoredString( hString, horizontalColor )})`;
const rightSide = probabilityOfHorizontal === null ?
unknownProbabilitySymbol :
Utils.toFixed( probabilityOfHorizontal, 2 );
return `${leftSide} = ${rightSide}`;
}
);
const probabilityOfVerticalStringProperty = new DerivedProperty(
[
probabilityOfVerticalProperty,
QuantumMeasurementStrings.PStringProperty,
QuantumMeasurementStrings.VStringProperty,
QuantumMeasurementStrings.unknownProbabilitySymbolStringProperty,
QuantumMeasurementColors.verticalPolarizationColorProperty
],
( probabilityOfVertical, pString, vString, verticalColor ) => {
return `${pString}(${getColoredString( vString, verticalColor )}) = ${Utils.toFixed( probabilityOfVertical, 2 )}`;
( probabilityOfVertical, pString, vString, unknownProbabilitySymbol, verticalColor ) => {
const leftSide = `${pString}(${getColoredString( vString, verticalColor )})`;
const rightSide = probabilityOfVertical === null ?
unknownProbabilitySymbol :
Utils.toFixed( probabilityOfVertical, 2 );
return `${leftSide} = ${rightSide}`;
}
);

Expand Down
3 changes: 3 additions & 0 deletions quantum-measurement-strings_en.json
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@
"unpolarized": {
"value": "Unpolarized"
},
"unknownProbabilitySymbol": {
"value": "?"
},
"zProjection": {
"value": "Z Projection"
},
Expand Down

0 comments on commit a08b078

Please sign in to comment.