protected override void InternalInteract(ElectronBeam electronBeam)
		{
			if (this.HighVoltageSupplyOn.Value == 0)
			{
				this.HighVoltageSupplyMeasured.Value = 0;
				return;
			}

			// Increase/decrease measured high voltage with respect to time delta and gradient
			if (this.HighVoltageSupplyPreset.Value < this.HighVoltageSupplyMeasured.Value)
			{
				// Up gradient
				var voltage = this.HighVoltageSupplyMeasured.Value + (this.HighVoltageSupplyPreset.Value * HighVoltageGradient * this.LastInteractionTimeDelta);
				this.HighVoltageSupplyMeasured.Value = voltage <= this.HighVoltageSupplyPreset.Value ? this.HighVoltageSupplyPreset.Value : voltage;
			}
			else if (this.HighVoltageSupplyPreset.Value > this.HighVoltageSupplyMeasured.Value)
			{
				// Down gradient
				var voltage = this.HighVoltageSupplyMeasured.Value - ((-350E3 - this.HighVoltageSupplyPreset.Value) * HighVoltageGradient * this.LastInteractionTimeDelta);
				this.HighVoltageSupplyMeasured.Value = voltage >= this.HighVoltageSupplyPreset.Value ? this.HighVoltageSupplyPreset.Value : voltage;
			}

			// Calculating the new velocity of the accelerated electron beam using F=qE=mA & E=Volt/d & V^2=Vo^2+2Ax => V=Sqrt(2.q.Volt/m + Vo^2)
			var velocity = Math.Round(Math.Sqrt(Math.Pow(electronBeam.Velocity.Dz, 2) + (2 * Electron.Charge * -this.HighVoltageSupplyMeasured.Value / Electron.Mass)));
			
			// Electron beam density decreases as much as the beam speed increases thus keeping beam current constant
			// ToDo: Electron speed exceeds the speed of light in case of V = -350kV so something is wrong
			// electronBeam.ElectronDensity = Math.Round(electronBeam.ElectronDensity * (electronBeam.Velocity.Dz / velocity));
			// electronBeam.Velocity = new Velocity(0, 0, velocity);
		}
Exemple #2
0
		protected override void InternalInteract(ElectronBeam electronBeam)
		{
			// Using Joule heating equation to calculate filament temperature: I2.R.t = m.c.Delta(T) => Delta(T) = I2.R.t / m.c
			var tempDelta = (Math.Pow(this.CathodeCurrent.Value, 2) * FilamentResistivity * this.LastInteractionTimeDelta) / (FilamentMass * FilamentSpecificHeatCapacity);
			var newTemp = this.CathodeTemperature.Value + tempDelta;

			// Some of the heat is radiated away each second, proportionally to the current filament temperature and the cooling constant
			// Formula for cooling is T(t) = TA + (To - TA)e^(-kt) ; T(t) = temp delta, TA = ambient temperature, To = object's temperature @ t=0, k = positive constant (should be around 0.00351 water - 0.00481 tube weld)
			this.CathodeTemperature.Value = Parameters.AmbientTemperature + ((newTemp - Parameters.AmbientTemperature) * Math.Pow(Math.E, -1 * 0.00205 * this.LastInteractionTimeDelta));
			
			if (this.BeamOn.Value == 0)
			{
				// Beam is cut-off
				electronBeam.Velocity = new Velocity(0, 0, 0);
			}
			else
			{
				// ToDo: Calculating thermionic emission density using Richardson/Dushman equation
				electronBeam.ElectronDensity = this.CathodeTemperature.Value * 45E11;

				// Same as the drift tube (in meters)
				electronBeam.Radius = Parameters.DriftTubeRadius;

				// ToDO: This should actually use tugnsten metal's work function to calculate leaving electrons' intial velocity
				electronBeam.Velocity = new Velocity(0, 0, this.CathodeTemperature.Value * 3);

				// ToDo: Set 100V barrier to 77ns interval & 500ps lenght (also set the 100V bias control)
				// Uses X = v.t formula to calculate the lenght in meters
				electronBeam.Length = electronBeam.Velocity.Dz * 77E-9;
			}
		}
