Skip to content

Commit

Permalink
Convert analysis to TypeScript, see #749
Browse files Browse the repository at this point in the history
  • Loading branch information
samreid committed Oct 15, 2021
1 parent 3014e74 commit 20768f3
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 95 deletions.
2 changes: 2 additions & 0 deletions js/model/CapacitorAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ class CapacitorAdapter extends DynamicCapacitor {
( typeof this.capacitorVoltageNode0 === 'number' || typeof this.capacitorVoltageNode0 === 'string' ) &&
( typeof this.capacitorVoltageNode1 === 'number' || typeof this.capacitorVoltageNode1 === 'string' ) ) {

// @ts-ignore
this.capacitor.mnaVoltageDrop = CCKCUtils.clampMagnitude( circuitResult.getFinalState().dynamicCircuitSolution.getNodeVoltage( this.capacitorVoltageNode1 )
// @ts-ignore
- circuitResult.getFinalState().dynamicCircuitSolution.getNodeVoltage( this.capacitorVoltageNode0 ) );
}

Expand Down
3 changes: 3 additions & 0 deletions js/model/CircuitResult.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class CircuitResult {
getTimeAverageCurrent( element: ModifiedNodalAnalysisCircuitElement | CapacitorAdapter | InductorAdapter ) {
let weightedSum = 0.0;
this.resultSet.states.forEach( stateObject => {
// @ts-ignore
weightedSum += stateObject.state.dynamicCircuitSolution.getCurrent( element ) * stateObject.dt;
} );
const number = weightedSum / this.resultSet.getTotalTime();
Expand All @@ -46,6 +47,7 @@ class CircuitResult {
* @public
*/
getInstantaneousCurrent( element: ModifiedNodalAnalysisCircuitElement ) {
// @ts-ignore
return this.getFinalState().dynamicCircuitSolution.getCurrent( element );
}

Expand All @@ -55,6 +57,7 @@ class CircuitResult {
* @public
*/
getInstantaneousVoltage( element: ModifiedNodalAnalysisCircuitElement ) {
// @ts-ignore
return this.getFinalState().dynamicCircuitSolution.getVoltage( element );
}

Expand Down
4 changes: 2 additions & 2 deletions js/model/DynamicCapacitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import DynamicElementState from './DynamicElementState.js';
class DynamicCapacitor {
dynamicCircuitCapacitor: DynamicCircuitCapacitor;
state: DynamicElementState;
capacitorVoltageNode0: number | null;
capacitorVoltageNode1: number | null;
capacitorVoltageNode0: string | number | null;
capacitorVoltageNode1: string | number | null;

/**
* @param {DynamicCircuit.Capacitor} dynamicCircuitCapacitor
Expand Down
50 changes: 32 additions & 18 deletions js/model/DynamicCircuit.js → js/model/DynamicCircuit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,25 @@ import DynamicState from './DynamicState.js';
import DynamicElementState from './DynamicElementState.js';
import DynamicInductor from './DynamicInductor.js';
import DynamicCapacitor from './DynamicCapacitor.js';
import ResistorAdapter from './ResistorAdapter.js';
import ResistiveBatteryAdapter from './ResistiveBatteryAdapter.js';
import CapacitorAdapter from './CapacitorAdapter.js';
import InductorAdapter from './InductorAdapter.js';
import ModifiedNodalAnalysisSolution from './ModifiedNodalAnalysisSolution';

class DynamicCircuit {
resistorAdapters: ResistorAdapter[];
resistiveBatteryAdapters: ResistiveBatteryAdapter[];
capacitorAdapters: CapacitorAdapter[];
inductorAdapters: InductorAdapter[];

/**
* @param {ResistorAdapter[]} resistorAdapters
* @param {ResistiveBatteryAdapter[]} resistiveBatteryAdapters
* @param {CapacitorAdapter[]} capacitorAdapters
* @param {InductorAdapter[]} inductorAdapters
*/
constructor( resistorAdapters, resistiveBatteryAdapters, capacitorAdapters, inductorAdapters ) {
constructor( resistorAdapters: ResistorAdapter[], resistiveBatteryAdapters: ResistiveBatteryAdapter[], capacitorAdapters: CapacitorAdapter[], inductorAdapters: InductorAdapter[] ) {

// @private
this.resistorAdapters = resistorAdapters;
Expand All @@ -45,11 +54,11 @@ class DynamicCircuit {
* @returns {DynamicCircuitSolution}
* @public
*/
solvePropagate( dt ) {
solvePropagate( dt: number ) {

const companionBatteries = []; // {ModifiedNodalAnalysisCircuitElement[]}
const companionResistors = []; // {ModifiedNodalAnalysisCircuitElement[]}
const currentCompanions = []; // {ModifiedNodalAnalysisCircuitElement[]}
const companionBatteries: ModifiedNodalAnalysisCircuitElement[] = [];
const companionResistors: ModifiedNodalAnalysisCircuitElement[] = [];
const currentCompanions: { element: any, getValueForSolution: any }[] = [];

// Node indices that have been used
let syntheticNodeIndex = 0;
Expand All @@ -67,7 +76,7 @@ class DynamicCircuit {
// We need to be able to get the current for this component
currentCompanions.push( {
element: resistiveBatteryAdapter,
getValueForSolution: solution => idealBattery.currentSolution
getValueForSolution: ( solution: ModifiedNodalAnalysisSolution ) => idealBattery.currentSolution
} );
} );

Expand Down Expand Up @@ -112,7 +121,7 @@ class DynamicCircuit {
// We need to be able to get the current for this component. In series, so the current is the same through both.
currentCompanions.push( {
element: capacitorAdapter,
getValueForSolution: solution => solution.getCurrentForResistor( resistor )
getValueForSolution: ( solution: ModifiedNodalAnalysisSolution ) => solution.getCurrentForResistor( resistor )
} );
} );

Expand All @@ -139,13 +148,13 @@ class DynamicCircuit {
// in series, so current is same through both companion components
currentCompanions.push( {
element: inductorAdapter,
getValueForSolution: solution => -solution.getCurrentForResistor( resistor )
getValueForSolution: ( solution: ModifiedNodalAnalysisSolution ) => -solution.getCurrentForResistor( resistor )
} );
} );

const newBatteryList = companionBatteries;
const newResistorList = [ ...this.resistorAdapters, ...companionResistors ];
const newCurrentList = []; // Placeholder for if we add other circuit elements in the future
const newCurrentList: ModifiedNodalAnalysisCircuitElement[] = []; // Placeholder for if we add other circuit elements in the future

const mnaCircuit = new ModifiedNodalAnalysisCircuit( newBatteryList, newResistorList, newCurrentList );

Expand All @@ -159,11 +168,13 @@ class DynamicCircuit {
* @returns {CircuitResult}
* @public
*/
solveWithSubdivisions( timestepSubdivisions, dt ) {
solveWithSubdivisions( timestepSubdivisions: TimestepSubdivisions<DynamicState>, dt: number ) {
CCKCUtils.clearAccumulatedSteps();
const steppable = {
update: ( a, dt ) => a.update( dt ),
distance: ( a, b ) => euclideanDistance( a.getCharacteristicArray(), b.getCharacteristicArray() )

// TODO: types
update: ( a: { update: ( arg0: any ) => any; }, dt: any ) => a.update( dt ),
distance: ( a: { getCharacteristicArray: () => number[]; }, b: { getCharacteristicArray: () => number[]; } ) => euclideanDistance( a.getCharacteristicArray(), b.getCharacteristicArray() )
};

// Turning the error threshold too low here can fail the inductor tests in MNATestCase
Expand All @@ -176,7 +187,7 @@ class DynamicCircuit {
* @returns {CircuitResult}
* @private
*/
solveWithSubdivisions2( dt ) {
solveWithSubdivisions2( dt: number ) {
return this.solveWithSubdivisions( new TimestepSubdivisions(), dt );
}

Expand All @@ -185,7 +196,7 @@ class DynamicCircuit {
* @returns {DynamicCircuit}
* @private
*/
updateWithSubdivisions( dt ) {
updateWithSubdivisions( dt: number ) {
return this.solveWithSubdivisions2( dt ).getFinalState().dynamicCircuit;
}

Expand All @@ -194,7 +205,7 @@ class DynamicCircuit {
* @returns {DynamicCircuitSolution}
* @public (unit-tests)
*/
solveItWithSubdivisions( dt ) {
solveItWithSubdivisions( dt: number ) {
return this.solveWithSubdivisions2( dt ).getFinalState().dynamicCircuitSolution;
}

Expand All @@ -203,7 +214,7 @@ class DynamicCircuit {
* @returns {DynamicCircuit}
* @public
*/
update( dt ) {
update( dt: number ) {
return this.updateCircuit( this.solvePropagate( dt ) );
}

Expand All @@ -214,9 +225,10 @@ class DynamicCircuit {
* @returns {DynamicCircuit}
* @public
*/
updateCircuit( solution ) {
updateCircuit( solution: DynamicCircuitSolution ) {
const updatedCapacitors = this.capacitorAdapters.map( capacitorAdapter => {
const newState = new DynamicElementState(
// @ts-ignore
solution.getNodeVoltage( capacitorAdapter.capacitorVoltageNode1 ) - solution.getNodeVoltage( capacitorAdapter.capacitorVoltageNode0 ),
solution.getCurrent( capacitorAdapter )
);
Expand All @@ -229,6 +241,8 @@ class DynamicCircuit {
);
return new DynamicInductor( inductorAdapter.dynamicCircuitInductor, newState );
} );

// @ts-ignore
return new DynamicCircuit( this.resistorAdapters, this.resistiveBatteryAdapters, updatedCapacitors, updatedInductors );
}
}
Expand All @@ -238,7 +252,7 @@ class DynamicCircuit {
* @param {number[]} y
* @returns {number}
*/
const euclideanDistance = ( x, y ) => {
const euclideanDistance = ( x: number[], y: number[] ) => {
assert && assert( x.length === y.length, 'Vector length mismatch' );
let sumSqDiffs = 0;
for ( let i = 0; i < x.length; i++ ) {
Expand Down
3 changes: 1 addition & 2 deletions js/model/DynamicCircuitCapacitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,4 @@ class DynamicCircuitCapacitor extends ModifiedNodalAnalysisCircuitElement {
}
}

export default DynamicCircuitCapacitor
;
export default DynamicCircuitCapacitor;
62 changes: 2 additions & 60 deletions js/model/ModifiedNodalAnalysisAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
* @author Sam Reid (PhET Interactive Simulations)
*/

import CCKCConstants from '../CCKCConstants.js';
import ResistiveBatteryAdapter from './ResistiveBatteryAdapter.js';
import ResistorAdapter from './ResistorAdapter.js';
import CapacitorAdapter from './CapacitorAdapter.js';
import InductorAdapter from './InductorAdapter.js';
import CCKCQueryParameters from '../CCKCQueryParameters.js';
Expand All @@ -17,75 +18,16 @@ import DynamicCircuit from './DynamicCircuit.js';
import Fuse from './Fuse.js';
import Inductor from './Inductor.js';
import LightBulb from './LightBulb.js';
import ModifiedNodalAnalysisCircuitElement from './ModifiedNodalAnalysisCircuitElement.js';
import Resistor from './Resistor.js';
import SeriesAmmeter from './SeriesAmmeter.js';
import Switch from './Switch.js';
import TimestepSubdivisions from './TimestepSubdivisions.js';
import VoltageSource from './VoltageSource.js';
import Wire from './Wire.js';
import DynamicCircuitResistiveBattery from './DynamicCircuitResistiveBattery.js';

// constants
const TIMESTEP_SUBDIVISIONS = new TimestepSubdivisions();

class ResistiveBatteryAdapter extends DynamicCircuitResistiveBattery {

/**
* @param {Circuit} circuit - the primary Circuit model instance, so we can look up Vertex indices
* @param {Battery} battery
*/
constructor( circuit, battery ) {
super(
battery.startVertexProperty.value.index,
battery.endVertexProperty.value.index,
battery.voltageProperty.value,
battery.internalResistanceProperty.value
);

// @public (read-only)
this.battery = battery;
}

/**
* @param {CircuitResult} circuitResult
* @public
*/
applySolution( circuitResult ) {
this.battery.currentProperty.value = circuitResult.getTimeAverageCurrent( this );
}
}

class ResistorAdapter extends ModifiedNodalAnalysisCircuitElement {

/**
* @param {Circuit} circuit
* @param {Resistor} resistor
*/
constructor( circuit, resistor ) {
super(
resistor.startVertexProperty.value.index,
resistor.endVertexProperty.value.index,
resistor,

// If a resistor goes to 0 resistance, then we cannot compute the current through as I=V/R. Therefore,
// simulate a small amount of resistance.
resistor.resistanceProperty.value || CCKCConstants.MINIMUM_RESISTANCE
);

// @private
this.resistor = resistor;
}

/**
* @param {CircuitResult} circuitResult
* @public
*/
applySolution( circuitResult ) {
this.resistor.currentProperty.value = circuitResult.getTimeAverageCurrent( this );
}
}

class ModifiedNodalAnalysisAdapter {

/**
Expand Down
34 changes: 34 additions & 0 deletions js/model/ResistiveBatteryAdapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import DynamicCircuitResistiveBattery from './DynamicCircuitResistiveBattery.js';
import Circuit from './Circuit.js';
import Battery from './Battery.js';
import CircuitResult from './CircuitResult.js';

class ResistiveBatteryAdapter extends DynamicCircuitResistiveBattery {
battery: Battery;

/**
* @param {Circuit} circuit - the primary Circuit model instance, so we can look up Vertex indices
* @param {Battery} battery
*/
constructor( circuit: Circuit, battery: Battery ) {
super(
battery.startVertexProperty.value.index,
battery.endVertexProperty.value.index,
battery.voltageProperty.value,
battery.internalResistanceProperty.value
);

// @public (read-only)
this.battery = battery;
}

/**
* @param {CircuitResult} circuitResult
* @public
*/
applySolution( circuitResult: CircuitResult ) {
this.battery.currentProperty.value = circuitResult.getTimeAverageCurrent( this );
}
}

export default ResistiveBatteryAdapter;
38 changes: 38 additions & 0 deletions js/model/ResistorAdapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import ModifiedNodalAnalysisCircuitElement from './ModifiedNodalAnalysisCircuitElement.js';
import CCKCConstants from '../CCKCConstants.js';
import Circuit from './Circuit.js';
import Resistor from './Resistor.js';
import CircuitResult from './CircuitResult.js';

class ResistorAdapter extends ModifiedNodalAnalysisCircuitElement {
resistor: Resistor;

/**
* @param {Circuit} circuit
* @param {Resistor} resistor
*/
constructor( circuit: Circuit, resistor: Resistor ) {
super(
resistor.startVertexProperty.value.index,
resistor.endVertexProperty.value.index,
resistor,

// If a resistor goes to 0 resistance, then we cannot compute the current through as I=V/R. Therefore,
// simulate a small amount of resistance.
resistor.resistanceProperty.value || CCKCConstants.MINIMUM_RESISTANCE
);

// @private
this.resistor = resistor;
}

/**
* @param {CircuitResult} circuitResult
* @public
*/
applySolution( circuitResult: CircuitResult ) {
this.resistor.currentProperty.value = circuitResult.getTimeAverageCurrent( this );
}
}

export default ResistorAdapter;
Loading

0 comments on commit 20768f3

Please sign in to comment.