Exemple #3
0
		protected override void InternalInteract(ElectronBeam electronBeam)
		{
			if (this.In.Value == 1)
			{
				// Aperture cuts the beam radius down to the aperture size
				electronBeam.Radius = this.Radius.Value;
			}
		}
Exemple #4
0
		protected override void InternalInteract(ElectronBeam electronBeam)
		{
			if (this.Closed.Value == 1)
			{
				// Cut the beam if the valve is closed
				electronBeam.ElectronDensity = 0;
				//electronBeam.Velocity = new Velocity(0, 0, 0);
			}
		}
Exemple #5
0
		protected override void InternalInteract(ElectronBeam electronBeam)
		{
			if (this.CurrentOn.Value == 1)
			{
				// Focus the beam (narrow down the beam radius while increasing the density thus keeping electron flow constant)
				// Using solenoid focal lenght formula: 1/f = q^2/8Tm . Integral(Bz^2, dz) ; T=longitudinal kinetic energy, Bz=Field strength
				// ToDo: Now simply assuming f=25cm with 400G magnetic field @300keV beam energy or else calculating I->G->Bz/T->f will take ages
				electronBeam.Divergence = -(Math.PI * this.Current.Value) / (4 * 2E4);
			}
		}
		protected override void InternalInteract(ElectronBeam electronBeam)
		{
			// If the current is lower than that of the previous blm measurement by a predefined limit, there is a beam loss
			// ToDo: Below is a temporary solution, rather use previous beamLoss measurement & Parameters.BeamLossThreshold
			if (electronBeam.ElectronDensity == 0)
			{
				this.BeamLoss.Value = 1;
			}
			else
			{
				this.BeamLoss.Value = 0;
			}
		}
		protected override void InternalInteract(ElectronBeam electronBeam)
		{
			if (this.XCurrentOn.Value == 1)
			{
				// Steering magnet has no effect on drift velocity
				electronBeam.Velocity = new Velocity(electronBeam.Velocity.Dx + (this.XCurrent.Value * 5), electronBeam.Velocity.Dy, electronBeam.Velocity.Dz);
			}

			if (this.YCurrentOn.Value == 1)
			{
				electronBeam.Velocity = new Velocity(electronBeam.Velocity.Dx, electronBeam.Velocity.Dy + (this.YCurrent.Value * 5), electronBeam.Velocity.Dz);
			}
		}
		/// <summary>
		/// Initiates electron beam - components interactions where the electron beam may come out with a simple measurement
		/// or may be affected by the component in one way or the other.
		/// </summary>
		/// <param name="electronBeam">Electron beam going through the beam line components.</param>
		public void Interact(ElectronBeam electronBeam)
		{
			// Calculate the time delta (seconds) from forward movement (Z) distance and speed
			// This measures the time elapsed during the electron beam's travel from one component to the next
			var locationDelta = this.Location.Z - electronBeam.Location.Z;
			var timeDelta = locationDelta / electronBeam.Velocity.Dz;
			if (!double.IsNaN(timeDelta))
			{
				SimulatorTime += timeDelta;
			}
			
			this.LastInteractionTimeDelta = SimulatorTime - this.lastInteractionTime;

			/* 1 tick is 100 nanoseconds
			Stopwatch _stopwatch = Stopwatch.StartNew();
			DateTime highresDT = _starttime.AddTicks(_stopwatch.Elapsed.Ticks);
			Synchronization & last interaction time
			*/

			// Beam velocity and density fades away as the beam gets farther away from the source (0.05% per meter of distance)
			// ToDo: electronBeam.Velocity = new Velocity(electronBeam.Velocity.Dx, electronBeam.Velocity.Dy, electronBeam.Velocity.Dz - ??);
			electronBeam.ElectronDensity = electronBeam.ElectronDensity * (1 - (locationDelta / 2000));

			// Update beam radius with respect to beam divergence while keeping electron flow constant
			if (electronBeam.Divergence != 0)
			{
				var oldRadius = electronBeam.Radius;
				electronBeam.Radius += locationDelta * Math.Sin(electronBeam.Divergence);
				electronBeam.ElectronDensity = electronBeam.ElectronDensity * Math.Pow(oldRadius, 2) / Math.Pow(electronBeam.Radius, 2);
			}

			// Update beam location))
			if (!double.IsNaN(timeDelta))
			{
				electronBeam.Location = new Location(
					electronBeam.Location.X + (electronBeam.Velocity.Dx * timeDelta),
					electronBeam.Location.Y + (electronBeam.Velocity.Dy * timeDelta),
					this.Location.Z);
			}
			else
			{
				electronBeam.Location = new Location(electronBeam.Location.X, electronBeam.Location.Y, this.Location.Z);
			}

			// Component specific interactions
			this.InternalInteract(electronBeam);

			// Update last interaction time
			this.lastInteractionTime = SimulatorTime;
		}
		/// <summary>
		/// Takes measurements on the electron beam.
		/// </summary>
		/// <param name="electronBeam">Electron beam going through the beam position monitor.</param>
		protected override void InternalInteract(ElectronBeam electronBeam)
		{
			// Check to see if the beams are getting dangerously close to the drift tube walls and if so, correct the beam path
			this.XPosition.Value = electronBeam.Location.X - this.Location.X;
			if (this.xCurrent != null)
			{
				if (this.XPosition.Value >= Parameters.DesiredBeamPositionRange)
				{
					// Directly putting the current on value to prevent I/O overhead for checking if it is already on (which EPICS does already)
					this.xCurrentOn.Value = 1;
					this.xCurrent.Value += this.XPosition.Value * -2;
				}
				else if (this.XPosition.Value <= -Parameters.DesiredBeamPositionRange)
				{
					this.xCurrentOn.Value = 1;
					this.xCurrent.Value += this.XPosition.Value * -2;
				}
			}

			this.YPosition.Value = electronBeam.Location.Y - this.Location.Y;
			if (this.yCurrent != null)
			{
				if (this.YPosition.Value >= Parameters.DesiredBeamPositionRange)
				{
					// Directly putting the current on value to prevent I/O overhead for checking if it is already on (which EPICS does already)
					this.yCurrentOn.Value = 1;
					this.yCurrent.Value += this.YPosition.Value * -2;
				}
				else if (this.YPosition.Value <= -Parameters.DesiredBeamPositionRange)
				{
					this.yCurrentOn.Value = 1;
					this.yCurrent.Value += this.YPosition.Value * -2;
				}
			}

			// Calculate beam loss and make adjustments. If the beam path overflows, electron density drops to zero
			if (this.XPosition.Value >= Parameters.DriftTubeRadius || this.XPosition.Value <= -Parameters.DriftTubeRadius
			    || this.YPosition.Value >= Parameters.DriftTubeRadius || this.YPosition.Value <= -Parameters.DriftTubeRadius)
			{
				electronBeam.ElectronDensity = 0;
			}

			// Measure electron beam current using I=nAvQ (http://en.wikipedia.org/wiki/Electric_current#Drift_speed)
			this.Current.Value = electronBeam.ElectronDensity * (Math.PI * Math.Pow(electronBeam.Radius, 2)) * electronBeam.Velocity.Dz * Electron.Charge;
		}
Exemple #10
0
		protected override void InternalInteract(ElectronBeam electronBeam)
		{
			if (this.Pressure.Value <= DesiredPressure * this.vacuumRest)
			{
				this.On.Value = 0;
				this.vacuumRest = VacuumRestFactor;
				this.Pressure.Value += this.Pressure.Value * VacuumGradient * 0.1 * this.LastInteractionTimeDelta;
			}
			else if (this.Pressure.Value > CriticalPressure)
			{
				this.On.Value = 2;
				var pressure = this.Pressure.Value - (this.Pressure.Value * VacuumGradient * 2 * this.LastInteractionTimeDelta);
				this.Pressure.Value = pressure < DesiredPressure ? DesiredPressure : pressure;
			}
			else if (this.Pressure.Value > DesiredPressure * this.vacuumRest)
			{
				this.On.Value = 1;
				this.vacuumRest = 1;
				var pressure = this.Pressure.Value - (this.Pressure.Value * VacuumGradient * this.LastInteractionTimeDelta);
				this.Pressure.Value = pressure < DesiredPressure ? DesiredPressure : pressure;
			}
		}
		private void InternalInitiate(Action<double> simulatorTime)
		{
			// Optional 6 seconds of waittime (for proper initialization)
			// Thread.Sleep(6000);

			// Create the beam line and fill it with components
			this.BeamLine = new List<BeamLineComponent>
				{
					// ToDo: Appoint component numbers automatically via reflection
					new Cathode(1, new Location(0, 0, 0)),
					new HighVoltageSupply(1, new Location(0, 0, 10)),
					new Vacuum(1, new Location(0, 0, 15)),
					new SteeringMagnet(1, new Location(0, 0, 20)),
					new BeamPositionMonitor(1, new Location(0, 0, 30)),
					new BeamLossMonitor(1, new Location(0, 0, 31)),
					new Aperture(1, new Location(0, 0, 31)),
					new BeamProfileMonitor(1, new Location(0, 0, 32)),
					new GateValve(1, new Location(0, 0, 33)),
					new Solenoid(1, new Location(0, 0, 38)),
					new SteeringMagnet(2, new Location(0, 0, 40)),
					new BeamPositionMonitor(2, new Location(0, 0, 50)),
					new BeamLossMonitor(2, new Location(0, 0, 51)),
					new Aperture(2, new Location(0, 0, 51)),
					new BeamProfileMonitor(2, new Location(0, 0, 52)),
					new GateValve(2, new Location(0, 0, 53)),
					new Vacuum(2, new Location(0, 0, 55)),
					new Solenoid(2, new Location(0, 0, 58)),
					new SteeringMagnet(3, new Location(0, 0, 60)),
					new BeamPositionMonitor(3, new Location(0, 0, 70)),
					new BeamLossMonitor(3, new Location(0, 0, 71)),
					new Aperture(3, new Location(0, 0, 71)),
					new BeamProfileMonitor(3, new Location(0, 0, 72)),
					new GateValve(3, new Location(0, 0, 73)),
					new Vacuum(3, new Location(0, 0, 75)),
					new Solenoid(3, new Location(0, 0, 78)),
					new SteeringMagnet(4, new Location(0, 0, 80)),
					new BeamPositionMonitor(4, new Location(0, 0, 90)),
					new BeamLossMonitor(4, new Location(0, 0, 931)),
					new Aperture(4, new Location(0, 0, 91)),
					new BeamProfileMonitor(4, new Location(0, 0, 92)),
					new GateValve(4, new Location(0, 0, 93)),
					new Solenoid(4, new Location(0, 0, 98)),
					new SteeringMagnet(5, new Location(0, 0, 100)),
					new BeamPositionMonitor(5, new Location(0, 0, 110)),
					new BeamLossMonitor(5, new Location(0, 0, 110)),
					new BeamProfileMonitor(5, new Location(0, 0, 112)),
					new Solenoid(5, new Location(0, 0, 118))
				};

			this.ResolveLinks(this.BeamLine);

			// ToDo: Timer is better suited for this job! var timer = new Timer(o => {}, null, 0, 0);

			// Start sending electron beams through the beam line
			var componentCount = this.BeamLine.Count;
			while (true)
			{
				// If the simulator is terminated, break out of the loop
				if (this.simulatorTerminated)
				{
					BeamLineComponent.SimulatorTime = 0;
					break;
				}

				// Initially the electron beam is a null beam which gets shaped by the initial component on the beamline: the electron gun
				var electronBeam = new ElectronBeam();
				
				foreach (var beamLineComponent in this.BeamLine)
				{
					beamLineComponent.Interact(electronBeam);
				}

				// Update simulator time display after every beamline transversal
				simulatorTime(BeamLineComponent.SimulatorTime);
				Thread.Sleep(80);
			}
		}
		protected abstract void InternalInteract(ElectronBeam electronBeam);
		protected override void InternalInteract(ElectronBeam electronBeam)
		{
			if (this.CameraOn.Value == 1)
			{
				if (!this.stopwatch.IsRunning)
				{
					this.stopwatch.Start();
				}
				else if (this.ViewScreenIn.Value == 0)
				{
					// Serialize then publish the new beam profile image
					using (var stream = new MemoryStream())
					{
						this.bitmap = new Bitmap(ImageSide, ImageSide, PixelFormat.Format24bppRgb);
						this.bitmap.Save(stream, ImageFormat.Gif);
						this.Image.Value = Convert.ToBase64String(stream.ToArray());
						this.stopwatch.Restart();
					}
				}
				else if (this.stopwatch.ElapsedMilliseconds > 1000)
				{
					// Take a snapshot of the beam profile once every second
					this.bitmap = new Bitmap(ImageSide, ImageSide, PixelFormat.Format24bppRgb);
					this.beamImageRadius = (int)((electronBeam.Radius * ImageSide) / (Parameters.DriftTubeRadius * 2));
					this.beamImageDensity = (int)(10000 * electronBeam.ElectronDensity / 2E15);
					this.imageCenterXOffset = (int)(((electronBeam.Location.X - this.Location.X) * ImageSide) / (Parameters.DriftTubeRadius * 2));
					this.imageCenterYOffset = (int)(((electronBeam.Location.Y - this.Location.Y) * ImageSide) / (Parameters.DriftTubeRadius * 2));
					this.beamImageCenterXCoordinate = (ImageSide / 2) + this.imageCenterXOffset;
					this.beamImageCenterYCoordinate = (ImageSide / 2) + this.imageCenterYOffset;

					for (var i = 0; i < this.beamImageDensity; i++)
					{
						this.imageXCoordinate = this.random.Next(0, ImageSide);
						this.imageYCoordinate = this.random.Next(0, ImageSide);
						this.randomRadius = (int)
							Math.Sqrt(
								((this.imageXCoordinate - this.beamImageCenterXCoordinate) * (this.imageXCoordinate - this.beamImageCenterXCoordinate))
								+ ((this.imageYCoordinate - this.beamImageCenterYCoordinate) * (this.imageYCoordinate - this.beamImageCenterYCoordinate)));

						if (this.LaserOn.Value == 1 && this.randomRadius < 5)
						{
							this.bitmap.SetPixel(this.imageXCoordinate, this.imageYCoordinate, Color.Red);
						}
						else if (this.randomRadius < this.beamImageRadius)
						{
							// ToDo: Performance can be improved via LockBits method (http://www.bobpowell.net/lockingbits.htm)
							this.bitmap.SetPixel(this.imageXCoordinate, this.imageYCoordinate, Color.Blue);
						}
						else
						{
							if (++this.imageOverflowScatter > 15)
							{
								this.imageOverflowScatter = 0;
								this.bitmap.SetPixel(this.imageXCoordinate, this.imageYCoordinate, Color.Blue);
							}
						}
					}

					// Serialize then publish the new beam profile image
					using (var stream = new MemoryStream())
					{
						this.bitmap.Save(stream, ImageFormat.Gif);
						this.Image.Value = Convert.ToBase64String(stream.ToArray());
						this.stopwatch.Restart();
					}
				}
			}
			else
			{
				if (this.stopwatch.IsRunning)
				{
					this.stopwatch.Stop();
				}
			}
		}